mybatis

mybatis

1. what is mybatis

MyBatis 是一款優(yōu)秀的持久層框架,它支持定制化 SQL并思、存儲(chǔ)過程以及高級(jí)映射入偷。MyBatis 避免了幾乎所有的 JDBC 代碼和手動(dòng)設(shè)置參數(shù)以及獲取結(jié)果集。MyBatis 可以使用簡(jiǎn)單的 XML 或注解來配置和映射原生信息,將接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java對(duì)象)映射成數(shù)據(jù)庫(kù)中的記錄坐求。 

2. how to use mybatis

1. 編程式
要使用 MyBatis讼载, 只需將 mybatis-x.x.x.jar 文件置于 classpath 中即可。
<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>x.x.x</version>
</dependency>
2. 集成式
1. MyBatis-Spring
要使用 MyBatis-Spring 模塊,你只需要包含 mybatis-spring-x.x.x.jar 文 件就可以了,并在類路徑中加入相關(guān)的依賴
<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis-spring</artifactId>
  <version>x.x.x</version>
</dependency>
SqlSessionFactoryBean
MapperFactoryBean
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dataSource" />
  <property name="mapperLocations" value="classpath*:sample/config/mappers/**/*.xml" />
</bean>
一個(gè)使用 MyBatis-Spring 的主要原因是它允許 MyBatis 參與到 Spring 的事務(wù)管理中儒溉。而 不是給 MyBatis 創(chuàng)建一個(gè)新的特定的事務(wù)管理器,MyBatis-Spring 利用了存在于 Spring 中的 DataSourceTransactionManager宦焦。
一旦 Spring 的 PlatformTransactionManager 配置好了,你可以在 Spring 中以你通常的做 法來配置事務(wù)。@Transactional 注解和 AOP(Aspect-Oriented Program,面向切面編程,譯 者注)樣式的配置都是支持的顿涣。在事務(wù)處理期間,一個(gè)單獨(dú)的 SqlSession 對(duì)象將會(huì)被創(chuàng)建 和使用波闹。當(dāng)事務(wù)完成時(shí),這個(gè) session 會(huì)以合適的方式提交或回滾。
一旦事務(wù)創(chuàng)建之后,MyBatis-Spring 將會(huì)透明的管理事務(wù)涛碑。
<bean id="transactionManager"           class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource" />
</bean>
SqlSessionTemplate
SqlSessionTemplate 是 MyBatis-Spring 的核心精堕。 這個(gè)類負(fù)責(zé)管理 MyBatis 的 SqlSession, 調(diào)用 MyBatis 的 SQL 方法, 翻譯異常。 SqlSessionTemplate 是線程安全的, 可以被多個(gè) DAO 所共享使用蒲障。

<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
  <property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" />
  <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
MapperScannerConfigurer
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  <property name="basePackage" value="org.mybatis.spring.sample.mapper" />
</bean>
2. mybatis/spring-boot-starter
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.2</version>
</dependency>
@MapperScan("com.neo.mapper")
或者直接在Mapper類上面添加注解@Mapper
@ImportResource({"classpath:config/spring/spring_*.xml"})
mybatis.mapperLocations=classpath*:**/mappers/*.xml

3. mybatis framework

1. Resources
String resource = "file:///C:\\Users\\banma\\Desktop\\academy\\demo\\src\\main\\resources\\static\\pom.xml";
String resource = "https://maven.apache.org/what-is-maven.html";
InputStream inputStream = Resources.getUrlAsStream(resource);

String resource = "static/pom.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
2. Configuration
public class SqlSessionFactoryBuilder
public SqlSessionFactory build(Configuration config)
{new DefaultSqlSessionFactory(config);}
public class DefaultSqlSessionFactory implements SqlSessionFactory
public SqlSession openSession()
{return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);}

Configuration
Environment   environment  {id transactionFactory dataSource}
LocalCacheScope localCacheScope = LocalCacheScope.SESSION; //一級(jí)緩存  session 級(jí)別SESSION,STATEMENT
ExecutorType defaultExecutorType = ExecutorType.SIMPLE;//SIMPLE, REUSE, BATCH
reflectorFactory  // model
mapperRegistry  {config Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();} //class  factory interface 
mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection");
//xml node namespace collection
resultMaps = new StrictMap<ResultMap>("Result Maps collection");
parameterMaps = new StrictMap<ParameterMap>("Parameter Maps collection");
keyGenerators = new StrictMap<KeyGenerator>("Key Generators collection");
Set<String> loadedResources = new HashSet<String>();// xml namespace interface 
sqlFragments = new StrictMap<XNode>("XML fragments parsed from previous mappers");

interceptorChain = new InterceptorChain();
typeHandlerRegistry = new TypeHandlerRegistry();
typeAliasRegistry = new TypeAliasRegistry();
3. Connection
public interface javax.sql.DataSource  
Connection getConnection()
public interface java.sql.Connection    
java.sql.Statement connection.prepareStatement(sql, keyColumnNames)
public interface java.sql.PreparedStatement extends Statement   
4. SqlSession
Resources  InputStream
SqlSessionFactoryBuilder
SqlSessionFactory openSession()  DefaultSqlSessionFactory / SqlSessionManager
SqlSession    -> DefaultSqlSession    
ResultHandler -> DefaultMapResultHandler     
ResultContext -> DefaultResultContext
MapperRegistry   MapperProxyFactory
MappedStatement
MapperProxyFactory
TypeHandler   -> IntegerTypeHandler / BaseTypeHandler<Integer>   
Plugin
Executor        ExecutorType
Interceptor     InterceptorChain

SqlSession
public interface org.apache.ibatis.session.SqlSession extends Closeable 
// insert delete update select
// commit rollback  close 
// getConfiguration() getMapper() getConnection()
public class DefaultSqlSession implements SqlSession
configuration
executor

public interface org.apache.ibatis.executor.Executor
public abstract class BaseExecutor implements Executor
  protected Transaction transaction;
    protected Executor wrapper;
  protected Configuration configuration;
public class CachingExecutor implements Executor
  Executor delegate
  tcm = new TransactionalCacheManager();

public interface Transaction
  protected java.sql.Connection connection;
  protected javax.sql.DataSource dataSource;
  protected TransactionIsolationLevel level;    
5. Proxy
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
MapperProxyFactory
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
(T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
public class MapperProxyFactory<T>
  private final Class<T> mapperInterface;
      private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();
public class MapperProxy<T> implements InvocationHandler, Serializable
  private final SqlSession sqlSession;
      private final Class<T> mapperInterface;
      private final Map<Method, MapperMethod> methodCache;
  public Object invoke(Object proxy, Method method, Object[] args)

result = sqlSession.selectOne(command.getName(), param);
SimpleExecutor
DataSource
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
return resultSetHandler.<E> handleResultSets(ps);

4. source code

1. public class MapperMethod 
        private final SqlCommand command;
        private final MethodSignature method;
2. public enum SqlCommandType 
{  UNKNOWN, INSERT, UPDATE, DELETE, SELECT, FLUSH;}

5. issues

1. n+1 問題
n+1次查詢 懶加載 (部分緩解 ) 1+n 問題  join
查詢主數(shù)據(jù)歹篓,是1次查詢,查詢出n條記錄揉阎;根據(jù)這n條主記錄庄撮,查詢從記錄,共需要n次毙籽,所以叫數(shù)據(jù)庫(kù)1+n問題 

N+1 查詢問題”洞斯。概括地講,N+1 查詢問題可以是這樣引起的:
你執(zhí)行了一個(gè)單獨(dú)的 SQL 語句來獲取結(jié)果列表(就是“+1”)。
對(duì)返回的每條記錄,你執(zhí)行了一個(gè)查詢語句來為每個(gè)加載細(xì)節(jié)(就是“N”)坑赡。
這個(gè)問題會(huì)導(dǎo)致成百上千的 SQL 語句被執(zhí)行烙如。這通常不是期望的。
MyBatis 能延遲加載這樣的查詢就是一個(gè)好處,因此你可以分散這些語句同時(shí)運(yùn)行的消 耗毅否。然而,如果你加載一個(gè)列表,之后迅速迭代來訪問嵌套的數(shù)據(jù),你會(huì)調(diào)用所有的延遲加 載,這樣的行為可能是很糟糕的亚铁。
2. 結(jié)果嵌套 查詢嵌套
3. 緩存
一級(jí)緩存  二級(jí)緩存
Mybatis 使用到了兩種緩存:本地緩存(local cache)和二級(jí)緩存(second level cache)。
每當(dāng)一個(gè)新 session 被創(chuàng)建搀突,MyBatis 就會(huì)創(chuàng)建一個(gè)與之相關(guān)聯(lián)的本地緩存刀闷。任何在 session 執(zhí)行過的查詢語句本身都會(huì)被保存在本地緩存中熊泵,那么,相同的查詢語句和相同的參數(shù)所產(chǎn)生的更改就不會(huì)二度影響數(shù)據(jù)庫(kù)了甸昏。本地緩存會(huì)被增刪改顽分、提交事務(wù)、關(guān)閉事務(wù)以及關(guān)閉 session 所清空施蜜。
默認(rèn)情況下卒蘸,本地緩存數(shù)據(jù)可在整個(gè) session 的周期內(nèi)使用,這一緩存需要被用來解決循環(huán)引用錯(cuò)誤和加快重復(fù)嵌套查詢的速度翻默,所以它可以不被禁用掉缸沃,但是你可以設(shè)置 localCacheScope=STATEMENT 表示緩存僅在語句執(zhí)行時(shí)有效。
注意修械,如果 localCacheScope 被設(shè)置為 SESSION趾牧,那么 MyBatis 所返回的引用將傳遞給保存在本地緩存里的相同對(duì)象。對(duì)返回的對(duì)象(例如 list)做出任何更新將會(huì)影響本地緩存的內(nèi)容肯污,進(jìn)而影響存活在 session 生命周期中的緩存所返回的值翘单。因此,不要對(duì) MyBatis 所返回的對(duì)象作出更改蹦渣,以防后患哄芜。
MyBatis 包含一個(gè)非常強(qiáng)大的查詢緩存特性,它可以非常方便地配置和定制。MyBatis 3 中的緩存實(shí)現(xiàn)的很多改進(jìn)都已經(jīng)實(shí)現(xiàn)了,使得它更加強(qiáng)大而且易于配置柬唯。

默認(rèn)情況下是沒有開啟緩存的,除了局部的 session 緩存,可以增強(qiáng)變現(xiàn)而且處理循環(huán) 依賴也是必須的认臊。要開啟二級(jí)緩存,你需要在你的 SQL 映射文件中添加一行:
<cache/>
映射語句文件中的所有 select 語句將會(huì)被緩存。
映射語句文件中的所有 insert,update 和 delete 語句會(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)用者或線程所做的潛在修改师坎。
The cache will only apply to statements declared in the mapping file where the cache tag is located. If you are using the Java API in conjunction with the XML mapping files, then statements declared in the companion interface will not be cached by default. You will need to refer to the cache region using the @CacheNamespaceRef annotation.
4. # $
# 創(chuàng)建一個(gè)預(yù)處理語句參數(shù)
5. XML 映射文件 使用 Java 注解

命名空間(Namespaces)

6. 作用域(Scope)和生命周期
SqlSessionFactoryBuilder 方法作用域(也就是局部方法變量)
SqlSessionFactory  最佳作用域是應(yīng)用作用域。最簡(jiǎn)單的就是使用單例模式或者靜態(tài)單例模式
SqlSession    每個(gè)線程都應(yīng)該有它自己的 SqlSession 實(shí)例堪滨。SqlSession 的實(shí)例不是線程安全的,因此是不能被共享的蕊温,所以它的最佳的作用域是請(qǐng)求或方法作用域袱箱。
  如果你現(xiàn)在正在使用一種 Web 框架,要考慮 SqlSession 放在一個(gè)和 HTTP 請(qǐng)求對(duì)象相似的作用域中义矛。換句話說发笔,每次收到的 HTTP 請(qǐng)求,就可以打開一個(gè) SqlSession凉翻,返回一個(gè)響應(yīng)了讨,就關(guān)閉它。這個(gè)關(guān)閉操作是很重要的,你應(yīng)該把這個(gè)關(guān)閉操作放到 finally 塊中以確保每次都能執(zhí)行關(guān)閉前计。
映射器實(shí)例(Mapper Instances)
  映射器是一個(gè)你創(chuàng)建來綁定你映射的語句的接口胞谭。映射器接口的實(shí)例是從 SqlSession 中獲得的。因此從技術(shù)層面講男杈,任何映射器實(shí)例的最大作用域是和請(qǐng)求它們的 SqlSession 相同的丈屹。盡管如此,映射器實(shí)例的最佳作用域是方法作用域伶棒。也就是說旺垒,映射器實(shí)例應(yīng)該在調(diào)用它們的方法中被請(qǐng)求,用過之后即可廢棄肤无。并不需要顯式地關(guān)閉映射器實(shí)例先蒋,盡管在整個(gè)請(qǐng)求作用域(request scope)保持映射器實(shí)例也不會(huì)有什么問題,但是很快你會(huì)發(fā)現(xiàn)宛渐,像 SqlSession 一樣竞漾,在這個(gè)作用域上管理太多的資源的話會(huì)難于控制。所以要保持簡(jiǎn)單皇忿,最好把映射器放在方法作用域(method scope)內(nèi)畴蹭。
7. 動(dòng)態(tài) SQL
if
choose (when, otherwise)
trim (where, set)
foreach
bind
8. Java API
每個(gè)映射器方法簽名應(yīng)該匹配相關(guān)聯(lián)的 SqlSession 方法,而字符串參數(shù) ID 無需匹配鳍烁。相反叨襟,方法名必須匹配映射語句的 ID。 
此外幔荒,返回類型必須匹配期望的結(jié)果類型糊闽,單返回值時(shí)為所指定類的值,多返回值時(shí)為數(shù)組或集合爹梁。所有常用的類型都是支持的右犹,包括:原生類 型、Map姚垃、POJO 和 JavaBean

你可以傳遞多個(gè)參數(shù)給一個(gè)映射器方法念链。如果你這樣做了,默認(rèn)情況下它們將會(huì)以 "param" 字符串緊跟著它們?cè)趨?shù)列表中的位置來命名积糯,比如:#{param1}掂墓、#{param2}等。如果你想改變參數(shù)的名稱(只在多參數(shù)情況下)看成,那么你可以在參數(shù)上使用 @Param("paramName") 注解君编。

你也可以給方法傳遞一個(gè) RowBounds 實(shí)例來限制查詢結(jié)果。
9. 日志
<setting name="logImpl" value="LOG4J"/>
10. generator
<build>
        <plugins>
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.5</version>
                <dependencies>
                    <dependency>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                        <version>5.1.39</version>
                    </dependency>
                </dependencies>
                <configuration>
                <!--配置文件的路徑-->                <configurationFile>${basedir}/src/main/resources/generatorConfig.xml</configurationFile>
                <overwrite>true</overwrite>
            </configuration>
            </plugin>
        </plugins>
    </build>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末川慌,一起剝皮案震驚了整個(gè)濱河市吃嘿,隨后出現(xiàn)的幾起案子祠乃,更是在濱河造成了極大的恐慌,老刑警劉巖兑燥,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亮瓷,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡贪嫂,警方通過查閱死者的電腦和手機(jī)寺庄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來力崇,“玉大人斗塘,你說我怎么就攤上這事×裂ィ” “怎么了馍盟?”我有些...
    開封第一講書人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)茧吊。 經(jīng)常有香客問我贞岭,道長(zhǎng),這世上最難降的妖魔是什么搓侄? 我笑而不...
    開封第一講書人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任瞄桨,我火速辦了婚禮,結(jié)果婚禮上讶踪,老公的妹妹穿的比我還像新娘芯侥。我一直安慰自己,他們只是感情好乳讥,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開白布柱查。 她就那樣靜靜地躺著,像睡著了一般云石。 火紅的嫁衣襯著肌膚如雪唉工。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,079評(píng)論 1 285
  • 那天汹忠,我揣著相機(jī)與錄音淋硝,去河邊找鬼。 笑死宽菜,一個(gè)胖子當(dāng)著我的面吹牛奖地,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播赋焕,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼仰楚!你這毒婦竟也來了隆判?” 一聲冷哼從身側(cè)響起犬庇,我...
    開封第一講書人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎侨嘀,沒想到半個(gè)月后臭挽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡咬腕,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年欢峰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片涨共。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡纽帖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出举反,到底是詐尸還是另有隱情懊直,我是刑警寧澤,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布火鼻,位于F島的核電站室囊,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏魁索。R本人自食惡果不足惜融撞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望粗蔚。 院中可真熱鬧尝偎,春花似錦、人聲如沸支鸡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽牧挣。三九已至急前,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間瀑构,已是汗流浹背裆针。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留寺晌,地道東北人世吨。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像呻征,于是被迫代替她去往敵國(guó)和親耘婚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容