MyBatis 映射文件詳解


普通的增改刪查

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.chy.mapper.StudentMapper">
    <insert id="insertStudent" parameterType="com.chy.pojo.Student">
        INSERT INTO student_tb(id,name,age,score)VALUES (#{id},#{name},#{age},#{score})
    </insert>

    <update id="updateStudent" parameterType="com.chy.pojo.Student">
        UPDATE student_tb SET name=#{name},age=#{age},score=#{score} WHERE id=#{id}
    </update>

    <delete id="deleteStudent" parameterType="Integer">
        DELETE FROM student_tb WHERE id=#{id}
    </delete>

    <select id="queryById" parameterType="Integer" resultType="com.chy.pojo.Student">
        SELECT * FROM student_tb WHERE id=#{id}
    </select>
</mapper>

<mapper>的namespace常用映射文件所在的 包名+映射文件名 。比如com.chy.mapper包下的映射文件StudentMapper.xml    =>    com.chy.mapper.StudentMapper

parameterType指定傳入的參數的數據類型,resultType指定將查詢結果映射為何種數據類型。

 

 

Student student = sqlSession.selectOne("com.chy.mapper.StudentMapper.queryById", 1);

通過namespace和id來引用相應的元素,傳入parameterType類型的參數。返回resultType指定的數據類型。

 事實上,如果通過id可以唯一確定要引用的元素,是可以省略namespace、只寫id的。 

 

 

 


 

 

 

模糊查詢

精確查詢:必須完全相同,比如WHERE name = 'chy',name字段必須是chy才匹配,不能是什么chy1。

模糊查詢:只要包含即可,比如WHERE name LIKE '%chy%',只要name字段包含chy即可,可以匹配chy、1chy1......

 

 

<select id="queryByName" parameterType="String" resultType="Student">
        SELECT * FROM student_tb WHERE name LIKE '%${value}%'
</select>

%是通配符,代表其他字符。

${}除了有#{}的功能外,還有連接字符串的作用。

 

 

使用${}連接字符串不安全,不能防止sql注入,為了安全,盡量采用sql的concat()函數來連接字符串:

<select id="queryByName" parameterType="String" resultType="String">
        SELECT name FROM student_tb WHERE name LIKE concat('%',#{value},'%') </select>

sql的concat()函數可連接多個字符串,將要連接的字符串依次傳入即可。

注意使用的是#{}

 

 

包含傳入的參數即可 concat('%',#{value},'%') '%${value}%'
以傳入的參數開頭 concat('%',#{value}) '%${value}'
以傳入的參數結尾 concat(#{value},'%') '${value}%'

 

 

 


  

 

如果傳入的是簡單的數據類型,比如數值型、String,#{}、${}中可以隨便寫變量名,為了見名知義,#{}中一般寫pojo類的字段名,${}中常寫value。

如果傳入的是pojo類的對象,#{}、${}中只能寫pojo類的字段名。

 

 


 

 

 

pojo類中基本類型的成員變量、映射文件中的基本數據類型,盡量使用包裝類型。

比如 int =>  Integer,long => Long 。

 

 

舉個例子:

成績表中某個同學缺考、財務表中本月支出尚未填寫,

在sql中如果使用0表示,別人會以為是考了0分、本月支出就是0元。

沒有值的字段要用null表示。別人一看到null,就知道這家伙沒成績、缺考了,這個月的支出還沒填寫。

 

 

數值型都可以轉換為包裝類型,比如 int型的0可以轉換為Integer型的0;

但包裝類型比基本數值類型多了一個值:null,這個值在基本數值型中是找不到對應的。

 

 

private int score; 我們沒給這個字段賦值,jvm給的初始值是0,插到數據庫的是0。

private Integer score;我們沒給這個字段賦值,jvm給包裝類的初始值是null,插到數據庫中就是null。如果值為0,給它賦值就是了score=0,這樣插到數據庫的就是0.

包裝類型比基本類型更全面些,基本類型可以表示的它也可以表示,基本類型不能表示的它也能表示。

pojo類的成員變量、映射文件中的數據類型盡量使用包裝類型。

 

 

 


 

 

 

 <mapper>常用的子元素

  • <select>、<insert>、<update>、<delete>
  • <sql>   用於定義可重用的sql片段
  • <resultMap>

 

 

<select>、<insert>、<update>、<delete>都具有的屬性

  • userCache   控制二級緩存的開啟、關閉,Boolean值
  • flushCache  調用sql語句之后,是否需要清空之前查詢的本地緩存和二級緩存,Boolean值
  • timeout   設置超時時間,默認單位秒,超時時會拋出異常
  • statementType   設置mybatis使用jdbc的哪種statement來工作,可選的值:STATEMENT、PREPARED(默認值)、CALLABLE,分別對應jdbc的Statement、PreparedStatement、CallableStatement

 

 

<select>元素獨有的屬性

  • resultType   將查詢結果映射到那種數據類型
  • resultMap  引用<resultMap>
  • fetchSize   獲取記錄的總條數

 

 


 

 

<resultMap>的用法

<resultMap>用於自定義查詢結果集的映射規則。

<resultMap id="" type="">
        <constructor>
            <idArg />
            <arg />
        </constructor>

        <id />
        <result />

     <discriminator>
        <case></case>
     </discriminator>
<association property="" /> <collection></collection> </resultMap>

type指定將結果集映射到哪種數據類型(哪個pojo類)。

<constructor>用於構造器注入,pojo類需提供帶參的構造器,這個基本不用。

<association>用於一對一關聯映射、<collection>用於一對多、多對多關聯映射。

 

 

<id>、<result>指定表的字段——pojo類的屬性之間的映射,id是主鍵字段的映射,result是普通字段的映射。

 <resultMap id="carMap" type="com.chy.pojo.Car"> <id property="id" column="car_id"/> <result property="name" column="car_name"/> <result property="price" column="car_price"/> </resultMap> 
    <select id="queryById" parameterType="Integer" resultMap="resultMap">
        SELECT * FROM car_tb WHERE car_id=#{car_id}
    </select>

如果表的字段名、pojo類的成員變量名完全一致,則可以缺省<id>、<result>(如果沒有關聯映射,可不使用<resultMap>),因為默認的映射就是表字段名、pojo類成員變量名一致。

如果表的字段名、pojo類的成員變量名不一致,則只配置不一致的字段即可。

 

 


 

 

 

<discriminator>  鑒別器

有時候需要將結果集中的記錄映射為不同類型的對象。

比如說商城首頁往往需要展示多種類型的商品。小米商城首頁要展示手機、電腦、電視.......從商品表中查詢新品,需要將這些記錄映射為不同的實體類:MobilePhone、Computer、TV。

<resultMap id="goodsMap" type="goods">
        <discriminator javaType="string" column="type">
            <case value="phone" resultType="mobilephone" />
            <case value="computer" resultType="computor" />
            <case value="tv" resultType="tv" />
        </discriminator>
</resultMap>

用結果集的某個字段來判斷,如果這個字段的值是xxx,就將這條記錄映射為指定的類型。

  • <resultMap>的type用於指定返回值類型,常使用父接口、父類
  • <discriminator>的column指定用哪個字段來判斷,javaType指定這個字段對應的java類型
  • <case>的value指定一個常量值,resultType指定返回值類型,常使用實現類、子類,如果這個字段的值是該常量值,就將這條記錄映射為指定的類型

如果我們沒有給<case>中的這些類寫一個共同的接口、父類,那<resultMap>的type可以寫成object。

 

 

如果該類型也需要配置映射,可以在<case>中進行配置:

<resultMap id="goodsMap" type="goods">
        <discriminator javaType="string" column="type">
            <case value="phone" resultType="mobilephone" />
            <case value="computer" resultType="computor" />
            <case value="tv" resultType="tv">
                <id />
                <result />
                <association property="" />
            </case>
        </discriminator>
</resultMap>

 

 

鑒別器常用於結果集中的記錄可以細分為多種類型的情況,比如查詢體測成績:

  • 身高、體重(公共項目)
  • 1000m、引體向上(男)
  • 800m、仰卧起坐(女)

那我可以寫一個父類PhysicalTest,把公共項目(身高、體重)的成績作為成員變量,

寫一個子類MalePhysicalTest  extends  PhysicalTest,里面添加男生的1000m、引體向上,

寫一個子類FemalePhysicalTest  extends  PhysicalTest,里面添加女生的800m、仰卧起坐。

在<discriminator>中根據gender來判斷,如果是男生,就映射為MalePhysicalTest,是女生就映射為FemalePhysicalTest。

 

把公共屬性寫在父類、父接口中,把特有屬性寫在子類中。

 

 


 

 

插入記錄與主鍵自增

有2種情況:

(1)使用的是支持主鍵自增的數據庫,比如mysql、sql server,設計表時勾選主鍵自增

插入記錄時不設置主鍵的值,數據庫會自動設置id的值。

<insert id="insertStudent" parameterType="com.chy.pojo.Student" keyProperty="id" useGeneratedKeys="true">
        INSERT INTO student_tb(name,age,score)VALUES (#{name},#{age},#{score})
</insert>

 

Student student = new Student();
student.setName("chy");
sqlSession.insert("com.chy.mapper.StudentMapper.insertStudent", student);
System.out.println(student.getId());
  • useGeneratedKeys   調用jdbc的getGeneratedKeys()來獲取數據庫中此條記錄主鍵字段的值。
  •  keyProperty   將值賦給pojo指定的字段,如果要賦給多個字段,逗號分隔即可。

這2個屬性的作用是將數據庫主鍵自增產生的值同步到pojo類的實例。

 

 

 

(2)使用的是不支持主鍵自增的數據庫,比如oracle,

    或者使用的是支持主鍵自增的數據庫,但設計表時沒有勾選主鍵自增。

那只能手動設置主鍵字段的值。在<selectKey>中手動寫一條sql語句來查詢主鍵字段的值咯。

<insert id="insertStudent" parameterType="com.chy.pojo.Student">
        <selectKey keyProperty="id" resultType="Integer" order="BEFORE">
            select if(max(id) is null ,1,max(id)+1) from student_tb
        </selectKey>
        INSERT INTO student_tb(id,name,age,score)VALUES (#{id},#{name},#{age},#{score})
</insert>

 

  • keyProperty指定主鍵對應pojo類的哪個屬性
  • resultType指定主鍵對應的java類型
  • order指定這2條sql語句的執行順序。

 

 

BEFORE:在執行insert 之前執行<selectKey>

 先執行<selectKey>中的sql語句,獲得主鍵字段的值,

再調用setter方法將這個值注入到pojo類的實例,然后將這個實例作為參數傳給insert語句。

主鍵字段已自動同步到pojo實例中。

 

 

AFTER:在執行insert之后才執行<selectKey>。

 順序是相對於insert而言的,畢竟insert才是主體,<selectKey>只是輔助用的。

使用before、after,在<selectKey>中寫的sql語句是不同的。

 

 

select if(max(id) is null ,1,max(id)+1) from student_tb

從表中查詢id字段(int)的最大值,如果一條記錄都沒有,返回1;如果有記錄,將id最大的值+1返回。

 

 

說明

<update>和<insert>一樣具有以上的屬性、子元素,<update>常用來返回所修改的記錄的id。

 

 

 


 

 

 

<sql>的用法示例

原來的寫法:

<select id="queryById" parameterType="Integer" resultType="com.chy.pojo.Student">
        SELECT * FROM student_tb WHERE id=#{id}
</select>

 

 

使用<sql>的寫法:

<sql id="tableName">
    student_tb
</sql>
<select id="queryById" parameterType="Integer" resultType="com.chy.pojo.Student">
    SELECT * FROM <include refid="tableName" /> WHERE id=#{id}
</select>

在<sql>中定義sql語句的部分代碼,然后使用<include />通過id將該部分代碼包含進來。


免責聲明!

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



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