1. 程式人生 > >Mybatis框架的一點個人心得

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 屬性對應實體類中的變數名,openclose 屬性就是單純的拼接,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 屬性來指定載入方式。