天天看點

MyBatis持久層Mapper配置

在開發持久層功能時,需要為對應的功能定義抽象方法,這些抽象方法應該存在于接口中,然後,在接口中添加抽象方法,

關于抽象方法的設計原則:

  • 如果方法對應的功能是執行增、删、改,可以使用`Integer`作為傳回值類型,表示“受影響的行數”,如果不關心傳回值,也可以使用`void`,如果方法對應的功能是查詢,傳回值可以根據實際使用需求來設計;
  • 方法的名稱可以自定義,但絕不可以重載;
  • 方法的參數按需設計;

注意:當方法的參數有多個時,直接聲明多個參數會出現比對不到,解決辦法:可以将這些參數封裝為一個類的屬性,提供get set方法,然後以這個類的對象為參數即可,還可以在每個參數前添加@Param("username")來定義所要比對的mapper.xml配置檔案中預定義的參數名 

package cn.tedu.mybatis;

public interface UserMapper {
    Integer countAll();
    //多個參數需要使用@Param注解來差別
    Integer addnew(@Param("username") String username,@Param("password") String password);
}
           
<?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="cn.tedu.mybatis.UserMapper" >
    <!--配置接口中的方法 id:方法名 resultType:傳回值類型,select語句必須有此屬性-->
    <!--若傳回值時一個List集合,則resultType值為集合中所存元素類型-->
    <select id="countAll" resultType="java.lang.Integer">
		select count(*) from t_user
	</select>

    <insert id="addnew">
     <!--#{}表達式内的名字必須與方法中定義的@Param注解中的值相同-->
     <!--若參數是一個自定義對象,則表達式内的名字必須與對象屬性的名字相同-->
     insert into t_user(username,password) values(#{username},#{password})
    </insert>		
</mapper>
           

實際開發中應該為每張表建立一個對應的實體類,該類封裝表中的所有字段作為屬性

查詢一張表中的一條資料時,傳回值可以是一個該表對應的實體類;

查詢一張表中的多條資料時,傳回值可以是一個該表對應的實體類集合;

關聯表查詢時,傳回值可以設計一個VO類,該類屬性與查詢結果對應;

一對多關聯查詢時(A表一條結果對應B表多條結果),傳回值可以設計一個VO類,該類屬性與查詢結果對應,其中多條結果可以設定為對應的實體類集合(B表對應類的集合);

在這種情況下,需要自定義<resultMap>節點,用于指導MyBatis如何将結果進行封裝:

<!-- id:自定義名稱 -->
<!-- type:傳回結果的類型 -->
<resultMap id="DepartmentVO_Map" type="cn.tedu.mybatis.DepartmentVO">
	<!-- id節點:用于配置主鍵 -->
	<!-- result節點:用于配置非主鍵 -->
	<!-- column:查詢結果的列名 -->
	<!-- property:傳回結果類型中的屬性名 -->
	<!-- 無論哪個節點,都是用于告之MyBatis将查詢結果中哪一列的資料放到傳回類型中的哪個屬性中-->
	<id column="id" property="id"/>
	<result column="name" property="name"/>
	<!-- collection節點:用于配置1對多關系 -->
	<!-- ofType:集合中的元素類型 -->
	<collection property="users" ofType="cn.tedu.mybatis.User">
		<id column="uid" property="id"/>
		<result column="username" property="username"/>
		<result column="password" property="password"/>
		<result column="age" property="age"/>
		<result column="phone" property="phone"/>
		<result column="email" property="email"/>
		<result column="is_delete" property="isDelete"/>
	</collection>
</resultMap>

<select id="findById"
		resultMap="DepartmentVO_Map">
		SELECT 
			t_department.id, name,
			t_user.id AS uid, username,
			password, age,
			phone, email,
			is_delete
		FROM
			t_department
		LEFT JOIN
			t_user
		ON
			t_department.id=t_user.department_id
		WHERE
			t_department.id=#{id}
	</select>
           
MyBatis持久層Mapper配置

需要查詢的結果中的列名與傳回值類型中的屬性名不一緻時,需要自定義别名,使得查詢結果中的列名與傳回值類型中的屬性名保持一緻,如下:User類中的屬性名為isDelete

<select id="findById" resultType="cn.tedu.mybatis.User">
	SELECT 
		id,username,
		password,age,
		phone,email,
		is_delete AS isDelete
	FROM 
		t_user 
	WHERE 
		id=#{id}
</select>
           

動态SQL

動态SQL指的是可以在配置SQL語句添加一些特殊的标簽,例如`<if>`、`<foreach>`等,可以根據參數的不同,最終生成不同的SQL語句,則稱之為動态SQL。

例如:根據若幹個id删除資料,大緻的SQL語句是:delete from t_user where id in (1,3,5,7,9)

在實際應用中,以上`IN`關鍵字後側的括号中的值是不确定的,不光是值本身,值的數量也是不确定,并且各值之間需要使用逗号進行分隔,當值的數量不确定時,逗号的數量也是無法确定的!

在設計參數時,可以使用`List`集合類型,也可以使用數組類型:Integer deleteByIds(List<Integer> ids);

<delete id="deleteByIds">
		DELETE FROM t_user
		WHERE id IN (
			<foreach collection="list"
				item="id" separator=",">
				#{id}
			</foreach>
		)
	</delete>

<!--
collection:需要被周遊的集合或資料,
    如果抽象方法隻有1個參數時,如果參數的類型是`List`集合,則取值為list,
    如果參數類型是數組,則取值為array;
    如果抽象方法有多個參數,則該屬性取值為@Param("xx")注解中使用的名稱。

item:周遊過程中,集合中的元素的名稱,可以使用#{item值}表示被周遊到的元素的值。

separator:分隔符。

open和close:周遊生成的SQL語句部分的最左側字元和最右側字元。
-->
           

#{}與${}占位符

在MyBatis中,配置SQL語句時,可以使用#{}與${}這2種占位符。

#{}:可以用于占位某些值,也就是在SQL中寫值的位置,都可以使用這種占位符(此前在學習JDBC時使用?的位置);

${}:可以表示SQL語句的任何部分!

在使用`#{}`對某個值進行占位時,架構對整個SQL語句是有預編譯處理的,無需考慮該值的資料類型的問題;而使用`${}`占位時,架構的處理方式其實就是非常單純的字元串拼接,需要考慮資料類型的問題,如果占位的值中包括字元串類型的值,則必須使用`''`引号!

由于`#{}`隻能對某個值進行占位,SQL語句本身是相對固定的,是以,這種做法實作的功能的局限性就非常明顯,由于是預編譯的,沒有SQL注入風險,且工作效率較高!而`${}`可以随意占位,功能可以非常靈活,但是,不是預編譯的,有SQL注入風險,工作效率較低。

繼續閱讀