深入理解MyBatis的原理(四):映射器的用法


前言:繼續深入學習 mybatis 的用法及原理,還是先會用再學習原理。

映射器的主要元素有:select、insert、update、delete、parameterMap(即將被刪除,不建議使用)、sql、resultMap、cache、cache-ref

各個元素的規則定義:見源碼中的文件 org/apache/ibatis/builder/xml/mybatis-3-mapper.dtd

目錄:

  一、select 元素

  二、insert 元素

  三、update 元素

  四、delete 元素

  五、參數

  六、SQL 片段重用

  七、resultMap 結果映射集

一、select 元素

1、查詢,select 元素有以下屬性:

  id:和 Mapper 的命名空間組合起來必須是唯一的,供給 MyBatis 上下文調用。

  parameterType:查詢參數類型。一般給出類的全命名,也可以給出類的別名。可以選擇 JavaBean、Map 等復雜的參數類型傳遞給 SQL。

  resultType:查詢返回數據類型。一般給出類的全命名,或者別名,不能和 resultMap 同時使用。

  resultMap:查詢返回映射集的引用,將執行強大的映射功能。不能和 resultType 同時使用。它是 MyBatis 最復雜的元素,可以自定義映射規則、級聯、typeHandle 等。

  flushCache:它的作用是在調用 SQL 后,是否要求 MyBatis 清空之前查詢的本地緩存和二級緩存。取值為 boolean,默認 false。

  useCache:啟動二級緩存的開關,是否要求 MyBatis 將此次結果緩存。取值為 boolean,默認 true。

  timeout:這是超時參數,等超時的時候將拋出異常,單位為秒。默認值為數據庫廠商提供的 JDBC 驅動所設置的秒數。

  fetchSize:獲取記錄的總條數。默認值為數據庫廠商提供的 JDBC 驅動所設置的條數。

  statementType:選擇使用 JDBC 的 Statement 工作,取值為 STATEMENT、PREPARED、CallableStatement。默認 PREPARED。

  resultSetType:很少使用

  databaseId:數據庫廠商標識,提供多數據庫的支持。

  resultOrdered:很少使用

  resultSets:很少使用

2、舉例  

dao 接口

    /**
     * 通過名字查找用戶
     * @param name
     * @return
     */
    User queryUserByName(String name);

xml

    <select id="queryUserByName" resultType="com.yule.user.entity.User">
        select t.id, t.name, t.age from t_user t
        where t.name = #{name,jdbcType=VARCHAR}
    </select>

3、自動映射

  當配置 autoMappingBehavior 不是 NONE 時,MyBatis 會提供自動映射功能,只要返回的 sql 列名(別名)和 JavaBean 的屬性一致,MyBatis 就會幫助我們回填這些字段無需任何配置,它可以在很大程度上簡化我們的配置工作。

  在實際中,通常我們是使用 sql 列名的別名的方式自動映射。上方例子的 resultType="com.yule.user.entity.User" 就是 MyBatis 的自動映射。

  在實際中,也可以通過在配置文件中開啟駝峰命名方式:mapUndersoreToCamlCase 為 true。這種方式的前提是數據庫命名是規范的,即每一個單詞都用下划線分割,POJO 采用的是駝峰命名方式,那么可以設置配置文件,從而達到從數據庫到 POJO 的自動映射了。

  自動映射在 MyBatis 的配置文件中,元素 settings 中可以配置 autoMappingBehavior 屬性值來設置其策略,它包含 3 個值:

  • NONE:取消自動映射
  • PARTIAL:只會自動映射,沒有定義嵌套結果集映射的結果集。為默認值。
  • FULL:會自動映射任意復雜的結果集(無論是否嵌套),性能會下降。

  在大部分的情況下 MyBatis 都會推斷你返回數據的類型,所以大部分情況下你都無需去配置參數類型和結果類型。要我們設置的往往只是可能返回為空的字段類型而已。因為 null 值,MyBatis 無法判斷其類型。

4、傳遞多個參數

  一、使用 map,缺點是業務關聯性不強,造成代碼可讀性下降。

  二、使用注解 @Param,xml 中無需定義參數類型。可讀性增強,但是當參數個數太多時,可讀性仍然會下降。

  三、使用 JavaBean 傳遞參數。

  這三種方式對比:

  • 使用 Map 傳遞參數。因為 Map 導致代碼的可讀性下降,會導致后面的擴展和維護比較困難,所以建議少使用這種方式。
  • 使用 @Param 注解方式。這種方式可讀性高,但是當參數個數很多的時候,同樣會導致可讀性和維護性下降,所以,當參數個數小於等於 5 時,建議采取這種方式。
  • 使用實體 JavaBean 的方式。當參數個數大於 5 時,建議采取這種方式。

5、使用 resultMap 映射結果集

   對於簡單的映射,建議采用自動映射就好,可以減少配置。resultMap 映射一般就用於復雜、級聯這些關聯的配置。所以這個放在 resultMap 結果映射集講。

二、insert 元素

1、插入,insert 元素有一下屬性:

  id:同 select

  parameterType:同 select

  flushCache:同 select

  timeout:同 select

  statemeterType:同 select

  keyProperty:表示以哪個列作為屬性的主鍵。不能和 keyColumn 同時使用。聯合主鍵可以用逗號隔開。

  useGeneratedKeys:這會令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法來取出數據庫內部生成的主鍵,使用該屬性后就必須使用keyColumn或者KeyProperty屬性中的一個。取值為 boolean 值,默認 false。

  keyColumn:指明第幾列是主鍵。不能和 keyProperty 同時使用。聯合主鍵可以用逗號隔開。只接受整形參數。

  databaseId:同 select

  lang:使用很少

2、舉例

 dao 接口

    /**
     * 新增用戶
     * @param user
     * @return
     */
    int insertUser(User user);

xml,自定義規則:使用序列實現主鍵回填,即執行完新增后返回主鍵 id。這個能把主鍵 id 回填到實體 User 上去。

  MyBatis 中 不允許同事包含連兩個 selectKey 標簽。

    <insert id="insertUser">
        <selectKey keyProperty="id" order="BEFORE" resultType="int">
          select t_user_s.nextval from dual
        </selectKey>
        insert into t_user
          (id, name, age)
        values
          (#{id}, #{name}, #{age})
    </insert>

測試

    @Test
    public void testInsertUser(){
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);

        User user = new User("yule", "24");

        mapper.insertUser(user);

        sqlSession.commit();
        sqlSession.close();

        System.out.println(user.toString());
    }

3、舉例2

xml,使用主鍵自增長(必須在表中設置 id 字段為自增字段),同時 sql 執行完成之后 MyBatis 自動將執行完 sql 后自動生成的 id 回填到我們的參數 User 對象中。

  <insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
        insert into t_user
        (name, age)
        values
        (#{name}, #{age})
    </insert>

三、update 元素

1、修改,和 insert 一樣,MyBatis 執行完后會返回一個整數,標出執行后影響的條數。

2、舉例

dao 接口

    /**
     * 修改用戶信息
     * @param user
     * @return
     */
    int updateUserById(User user);

xml

    <update id="updateUserById">
        update t_user t set t.age = #{age}, t.name = #{name}
        where t.id = #{id}
    </update>

四、delete 元素

1、刪除,和 insert 一樣,MyBatis 執行完后會返回一個整數,標出執行后影響的條數。

2、舉例

dao 接口

    int deleteUserById(String id);

xml

    <delete id="deleteUserById">
        delete t_user t where t.ID = #{id}
    </delete>

五、參數   

  定義參數屬性時,MyBatis 不允許換行!!!

1、參數配置

  我們可以通過制定參數的類型去讓對應的 typeHandle 處理它們,也可以通過指定對應的 JavaType、JdbcType 來明確使用哪個 typeHandle 處理參數。詳見 https://www.cnblogs.com/yuxiaole/p/9464019.html#typeHandler

2、存儲過程支持

   對於存儲過程而言,存在 3 種參數,輸入參數(IN)、輸出參數(OUT)、輸入輸出參數(INOUT)。MyBatis 的參數規則為其提供了良好的支持。

3、特殊字符串替換和處理(# 和 $)

  使用 #{} 方式,MyBatis 會用創建預編譯的語句,然后 MyBatis 為它設值。

  使用 ${} 方式,傳遞 SQL 語句本身,比如傳遞 SQL 的列名、根據某些列排序等。比如 select ${columns} from t_tablename 來支持傳遞動態列名。不過使用這種方式是不安全的,所以雖然 MyBatis 是給了靈活性,但是自己也需要控制參數來保證 SQL 運轉的正確性和安全性。

六、SQL 片段重用

  采用  <include refid="sql_id"></include> 來實現 SQL 片段的重用。SQL 片段是指用 <sql></sql> 定義的片段。

  比如:給 include 標簽加一個 refid 屬性進行引用,從而達到重用的功能

    <sql id="user_columns">
        ${prefix}.id, ${prefix}.name, ${prefix}.age
    </sql>
    <select id="queryUserByName" resultType="com.yule.user.entity.User">
        select
          <include refid="user_columns">
              <property name="prefix" value="t"/>
          </include>
        from t_user t
        where t.name = #{name,jdbcType=VARCHAR}
    </select>

  或者,可以直接給 refid 一個參數值,由程序制定引入 SQL

    <select id="queryUserList" resultType="User" >
        <include refid="common_query">
            <property name="columnsName" value="user_columns"/>
        </include>
    </select>
    <sql id="common_query">
        select
        <include refid="${columnsName}">
              <property name="prefix" value="t"/>
        </include>
        from t_user t
    </sql>

七、resultMap 結果映射集

  resultMap 是 MyBatis 中最復雜的元素。主要是定義一個查詢中的結果集的映射關系,不支持修改、刪除。作用是定義映射規則、級聯的更新、定制類型轉換器等。

1、resultMap 元素里面的構成

  見源碼:org/apache/ibatis/builder/xml/mybatis-3-mapper.dtd

<!ELEMENT resultMap (constructor?,id*,result*,association*,collection*, discriminator?)>

  其中,constructor 元素用於配置實體構造方法。表示告訴 MyBatis 用實體的哪個構造方法來構造實體。

<!ELEMENT constructor (idArg*,arg*)>

  其中,id 元素是表示哪個列是主鍵,允許多個主鍵,多個主鍵稱為聯合主鍵。

  其中,result 元素是配置 POJO 到 SQL 列名的映射關系。

  result 和 id 兩個元素都有如下屬性:

  • property:代表 POJO 的屬性名稱。映射到列結果的字段或屬性,如果 POJO 的屬性匹配是存在的,和給定 SQL 列名(column 元素)相同的,那么 MyBatis 就會映射到 POJO 上。
  • column:對應的是 SQL 的列名。
  • javaType:配置 Java 的字段類型
  • jdbcType:配置數據庫中的字段類型
  • typeHandle:類型處理器

2、使用 map 存儲結果集

  select 元素中使用 resultMap 會使可讀性下降,所以建議更多時候使用 POJO 的方式來自動映射,即 resultType。

  resultMap 元素的屬性 id 代表這個 resultMap 的標識,type 代表需要映射的 POJO。

<!ATTLIST resultMap
id CDATA #REQUIRED
type CDATA #REQUIRED
extends CDATA #IMPLIED
autoMapping (true|false) #IMPLIED
>

舉例:SQL 語句的列名需要和 column 一 一對應。

    <resultMap id="userResultMap" type="com.yule.user.entity.User">
        <constructor>
            <idArg column="id" javaType="string"/>
            <arg column="name" javaType="string"/>
            <arg column="age" javaType="string"/>
        </constructor>
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="age" column="age"/>
    </resultMap>
    <select id="queryUserById" resultMap="userResultMap">
         select t.id, t.name, t.age from t_user t
        where t.id = #{id}
    </select>

3、級聯

  有 3 中關系:一對一、一對多、多對多。多對多可用一對多雙向標識。

  在 MyBatis 中級聯分為這么 3 種:

  • association:一對一。
  • collection:一對多。
  • discriminator:鑒別器。可以根據實際選擇采用哪個類作為實例,允許根據特定的條件去關聯不同的結果集。

舉例:

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM