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

Mybatis 學習總結

1 Mybatis入門

1.1 單獨使用jdbc程式設計問題總結

1.1.1 jdbc程式

public static void main(String[] args) {
           Connection connection = null;
           PreparedStatement preparedStatement = null;
           ResultSet resultSet = null;
          
           try {
              //載入資料庫驅動
              Class.forName("com.mysql.jdbc.Driver");
             
              
//通過驅動管理類獲取資料庫連結 connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "mysql"); //定義sql語句 ?表示佔位符 String sql = "select * from user where username = ?"; //獲取預處理statement preparedStatement = connection.prepareStatement(sql);
//設定引數,第一個引數為sql語句中引數的序號(從1開始),第二個引數為設定的引數值 preparedStatement.setString(1, "王五"); //向資料庫發出sql執行查詢,查詢出結果集 resultSet = preparedStatement.executeQuery(); //遍歷查詢結果集 while(resultSet.next()){ System.out.println(resultSet.getString(
"id")+" "+resultSet.getString("username")); } } catch (Exception e) { e.printStackTrace(); }finally{ //釋放資源 if(resultSet!=null){ try { resultSet.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(preparedStatement!=null){ try { preparedStatement.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(connection!=null){ try { connection.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }

上邊使用jdbc的原始方法(未經封裝)實現了查詢資料庫表記錄的操作。

1.1.2  jdbc程式設計步驟:

  1. 載入資料庫驅動
  2. 建立並獲取資料庫連結
  3. 建立jdbc statement物件
  4. 設定sql語句
  5. 設定sql語句中的引數(使用preparedStatement)
  6. 通過statement執行sql並獲取結果
  7. 對sql執行結果進行解析處理
  8. 釋放資源(resultSet、preparedstatement、connection)

1.1.3  jdbc問題總結如下:

  1. 資料庫連結建立、釋放頻繁造成系統資源浪費從而影響系統性能,如果使用資料庫連結池可解決此問題。
  2. Sql語句在程式碼中硬編碼,造成程式碼不易維護,實際應用sql變化的可能較大,sql變動需要改變java程式碼。
  3. 使用preparedStatement向佔有位符號傳引數存在硬編碼,因為sql語句的where條件不一定,可能多也可能少,修改sql還要修改程式碼,系統不易維護。
  4. 對結果集解析存在硬編碼(查詢列名),sql變化導致解析程式碼變化,系統不易維護,如果能將資料庫記錄封裝成pojo物件解析比較方便。

1.2  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物件並返回。

1.3    Mybatis架構

 

  1. mybatis配置

SqlMapConfig.xml,此檔案作為mybatis的全域性配置檔案,配置了mybatis的執行環境等資訊。

mapper.xml檔案即sql對映檔案,檔案中配置了操作資料庫的sql語句。此檔案需要在SqlMapConfig.xml中載入。

  1. 通過mybatis環境等配置資訊構造SqlSessionFactory即會話工廠
  2. 由會話工廠建立sqlSession即會話,操作資料庫需要通過sqlSession進行。
  3. mybatis底層自定義了Executor執行器介面操作資料庫,Executor介面有兩個實現,一個是基本執行器、一個是快取執行器。
  4. Mapped Statement也是mybatis一個底層封裝物件,它包裝了mybatis配置資訊及sql對映資訊等。mapper.xml檔案中一個sql對應一個Mapped Statement物件,sql的id即是Mapped statement的id。
  5. Mapped Statement對sql執行輸入引數進行定義,包括HashMap、基本型別、pojo,Executor通過Mapped Statement在執行sql前將輸入的java物件對映至sql中,輸入引數對映就是jdbc程式設計中對preparedStatement設定引數。
  6. Mapped Statement對sql執行輸出結果進行定義,包括HashMap、基本型別、pojo,Executor通過Mapped Statement在執行sql後將輸出結果對映至java物件中,輸出結果對映過程相當於jdbc程式設計中對結果的解析處理過程。

1.4    mybatis下載

mybaits的程式碼由github.com管理,地址:https://github.com/mybatis/mybatis-3/releases

 

mybatis-3.2.7.jar----mybatis的核心包

lib----mybatis的依賴包

mybatis-3.2.7.pdf----mybatis使用手冊

1.5    建立mysql資料庫

先匯入sql_table.sql,再匯入 sql_data.sql指令碼:

 

如下:

 

1.6    Mybatis入門程式

1.6.1  需求

實現以下功能:

根據使用者id查詢一個使用者資訊

根據使用者名稱稱模糊查詢使用者資訊列表

新增使用者

更新使用者

刪除使用者

1.6.2  第一步:建立java工程

使用eclipse建立java工程,jdk使用1.7.0_72。

1.6.3  第二步:加入jar包

加入mybatis核心包、依賴包、資料驅動包。

1.6.4  第三步:log4j.properties

在classpath下建立log4j.properties如下:

# Global logging configuration

log4j.rootLogger=DEBUG, stdout

# Console output...

log4j.appender.stdout=org.apache.log4j.ConsoleAppender

log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

mybatis預設使用log4j作為輸出日誌資訊。

1.6.5  第四步:SqlMapConfig.xml

在classpath下建立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>

   <!-- 和spring整合後 environments配置將廢除-->

   <environments default="development">

      <environment id="development">

      <!-- 使用jdbc事務管理-->

         <transactionManager type="JDBC" />

      <!-- 資料庫連線池-->

         <dataSource type="POOLED">

            <property name="driver" value="com.mysql.jdbc.Driver" />

            <property name="url"value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8"/>

            <property name="username" value="root" />

            <property name="password" value="mysql" />

         </dataSource>

      </environment>

   </environments>

  

</configuration>

SqlMapConfig.xml是mybatis核心配置檔案,上邊檔案的配置內容為資料來源、事務管理。

1.6.6  第五步:po類

Po類作為mybatis進行sql對映使用,po類通常與資料庫表對應,User.java如下:

public class User {

    private int id;

    private String username;// 使用者姓名

    private String sex;// 性別

    private Date birthday;// 生日

    private String address;// 地址

get/set……

1.6.7  第六步:程式編寫

1.6.7.1 查詢

1.6.7.1.1    對映檔案:

在classpath下的sqlmap目錄下建立sql對映檔案Users.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="test">

</mapper>

namespace :名稱空間,用於隔離sql語句,後面會講另一層非常重要的作用。

在SqlMapConfig.xml中新增:

<!-- 根據id獲取使用者資訊 -->

    <select id="findUserById" parameterType="int"resultType="cn.itcast.mybatis.po.User">

       select * from user where id = #{id}

    </select>

    <!-- 自定義條件查詢使用者列表 -->

    <select id="findUserByUsername" parameterType="java.lang.String"

           resultType="cn.itcast.mybatis.po.User">

       select * from user where username like '%${value}%'

    </select>

parameterType:定義輸入到sql中的對映型別,#{id}表示使用preparedstatement設定佔位符號並將輸入變數id傳到sql。

resultType:定義結果對映型別。

1.6.7.1.2         載入對映檔案

mybatis框架需要載入對映檔案,將Users.xml新增在SqlMapConfig.xml,如下:

 

<mappers>

       <mapper resource="sqlmap/User.xml"/>

</mappers>
1.6.7.1.3         測試程式:
public class Mybatis_first {

   

    //會話工廠

    private SqlSessionFactory sqlSessionFactory;

 

    @Before

    public void createSqlSessionFactory() throws IOException {

       // 配置檔案

       String resource = "SqlMapConfig.xml";

       InputStream inputStream = Resources.getResourceAsStream(resource);

 

       // 使用SqlSessionFactoryBuilder從xml配置檔案中建立SqlSessionFactory

       sqlSessionFactory = new SqlSessionFactoryBuilder()

              .build(inputStream);

 

    }

 

    // 根據 id查詢使用者資訊

   @Test

   public void testFindUserById() {

      // 資料庫會話例項

      SqlSession sqlSession = null;

      try {

         // 建立資料庫會話例項sqlSession

         sqlSession = sqlSessionFactory.openSession();

         // 查詢單個記錄,根據使用者id查詢使用者資訊

         User user = sqlSession.selectOne("test.findUserById", 10);

         // 輸出使用者資訊

         System.out.println(user);

      } catch (Exception e) {

         e.printStackTrace();

      } finally {

         if (sqlSession != null) {

            sqlSession.close();

         }

      }

 

   }

 

   // 根據使用者名稱稱模糊查詢使用者資訊

   @Test

   public void testFindUserByUsername() {

      // 資料庫會話例項

      SqlSession sqlSession = null;

      try {

         // 建立資料庫會話例項sqlSession

         sqlSession = sqlSessionFactory.openSession();

         // 查詢單個記錄,根據使用者id查詢使用者資訊

         List<User> list = sqlSession.selectList("test.findUserByUsername", "張");

         System.out.println(list.size());

      } catch (Exception e) {

         e.printStackTrace();

      } finally {

         if (sqlSession != null) {

            sqlSession.close();

         }

      }

 

   }

}

 
1.6.7.1.4         #{}和${}

#{}表示一個佔位符號,通過#{}可以實現preparedStatement向佔位符中設定值,自動進行java型別和jdbc型別轉換,#{}可以有效防止sql注入。 #{}可以接收簡單型別值或pojo屬性值。 如果parameterType傳輸單個簡單型別值,#{}括號中可以是value或其它名稱。

${}表示拼接sql串,通過${}可以將parameterType 傳入的內容拼接在sql中且不進行jdbc型別轉換, ${}可以接收簡單型別值或pojo屬性值,如果parameterType傳輸單個簡單型別值,${}括號中只能是value。

1.6.7.1.5         parameterType和resultType

parameterType:指定輸入引數型別,mybatis通過ognl從輸入物件中獲取引數值拼接在sql中。

resultType:指定輸出結果型別,mybatis將sql查詢結果的一行記錄資料對映為resultType指定型別的物件。

1.6.7.1.6         selectOne和selectList

selectOne查詢一條記錄,如果使用selectOne查詢多條記錄則丟擲異常:

org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 3

    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:70)

selectList可以查詢一條或多條記錄。

1.6.7.2 新增

1.6.7.2.1         對映檔案:

在SqlMapConfig.xml中新增:

<!-- 新增使用者 -->

    <insert id="insertUser"parameterType="cn.itcast.mybatis.po.User">

    <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>

 
1.6.7.2.2         測試程式:
// 新增使用者資訊

    @Test

    public void testInsert() {

       // 資料庫會話例項

       SqlSession sqlSession = null;

       try {

           // 建立資料庫會話例項sqlSession

           sqlSession = sqlSessionFactory.openSession();

           // 新增使用者資訊

           User user = new User();

           user.setUsername("張小明");

           user.setAddress("河南鄭州");

           user.setSex("1");

           user.setPrice(1999.9f);

           sqlSession.insert("test.insertUser", user);

           //提交事務

           sqlSession.commit();

       } catch (Exception e) {

           e.printStackTrace();

       } finally {

           if (sqlSession != null) {

              sqlSession.close();

           }

       }

    }
1.6.7.2.3         mysql自增主鍵返回

通過修改sql對映檔案,可以將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值。

1.6.7.2.4         Mysql使用 uuid實現主鍵

需要增加通過select uuid()得到uuid值

<insert  id="insertUser" parameterType="cn.itcast.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”

1.6.7.2.5         Oracle使用序列生成主鍵

首先自定義一個序列且用於生成主鍵,selectKey使用如下:

<insert  id="insertUser" parameterType="cn.itcast.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”

1.6.7.3 刪除

1.6.7.3.1         對映檔案:
<!-- 刪除使用者 -->

    <delete id="deleteUserById" parameterType="int">

       delete from user where id=#{id}

    </delete>
1.6.7.3.2         測試程式:

 

// 根據id刪除使用者

    @Test

    public void testDelete() {

       // 資料庫會話例項

       SqlSession sqlSession = null;

       try {

           // 建立資料庫會話例項sqlSession

           sqlSession = sqlSessionFactory.openSession();

           // 刪除使用者

           sqlSession.delete("test.deleteUserById",18);

           // 提交事務

           sqlSession.commit();

       } catch (Exception e) {

           e.printStackTrace();

       } finally {

           if (sqlSession != null) {

              sqlSession.close();

           }

       }

    }

1.6.7.4 修改

1.6.7.4.1         對映檔案
<!-- 更新使用者 -->

    <update id="updateUser"parameterType="cn.itcast.mybatis.po.User">

       update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address}

       where id=#{id}

    </update>
1.6.7.4.2         測試程式

 

// 更新使用者資訊

    @Test

    public void testUpdate() {

       // 資料庫會話例項

       SqlSession sqlSession = null;

       try {

           // 建立資料庫會話例項sqlSession

           sqlSession = sqlSessionFactory.openSession();

           // 新增使用者資訊

           User user = new User();

           user.setId(16);

           user.setUsername("張小明");

           user.setAddress("河南鄭州");

           user.setSex("1");

           user.setPrice(1999.9f);

           sqlSession.update("test.updateUser", user);

           // 提交事務

           sqlSession.commit();

 

       } catch (Exception e) {

           e.printStackTrace();

       } finally {

           if (sqlSession != null) {

               sqlSession.close();

           }

       }

    }

  

1.6.8  Mybatis解決jdbc程式設計的問題

  1. 資料庫連結建立、釋放頻繁造成系統資源浪費從而影響系統性能,如果使用資料庫連結池可解決此問題。

解決:在SqlMapConfig.xml中配置資料鏈接池,使用連線池管理資料庫連結。

  1. Sql語句寫在程式碼中造成程式碼不易維護,實際應用sql變化的可能較大,sql變動需要改變java程式碼。

解決:將Sql語句配置在XXXXmapper.xml檔案中與java程式碼分離。

  1. 向sql語句傳引數麻煩,因為sql語句的where條件不一定,可能多也可能少,佔位符需要和引數一一對應。

解決:Mybatis自動將java物件對映至sql語句,通過statement中的parameterType定義輸入引數的型別。

  1. 對結果集解析麻煩,sql變化導致解析程式碼變化,且解析前需要遍歷,如果能將資料庫記錄封裝成pojo物件解析比較方便。

解決:Mybatis自動將sql執行結果對映至java物件,通過statement中的resultType定義輸出結果的型別。

1.6.9  與hibernate不同

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

Mybatis學習門檻低,簡單易學,程式設計師直接編寫原生態sql,可嚴格控制sql執行效能,靈活度高,非常適合對關係資料模型要求不高的軟體開發,例如網際網路軟體、企業運營類軟體等,因為這類軟體需求變化頻繁,一但需求變化要求成果輸出迅速。但是靈活的前提是mybatis無法做到資料庫無關性,如果需要實現支援多種資料庫的軟體則需要自定義多套sql對映檔案,工作量大。

 

Hibernate物件/關係對映能力強,資料庫無關性好,對於關係模型要求高的軟體(例如需求固定的定製化軟體)如果用hibernate開發可以節省很多程式碼,提高效率。但是Hibernate的學習門檻高,要精通門檻更高,而且怎麼設計O/R對映,在效能和物件模型之間如何權衡,以及怎樣用好Hibernate需要具有很強的經驗和能力才行。

總之,按照使用者的需求在有限的資源環境下只要能做出維護性、擴充套件性良好的軟體架構都是好架構,所以框架只有適合才是最好。 

2 Dao開發方法

 使用Mybatis開發Dao,通常有兩個方法,即原始Dao開發方法和Mapper介面開發方法。

2.1    需求

將下邊的功能實現Dao:

根據使用者id查詢一個使用者資訊

根據使用者名稱稱模糊查詢使用者資訊列表

新增使用者資訊

 

2.2    SqlSession的使用範圍

         SqlSession中封裝了對資料庫的操作,如:查詢、插入、更新、刪除等。

通過SqlSessionFactory建立SqlSession,而SqlSessionFactory是通過SqlSessionFactoryBuilder進行建立。

 

2.2.1  SqlSessionFactoryBuilder

SqlSessionFactoryBuilder用於建立SqlSessionFacoty,SqlSessionFacoty一旦建立完成就不需要SqlSessionFactoryBuilder了,因為SqlSession是通過SqlSessionFactory生產,所以可以將SqlSessionFactoryBuilder當成一個工具類使用,最佳使用範圍是方法範圍即方法體內區域性變數。

 

2.2.2  SqlSessionFactory

         SqlSessionFactory是一個介面,介面中定義了openSession的不同過載方法,SqlSessionFactory的最佳使用範圍是整個應用執行期間,一旦建立後可以重複使用,通常以單例模式管理SqlSessionFactory。

 

2.2.3  SqlSession

         SqlSession是一個面向使用者的介面, sqlSession中定義了資料庫操作,預設使用DefaultSqlSession實現類。

 

執行過程如下:

  1. 載入資料來源等配置資訊

Environment environment = configuration.getEnvironment();

  1. 建立資料庫連結
  2. 建立事務物件
  3. 建立Executor,SqlSession所有操作都是通過Executor完成,mybatis原始碼如下:

 

if (ExecutorType.BATCH == executorType) {

      executor = newBatchExecutor(this, transaction);

    } elseif (ExecutorType.REUSE == executorType) {

      executor = new ReuseExecutor(this, transaction);

    } else {

      executor = new SimpleExecutor(this, transaction);

    }

if (cacheEnabled) {

      executor = new CachingExecutor(executor, autoCommit);

    }

 
  1. SqlSession的實現類即DefaultSqlSession,此物件中對操作資料庫實質上用的是Executor

結論:

         每個執行緒都應該有它自己的SqlSession例項。SqlSession的例項不能共享使用,它也是執行緒不安全的。因此最佳的範圍是請求或方法範圍。絕對不能將SqlSession例項的引用放在一個類的靜態欄位或例項欄位中。

         開啟一個 SqlSession;使用完畢就要關閉它。通常把這個關閉操作放到 finally塊中以確保每次都能執行關閉。如下:

     SqlSession session = sqlSessionFactory.openSession();

         try {

                  // do work

         } finally {

                session.close();

         }

2.3    原始Dao開發方式

         原始Dao開發方法需要程式設計師編寫Dao介面和Dao實現類。

2.3.1  對映檔案

<?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="test">

<!-- 根據id獲取使用者資訊 -->

    <select id="findUserById" parameterType="int"resultType="cn.itcast.mybatis.po.User">

       select * from user where id = #{id}

    </select>

<!-- 新增使用者 -->

    <insert id="insertUser"parameterType="cn.itcast.mybatis.po.User">

    <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>

</mapper>

2.3.2  Dao介面

Public interface UserDao {

    public User getUserById(int id) throws Exception;

    public void insertUser(User user) throws Exception;

}

 

Public class UserDaoImpl implements UserDao {

   

    //注入SqlSessionFactory

    public UserDaoImpl(SqlSessionFactory sqlSessionFactory){

       this.setSqlSessionFactory(sqlSessionFactory);

    }

   

    private SqlSessionFactory sqlSessionFactory;

    @Override

    public User getUserById(int id) throws Exception {

       SqlSession session = sqlSessionFactory.openSession();

       User user = null;

       try {

           //通過sqlsession呼叫selectOne方法獲取一條結果集

           //引數1:指定定義的statement的id,引數2:指定向statement中傳遞的引數

           user = session.selectOne("test.findUserById", 1);

           System.out.println(user);

                    

       } finally{

           session.close();

       }

       return user;

    }

   

    @Override

    Public void insertUser(User user) throws Exception {

       SqlSession sqlSession = sqlSessionFactory.openSession();

       try {

           sqlSession.insert("insertUser", user);

           sqlSession.commit();

       } finally{

           session.close();

       }

      

    }

}

 

2.3.3  問題

原始Dao開發中存在以下問題:

  • Dao方法體存在重複程式碼:通過SqlSessionFactory建立SqlSession,呼叫SqlSession的資料庫操作方法
  • 呼叫sqlSession的資料庫操作方法需要指定statement的id,這裡存在硬編碼,不得於開發維護。

2.4    Mapper動態代理方式

2.4.1  實現原理

         Mapper介面開發方法只需要程式設計師編寫Mapper介面(相當於Dao介面),由Mybatis框架根據介面定義建立介面的動態代理物件,代理物件的方法體同上邊Dao介面實現類方法。

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

  1. Mapper.xml檔案中的namespace與mapper介面的類路徑相同。
  2. Mapper介面方法名和Mapper.xml中定義的每個statement的id相同
  3. Mapper介面方法的輸入引數型別和mapper.xml中定義的每個sql 的parameterType的型別相同
  4. Mapper介面方法的輸出引數型別和mapper.xml中定義的每個sql的resultType的型別相同

2.4.2  Mapper.xml(對映檔案)

         定義mapper對映檔案UserMapper.xml(內容同Users.xml),需要修改namespace的值為 UserMapper介面路徑。將UserMapper.xml放在classpath下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="cn.itcast.mybatis.mapper.UserMapper">

<!-- 根據id獲取使用者資訊 -->

    <select id="findUserById" parameterType="int"resultType="cn.itcast.mybatis.po.User">

       select * from user where id = #{id}

    </select>

<!-- 自定義條件查詢使用者列表 -->

    <select id="findUserByUsername" parameterType="java.lang.String"

           resultType="cn.itcast.mybatis.po.User">

       select * from user where username like '%${value}%'

    </select>

<!-- 新增使用者 -->

    <insert id="insertUser"parameterType="cn.itcast.mybatis.po.User">

    <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>

 

</mapper>

 

2.4.3  Mapper.java(介面檔案)

/**

 * 使用者管理mapper

 */

Public interface UserMapper {

    //根據使用者id查詢使用者資訊

    public User findUserById(int id) throws Exception;

    //查詢使用者列表

    public List<User> findUserByUsername(String username) throwsException;

    //新增使用者資訊

    public void insertUser(User user)throws Exception;

}

 

介面定義有如下特點:

  1. Mapper介面方法名和Mapper.xml中定義的statement的id相同
  2. Mapper介面方法的輸入引數型別和mapper.xml中定義的statement的parameterType的型別相同
  3. Mapper介面方法的輸出引數型別和mapper.xml中定義的statement的resultType的型別相同

2.4.4  載入UserMapper.xml檔案

修改SqlMapConfig.xml檔案:

 <!-- 載入對映檔案 -->

  <mappers>

    <mapper resource="mapper/UserMapper.xml"/>

  </mappers>

2.4.5  測試

Public class UserMapperTest extends TestCase {

 

    private SqlSessionFactory sqlSessionFactory;

   

    protected void setUp() throws Exception {

       //mybatis配置檔案

       String resource = "sqlMapConfig.xml";

       InputStream inputStream = Resources.getResourceAsStream(resource);

       //使用SqlSessionFactoryBuilder建立sessionFactory

       sqlSessionFactory = newSqlSessionFactoryBuilder().build(inputStream);

    }

 

   

    Public void testFindUserById() throws Exception {

       //獲取session

       SqlSession session = sqlSessionFactory.openSession();

       //獲取mapper介面的代理物件

       UserMapper userMapper = session.getMapper(UserMapper.class);

       //呼叫代理物件方法

       User user = userMapper.findUserById(1);

       System.out.println(user);

       //關閉session

       session.close();

      

    }

    @Test

    public void testFindUserByUsername() throws Exception {

       SqlSession sqlSession = sqlSessionFactory.openSession();

       UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

       List<User> list = userMapper.findUserByUsername("張");

       System.out.println(list.size());

 

    }

Public void testInsertUser() throws Exception {

       //獲取session

       SqlSession session = sqlSessionFactory.openSession();

       //獲取mapper介面的代理物件

       UserMapper userMapper = session.getMapper(UserMapper.class);

       //要新增的資料

       User user = new User();

       user.setUsername("張三");

       user.setBirthday(new Date());

       user.setSex("1");

       user.setAddress("北京市");

       //通過mapper介面新增使用者

       userMapper.insertUser(user);

       //提交

       session.commit();

       //關閉session

       session.close();

    }

   

 

}

 

2.4.6  總結

  • selectOne和selectList

動態代理物件呼叫sqlSession.selectOne()和sqlSession.selectList()是根據mapper介面方法的返回值決定,如果返回list則呼叫selectList方法,如果返回單個物件則呼叫selectOne方法。

  • namespace

mybatis官方推薦使用mapper代理方法開發mapper介面,程式設計師不用編寫mapper介面實現類,使用mapper代理方法時,輸入引數可以使用pojo包裝物件或map物件,保證dao的通用性。

3  SqlMapConfig.xml配置檔案

3.1    配置內容

SqlMapConfig.xml中配置的內容和順序如下:

properties(屬性)

settings(全域性配置引數)

typeAliases(類型別名)

typeHandlers(型別處理器)

objectFactory(物件工廠)

plugins(外掛)

environments(環境集合屬性物件)

environment(環境子屬性物件)

transactionManager(事務管理)

dataSource(資料來源)

mappers(對映器)

3.2    properties(屬性)

SqlMapConfig.xml可以引用java屬性檔案中的配置資訊如下:

在classpath下定義db.properties檔案,

jdbc.driver=com.mysql.jdbc.Driver

jdbc.url=jdbc:mysql://localhost:3306/mybatis

jdbc.username=root

jdbc.password=mysql

SqlMapConfig.xml引用如下:

 

<properties resource="db.properties"/>

    <environments default="development">

       <environment id="development">

           <transactionManager type="JDBC"/>

           <dataSource type="POOLED">

              <property name="driver" value="${jdbc.driver}"/>

              <property name="url" value="${jdbc.url}"/>

              <property name="username" value="${jdbc.username}"/>

              <property name="password" value="${jdbc.password}"/>

           </dataSource>

       </environment>

    </environments>

注意: MyBatis 將按照下面的順序來載入屬性:

  • 在 properties 元素體內定義的屬性首先被讀取。
  • 然後會讀取properties 元素中resource或 url 載入的屬性,它會覆蓋已讀取的同名屬性。
  • 最後讀取parameterType傳遞的屬性,它會覆蓋已讀取的同名屬性。

因此,通過parameterType傳遞的屬性具有最高優先順序,resource或 url 載入的屬性次之,最低優先順序的是 properties 元素體內定義的屬性。

3.3    settings(配置)

mybatis全域性配置引數,全域性引數將會影響mybatis的執行行為。

詳細參見“學習資料/mybatis-settings.xlsx”檔案

 

 

 

 

3.4    typeAliases(類型別名)

3.4.1  mybatis支援別名:

別名

對映的型別

_byte

byte

_long

long

_short

short

_int

int

_integer

int

_double

double

_float

float

_boolean

boolean

string

String

byte

Byte

long

Long

short

Short

int

Integer

integer

Integer

double

Double

float

Float

boolean

Boolean

date

Date

decimal

BigDecimal

bigdecimal

BigDecimal

 

 

3.4.2  自定義別名:

在SqlMapConfig.xml中配置:

<typeAliases>

    <!-- 單個別名定義 -->

    <typeAlias alias="user" type="cn.itcast.mybatis.po.User"/>

    <!-- 批量別名定義,掃描整個包下的類,別名為類名(首字母大寫或小寫都可以) -->

    <package name="cn.itcast.mybatis.po"/>

    <package name="其它包"/>

</typeAliases>

3.5    typeHandlers(型別處理器)

型別處理器用於java型別和jdbc型別對映,如下:

<select id="findUserById" parameterType="int" resultType="user">

       select * from user where id = #{id}

</select>

 

mybatis自帶的型別處理器基本上滿足日常需求,不需要單獨定義。

mybatis支援型別處理器:

 

型別處理器

Java型別

JDBC型別

BooleanTypeHandler

Boolean,boolean

任何相容的布林值

ByteTypeHandler

Byte,byte

任何相容的數字或位元組型別

ShortTypeHandler

Short,short

任何相容的數字或短整型

IntegerTypeHandler

Integer,int

任何相容的數字和整型

LongTypeHandler

Long,long

任何相容的數字或長整型

FloatTypeHandler

Float,float

任何相容的數字或單精度浮點型

DoubleTypeHandler

Double,double

任何相容的數字或雙精度浮點型

BigDecimalTypeHandler

BigDecimal

任何相容的數字或十進位制小數型別

StringTypeHandler

String

CHAR和VARCHAR型別

ClobTypeHandler

String

CLOB和LONGVARCHAR型別

NStringTypeHandler

String

NVARCHAR和NCHAR型別

NClobTypeHandler

String

NCLOB型別

ByteArrayTypeHandler

byte[]

任何相容的位元組流型別

BlobTypeHandler

byte[]

BLOB和LONGVARBINARY型別

DateTypeHandler

Date(java.util)

TIMESTAMP型別

DateOnlyTypeHandler

Date(java.util)

DATE型別

TimeOnlyTypeHandler

Date(java.util)

TIME型別

SqlTimestampTypeHandler

Timestamp(java.sql)

TIMESTAMP型別

SqlDateTypeHandler

Date(java.sql)

DATE型別

SqlTimeTypeHandler

Time(java.sql)

TIME型別

ObjectTypeHandler

任意

其他或未指定型別

EnumTypeHandler

Enumeration型別

VARCHAR-任何相容的字串型別,作為程式碼儲存(而不是索引)。

 

3.6    mappers(對映器)

Mapper配置的幾種方法:

3.6.1  <mapper resource=" " />

使用相對於類路徑的資源

如:<mapper resource="sqlmap/User.xml" />

3.6.2  <mapper url=" " />

使用完全限定路徑

如:<mapper url="file:///D:\workspace_spingmvc\mybatis_01\config\sqlmap\User.xml" />

 

3.6.3  <mapper class=" " />

使用mapper介面類路徑

如:<mapper class="cn.itcast.mybatis.mapper.UserMapper"/>

 

注意:此種方法要求mapper介面名稱和mapper對映檔名稱相同,且放在同一個目錄中。

 

3.6.4  <package name=""/>

註冊指定包下的所有mapper介面

如:<package name="cn.itcast.mybatis.mapper"/>

注意:此種方法要求mapper介面名稱和mapper對映檔名稱相同,且放在同一個目錄中。

4  Mapper.xml對映檔案

Mapper.xml對映檔案中定義了操作資料庫的sql,每個sql是一個statement,對映檔案是mybatis的核心。

4.1    parameterType(輸入型別)

4.1.1   #{}與${}

#{}實現的是向prepareStatement中的預處理語句中設定引數值,sql語句中#{}表示一個佔位符即?。

<!-- 根據id查詢使用者資訊 -->

    <select id="findUserById" parameterType="int" resultType="user">

       select * from user where id = #{id}

    </select>

使用佔位符#{}可以有效防止sql注入,在使用時不需要關心引數值的型別,mybatis會自動進行java型別和jdbc型別的轉換。#{}可以接收簡單型別值或pojo屬性值,如果parameterType傳輸單個簡單型別值,#{}括號中可以是value或其它名稱。

${}和#{}不同,通過${}可以將parameterType 傳入的內容拼接在sql中且不進行jdbc型別轉換, ${}可以接收簡單型別值或pojo屬性值,如果parameterType傳輸單個簡單型別值,${}括號中只能是value。使用${}不能防止sql注入,但是有時用${}會非常方便,如下的例子:

 

<!-- 根據名稱模糊查詢使用者資訊 -->

    <select id="selectUserByName" parameterType="string"resultType="user">

       select * from user where username like '%${value}%'

    </select>

 

如果本例子使用#{}則傳入的字串中必須有%號,而%是人為拼接在引數中,顯然有點麻煩,如果採用${}在sql中拼接為%的方式則在呼叫mapper介面傳遞引數就方便很多。

//如果使用佔位符號則必須人為在傳引數中加%

List<User> list = userMapper.selectUserByName("%管理員%");

//如果使用${}原始符號則不用人為在引數中加%

List<User>list = userMapper.selectUserByName("管理員");

再比如order by排序,如果將列名通過引數傳入sql,根據傳的列名進行排序,應該寫為:

ORDER BY ${columnName}

如果使用#{}將無法實現此功能。

4.1.2   傳遞簡單型別

參考上邊的例子。

4.1.3   傳遞pojo物件

Mybatis使用ognl表示式解析物件欄位的值,如下例子:

 

<!—傳遞pojo物件綜合查詢使用者資訊 -->

    <select id="findUserByUser" parameterType="user"resultType="user">

       select * from user where id=#{id} and username like '%${username}%'

    </select>

 

上邊紅色標註的是user物件中的欄位名稱。

測試:

 

Public void testFindUserByUser()throws Exception{

       //獲取session

       SqlSession session = sqlSessionFactory.openSession();

       //獲限mapper介面例項

       UserMapper userMapper = session.getMapper(UserMapper.class);

       //構造查詢條件user物件

       User user = new User();

       user.setId(1);

       user.setUsername("管理員");

       //傳遞user物件查詢使用者列表

       List<User>list = userMapper.findUserByUser(user);

       //關閉session

       session.close();

    }

 
<