1. 程式人生 > >Mybatis學習總結一

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物件,sqlid即是Mapped statementid

  (6) Mapped Statementsql執行輸入引數進行定義,包括HashMap、基本型別、pojoExecutor通過Mapped Statement在執行sql前將輸入的java物件對映至sql中,輸入引數對映就是jdbc程式設計中對preparedStatement

設定引數。

  (7) Mapped Statementsql執行輸出結果進行定義,包括HashMap、基本型別、pojoExecutor通過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中的哪個屬性

orderselectKey的執行順序,是相對與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的比較

Mybatishibernate不同,它不完全是一個ORM框架,因為MyBatis需要程式設計師自己編寫Sql語句,不過mybatis可以通過XML或註解方式靈活配置要執行的sql語句,並將java物件和sql語句對映生成最終執行的sql,最後將sql執行的結果再對映生成java物件。 

    Mybatis學習門檻低,簡單易學,程式設計師直接編寫原生態sql,可嚴格控制sql執行效能,靈活度高,非常適合對關係資料模型要求不高的軟體開發,例如網際網路軟體、企業運營類軟體等,因為這類軟體需求變化頻繁,一但需求變化要求成果輸出迅速。但是靈活的前提是mybatis無法做到資料庫無關性,如果需要實現支援多種資料庫的軟體則需要自定義多套sql對映檔案,工作量大。專注是sql本身,需要程式設計師自己編寫sql語句,sql修改、優化比較方便。mybatis是一個不完全 的ORM框架,可以簡單理解為SQL Mapper,雖然程式設計師自己寫sqlmybatis 也可以實現對映(輸入對映、輸出對映)。應用場景:適用與需求變化較多的專案,比如:網際網路專案。 

    Hibernate物件/關係對映能力強,資料庫無關性好,對於關係模型要求高的軟體(例如需求固定的定製化軟體)如果用hibernate開發可以節省很多程式碼,提高效率。但是Hibernate的學習門檻高,要精通門檻更高,而且怎麼設計O/R對映,在效能和物件模型之間如何權衡,以及怎樣用好Hibernate需要具有很強的經驗和能力才行。是一個標準ORM框架(物件關係對映)。入門門檻較高的,不需要程式寫sqlsql語句自動生成了,sql語句進行優化、修改比較困難的。應用場景:適用與需求變化不多的中小型專案,比如:後臺管理系統,erpormoa

6.Mapper動態代理方式

(1)實現原理

Mapper介面開發方法只需要程式設計師編寫Mapper介面(相當於Dao介面),由Mybatis框架根據介面定義建立介面的動態代理物件,代理物件的方法體同上邊Dao介面實現類方法。這樣通過動態代理就實現了將模板方法進行封裝,只需要實現具體的實現即可。

Mapper介面開發需要遵循以下規範:

a、 Mapper.xml檔案中的namespacemapper介面的類路徑相同。

b、 Mapper介面方法名和Mapper.xml中定義的每個statementid相同 。

c、 Mapper介面方法的輸入引數型別和mapper.xml中定義的每個sql parameterType的型別相同。

d、 Mapper介面方法的輸出引數型別和mapper.xml中定義的每個sqlresultType的型別相同。

(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中定義的statementresultType的型別相同。

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的通用性。