Spring整合MyBatis

MyBatis是一個(gè)半自動(dòng)的ORM框架,它要求開發(fā)者編寫具體的SQL語句平挑。
MyBatis解決的問題:
JDBC使用復(fù)雜艘策,需要操作Connection、Statement撕贞、ResultSet等對象更耻,并要處理異常、正確關(guān)閉資源等捏膨。
MyBatis是一種ORM模型秧均。ORM簡單來說就是數(shù)據(jù)庫表和JAVA對象相互映射

一.配置MyBatis

每個(gè)MyBatis的應(yīng)用程序都以一個(gè)SqlSessionFactory對象實(shí)例為核心食侮。這個(gè)對象由SqlSessionFactoryBuilder從XML配置文件或Configuration(?)類的實(shí)例中構(gòu)建SqlSessionFactory對象目胡。

1.1在Spring中配置MyBatis

  1. 將mybatis-spring依賴在pom.xml中引入

  2. 在Mybatis.xml配置dataSource锯七、sqlSessionFactory、MapperScannerConfigurer
    注:配置文件的名字可以自己起誉己,不一定是MyBatis.xml

dataSource:數(shù)據(jù)源眉尸,這個(gè)只要連接數(shù)據(jù)庫都要配置

sqlSessionFactory:注入數(shù)據(jù)源,配置文件巨双,sql映射文件掃描位置噪猾。注意mapperLocations屬性,用它說明sql映射文件的存儲位置筑累,不用再依次列出每個(gè)文件了袱蜡,新添加映射文件時(shí)也不用再做修改。

MapperScannerConfigurer:這是mybatis-spring提供的一個(gè)轉(zhuǎn)換器慢宗,可以將映射接口轉(zhuǎn)換為Spring容器中的Bean坪蚁,這就是為什么我們只定義了dao層接口并沒有實(shí)現(xiàn),卻可以在service層直接注入dao的原因镜沽。MapperScannerConfigure將掃描basePackage包下的所有接口迅细,如果它們在sql映射文件中定義過,則將它們動(dòng)態(tài)定義為一個(gè)Spring Bean淘邻。

下面是一個(gè)配置的具體例子:

<!-- 添加連接池則改變數(shù)據(jù)源 -->
    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${driver}" />
        <property name="url" value="${url}" />
        <property name="username" value="${username}" />
        <property name="password" value="${password}" />
    </bean>

    <!-- spring和MyBatis整合,不需要在mybatis的配置文件中寫每個(gè)entity的映射文件 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation" value="classpath:mybatis-config.xml"></property>
        <!-- 自動(dòng)掃描mapper.xml文件 -->
        <property name="mapperLocations" value="classpath:sqlmapper/*.xml"></property>
    </bean>

    <!-- mapper接口所在包名湘换,Spring會自動(dòng)查找其下的類 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="cn.edu.xidian.see.mapper" />
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
    </bean>

對于將映射接口宾舅,轉(zhuǎn)換為可以使用的實(shí)例,Spring還提供了SqlSessionTemplate彩倚,可以通過其getMapper(Class<T> type)來獲得一個(gè)實(shí)例筹我,通過這個(gè)實(shí)例即可調(diào)用sql映射文件定義的映射項(xiàng)。

二.使用MyBatis

使用MyBatis訪問數(shù)據(jù)庫可以分為三步:

  1. 定義Mapper映射接口(java接口)帆离。Sql映射文件通過namespace和Mapper接口一一對應(yīng)蔬蕊,每個(gè)select\update\insert等標(biāo)簽對應(yīng)一個(gè)接口中的方法。哥谷。
  2. 定義MyBatis Sql映射文件岸夯。ResultMap,動(dòng)態(tài)SQL
  3. 在Service層等調(diào)用處们妥,注入Java接口猜扮。因?yàn)镸apperScannerConfigurer已經(jīng)將接口映射為Spring Bean實(shí)例,可以直接使用Autowire注入Dao监婶。

sql映射文件中的動(dòng)態(tài)SQL一般用于拼接SQL語句旅赢,主要有一下幾種

  1. <if>
<select id="selectUserByUsernameAndSex" resultType="user" parameterType="com.ys.po.User">
    select * from user where
        <if test="username != null">
           username=#{username}
        </if>
         
        <if test="sex!= null">
           and sex=#{sex}
        </if>
</select>
  1. <if> + <where>
    上述<if>的例子中齿桃,如果username==null,sex!=null煮盼,就會拼接出錯(cuò)誤的sql語句短纵。將條件放入where標(biāo)簽中,它將去掉多余的and僵控,如果返回的內(nèi)容為空的話香到,它也不會插入‘where’
<select id="selectUserByUsernameAndSex" resultType="user" parameterType="com.ys.po.User">
    select * from user
<where>
        <if test="username != null">
           username=#{username}
        </if>
         
        <if test="sex!= null">
           and sex=#{sex}
        </if>
</where>
</select>

3.適用于update語句的<set> <if>組合
如果需求是:根據(jù)屬性是否為null來決定是否更新字段那么,可以用此組合喉祭。
如果有多余的“养渴,”set標(biāo)簽會刪除掉

<update id="updateUserById" parameterType="com.ys.po.User">
    update user u
        <set>
            <if test="username != null and username != ''">
                u.username = #{username},
            </if>
            <if test="sex != null and sex != ''">
                u.sex = #{sex}
            </if>
        </set>
     
     where id=#{id}
</update>

4.choose(when,otherwise)語句
依次判斷when的條件,當(dāng)有一個(gè)滿足時(shí)泛烙,結(jié)束判斷理卑,當(dāng)都不滿足是使用otherwise中的語句。

<select id="selectUserByChoose" resultType="com.ys.po.User" parameterType="com.ys.po.User">
      select * from user
      <where>
          <choose>
              <when test="id !='' and id != null">
                  id=#{id}
              </when>
              <when test="username !='' and username != null">
                  and username=#{username}
              </when>
              <otherwise>
                  and sex=#{sex}
              </otherwise>
          </choose>
      </where>
  </select>

5.trim語句
可以實(shí)現(xiàn)where或set的功能蔽氨,是更一般化的標(biāo)簽藐唠,可以指定開頭(prefix)、結(jié)尾(suffix)鹉究、開頭處的多余字符(prefixOverrides)宇立、結(jié)尾處的多余字符(suffixOverrides)

<select id="selectUserByUsernameAndSex" resultType="user" parameterType="com.ys.po.User">
        select * from user
        <trim prefix="where" prefixOverrides="and | or">
            <if test="username != null">
               and username=#{username}
            </if>
            <if test="sex != null">
               and sex=#{sex}
            </if>
        </trim>
    </select>
   <update id="updateUserById" parameterType="com.ys.po.User">
        update user u
            <trim prefix="set" suffixOverrides=",">
                <if test="username != null and username != ''">
                    u.username = #{username},
                </if>
                <if test="sex != null and sex != ''">
                    u.sex = #{sex},
                </if>
            </trim>
         
         where id=#{id}
    </update>

6.foreach語句
實(shí)現(xiàn)遍歷list。

<select id="selectUserByListId" parameterType="com.ys.vo.UserVo" resultType="com.ys.po.User">
        select * from user
        <where>
            <!--
                collection:指定輸入對象中的集合屬性
                item:每次遍歷生成的對象
                open:開始遍歷時(shí)的拼接字符串
                close:結(jié)束時(shí)拼接的字符串
                separator:遍歷對象之間需要拼接的字符串
                select * from user where 1=1 and id in (1,2,3)
              -->
            <foreach collection="ids" item="id" open="and id in (" close=") " separator=",">
                #{id}
            </foreach>
        </where>
    </select>

三.MyBatis運(yùn)行原理

MyBatis的核心組件:
SqlSessionFactoryBuilder:生成SqlSessionFactory
SqlSessionFactory:生成SqlSession
SqlSession:發(fā)送SQL去執(zhí)行自赔,并返回結(jié)果

MyBatis的運(yùn)行包括兩部分:一妈嘹。讀取配置文件,構(gòu)建SqlSessionFactory對象绍妨。二润脸。SqlSession的執(zhí)行過程。以下分析較為復(fù)雜的第二部分他去。

先看一個(gè)問題:使用MyBatis時(shí)需要定義Mapper接口和SQL映射文件毙驯,這里的Mapper只是個(gè)接口,他是如何執(zhí)行的灾测?

答案就是動(dòng)態(tài)代理爆价。

動(dòng)態(tài)代理有兩種實(shí)現(xiàn):1是JDK通過反射提供的動(dòng)態(tài)代理;2是CGLIB動(dòng)態(tài)代理媳搪。區(qū)別:JDK代理需要提供接口铭段,CGLIB不需要;MyBatis中這兩種方式都使用了秦爆。

一般來說實(shí)現(xiàn)代理稠项,代理的是一個(gè)目標(biāo)類。但是MyBatis使用時(shí)并沒有類鲜结,只有一個(gè)接口展运。這也是可以的活逆。JDK動(dòng)態(tài)代理可以直接生成 一個(gè)接口的實(shí)現(xiàn)類。

JDK動(dòng)態(tài)代理的使用:

//首先是實(shí)現(xiàn)InvocationHandler接口拗胜,實(shí)現(xiàn)invoke方法
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable {
  //method是要被代理執(zhí)行的方法
  //args是要傳入的參數(shù)
  //被代理類方法的執(zhí)行:
  
  Object result = method.invoke(args);
  
//可加入其他邏輯
}

//二是要生成代理類蔗候,使用Proxy.newProxyInstance()
//這里的傳入的第三個(gè)參數(shù)this應(yīng)該是一個(gè)實(shí)現(xiàn)InvocationHandler接口的類的對象
//這個(gè)例子是還是先有了一個(gè)目標(biāo)類,但只有接口的情況也是可以的
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);

//只有接口的情況

CGLIB

public class HelloServiceCGLib implements MethodInterceptor {
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("代理之前");
        Object result = methodProxy.invokeSuper(o, objects);
        System.out.println("代理之后");
        return result;
    }

    private Object target;

    public Object getProxy(Object target) {
        this.target = target;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }
}

//Main.java
public class Main {
    public static void main(String[] args) {
        HelloServiceCGLib helloServiceCGLib = new HelloServiceCGLib();
        HelloService target = new HelloServiceImpl();
        HelloService helloService = (HelloService) helloServiceCGLib.getProxy(target);
        helloService.sayHello("xiaoming");
    }
}

動(dòng)態(tài)代理實(shí)現(xiàn)原理

JDK動(dòng)態(tài)代理:
利用反射實(shí)現(xiàn)埂软;
只依賴JDK本身锈遥,不需要依賴外部庫;JDK比外部庫更加可靠勘畔;
需要被代理類實(shí)現(xiàn)接口所灸;
代碼實(shí)現(xiàn)簡單一些。

CGLIB動(dòng)態(tài)代理:
基于ASM實(shí)現(xiàn)炫七;
不需要目標(biāo)類實(shí)現(xiàn)接口爬立;
不能代理final類,因?yàn)椴荒苌善渥宇悾?br> 高性能万哪。

反射:
涉及Class,Field,Method,Constructor等類

SqlSessionFactory的構(gòu)建過程侠驯,略

主要是讀取配置文件到Configuration類,在通過SqlSessionFactoryBuilder類生成

SqlSession的執(zhí)行流程

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末奕巍,一起剝皮案震驚了整個(gè)濱河市吟策,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌的止,老刑警劉巖檩坚,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異诅福,居然都是意外死亡匾委,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進(jìn)店門权谁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人憋沿,你說我怎么就攤上這事旺芽。” “怎么了辐啄?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵采章,是天一觀的道長。 經(jīng)常有香客問我壶辜,道長悯舟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任砸民,我火速辦了婚禮抵怎,結(jié)果婚禮上奋救,老公的妹妹穿的比我還像新娘。我一直安慰自己反惕,他們只是感情好尝艘,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著姿染,像睡著了一般背亥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上悬赏,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天狡汉,我揣著相機(jī)與錄音,去河邊找鬼闽颇。 笑死盾戴,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的进萄。 我是一名探鬼主播捻脖,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼中鼠!你這毒婦竟也來了可婶?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤援雇,失蹤者是張志新(化名)和其女友劉穎矛渴,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體惫搏,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡具温,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了筐赔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片铣猩。...
    茶點(diǎn)故事閱讀 39,902評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖茴丰,靈堂內(nèi)的尸體忽然破棺而出达皿,到底是詐尸還是另有隱情,我是刑警寧澤贿肩,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布峦椰,位于F島的核電站,受9級特大地震影響汰规,放射性物質(zhì)發(fā)生泄漏汤功。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一溜哮、第九天 我趴在偏房一處隱蔽的房頂上張望滔金。 院中可真熱鬧色解,春花似錦、人聲如沸鹦蠕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽钟病。三九已至萧恕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間肠阱,已是汗流浹背票唆。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留屹徘,地道東北人走趋。 一個(gè)月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像噪伊,于是被迫代替她去往敵國和親簿煌。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評論 2 354

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

  • 1. 簡介 1.1 什么是 MyBatis 鉴吹? MyBatis 是支持定制化 SQL姨伟、存儲過程以及高級映射的優(yōu)秀的...
    笨鳥慢飛閱讀 5,520評論 0 4
  • Spring學(xué)習(xí)手冊(12)—— Spring JDBC數(shù)據(jù)庫訪問我們學(xué)習(xí)了如何使用Spring的JDBC抽象進(jìn)行...
    澤_淵閱讀 1,219評論 0 13
  • 1 Mybatis入門 1.1 單獨(dú)使用jdbc編程問題總結(jié) 1.1.1 jdbc程序 上邊使...
    哇哈哈E閱讀 3,306評論 0 38
  • 一 、 Mybatis概覽 說到mybatis就不得不說ORM框架豆励,即對象-關(guān)系映射(Object-Relatio...
    ZMRWEGo閱讀 5,273評論 0 14
  • 【朋朋日歷】 2018 年 8 月 15 日 星期三 農(nóng)歷 七月初五 戊戌年 庚申月 己卯日 **********...
    劉書朋閱讀 203評論 0 0