在開發持久層功能時,需要為對應的功能定義抽象方法,這些抽象方法應該存在于接口中,然後,在接口中添加抽象方法,
關于抽象方法的設計原則:
- 如果方法對應的功能是執行增、删、改,可以使用`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>

需要查詢的結果中的列名與傳回值類型中的屬性名不一緻時,需要自定義别名,使得查詢結果中的列名與傳回值類型中的屬性名保持一緻,如下: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注入風險,工作效率較低。