Mybatis學習總結一
1.MyBatis簡介
MyBatis 本是apache的一個開源專案iBatis, 2010年這個專案由apache software foundation 遷移到了google code,並且改名為MyBatis,實質上Mybatis對ibatis進行一些改進。
MyBatis是一個優秀的持久層框架,它對jdbc的操作資料庫的過程進行封裝,使開發者只需要關注 SQL 本身,而不需要花費精力去處理例如註冊驅動、建立connection、建立statement、手動設定引數、結果集檢索等jdbc繁雜的過程程式碼。
Mybatis通過xml或註解的方式將要執行的各種statement(statement、preparedStatemnt、CallableStatement)配置起來,並通過java物件和statement中的sql進行對映生成最終執行的sql語句,最後由mybatis框架執行sql並將結果對映成java物件並返回。
MyBatis架構圖如下:
(1)mybatis配置
SqlMapConfig.xml,此檔案作為mybatis的全域性配置檔案,配置了mybatis的執行環境等資訊。
mapper.xml檔案即sql對映檔案,檔案中配置了操作資料庫的sql語句。此檔案需要在SqlMapConfig.xml中載入。
(2) 通過mybatis環境等配置資訊構造SqlSessionFactory即會話工廠。
(3) 由會話工廠建立sqlSession即會話,操作資料庫需要通過sqlSession進行。
(4)mybatis底層自定義了Executor執行器介面操作資料庫,Executor
(5) Mapped Statement也是mybatis一個底層封裝物件,它包裝了mybatis配置資訊及sql對映資訊等。mapper.xml檔案中一個sql對應一個Mapped Statement物件,sql的id即是Mapped statement的id。
(6) Mapped Statement對sql執行輸入引數進行定義,包括HashMap、基本型別、pojo,Executor通過Mapped Statement在執行sql前將輸入的java物件對映至sql中,輸入引數對映就是jdbc程式設計中對preparedStatement
(7) Mapped Statement對sql執行輸出結果進行定義,包括HashMap、基本型別、pojo,Executor通過Mapped Statement在執行sql後將輸出結果對映至java物件中,輸出結果對映過程相當於jdbc程式設計中對結果的解析處理過程。
2.對映檔案
<mapper namespace="user">
<select id="findUserById" parameterType="int" resultType="com.luchao.mybatis.first.po.User">
select * from user where id = #{id}
</select>
</mapper>
namespace :名稱空間,對sql進行分類化管理,用於隔離sql語句。
id:和namespace 一起標識statement。
parameterType:定義輸入到sql中的對映型別,#{id}表示使用preparedstatement設定佔位符號並將輸入變數id傳到sql。
resultType:定義結果對映型別。
3.#{}與${} #{}表示一個佔位符號,通過#{}可以實現preparedStatement向佔位符中設定值,自動進行java型別和jdbc型別轉換,#{}可以有效防止sql注入。 #{}可以接收簡單型別值或pojo屬性值。 如果parameterType傳輸單個簡單型別值,#{}括號中可以是value或其它名稱。
${}表示拼接sql串,通過${}可以將parameterType 傳入的內容拼接在sql中且不進行jdbc型別轉換, ${}可以接收簡單型別值或pojo屬性值,如果parameterType傳輸單個簡單型別值,${}括號中只能是value。
4.新增並返回主鍵
如果mysql是自增主鍵,對映檔案如下:
insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
<!-- selectKey將主鍵返回,需要再返回 -->
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
select LAST_INSERT_ID()
</selectKey>
insert into user(username,birthday,sex,address)
values(#{username},#{birthday},#{sex},#{address});
</insert>
新增selectKey實現將主鍵返回
keyProperty:返回的主鍵儲存在pojo中的哪個屬性
order:selectKey的執行順序,是相對與insert語句來說,由於mysql的自增原理執行完insert語句之後才將主鍵生成,所以這裡selectKey的執行順序為after
resultType:返回的主鍵是什麼型別
LAST_INSERT_ID():是mysql的函式,返回auto_increment自增列新記錄id值。
如果mysql是UUID實現,對映檔案如下:
<insert id="insertUser" parameterType="cn.luchao.mybatis.po.User">
<selectKey resultType="java.lang.String" order="BEFORE" keyProperty="id">
select uuid()
</selectKey>
insert into user(id,username,birthday,sex,address)
values(#{id},#{username},#{birthday},#{sex},#{address})
</insert>
注意這裡使用的order是“BEFORE”。
Oracle使用序列實現,對映檔案如下:
<insert id="insertUser" parameterType="cn.luchao.mybatis.po.User">
<selectKey resultType="java.lang.Integer" order="BEFORE" keyProperty="id">
SELECT 自定義序列.NEXTVAL FROM DUAL
</selectKey>
insert into user(id,username,birthday,sex,address)
values(#{id},#{username},#{birthday},#{sex},#{address})
</insert>
注意這裡使用的order是“BEFORE”。
5.MyBatis與Habernate的比較
Mybatis和hibernate不同,它不完全是一個ORM框架,因為MyBatis需要程式設計師自己編寫Sql語句,不過mybatis可以通過XML或註解方式靈活配置要執行的sql語句,並將java物件和sql語句對映生成最終執行的sql,最後將sql執行的結果再對映生成java物件。
Mybatis學習門檻低,簡單易學,程式設計師直接編寫原生態sql,可嚴格控制sql執行效能,靈活度高,非常適合對關係資料模型要求不高的軟體開發,例如網際網路軟體、企業運營類軟體等,因為這類軟體需求變化頻繁,一但需求變化要求成果輸出迅速。但是靈活的前提是mybatis無法做到資料庫無關性,如果需要實現支援多種資料庫的軟體則需要自定義多套sql對映檔案,工作量大。專注是sql本身,需要程式設計師自己編寫sql語句,sql修改、優化比較方便。mybatis是一個不完全 的ORM框架,可以簡單理解為SQL Mapper,雖然程式設計師自己寫sql,mybatis 也可以實現對映(輸入對映、輸出對映)。應用場景:適用與需求變化較多的專案,比如:網際網路專案。
Hibernate物件/關係對映能力強,資料庫無關性好,對於關係模型要求高的軟體(例如需求固定的定製化軟體)如果用hibernate開發可以節省很多程式碼,提高效率。但是Hibernate的學習門檻高,要精通門檻更高,而且怎麼設計O/R對映,在效能和物件模型之間如何權衡,以及怎樣用好Hibernate需要具有很強的經驗和能力才行。是一個標準ORM框架(物件關係對映)。入門門檻較高的,不需要程式寫sql,sql語句自動生成了,對sql語句進行優化、修改比較困難的。應用場景:適用與需求變化不多的中小型專案,比如:後臺管理系統,erp、orm、oa。
6.Mapper動態代理方式
(1)實現原理
Mapper介面開發方法只需要程式設計師編寫Mapper介面(相當於Dao介面),由Mybatis框架根據介面定義建立介面的動態代理物件,代理物件的方法體同上邊Dao介面實現類方法。這樣通過動態代理就實現了將模板方法進行封裝,只需要實現具體的實現即可。
Mapper介面開發需要遵循以下規範:
a、 Mapper.xml檔案中的namespace與mapper介面的類路徑相同。
b、 Mapper介面方法名和Mapper.xml中定義的每個statement的id相同 。
c、 Mapper介面方法的輸入引數型別和mapper.xml中定義的每個sql 的parameterType的型別相同。
d、 Mapper介面方法的輸出引數型別和mapper.xml中定義的每個sql的resultType的型別相同。
(2)Mapper.xml(對映檔案)對映檔案與原始Dao開發的對映檔案相似,只需要將namespace定於為mapper介面全路徑。
<?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.luchao.mybatis.first.mapper.UserMapper">
<!-- 根據id獲取使用者資訊 -->
<select id="findUserById" parameterType="int" resultType="user">
select * from user where id = #{id}
</select>
<!-- 根據username模糊查詢使用者資訊 -->
<select id="findUserByName" parameterType="java.lang.String" resultType="com.luchao.mybatis.first.po.User">
select * from user where username like '%${value}%'
</select>
<!-- 新增使用者資訊 -->
<insert id="insertUser" parameterType="com.luchao.mybatis.first.po.User">
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
select LAST_INSERT_ID()
</selectKey>
insert into user(username,birthday,sex,address) value (#{username},#{birthday},#{sex},#{address});
</insert>
<!-- 根據id刪除使用者資訊 -->
<delete id="deleteUser" parameterType="int">
delete from user where id=#{id}
</delete>
<!-- 修改使用者資訊 -->
<update id="updateUser" parameterType="com.luchao.mybatis.first.po.User">
update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address}
where id=#{id}
</update>
</mapper>
(3)Mapper.java(介面檔案)public interface UserMapper {
//根據ID查詢使用者資訊
public User findUserById(int id) throws Exception;
//新增使用者資訊
public void insertUser(User user) throws Exception;
//刪除使用者資訊
public void deleteUser(int id) throws Exception;
//更新使用者資訊
public void updateUser(User user) throws Exception;
//根據使用者名稱模糊查詢
public List<User> findUserByName(String user) throws Exception;
}
介面定義有如下特點:
a、 Mapper介面方法名和Mapper.xml中定義的statement的id相同。
b、 Mapper介面方法的輸入引數型別和mapper.xml中定義的statement的parameterType的型別相同。
c、 Mapper介面方法的輸出引數型別和mapper.xml中定義的statement的resultType的型別相同。
Mapper動態代理總結:a、動態代理物件呼叫sqlSession.selectOne()和sqlSession.selectList()是根據mapper介面方法的返回值決定,如果返回list則呼叫selectList方法,如果返回單個物件則呼叫selectOne方法。
b、使用mapper代理方法時,輸入引數可以使用pojo包裝物件或map物件,保證dao的通用性。在系統中,dao層的程式碼是被業務層公用的。即使mapper介面只有一個引數,可以使用包裝型別的pojo滿足不同的業務方法的需求。
注意:持久層方法的引數可以包裝型別、map等,service方法中建議不要使用包裝型別(不利於業務層的可擴充套件)。 mybatis開發dao的方法有兩種:原始Dao開發和Mapper動態代理開發,這兩種各有優點。原始Dao開發:程式設計師要寫Dao和Dao實現,需要些較多的程式碼,但是比較好理解。Mapper動態代理:程式設計師只需要寫Mapper介面,然後按照規範進行配置,MyBatis就會自動實現類似Dao實現,減少模板方法。mybatis官方推薦使用mapper代理方法開發mapper介面,程式設計師不用編寫mapper介面實現類,使用mapper代理方法時,輸入引數可以使用pojo包裝物件或map物件,保證dao的通用性。