Mybatis框架的一點個人心得
MyBatis
mybatis 框架是現在比較流行的一個持久層框架,以下是我自己寫的一些總結,主要講的時它的使用方式,詳細資料請訪問他們的官網。
概述
mybatis 是一個優秀的基於 java 的持久層框架,它內部封裝了 jdbc,使開發者只需要關注 sql 語句本身,而不需要花費精力去處理載入驅動、建立連線、建立 statement
等繁雜的過程。
mybatis 通過 xml 或註解的方式將要執行的各種 statement
配置起來,並通過 java 物件和 statement
中sql 的動態引數進行對映生成最終執行的 sql 語句,最後由 mybatis 框架執行 sql 並將結果對映為 java 物件並返回。
採用 ORM 思想解決了實體和資料庫對映的問題,對 jdbc 進行了封裝,遮蔽了 jdbc api 底層訪問細節,使我們不用與 jdbc api 打交道,就可以完成對資料庫的持久化操作。
ORM:
Object Relational Mappging 物件關係對映
簡單的說:就是把資料庫表和實體類及實體類的屬性對應起來讓我們可以操作實體類就實現操作資料庫表。
開發方式
它的使用方法分為兩種一種是 xml 配置檔案,另一種是直接使用註解。
這兩種方式各有優勢,其中 xml 配置檔案的優勢在於思路清晰,維護方便,在需要修改專案時,不需要重新編譯,只需要修改配置檔案即可;而註解開發,因為不需要去配置檔案,所以它的開發速度更快,也是因為這點,近幾年來也更流行使用註解開發。
主配置檔案的編寫,通常命名為SqlMapConfig.xml
首先是主配置檔案編寫,以及需要注意的地方。在配置完之後,就可以選擇兩種不同開發方式了。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 配置properties--> <properties resource="jdbcConfig.properties"></properties> <!--使用typeAliases配置別名,它只能配置domain中類的別名,批量別名定義,掃描整個包下的類,別名為類名(首字母大寫或小寫都可以) --> <typeAliases> <package name="com.itheima.domain"></package> </typeAliases> <!-- 配置 mybatis 的環境 --> <environments default="mysql"> <!-- 配置 mysql 的環境 --> <environment id="mysql"> <!-- 配置事務的型別 --> <transactionManager type="JDBC"></transactionManager> <!-- 配置連線資料庫的資訊:用的是資料來源(連線池) --> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"></property> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </dataSource> </environment> </environments> <!-- 告知 mybatis 對映配置的位置 --> <mappers> <package name="com.itheima.dao"></package> </mappers> </configuration>
- 在使用
properties
標籤配置時,我們可以配置檔案來指定屬性配置。這樣,下面的資料庫資訊就可以引用配置檔案,方便以後修改。 - 在使用
typeAliases
標籤,我們可以也可以採用自定義別名的方式來開發,別名不區分大小寫。 mappers
標籤有兩種子標籤mapper
標籤裡面有兩個常用屬性(注意:資源路徑之間用/分隔,包路徑用.分隔。)mapper
標籤裡的的resource
屬性使用相對於類路徑的資源,使用 xml 開發時才使用。mapper
標籤裡的的class
屬性使用mapper
介面類路徑,使用註解開發時才使用。(注意:此種方法要求mapper
介面名稱和mapper
對映檔名稱相同,且放在同一個目錄中。)
package
標籤裡的name
屬性指定包下的所有mapper
介面,兩種開發方式均可使用,也更為常用,它可以用來替代mapper
標籤。(注意:此種方法要求mapper
介面名稱和mapper
對映檔名稱相同,且放在同一個目錄中。)
xml開發方式
只是寫了對映配置檔案的編寫以及其中需要注意的地方。
對映配置檔案的編寫
基本使用方法
<?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.itheima.dao.IUserDao">
<!-- 配置 查詢結果的列名和實體類的屬性名的對應關係 -->
<resultMap id="userMap" type="uSeR">
<!-- 主鍵欄位的對應 -->
<id property="userId" column="id"></id>
<!--非主鍵欄位的對應-->
<result property="userName" column="username"></result>
<result property="userAddress" column="address"></result>
<result property="userSex" column="sex"></result>
<result property="userBirthday" column="birthday"></result>
</resultMap>
<!-- 查詢所有 -->
<select id="findAll" resultMap="userMap">
<!--select id as userId,username as userName,address as userAddress,sex as userSex,birthday as userBirthday from user;-->
select * from user;
</select>
</mapper>
- 在使用
mapper
標籤時,其中的namespace
屬性必須是 dao 類的全限定類名,因為 mabatis 框架是根據namespace
屬性和statemen
標籤中的id
屬性來對資料庫進行操作的,也就是根據com.itheima.dao.IUserDao.findAll 反射來確定的。 - 資料庫中表的列名與我們實體類中的成員變數名不一致時,我們可以通過取別名的方式來對結果封裝,或者是用
resultMap
標籤來指定列名及其對應的變數名,當我們在對查詢結果封裝需要用到它時,就可以直接使用resultMap
屬性來引用它,如果不需要時,就可以直接使用resultType
屬性來直接指定所要封裝的類。 - 對資料庫的四種增刪改查操作分別對應
insert
delete
update
select
四種標籤
根據條件查詢時
<!-- 根據id查詢使用者 -->
<select id="findById" parameterType="INT" resultMap="userMap">
select * from user where id = #{uid}
</select>
<!-- 根據名稱模糊查詢 -->
<select id="findByName" parameterType="string" resultMap="userMap">
select * from user where username like #{name}
<!-- select * from user where username like '%${value}%'-->
</select>
- 查詢的條件使用
#{xxx}
來作為佔位符使用,當只有一個條件時,花括號裡的內容可以隨便寫,當有多個條件時,花括號裡的內容就必須與實體類中的變數名相同。 - 使用模糊查詢時的佔位符有兩種形式
#{name}
或'%${value}%'
,前者花括號內可以隨便寫,而後者必須寫value
,但是前者的 % 符號只能在 java 語句中去拼接,而後者就可以在配置檔案中寫好。
動態sql語句
<select id="findUserByCondition" resultMap="userMap" parameterType="user">
select * from user
<where>
<if test="userName != null">
and username = #{userName}
</if>
<if test="userSex != null">
and sex = #{userSex}
</if>
<if test="ids != null and ids.size()>0">
<foreach collection="ids" open="and id in (" close=")" item="uid" separator=",">
#{uid}
</foreach>
</if>
</where>
</select>
where
標籤是用來代替 sql 語句中的where
或者and
關鍵字的,它會根據實際情況判斷。if
標籤是用來判斷是否需要用到這個條件時的。foreach
標籤就是進行範圍查詢時使用,其中的collection
屬性對應實體類中的變數名,open
和close
屬性就是單純的拼接,item
屬性是指定每一個遍歷的變數名,separator
屬性是指定分隔符。標籤體中的內容與就是每一次遍歷的佔位符,花括號裡的內容與item
屬性保持一致。
多表查詢
在 mybatis 中只有一對一和一對多,它將多對多當成了多個一對多,而多對一就是多個一對一。
一對一
<!-- 定義封裝account和user的resultMap -->
<resultMap id="accountUserMap" type="account">
<id property="id" column="aid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!-- 一對一的關係對映:配置封裝user的內容-->
<association property="user" column="uid" javaType="user">
<id property="id" column="id"></id>
<result column="username" property="username"></result>
<result column="address" property="address"></result>
<result column="sex" property="sex"></result>
<result column="birthday" property="birthday"></result>
</association>
</resultMap>
<!-- 查詢所有 -->
<select id="findAll" resultMap="accountUserMap">
select u.*,a.id as aid,a.uid,a.money from account a , user u where u.id = a.uid;
</select>
- 使用
association
標籤來指定關聯的對應表的單條資料,其中的property
屬性對應實體類中的變數名,column
屬性對應關聯的外來鍵名稱,javaType
指定要封裝的實體類。在標籤體中,必須先寫從表的主鍵列。
一對多
<!-- 定義User的resultMap-->
<resultMap id="userAccountMap" type="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<!-- 配置user物件中accounts集合的對映 -->
<collection property="accounts" ofType="account">
<id column="aid" property="id"></id>
<result column="uid" property="uid"></result>
<result column="money" property="money"></result>
</collection>
</resultMap>
<!-- 查詢所有 -->
<select id="findAll" resultMap="userAccountMap">
select * from user u left outer join account a on u.id = a.uid
</select>
- 使用
collection
標籤來指定關聯的對應表的多條資料,其中其中的property
屬性對應實體類中的變數名,ofType
指定每一條資料所要封裝的實體類。在標籤體中,必須先寫從表的主鍵列。
延遲載入和立即載入
延遲載入就是在需要用到資料時才進行載入,不需要用到資料時就不載入資料。延遲載入也稱懶載入。在一對多時通常採用延遲載入,而在一對一時通常採用立即載入,因為這樣能提高資料庫效能。
首先要在主配置檔案中開啟延遲載入
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
然後在對映檔案中進行配置
<!-- 定義封裝account和user的resultMap -->
<resultMap id="accountUserMap" type="account">
<id property="id" column="id"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<association property="user" column="uid" javaType="user" select="com.itheima.dao.IUserDao.findById"></association>
</resultMap>
<!-- 查詢所有 -->
<select id="findAll" resultMap="accountUserMap">
select * from account
</select>
<!-- 根據使用者id查詢賬戶列表 -->
<select id="findAccountByUid" resultType="account">
select * from account where uid = #{uid}
</select>
<!-- 定義User的resultMap-->
<resultMap id="userAccountMap" type="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<!-- 配置user物件中accounts集合的對映 -->
<collection property="accounts" ofType="account" select="com.itheima.dao.IAccountDao.findAccountByUid" column="id"></collection>
</resultMap>
<!-- 查詢所有 -->
<select id="findAll" resultMap="userAccountMap">
select * from user
</select>
<!-- 根據id查詢使用者 -->
<select id="findById" parameterType="INT" resultType="user">
select * from user where id = #{uid}
</select>
- 上面分別是一對一和一對多的延遲載入配置,其實就是在
association
標籤或者是collection
標籤中新增select
屬性來指定關聯的表需要用到哪個方法來查詢,即對應的類的dao介面的全限定名.方法名,以及column
屬性來指定關聯的外來鍵名稱。可以省去我們在多表查詢時編寫複雜的 sql 語句。
註解開發方式
在使用註解開發時,不要有對映配置檔案的存在,否則程式會以為你要使用 xml 配置檔案開發。
基本使用方法
public interface IUserDao {
@Select("select * from user")
@Results(id="userMap",value={
@Result(id=true,column = "id",property = "userId"),
@Result(column = "username",property = "userName"),
@Result(column = "address",property = "userAddress"),
@Result(column = "sex",property = "userSex"),
@Result(column = "birthday",property = "userBirthday")
})
List<User> findAll();
@Select("select * from user where id=#{id} ")
@ResultMap("userMap")
User findById(Integer userId);
}
- 只需要在方法上添加註解,並且在註解中表明 sql 語句即可。對資料庫的四種增刪改查操作D分別對應
@Insert
@delete
@Update
@Select
四種註解。 - 資料庫中表的列名於我們實體類中的成員變數名不一致時,我們可以通過取別名的方式來對結果封裝,或者是用
@Results
標籤來指定列名及其對應的變數名。當其它的方法在對查詢結果封裝需要用到它時,就可以直接使用@ResultMap
註解來引用它。
根據條件查詢時
@Select("select * from user where id=#{id} ")
@ResultMap("userMap")
User findById(Integer userId);
@Select("select * from user where username like #{username} ")
@ResultMap("userMap")
List<User> findUserByName(String username);
- 查詢的條件使用
#{xxx}
來作為佔位符使用,當只有一個條件時,花括號裡的內容可以隨便寫,當有多個條件時,花括號裡的內容就必須與實體類中的變數名相同。 - 使用模糊查詢時的佔位符只有一種形式
#{name}
,花括號內可以隨便寫。
動態 sql 語句查詢
使用註解進行動態 sql 語句查詢時,需要用到上述 xml 開發方式裡的動態 sql 語句查詢的標籤,並且將其置於<script>
</script>
標籤中,將其當作指令碼執行,使用起來極其不便,不推薦使用。
多表查詢
@Select("select * from account")
@Results(id="accountMap",value = {
@Result(id=true,column = "id",property = "id"),
@Result(column = "uid",property = "uid"),
@Result(column = "money",property = "money"),
@Result(property = "user",column = "uid",
[email protected](select="com.itheima.dao.IUserDao.findById",
fetchType= FetchType.EAGER))
})
List<Account> findAll();
-
在一對一查詢時,使用
@Result
註解來指定關聯的對應表的單條資料,其中的property
屬性對應實體類中的變數名,column
屬性對應關聯的外來鍵名稱,然後在註解中使用@One
註解新增select
屬性來指定關聯的表需要用到哪個方法來查詢,即對應的類的dao介面的全限定名.方法名,以及fetchType
屬性來指定載入方式。@Select("select * from user") @Results(id="userMap",value={ @Result(id=true,column = "id",property = "userId"), @Result(column = "username",property = "userName"), @Result(column = "address",property = "userAddress"), @Result(column = "sex",property = "userSex"), @Result(column = "birthday",property = "userBirthday"), @Result(property = "accounts",column = "id", many = @Many(select = "com.itheima.dao.IAccountDao.findAccountByUid", fetchType = FetchType.LAZY)) }) List<User> findAll();
-
在一對多查詢時,使用
@Result
註解來指定關聯的對應表的單條資料,其中的property
屬性對應實體類中的變數名,column
屬性對應關聯的外來鍵名稱,然後在註解中使用@Many
註解新增select
屬性來指定關聯的表需要用到哪個方法來查詢,即對應的類的dao介面的全限定名.方法名,以及fetchType
屬性來指定載入方式。