mybatis----基礎

weixin_34054866發表於2018-08-01

基礎知識

  • 安裝
<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>x.x.x</version>
</dependency>

對原生態jdbc程式中問題總結

  • 環境

java環境:jdk

  • jdbc程式

使用jdbc查詢mysql資料庫中使用者表的記錄

  • 問題總結
    • 資料庫連線、使用時建立、不使用時就立即釋放,對資料庫進行頻繁連線開啟和關閉,造成資料庫資源浪費,影響資料庫效能(使用連線池管理資料庫來連線進行優化)
    • 將sql語句硬編碼到Java程式碼中,如果sql語句修改,需要重新編譯程式碼,不利於系統維護(將sql語句配置在xml配置檔案中,即使sql變化,也不需要對java程式碼進行重新編譯)
    • 向preparedStatement中設定引數,對佔位符號位置和設定引數值,硬編碼在Java程式碼中,不利於系統維護(將sql語句及佔位符號和引數全部配置在xml中)
    • 從resultSet中遍歷結果集資料時,存在硬編碼,將獲取表的欄位進行硬編碼,不利於系統維護(將查詢的結果集,自動對映成java物件。)

mybatis是什麼

mybatis是一個持久層框架,是apache下的頂級專案。
mybatis是讓程式設計師將主要精力放在sql上,通過mybatis提供的對映方式,自由靈活的生成(半自動化,大部分需要程式設計師編寫sql)滿足需要的sql語句
mybatis可以將向preparedStatement中的輸入引數自動進行輸入對映,將查詢結果集靈活對映成java物件(輸出對映)

mybatis框架

SqlMapConfig.xml     是mybatis的全域性配置檔案,配置了資料來源、事務等mybatis執行環境(第三方軟體進行配置)

mybatis自己還需要配置對映檔案(mapper.xml、mapper.xml、mapper.xml……【對映檔案】)也就是配置sql語句

SqlSessionFactory(會話工廠),根據配置檔案建立工廠
作用:建立SqlSession
SqlSession(會話),是一個介面,面向使用者(程式設計師)的介面
作用:運算元據庫(發出增、刪、改、查)
Executor(執行器),也是一個介面(基本執行器、快取執行器)
作用:運算元據庫(發出增、刪、改、查)
mapped statement(底層封裝物件)
作用:對運算元據庫儲存封裝,包括sql語句,輸入引數、輸出結果型別

入門程式

  • 編寫log4j.properties進行日誌輸出
# Global logging configuration
#在開發環境下日誌級別要設定成DEBUG,生成環境設定成info或ERROR
log4j.rootLogger=DEBUG, stdout
# MyBatis logging configuration...
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
  • 編寫全域性配置SqlMapConfig.xml
  • 對映檔案
    • 對映檔案命名
User.xml(原始mybatis命名),mapper代理開發對映檔案叫xxxMapper.xml,比如:UserMapper.xml
在對映檔案中配置sql語句
6609243-2cf76f09ba758587.png
image.png

6609243-439dd8f254cf63be.png
image.png

#{}與${}

  • #{} 表示一個佔位符,#{}接受輸入引數,型別可以是簡單的型別,pojo、hashmap。
    如果接受簡單型別,#{}中可以寫成value或其他名稱
    #{}接受pojo物件值,通過OGNL讀取物件中的屬性值,通過屬性。屬性。屬性……的方式獲取物件屬性值
  • ${} 表示一個拼接符號,會引起sql注入,所以不建議使用
    ${}接受輸入引數,型別可以是簡單的型別,pojo、hashmap。
    如果接受簡單型別,${}中只可以寫成value

parameterType、resuletType

parameterType : 指定輸入引數的型別
resuletType : 指定輸出引數的型別

自增主鍵返回

mysql自增主鍵,執行insert提交之前自動生成一個自增主鍵。
通過mysql函式獲取到剛插入記錄的自增主鍵:
LAST_INSERT_ID()
是在insert之後呼叫此函式,需要修改UserInsert的定義

<insert id=“insertUser” parameter="cn.persist.entily.User">
    <!-- 
      將插入資料的主鍵返回,返回到user物件中
      SELECT LAST_INSERT_ID():得到剛insert進去的記錄的主鍵的值,只適用於自增主鍵
      KeyProperty:將查詢到的主鍵值parameterType指定的物件的哪個屬性
      order:SELECT LAST_INSERT_ID()執行順序,相對於insert語句來說它的執行順序
      resultType:指定SELECT LAST_INSERT_ID()的結果型別
     -->
    <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Inteager">
          SELECT LAST_INSERT_ID()
    </selectKey>
    <!--
          username,password,address是資料表中的對應的欄位名稱
          #{username},#{password},#{address}是實體類中對應的屬性名
    -->
    INSERT into user(username,password,address) value(#{username},#{password},#{address})
</insert>

非自增主鍵返回(使用uuid)

使用mysql的uuid()函式生成主鍵,需要修改表中id欄位型別為string,長度設定成35位
執行思路:
先通過uuid()查詢到主鍵,將主鍵輸入到sql語句中
執行uuid()語句順序相對於insert語句之前執行

<insert id=“insertUser” parameter="cn.persist.entily.User">
    <!-- 
      使用mysql的uuid()生成主鍵
      執行過程:
      首先通過uuid()得到主鍵,將主鍵設定到user物件的id屬性中
      其次在insert執行時,從user物件中取出id屬性值
     -->
    <selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
          SELECT uuid()
    </selectKey>
    <!--
          id,username,password,address是資料表中的對應的欄位名稱
          #{id},#{username},#{password},#{address}是實體類中對應的屬性名
    -->
    INSERT into user(id,username,password,address) value(#{id},#{username},#{password},#{address})
</insert>

mybatis開發dao的方法

  • sqlSession使用範圍
    • sqlSessionFactoryBuilder
      通過sqlSessionFactoryBuilder建立會話工廠sqlSessionFactory
    • sqlSessionFactory
      通過sqlSessionFactory建立sqlSession,通過單例模式管理sqlSessionFactory(工廠一旦建立,一直使用一個例項)
    • sqlSession
      是一個面向使用者的介面(程式設計師)的介面
      sqlSession中提供了很多運算元據庫的方法:例如:selectOne(返回單個物件)selectList(返回單個或多個物件)
      sqlSession是執行緒不安全的,在sqlSession實現類中除了有介面中的方法(運算元據庫的方法)還有資料域屬性
      sqlSession最佳應用場合在方法體內,定義為區域性變數使用

原始dao開發方法(程式設計師需要寫dao介面和dao實現類)

  • 思路:

程式設計師需要寫dao介面和dao實現類。
需要向dao實現類中注入sqlSessionFactory(會話工廠),在方法體內通過工廠(sqlSessionFactory)建立sqlSession

  • 總結原始開發dao的問題

1.dao的介面實現類方法中存在大量模板方法,設想能否將這些程式碼提取出來
2.呼叫sqlSession方法時將statement的id硬編碼了
3.呼叫sqlSession方法時傳入的變數,由於sqlSession方法使用泛型,即使變數型別傳入錯誤,在編譯階段也不報錯,只有在執行時報錯,不利於程式開發

mapper代理方法(程式設計師只需要mapper介面(相當於dao介面))

  • 思路

1.程式設計師只需要mapper介面(相當於dao介面),需要遵循一些開發規範,mybatis可以自動生成mapper介面實現類的代理物件
2.程式設計師還需要編寫mapper.xml對映檔案

  • 開發規範:
    1.在mapper.xml中namespace等於mapper介面地址


    6609243-2c687d0802d7b8e4.png
    image.png

    2.mapper.java介面中的方法名和mapper.xml中statement的id一致
    3.mapper.java介面中的方法輸入引數型別和mapper.xml中statement的parameterType指定的型別一致
    4.mapper.java介面中的方法返回值型別和mapper.xml中statement的resultType指定的型別一致


    6609243-cf2db39e958e638a.png
    image.png

    6609243-8bff8bee5fe72de2.png
    image.png

總結

以上開發規範主要是對下邊的程式碼進行統一的生成:


6609243-14a0c9518fdce5d9.png
image.png

SqlMapConfig.xml

  • properties(屬性)

需求:
將資料庫連線的引數單獨配置在db.properties中,只需要在sqlMapConfig.xml中載入db.properties的屬性值
SqlMapConfig.xml中就不需要對資料庫連線引數硬編碼
將資料庫連線引數只配置在db.properties中,原因:方便對引數進行統一的管理,其他xml可以引用該db.properties

db.properties的檔案

6609243-547c682347ed44c9.png
image.png

sqlMapConfig.xml載入屬性名稱

6609243-c0462831c9667283.png
image.png

6609243-94393bd6b1aaf649.png
image.png

建議:
不要在properties元素體內新增任何屬性值,只將屬性值定義在properties檔案中

  • setting(全域性配置引數)需要時設定,不需要就不要設定(會影響mybatis的執行)

mybatis框架在執行時可以調整一些執行引數
比如:開啟二級快取、開啟延時載入……
全域性引數將會影響mybatis的執行行為

  • typeAliases(型別別名)
    • 單個定義別名


      6609243-cfc023aec44bf337.png
      image.png
    • 批量定義別名


      6609243-12d58ffefd6f8630.png
      image.png

在dao.xml中的返回值型別填實體類的名稱,首字母大寫小寫都可以

  • typeHandles(型別處理器)

在mybatis中通過typeHandles完成jdbc型別和java型別的轉換

  • objectFactory(物件工廠)
  • plugins(外掛)
  • environments(環境集合屬性物件)
    • environment(環境子屬性物件)
      • transactionManager(事務管理)
      • dataSource(資料來源)
  • mappers(對映器)
    • 通過resource載入單個對映檔案


      6609243-fde15c4a457c1812.png
      image.png
    • 通過mapper介面載入
      • 載入單個對映檔案


        6609243-e958436fe22d4d49.png
        image.png
      • 批量載入對映檔案(建議使用)


        6609243-b164d93462cccfb6.png
        image.png

動態sql

  • 什麼是動態sql

mybatis核心就是對sql語句進行靈活的操作,通過表示式進行判斷,對sql進行靈活拼接、組裝

  • 需求:

使用者資訊總和查詢列表和使用者資訊查詢列表總數這兩個statement的定義使用動態sql
對查詢條件進行判斷,如果輸入引數不為空才能進行查詢條件拼接;例如:

   <select id="findUserById" parameterType="User" resultType="user">
        select * from user
        <!--where 可以自動去掉條件中的第一個and-->
        <where>
            <if test="userCustom!=null">
                <if test="userCustom.usermame!=null and userCustom!=''">
                    and user.username = #{userCustom.username}
                </if>
                <if test="userCustom.sex != null and userCustom.sex != ''">
                    and user.sex = #{userCustom.sex}
                </if>
            </if>
        </where>
    </select>

sql片段

  • 需求:

將上邊實現的動態sql判斷程式碼塊抽取出來,組成一個sql片段。其他的statement中就可以引用sql片段

  • 定義sql片段
    <!--定義sql片段
    id:sql片段的唯一標識
    經驗:是基於表單來定義sql片段可重用性高
    在sql片段中不要包括where
    -->
    <sql id="query_user_where">
        <if test="userCustom!=null">
            <if test="userCustom.usermame!=null and userCustom!=''">
                and user.username = #{userCustom.username}
            </if>
            <if test="userCustom.sex != null and userCustom.sex != ''">
                and user.sex = #{userCustom.sex}
            </if>
        </if>
    </sql>

應用sql片段

<select id="findUserById" parameterType="User" resultType="user">
        select * from user
        <!--where 可以自動去掉條件中的第一個and-->
        <where>
            /*應用sql片段*/
            <include refid="query_user_where" />
            /*在這裡還會引用其他的sql片段*/
        </where>
    </select>

foreach

向sql傳遞陣列或list,mybatis使用foreach解析

  • 需求

在使用者查詢列表和查詢總數的statement中增加多個id輸入查詢
sql語句如下:
select * from user where id=1 or id=10 or id=16select * from user where id in(1,10,16)

  • 在輸入引數型別中新增List<Integer>傳入多個id
    private List<Integer> ids傳入多個id
  • mapper.xml的配置

在查詢條件中,查詢條件定義成一個sql片段,需要修改sql片段

<!--定義sql片段
   id:sql片段的唯一標識
   經驗:是基於表單來定義sql片段可重用性高
   在sql片段中不要包括where
   -->
    <sql id="query_user_where">
        <if test="ids!=null">
            <!--使用foreach遍歷傳入ids
            collection:指定輸入物件中集合屬性
            item:每次遍歷生成的物件
            open:開始遍歷時拼接的串
            close:結束遍歷時拼接的串
            separator:遍歷的兩個物件中需要拼接的串
            -->
            <foreach collection="ids" item="user_id" open="and (" close=")" separator="or">
                /*每次遍歷需要拼接的串*/
                id=#{user_id}
            </foreach>
        </if>
    </sql>

select * from user where id in(1,10,16)的foreach查詢方法

6609243-667a765701de5f8f.png
image.png

相關文章