MyBatis實用總結


 

xml映射文件

與mapper接口的對應關係

  • namespace和接口名一致(xml文件名不需要和接口名一致)
  • id和接口中的方法名一致
  • 參數類型、返回值類型與接口方法中的一致

 

parameterType、resultType

  • 如果是基本類型,一律使用包裝類型
  • 別名規則:類名全小寫
  • 如果返會的結果集中有多條記錄(List),resultType不能寫成list,和返回單條記錄一樣都是寫元素類型,eg. List<User> => user ,如果返回了多條記錄,會自動映射爲指定類型的List。

 

參數問題

如果使用了parameterType,只能傳入一個參數,如果要傳入多個參數,可以放到list、map中傳入

<!-- 傳入list -->
<select id="xxx" parameterType="list" resultType="xxx">
	<!-- 默認的列表名是list,通過下標取值 -->
    SELECT * FROM tb_user WHERE name=#{list[2]}
</select>


<!-- 傳入對象 -->
<select id="xxx" parameterType="user" resultType="xxx">
	<!-- 通過成員變量名直接取,會自動調用對應的getter方法 -->
    SELECT * FROM tb_user WHERE name=#{name}
</select>

<!-- 傳入map -->
<select id="xxx" parameterType="map" resultType="xxx">
	<!-- 通過key直接取 -->
    SELECT * FROM tb_user WHERE name=#{name}
</select>

 

不使用parameterType,可直接傳入多個參數

public interface UserMapper{
    User findUser(Integer id, String name);
}
<!-- 不要parameterType -->
<select id="findUser" resultType="user">
    SELECT * FROM tb_user WHERE id=#{id} and name=#{name}
</select>

 

@Param可解決mapper接口、xml映射文件參數名不同的問題

public interface UserMapper{
    // 通過@Param綁定xml中的name變量
    User findUser(Integer id, @Param("name") String username);
}
<select id="findUser" resultType="user">
    SELECT * FROM tb_user WHERE id=#{id} and name=#{name}
</select>

 

#{ }、${ }的區別

#{ }用於取值,${ }除了有#{ }的功能,還可以拼接字符串,但使用${ }拼接字符串有sql注入的風險。

以模糊查詢爲例

<select id="xxx" parameterType="string" resultType="user">
	SELECT * FROM tb_user WHERE name LIKE '%${name}%'
</select>


<select id="xxx" parameterType="string" resultType="user">
	<!-- 使用sql的concat()函數拼接字符串,使用#{}取值 -->
	SELECT * FROM tb_user WHERE name LIKE concat('%',#{name},'%')
</select>

 

resultMap的使用

<resultMap> 用於自定義結果集映射

<!-- resultType不能和resultMap同時使用,fetchSize指定返回的記錄數,未指定時默認返回所有滿足要求的記錄 -->
<select id="" parameterType="" resultMap="resultMap" resultType="user" fetchSize="10">

</select>


<!-- type指定po -->
<resultMap id="userMap" type="user">
    <!-- 默認映射規則是同名映射,我們只需指定名稱不一致的字段,主鍵字段用id指定,普通字段用result指定 -->
    <id property="id" column="user_id"/>
    <result property="username" column="user_name"/>
</resultMap>

<!-- resultMap屬性指定要使用的<resultMap> -->
<select id="" parameterType="" resultMap="userMap">

</select>

此外,<resultMap>還有2個常用子元素<association>、<collection>,用於關聯映射。

 

關聯映射

關係數據庫中,多表之間有三種關聯關係

  • 一對一:一張身份證對應一個人 <=> 一個人也只對應一張身份證
  • 一對多:一個用戶可以有多個訂單 <=> 這多個訂單都屬於同一個用戶
  • 多對多:一個訂單可以包含多種商品 <=> 一種商品可以屬於多個訂單

 

設計數據庫時如何處理三種關聯關係?

  • 一對一:在一方引入另一方的主鍵作爲外鍵
  • 一對多:在多的一方,引入一的一方的主鍵作爲外鍵
  • 多對多:新建一張中間表,引入2張表的主鍵作爲外鍵,可以使用這2個外鍵作爲中間表的聯合主鍵,也可以新建id字段作爲中間表的主鍵

 

java如何處理、描述三種關聯關係?

// 一對一
class A{
    B b;
}

class B{
    A a;
}
// 一對多,A是一,B是多
class A{
    List<B> b;
}

class B{
    A a;
}
// 多對多
class A{
    List<B> b;
}

class B{
    List<A> a;
}

 

如果多表查詢返回的結果集中包含另一方的字段,如何映射?

<select id="findStudentById" parameterType="integer" resultMap="studentWithScoreMap">
    <!-- 一對一、一對多都是根據關聯外鍵來查2張表,多對多是根據中間表來查2張表、是3表聯查 -->
    SELECT st.*,sc.* FROM tb_student st ,tb_score sc  WHERE st.id=#{id} AND st.id=sc.student_id
 </select>


<resultMap id="studentWithScoreMap" type="student">
    <!-- 如果其它字段名稱不一致,手動映射 -->
    <id property="" column=""/>
    <result property="" column=""/>

    <!--  一對一用association,javaType指定成員變量類型 -->
    <association property="score" javaType="score" />

    <!-- 如果名稱不匹配,手動指定映射 -->
    <association property="score" javaType="score">
        <id property="" column="" />
        <result property="" column=""/>
    </association>


    <!-- 一對多、多對多用collection。注意是ofType,指定List元素類型 -->
    <collection property="" ofType="" />

    <!-- 如果名稱不匹配,手動指定映射 -->
    <collection property="" ofType="">
        <id property="" column="" />
        <result property="" column=""/>
    </collection>
    
</resultMap>

 

動態sql

動態sql是mybatis的強大特性之一,可以實現sql語句的動態組裝。
 

<where>、<if>
where:如果有內容就添加關鍵字WHERE
if:如果條件爲true就添加內容
常用於多條件查詢,一個輸入框指定一個條件,有的輸入框可能沒填

<select id="findUser" resultType="user">
	SELECT * FROM tb_user
	<where>
	   <if test="name!=null and name!=''">
	       name=#{name}
	   </if>
	   <if test="gender!=null and gender!=''">
	       AND tel=#{gender}
	   </if>
	</where>
</select>

 

<choose>、<when>、<otherwise>
相當於switch語句,<when>相當於case,<otherwise>相當於default,條件爲true就加上對應的sql語句

<select id="findStudent" resultType="student">
	SELECT * FROM tb_student WHERE dep=#{dep}
	<choose>
	    <when test="englishLevel=='cet4'">
	        AND english_level='cet4'
	    </when>
	    <when test="englishLevel=='cet6'">
	        AND english_level='cet6'
	    </when>
	    <otherwise>
	        AND english_level<>'cet4' AND english_level<>'cet6'
	    </otherwise>
	</choose>
</select>

 

<set>
傳入pojo類型,更新多個字段,但對象的部分字段可能沒有值,不能用jvm賦的初值null、0去覆蓋表中原來的值,需要先判斷。

<set>用於更新操作,可更新一個對象、也可批量更新(list)。如果有內容,會自動加關鍵字SET,並自動去除內容中多餘的逗號。

<select id="updateUser" parameterType="user">
	UPDATE tb_user
	<set>
	    <if test="name!=null and name!=''">
	    	<!-- 如果後面的內容都爲false,會自動去掉這個逗號 -->
	        name=#{name},
	    </if>
	    <if test="age!=0">
	        age=#{age},
	    </if>
	    <if test="tel!=null and tel!=''">
	        tel=#{tel},
	    </if>
	</set>
	where id=#{id}
</select>

update語句至少要有一個字段更新,不然會報:語法錯誤。

 

<foreach>
<foreach>用於迭代集合,常配合sql關鍵字in使用,批量操作記錄。

  • collection  要迭代的集合的數據類型,List=>list,Map=>key的數據類型
  • index  當前迭代次數,從0開始
  • item  當前迭代元素,map是key
  • open  拼接這整段字符串時以什麼開頭
  • close  拼接這整段字符串時以什麼結尾
  • separator  迭代添加的元素之間用什麼分隔

collection必需,其餘均可選。

<select id="findStudent" parameterType="list" resultType="student">
	SELECT * FROM tb_student WHERE dep IN
	<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
	   #{item}
	</foreach>
</select>

 

<bind>
${ }可拼接字符串,但有sql注入的風險。

使用數據庫自帶的方式拼接字符串沒有sql注入的風險,mysql可以使用concat()拼接字符串,oracle可以使用 || 拼接字符串,但都只能針對特定的數據庫使用,不利於項目移植。

<bind>可拼接字符串,沒有sql注入的風險,所有數據庫都可用。

<!-- 模糊查詢 -->
<select id="queryUser" parameterType="string" resultType="user">
	<bind name="pattern_name" value="'%'+name+'%'"/>
	SELECT * FROM user_tb WHERE name LIKE #{pattern_name}
</select>

 

說明

1、在元素屬性中訪問參數,不加#{ }、${ },直接訪問;在標籤體中訪問參數,要加#{ }、${ }
 
2、test屬性

  • 相等判斷:==,!=
  • 邏輯與:只能用and,不能用&&
  • 邏輯或:or、||均可

 

BindingException: Invalid bound statement (not found)

檢查以下方面

1、xml映射文件的namespace和接口名是否一致,namespace要是接口名的全路徑,id和接口中的函數名是否一致,參數類型、返回值類型是否一致

2、application.properties中mybatis的配置是否正確

3、xml映射文件是否忘寫了後綴.xml
在這裏插入圖片描述
第二個纔是對的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章