MyBatis基礎_鏈接池與事務、動態SQL、註解開發

1、MyBatis鏈接池及事務控制

一、鏈接池

在實際開發中,都會使用鏈接池,由於它能夠減小獲取鏈接縮消耗的時間。所謂鏈接池,就是存儲數據庫鏈接的容器。鏈接池中存儲必定數量的數據庫鏈接,當線程須要使用到鏈接時,就從鏈接池中獲取數據庫鏈接,線程使用完數據庫鏈接會還回鏈接池中。java

鏈接池:其實就是一個集合對象,該集合必須是線程安全的;並且線程必須實現對列,知足 」 先進先出 「 的特性web

二、MyBatis中的鏈接池

三種配置方式sql

配置位置:MyBatis主配置文件中,<dataSource> 元素;type屬性的值表示採用何種鏈接池;數據庫

  • POOLED:採用傳統的 javax.sql.DataSource 接口規範中的鏈接池,MyBatis中有該規範的實現;緩存

  • UNPOOLED:採用傳統獲取數據庫鏈接的方式,雖然實現了 javax.sql.DataSource 接口,但沒有鏈接池的思想——即須要時才建立數據庫鏈接;安全

  • JNDI:採用服務器提供的 JNDI 技術實現,來獲取 DataSource 對象,不一樣服務器的拿到的 DataSource 對象是不一樣的;服務器

    注意:不是 web 或 maven 工程,是不能使用的。Tomcat 服務器中,採用鏈接池是 dbcp 鏈接池session

三、事務

什麼是事務?mybatis

事物的四大特性ACIDapp

不考慮隔離性會產生的3個問題

解決方法:四種隔離級別

MyBatis 中的事務控制默認沒有開啓自動提交,可使用 SqlSessionFactory.opensession(boolean autoCommit) 方法建立設置是否開啓自動提交事務的 Sqlsession 對象。但有一點須要注意的是:開啓了自動提交事務,MyBatis是對一個數據庫操做(並不是多個)進行事務提交。沒有開啓自動提交事務時,是使用 SqlSession 對象的 commit 方法 和 rollback 方法進行事務的提交的回滾。

2、動態SQL語句

一、參數傳遞

  • 單參數——定義傳入參數的類型,能夠是基本類型、引用類型、映射;

    • 直接使用映射的 key 值:#{key},該 key 值能夠不與方法的參數名匹配;
  • 多參數——須要在接口類中的抽象方法的參數前使用註解 @Param("") 指定參數名;

    • 使用 #{索引}、#{param+數字} 指定參數;
    • 在SQL語句中,使用 #{參數名} 、或 #{param+數字} 指定參數;
    <!--接口方法:User findUser(String username, String password); -->
    
    <select id="findUser" resultType="*.user">  
        select * from user where username=#{0} and password=#{1} 
    </select>
    <!--User findUser(@Param("username") String username, @Param("password") String password);-->
    
    <select id="findUser" resultType="user">  
        select * from user where username=#{username} and password=#{password} </select>

二、MyBatis標籤

  1. if 標籤:用於進行條件判斷, test 屬性用於指定判斷條件。爲了拼接條件, 在 SQL 語句後強行添加 1=1 的恆成立條件

    <select id="sel" resultType="user">
        select * from user where 1=1  
        <if test="username != null and username != ''">   
            and username=#{username}  
        </if>  
        <if test="password != null and password != ''">   
            and password=#{password}  
        </if> 
    </select>
  2. choose(when otherwise)標籤:這是一套標籤, 功能相似於 switch...case...

    <select id="sel" resultType="user">  
        select * from user  
        <where>   
            <choose>    
                <when test="username != null and username != ''">     
                    and username = #{username}    
                </when>    
                <when test="password != null and password != ''">     
                    and password = #{password}    
                </when>    
                <otherwise>     
                    and 1=1    
                </otherwise>   
            </choose>  
        </where> 
    </select>
  3. where/set標籤
    • 用於管理 where 子句,有以下功能:

      1. 若是沒有條件, 不會生成 where 關鍵字;
      2. 若是有條件, 會自動添加 where 關鍵字;
      3. 若是第一個條件中有 and 關鍵字, 去除之;
      <select id="sel" resultType="user">
          select * from user
          <where>
              <if test="username != null and username != ''">   
                  and username=#{username}  
              </if>  
              <if test="password != null and password != ''">   
                  and password=#{password}  
              </if> 
          </where>
      </select>
    • 用於維護 update 語句中的 set 子句,功能以下:

      1. 知足條件時, 會自動添加 set 關鍵字;
      2. 會去除 set 子句中多餘的逗號;
      3. 不知足條件時, 不會生成 set 關鍵字;
      <update id="updUser" parameterType="user">  
          update user  
          <set>   
              id=#{id}, 
              <!-- 防止全部條件不成立時的語法錯誤 -->   
              <if test="username != null and username != ''">    
                  username=#{username},   
              </if>   
              <if test="password != null and password != ''">    
                  password=#{password},   
              </if>  
          </set>  
          where id=#{id} 
      </update>
  4. trim() 標籤:用於在先後添加或刪除一些內容

    • prefix:在前面添加內容;
    • prefixOverrides:從前面去除內容;
    • suffix:向後面添加內容;
    • suffixOverrides:從後面去除內容;
    <update id="updUser" parameterType="user">  
        update user  
        <!--    prefix: 前綴, 表示向前面添加內容   
             prefixOverrides: 從前面刪除內容   
             suffix: 後綴, 表示向後面添加內容   
             suffixOverrides: 從後面刪除內容   -->  
        <trim prefix="set" prefixOverrides="user" suffix="hahah" suffixOverrides=","> 
            username=#{username},  
        </trim>  
        where id=#{id} 
    </update>
  5. bind標籤:用於對數據進行再加工。好比,模糊查詢中對數據的拼接

    <select id="sel" resultType="user">  
        select * from user  
        <where>   
            <if test="username!=null and username!=''">    
                <bind name="username" value="'%' + username + '%'"/>    
                and username like #{username} 
            </if>  
        </where> 
    </select>
  6. foreach標籤:用於在 SQL 語句中遍歷集合參數, 在 in 查詢中使用

    • collection: 待遍歷的集合;
    • open: 設置開始符號;
    • item: 迭代變量;
    • separator: 項目分隔符;
    • close: 設置結束符號;
    <select id="selIn" parameterType="list" resultType="user">  
        select * from user  
        <where>
        <foreach collection="list" open="id in (" separator="," close=")" item="item"> 
            #{item}  
        </foreach>
        </where>
    </select>
  7. sql/include標籤<sql> 用於提取 SQL 語句, <include>用於引用 SQL 語句

    <sql id="mySql">  
        select * from user  
    </sql> 
    
    <select id="selIn" parameterType="list" resultType="user">
        <include refid="mySql"/>   
        from t_user where id in  
        <foreach collection="list" open="(" separator="," close=")" item="item">   
            #{item}
        </foreach> 
    </select>

3、MyBatis的延遲加載

問題:在一對多中,當咱們有一個用戶,它有100個帳戶。1)當查詢用戶時,要不要把關聯的帳戶查出來?2)當查詢帳戶時,要不要把關聯的用戶查出來?

一對多的關係中,Java 中是使用集合來存儲多的一方,若是,僅僅只想查詢用戶信息,並不關心其帳戶的信息,這時,若是還將該用戶下的全部帳戶查詢出來,不只影響效率,也佔用內存。

什麼是延時加載(懶加載)?——在真正使用數據時才發起查詢,不使用時不查詢,也就是:按需查詢。

什麼是當即加載?——無論用不用,只要一調用方法,就發起查詢。

什麼時候使用延時加載,什麼時候使用當即加載?——一對多、多對多:一般採用延時加載;多對一,一對一:一般採用當即加載;

延時加載實現

在 mapping 配置文件中,配置 resultMap 元素,在須要使用延遲加載的對象使用 <association> 元素或 collection 元素關聯;並經過如下屬性,引用查詢語句和傳遞查詢條件,MyBatis會將查詢結果封裝到延遲加載的對象:

  • select:查詢語句;
  • column:查詢語句的條件;

但這尚未啓用懶加載方式。須要啓用懶加載方式,在主配置文件 <settings> 元素中配置如下 setting 子元素:

<settings>
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>
  • lazyLoadingEnabled:全局啓用或禁用延遲加載。當禁用時, 全部關聯對象都會即時加載。 默認值:(==true==|false)
  • aggressiveLazyLoading:當啓用時, 有延遲加載屬性的對象在被調用時將會徹底加載任意屬性。不然, 每種屬性將會按須要加載。 默認值:(==true==|false)

在沒有啓用延遲加載時,MyBatis會加載全部查詢數據;啓用延遲加載時,當延遲加載的對象被調用,纔會加載;

4、MyBatis緩存機制

什麼是緩衝?——存儲在內存中的臨時數據;

爲何使用緩衝?——減小和數據庫的交互次數,提升執行效率;

什麼數據能使用緩存,什麼數據不能?

  • 適用於緩存:常常查詢且不常改變、數據的正確與否對最終結果影響不大;
  • 不適用緩存:常常改變的數據、數據的正確與否對最終結果影響很大;好比:商品的庫存,銀行的匯率,股市的牌價等;

一級緩存和二級緩存

  1. 一級緩存

    指的是 MyBatis 中 SqlSession 對象的緩存。

    當執行查詢以後,查詢結果會同時存入到 SqlSession 提供的一個 Map 區域中;當再次查詢相同的數據時,MyBatis 會先去 Map 區域中查找,沒有找到在執行查詢操做。當 SqlSession 對象消失或清空緩存操做時,一級緩存也就消失了

    如何保證數據庫數據和一級緩存數據保持一致(數據同步)?

    若是 sqlSession 執行 commit 操做(執行插入、更新、刪除),會清空 SqlSession 中的一級緩存,這樣作的目的爲了讓緩存中存儲的是最新的信息,避免髒讀。

  2. 二級緩存

    指的是 MyBatis 中 SqlSessionFactory 對象的緩存,有同一個 SqlSessionFactory 對象建立並共享緩存。

    二級緩存的使用步驟

    1. 讓 MyBatis 支持二級緩存(在主配置文件中配置);

      <settings>
          <setting name="cacheEnabled" value="true"/>
      </settings>
    2. 讓當前映射文件支持二級緩存(在 mapper 配置文件配置);

      <cache/>
    3. 讓當前操做支持二級緩存(select 元素中配置)

      <select id="findAll"resultMap="user" useCache="true">
          select * from class
      </select>

    二級緩存中存放的內容是數據,而不是對象

5、註解開發

當使用註解開發時,相同包名下不能有 mapper 配置文件,會發生配置文件解析衝突錯誤。

一、增刪改查

  1. @Select()
  2. @Delete()
  3. @Update()
  4. @Insert()

二、POJO類屬性名與列名不一致

  1. 定義屬性名與列名映射

    @Results(id="UserMap",value={
        @Result(id=true,column="",property=""),
        @Result(column="",property=""),
        @Result(column="",property=""),
    })
  2. 引用映射,引用 @Results 中的 ID 值

    @ResultMap(value={"UserMap"})

三、多表查詢

  1. 一對一

    @Results(id="UserMap",value={
        @Result(id=true,column="",property=""),
        @Result(column="",property=""),
        @Result(column="",property=""),
        @Result(column="做爲查詢的列名",property="屬性名",
             one=@One(
             select="全限定查詢方法"
             fetchType=FetchType.EAGER
             ))
    })

    使用 @One 註解定義查詢方法,根據 column 中的屬性做爲查詢條件,返回一條數據;

    • select:查詢語句(包名.類名.方法名);
    • fetchType:加載方式;FetchType對象的 LAZY(延遲加載)、EAGER(當即加載)、DEFAULT
  2. 一對多

    @Results(id="UserMap",value={
        @Result(id=true,column="",property=""),
        @Result(column="",property=""),
        @Result(column="",property=""),
        @Result(column="做爲查詢的列名",property="屬性名",
             many=@Many(
             select="全限定查詢方法"
             fetchType=FetchType.LAZY
             ))
    })

四、開啓二級緩存

  1. 在主配置文件中配置開啓二級緩存;

    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>
  2. 在接口類級別上使用 @CacheNamespace(blocking= true)

相關文章
相關標籤/搜索