參考資料
執(zhí)行
加載mybatis配置周叮,創(chuàng)建sqlSessionFactory
public static void setUp() throws Exception {
Connection conn = null;
try {
Class.forName("org.hsqldb.jdbcDriver");
conn = DriverManager.getConnection("jdbc:hsqldb:mem:multidb", "sa", "");
Reader reader = Resources.getResourceAsReader("org/apache/ibatis/submitted/multidb/CreateDB.sql");
ScriptRunner runner = new ScriptRunner(conn);
runner.setLogWriter(null);
runner.setErrorLogWriter(null);
runner.runScript(reader);
conn.commit();
reader.close();
reader = Resources.getResourceAsReader("org/apache/ibatis/submitted/multidb/MultiDbConfig.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
reader.close();
} finally {
if (conn != null) {
conn.close();
}
}
}
- 以Mapper類執(zhí)行sql
SqlSession sqlSession = sqlSessionFactory.openSession();
MultiDbMapper mapper = sqlSession.getMapper(MultiDbMapper.class);
- 直接調(diào)用拨拓。
sqlSession.insert("org.apache.ibatis.submitted.selectkey.Table1.insert", parms);
sqlSession.select,update,delete
使用
基于xml和java注解的方式做映射庆尘。
這些屬性都是可外部配置且可動(dòng)態(tài)替換的,既可以在典型的 Java 屬性文件中配置,亦可通過 properties 元素的子元素來傳遞凌停。例如:
<properties resource="org/mybatis/example/config.properties">
<property name="username" value="dev_user"/>
<property name="password" value="F2Fa3!33TYyg"/>
</properties>
也可以把username和password 配置在config.properties文件中。
其中的屬性就可以在整個(gè)配置文件中使用來替換需要?jiǎng)討B(tài)配置的屬性值售滤。比如:
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
如果屬性在不只一個(gè)地方進(jìn)行了配置罚拟,那么 MyBatis 將按照下面的順序來加載:
- 在 properties 元素體內(nèi)指定的屬性首先被讀取。
- 然后根據(jù) properties 元素中的 resource 屬性讀取類路徑下屬性文件或根據(jù) url 屬性指定的路徑讀取屬性文件完箩,并覆蓋已讀取的同名屬性赐俗。
- 最后讀取作為方法參數(shù)傳遞的屬性,并覆蓋已讀取的同名屬性弊知。
因此阻逮,通過方法參數(shù)傳遞的屬性具有最高優(yōu)先級(jí),resource/url 屬性中指定的配置文件次之秩彤,最低優(yōu)先級(jí)的是 properties 屬性中指定的屬性叔扼。
sql重用(字符串替換)事哭,sql 包含(include)
<select id="select" resultType="map">
SELECT
${field_name}1, ${field_name}2, ${field_name}3
from
<include refid="sometable">
<property name="prefix" value="Some"/>
</include>
</select>
如上,字符串替換的 ${field_name} 需要配置在配置文件<configuration>的<properties>中:
<properties>
<property name="field_name" value="field"/>
</properties>
如上的 <include refid="sometable"> 需要卸載<sql>中瓜富,同時(shí)通過屬性prefix傳遞了值Some:
<sql id="sometable">
${prefix}Table
</sql>
參數(shù)
#{property,javaType=int,jdbcType=NUMERIC}
參數(shù)類型由javaType確定
如果 null 被當(dāng)作值來傳遞鳍咱,對(duì)于所有可能為空的列,jdbcType 是需要的
緩存
- 映射語(yǔ)句文件中的所有 select 語(yǔ)句將會(huì)被緩存与柑。
- 映射語(yǔ)句文件中的所有 insert,update 和 delete 語(yǔ)句會(huì)刷新緩存谤辜。
- 緩存會(huì)使用 Least Recently Used(LRU,最近最少使用的)算法來收回。
- 根據(jù)時(shí)間表(比如 no Flush Interval,沒有刷新間隔), 緩存不會(huì)以任何時(shí)間順序 來刷新价捧。
- 緩存會(huì)存儲(chǔ)列表集合或?qū)ο?無論查詢方法返回什么)的 1024 個(gè)引用丑念。
- 緩存會(huì)被視為是 read/write(可讀/可寫)的緩存,意味著對(duì)象檢索不是共享的,而 且可以安全地被調(diào)用者修改,而不干擾其他調(diào)用者或線程所做的潛在修改。
參考文章:
- MyBatis的緩存
-
深入了解MyBatis二級(jí)緩存
- 針對(duì)一個(gè)表的某些操作不在他獨(dú)立的namespace下進(jìn)行 ,不能用二級(jí)緩存干旧,否則會(huì)有臟數(shù)據(jù)
<cache
eviction="FIFO" // 緩存策略
flushInterval="60000" // 刷新間隔60秒
size="512" // 最大引用個(gè)數(shù)
readOnly="true"/>
寫在mapper里
<mapper namespace="org.apache.ibatis.submitted.cacheorder.Mapper">
<!--cache-ref 引用另一個(gè)mapper文件-->
<!--<cache-ref namespace="org.apache.ibatis.submitted.cacheorder.Mapper2"/>-->
<cache/>
<select id="getUser" resultType="org.apache.ibatis.submitted.cacheorder.User">
select * from users
</select>
</mapper>
自定義緩存測(cè)試:
@Test
public void testMyCache() {
System.out.println("---------select------------");
SqlSession session = sqlSessionFactory.openSession(true);
User user = session.selectOne("org.apache.ibatis.submitted.cacheorder.Mapper.getUser");
System.out.println(user);
session.commit();
// System.out.println("----------update----------");
// session = sqlSessionFactory.openSession(true);
// session.update("org.apache.ibatis.submitted.cacheorder.Mapper.update");
// session.commit();
System.out.println("--------select----------");
session = sqlSessionFactory.openSession(true);
User user2 = session.selectOne("org.apache.ibatis.submitted.cacheorder.Mapper.getUser");
System.out.println(user2);
session.commit();
}
public class MyCache implements Cache {
private ConcurrentHashMap<Object, Object> cache = new ConcurrentHashMap<>(10);
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private String id;
public MyCache(String id) {
this.id = id;
}
@Override
public String getId() {
System.out.println("getId = " + id);
return id;
}
@Override
public void putObject(Object key, Object value) {
System.out.println("put ["+key+"] value="+value);
cache.put(key, value);
}
@Override
public Object getObject(Object key) {
System.out.println("get objkey="+key+" "+cache.get(key));
return cache.get(key);
}
@Override
public Object removeObject(Object key) {
System.out.println("remove obj");
return cache.remove(key);
}
@Override
public void clear() {
cache.clear();
}
@Override
public synchronized int getSize() {
System.out.println("getsize");
return cache.size();
}
@Override
public ReadWriteLock getReadWriteLock() {
return lock;
}
}
配置
<cache type="org.apache.ibatis.submitted.cacheorder.MyCache"/>
我們一般會(huì)在自定義Cache里面使用Redis或者其他第三方存儲(chǔ)介質(zhì)來存數(shù)據(jù)渠欺。來提高性能,或統(tǒng)一管理椎眯。
mybatis緩存分為一級(jí)緩存和二級(jí)緩存
SqlSession commit或close之后挠将,二級(jí)緩存才會(huì)生效這個(gè)問題
二級(jí)緩存的作用域是全局的(跨session的)
一級(jí)緩存的作用域是一個(gè)session
緩存流程:
- 查詢數(shù)據(jù)的話,先從二級(jí)緩存中拿數(shù)據(jù)编整,如果沒有的話舔稀,去一級(jí)緩存中拿,一級(jí)緩存也沒有的話再查詢數(shù)據(jù)庫(kù)掌测。
- SqlSession commit或close之后内贮,二級(jí)緩存才會(huì)生效。
緩存執(zhí)行流程
DefaultSqlSession#selectList:
CachingExecutor#query: 獲取二級(jí)緩存汞斧,查二級(jí)緩存夜郁。查到直接返回
2.1 從TransactionalCache的entriesToAddOnCommit中找查不到則去父類BaseExecutor查:
3.1 查一級(jí)緩存(localCache 是PerpetualCache)。
3.2 一級(jí)緩存拿不到粘勒,數(shù)據(jù)庫(kù)拿竞端。
3.3 TransactionalCacheManager:事務(wù)緩存管理,將需要一個(gè)事務(wù)(session)的數(shù)據(jù)緩存在TransactionalCache中的
Map<Object, Object> entriesToAddOnCommit中庙睡。SqlSession commit或close之后 事富,調(diào)用flushPendingEntries方法將entriesToAddOnCommit中的緩存數(shù)據(jù)put到實(shí)現(xiàn)了Cache接口的緩存中(調(diào)用putObject)。所以二級(jí)緩存的作用域是全局的(跨session的)
4.1 刪除一級(jí)緩存clearLocalCache乘陪。即把PerpetualCache的mapper數(shù)據(jù)刪除统台。所以一級(jí)緩存的作用域是一個(gè)session
Cache接口采用裝飾者設(shè)計(jì)模式
動(dòng)態(tài)sql
<!-- 等效于 WHERE description LIKE concat('%',#{parameter},'%') _parameter表示輸入?yún)?shù) -->
<!-- 等效于 WHERE description LIKE '${'%' + _parameter + '%'}'-->
<select id="selectLike" resultType="map" parameterType="string">
<bind name="pattern" value="'%' + _parameter + '%'" />
SELECT *
FROM ibtest.names
WHERE description LIKE #{pattern}
ORDER BY id
</select>
<bind>的value值會(huì)使用OGNL計(jì)算。
注解
- @SelectKey 可以用來獲取自動(dòng)增長(zhǎng)的id的返回值啡邑,或者實(shí)現(xiàn)自動(dòng)增長(zhǎng)id