Mybatis全面詳解——上(學習總結)


原文地址:https://blog.csdn.net/ITITII/article/details/79969447

一、什么是Mybatis

這里借用官網的一句話介紹什么是mybatis:MyBatis 是一款優秀的持久層框架,它支持定制化 SQL、存儲過程以及高級映射。MyBatis 避免了幾乎所有的 JDBC 代碼和手動設置參數以及獲取結果集。MyBatis 可以使用簡單的 XML 或注解來配置和映射原生信息,將接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java對象)映射成數據庫中的記錄。

二、Mybatis相對JDBC有哪些優勢

首先我們來看一看jdbc連接數據庫的連接方法:


   
   
   
           
  1. public static void main(String[] args) {
  2. Connection connection = null;
  3. PreparedStatement preparedStatement = null;
  4. ResultSet resultSet = null;
  5. try {
  6. //1、加載數據庫驅動
  7. Class.forName( "com.mysql.jdbc.Driver");
  8. //2、通過驅動管理類獲取數據庫鏈接
  9. connection = DriverManager.getConnection( "jdbc:mysql://localhost:3306/mybatis", "root", "root");
  10. //3、定義sql語句 ?表示占位符
  11.         String sql = "select * from user where username = ?";
  12. //4、獲取預處理statement
  13. preparedStatement = connection.prepareStatement(sql);
  14. //5、設置參數,第一個參數為sql語句中參數的序號(從1開始),第二個參數為設置的參數值
  15. preparedStatement.setString( 1, "王五");
  16. //6、向數據庫發出sql執行查詢,查詢出結果集
  17. resultSet = preparedStatement.executeQuery();
  18. //7、遍歷查詢結果集
  19. while(resultSet.next()){
  20. User user
  21. System.out.println(resultSet.getString( "id")+ " "+resultSet.getString( "username"));
  22. }
  23. } catch (Exception e) {
  24. e.printStackTrace();
  25. } finally{
  26. //8、釋放資源
  27. if(resultSet!= null){
  28. try {
  29. resultSet.close(); //釋放結果集
  30. } catch (SQLException e) {
  31. // TODO Auto-generated catch block
  32. e.printStackTrace();
  33. }
  34. }
  35. if(preparedStatement!= null){
  36. try {
  37. preparedStatement.close();
  38. } catch (SQLException e) {
  39. // TODO Auto-generated catch block
  40. e.printStackTrace();
  41. }
  42. }
  43. if(connection!= null){
  44. try {
  45. connection.close(); //關閉數據庫連接
  46. } catch (SQLException e) {
  47. // TODO Auto-generated catch block
  48. e.printStackTrace();
  49. }
  50. }
  51. }
  52. }

通過上面的一段jdbc連接數據代碼,我們看有哪些不好的地方:

1.在創建connection的時候,存在硬編碼問題(也就是直接把連接信息寫死,不方便后期維護)

2.preparedStatement對象在執行sql語句的時候存在硬編碼問題。

3.每次在進行一次數據庫連接后都會關閉數據庫連接,頻繁的開啟/關閉數據連接影響性能。

簡單的說一下mybatis相對jdbc的優勢:

1.mybatis是把連接數據庫的信息都是寫在配置文件中,因此不存在硬編碼問題,方便后期維護。

2.mybatis執行的sql語句都是通過配置文件進行配置,不需要寫在java代碼中。

3.mybatis的連接池管理、緩存管理等讓連接數據庫和查詢數據效率更高。

........

三、Mybatis框架的原理介紹

這里就通過一張圖來對mybatis框架原理進行介紹吧:

四、Mybatis全局配置文件

SqlMapConfig.xml是Mybatis的全局配置文件,它的名稱可以是任意,但是一般命名都為(SqlMapConfig)

4.1.全局配置文件的類容和順序

Properties(屬性)

Settings(全局參數設置)

typeAliases(類型別名)

typeHandlers(類型處理器)

objectFactory(對象工廠)

plugins(插件)

environments(環境信息集合)

environment(單個環境信息)

transactionManager(事物)

dataSource(數據源)

mappers(映射器)

4.2.常見配置詳解

properties標簽:

Mybatis可以通過該標簽來讀取java配置信息:

例如在工程中對數據源信息寫在db.properties文件中,可以通過properties標簽來加載該文件。

db.properties:


   
   
   
           
  1. db.driver=com.mysql.jdbc.Driver
  2. db.url=jdbc:mysql://localhost:3306/mybatis
  3. db.username=root
  4. db.password=12345678

SqlMapConfig.xml使用properties標簽:


   
   
   
           
  1. <!-- 通過properties標簽,讀取java配置文件的內容 -->
  2. <properties resource= "db.properties" />
  3. <!-- 配置mybatis的環境信息 -->
  4. <environments default= "development">
  5. <environment id= "development">
  6. <!-- 配置JDBC事務控制,由mybatis進行管理 -->
  7. <transactionManager type= "JDBC"></transactionManager>
  8. <!-- 配置數據源,采用dbcp連接池 -->
  9. <dataSource type= "POOLED">
  10. <property name= "driver" value= "${db.driver}"/>
  11. <property name= "url" value= "${db.url}"/>
  12. <property name= "username" value= "${db.username}"/>
  13. <property name= "password" value= "${db.password}"/>
  14. </dataSource>
  15. </environment>
  16. </environments>

注意:

1、 先加載propertiesproperty標簽聲明的屬性

因此在property中的name屬性的值和value比properties中的resource屬性先加載。后加載的db.properties會覆蓋於property加載屬性和值。

<properties resource="db.properties">

    <property name="db.username",value="1234"/>

</properties>  

2、 再加載properties標簽引入的java配置文件中的屬性

3、 parameterType的值會和properties的屬性值發生沖突。因此,在properties文件里的內容命名最好加上db.代表是跟數據源相關的屬性,這樣就不容易跟以后的屬性發生沖突。

settings標簽:

該標簽時mybatis的全局設置,該設置會影響mybatis的運行。

一般我們使用使用該標簽來開啟二級緩存和懶加載。

以下是幾張settings配置項的說明:



typeAliases標簽

該標簽是對po類進行別名設置,這樣,在后面使用po類的時候就可以直接通過別名引用,而不需要通過po類的全限定名來引用。這樣可以提高我們的開發效率。

首先介紹下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

自定義單個別名:這種方式只能定義單個類的別名。

下面的代碼就是把com.lc.mybatis.po.User類定義為user的別名


   
   
   
           
  1. <typeAliases>
  2. <!-- 設置單個別名 -->
  3. <typeAlias type="com.lc.mybatis.po.User" alias="user"/>
  4. </typeAliases>

自定義之批量定義別名:

下面代碼是把com.lc.mybatis.po類下的所有類都聲明別名,默認的別名就是類名(類名大小寫都可以)


   
   
   
           
  1. <!-- 設置別名 -->
  2. <typeAliases>
  3. <!-- 批量設置別名 -->
  4. <!-- package:指定包名稱來為該包下的po類聲明別名,默認的別名就是類名(類名首字母大小寫都可以) -->
  5. <package name="com.lc.mybatis.po"/>
  6. </typeAliases>

mappers標簽

該標簽的作用是加載映射文件

方式一:<mapper resource=""/>

該方式是加載相對於類路徑下的映射文件:


   
   
   
           
  1. <mappers>
  2. <mapper resource="sqlmap/User.xml"/>
  3. </mappers>

方式二:<mapper url=""/>

該方式使用全限定路徑

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

方式三:<mapper class=""/>

該方式使用mapper接口的全限定類名

<mapper class="cn.itcast.lc.mapper.UserMapper"/>
  
  
  
          

此方式要求:

    Mapper接口Mapper映射文件名稱相同且在同一個目錄下。

方式四:<package name=""/>

    該方式是加載指定包下的所有映射文件

<package name="cn.lc.mybatis.mapper"/>
  
  
  
          

此方式要求:

    Mapper接口Mapper映射文件名稱相同且在同一個目錄下。

五、映射文件

5.1.輸入映射parameterType

第一種:簡單類型

#{}表示占位符?parameterType接收簡單類型的參數時里面的名稱可以任意


   
   
   
           
  1. <select id="findUserById" parameterType="java.lang.Integer" resultType="user">
  2. SELECT * FROM USER WHERE id = #{id}
  3. </select>

${}表示拼接符,parameterType接收簡單類型的參數時里面的名稱必須value


   
   
   
           
  1. <select id="findUsersByName" parameterType="java.lang.String" resultType="com.lc.mybatis.po.User">
  2. SELECT * FROM USER WHERE username LIKE "%${value}%"
  3. </select>

第二種:pojo類型

這里通過用戶的用戶名進行模糊查詢演示pojo類型

在映射文件中添加模糊查詢語句:


   
   
   
           
  1. <!-- parameterType傳遞pojo類型 -->
  2. <select id="findUsersByPojo" parameterType="com.lc.mybatis.po.User" resultType="com.lc.mybatis.po.User">
  3. SELECT * FROM USER WHERE username LIKE "%${username}%"
  4. </select>

user類


   
   
   
           
  1. public class User {
  2. private Integer id;
  3. private String username;
  4. private Date birthday;
  5. private String sex;
  6. private String address;
  7. }

測試類:


   
   
   
           
  1. public class UserDao{
  2. //根據用戶名進行模糊查詢
  3. @Override
  4. public List<User> findUserByPojo(){
  5. //全局配置文件路徑:
  6. String resource = "SqlMapConfig.xml";
  7. InputStream inputStream = Resources.getResourceAsStream(resource);
  8. //創建SqlSessionFactory
  9. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  10. SqlSession sqlSession = sqlSessionFactory.openSession();
  11. User user = new User();
  12. user.setUsetname( "張三");
  13. List<User> users = (List<User>)sqlSession.selectList( "test.findUsersByPojo",user); //傳入pojo
  14. System.out.println(users);
  15. sqlSession.close();
  16. return users;
  17. }
  18. }

第三種:包裝類型pojo

這里通過用戶名和用戶地址對用戶進行查詢來演示包裝類型pojo:

首先創建包裝pojo類:


   
   
   
           
  1. public class UserVO {
  2. private User user;
  3. public User getUser() {
  4. return user;
  5. }
  6. public void setUser(User user) {
  7. this.user = user;
  8. }
  9. }

在映射文件中添加查詢語句:


   
   
   
           
  1. <!-- parameterType傳遞pojo包裝類型 -->
  2. <select id="findUsersByPojo1" parameterType="com.lc.mybatis.po.UserVO" resultType="user">
  3. SELECT * FROM USER WHERE username LIKE "%${user.username}%" AND address=#{user.address}
  4. </select>

測試類:


   
   
   
           
  1. public class UserDao{
  2. //根據用戶名和地址進行查詢
  3. @Override
  4. public List<User> findUserByPojo1(){
  5.                  //全局配置文件路徑:
  6.                 String resource = "SqlMapConfig.xml";
  7.                 InputStream inputStream = Resources.getResourceAsStream(resource);
  8.                  //創建SqlSessionFactory
  9.                 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  10.                 SqlSession sqlSession = sqlSessionFactory.openSession();
  11. User user = new User();
  12. user.setUsetname( "張三");
  13.                 user.setAddress( "郝漢山");
  14.                 UserVO userVo = new UserVO();
  15.                 userVo.setUser(user);
  16. List<User> users = (List<User>)sqlSession.selectList( "test.findUsersByPojo1",userVo); //傳入pojo包裝類
  17. System.out.println(users);
  18. sqlSession.close();
  19. return users;
  20. }
  21. }

第四種:map集合類型

這里通過查詢用戶信息演示:

在映射文件中添加該查詢語句:


   
   
   
           
  1. <!-- parameterType傳遞hashmap類型 -->
  2. <select id="findUsersByMap" parameterType="java.util.Map" resultType="user">
  3. SELECT * FROM USER WHERE username LIKE "%${username}%" AND address=#{address}
  4. </select>

測試方法:


   
   
   
           
  1. public class UserDao{
  2. //根據用戶名和地址進行查詢
  3. @Override
  4. public List<User> findUserByMap(){
  5. //全局配置文件路徑:
  6. String resource = "SqlMapConfig.xml";
  7. InputStream inputStream = Resources.getResourceAsStream(resource);
  8. //創建SqlSessionFactory
  9. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  10. SqlSession sqlSession = sqlSessionFactory.openSession();
  11. Map<String,String> map = new HashMap<>();
  12.                 map.put( "username", "張三");
  13.                 map.put( "address", "郝漢山");
  14.                 List<User> users = (List<User>) sqlSession.selectList( "test.findUsersByMap",map); //傳入pojo包裝類
  15. System.out.println(users);
  16. sqlSession.close();
  17. return users;
  18. }
  19. }
5.2.resultType結果映射

resultType結果映射要求:需要查詢結果的列名和映射的對象的屬性名一致,這樣才能映射成功。如果映射沒成功也不會報錯,只是映射結果中對象的相應屬性沒有值,為空。如果映射的列名和對象中的屬性名全部不一致,那么映射的對象為空。如果在使用sql語句查詢的時候給查詢結果列設置了別名,則別名要和映射結果對象的屬性名一致,這樣才能保證映射成功。

第一種:簡單類型

注意: 如果結果映射為簡單類型,則需要查詢的結果為一列才能映射成功。

例如:查詢用戶表中用戶的總數。

映射文件為:


   
   
   
           
  1. <!-- resultType:輸出為簡單類型 -->
  2. <select id="findUserCount" resultType="int">
  3. select count(*) from user;
  4. </select>

測試代碼:


   
   
   
           
  1. public class UserDao{
  2. @Override
  3. public int findUserCount(){
  4. //全局配置文件路徑:
  5. String resource = "SqlMapConfig.xml";
  6. InputStream inputStream = Resources.getResourceAsStream(resource);
  7. //創建SqlSessionFactory
  8. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  9. SqlSession sqlSession = sqlSessionFactory.openSession();
  10. int userCount= sqlSession.selectOne( "test.findUserCount");
  11. System.out.println(userCount);
  12. sqlSession.close();
  13. return userCount;
  14. }
  15. }

第二種:pojo結果映射

這里操作pojo輸入映射。

5.3.resultMap結果映射

使用resultMap結果映射時,不需要查詢出來的結果集的列名和映射結果對象的屬性名相同,但是需要聲明一個resultMap,手動的方式來對列名和對象屬性進行映射。(resultMap一般用於多表關聯映射)

例如:通過查詢用戶表中的用戶,並對查詢出來的用戶表的列名設置別名。

映射文件添加查詢語句:

[id]:定義resultMap的唯一標識

[type]:定義該resultMap最終映射的pojo對象

[id標簽]:映射結果集的唯一標識列,如果是多個字段聯合唯一,則定義多個id標簽

[result標簽]:映射結果集的普通列

[column]:SQL查詢的列名,如果列有別名,則該處填寫別名

[property]:pojo對象的屬性名


   
   
   
           
  1. <!-- 如果查詢出來的列名有別名就不能通過resultType來接收輸出類型了。需要通過resultMap來聲明傳出類型(resultMap需要聲明) -->
  2. <resultMap type="user" id="userMap">
  3. <!-- id標簽:專門查詢結果中唯一列映射 -->
  4. <id column="id_" property="id"/>
  5. <!-- result標簽:映射查詢結果中的普通列 -->
  6. <result column="username_" property="username"/>
  7. <result column="address_" property="address"/>
  8. </resultMap>
  9. <select id="findUserResultMap" parameterType="int" resultMap="userMap">
  10. select id id_,username username_,address address_ from user where id=#{id}
  11. </select>

測試類:


   
   
   
           
  1. public class UserDao{
  2. @Override
  3. public User findUserResultMap(){
  4. //全局配置文件路徑:
  5. String resource = "SqlMapConfig.xml";
  6. InputStream inputStream = Resources.getResourceAsStream(resource);
  7. //創建SqlSessionFactory
  8. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  9. SqlSession sqlSession = sqlSessionFactory.openSession();
  10. User user = sqlSession.selectOne( "test.findUserResultMap", 1);
  11. System.out.println(user);
  12. sqlSession.close();
  13. return user;
  14. }
  15. }
5.4.動態sql

在mybatis中提供了一些動態sql標簽,可以讓我們開發效率更快,這些動態sql語句可以增加我們寫的sql語句的重用性,常用的動態sql語句標簽有:if標簽、sql片段(需要先定義后使用)、where標簽、foreach標簽

通過下面例子來演示動態sql常用的標簽:

需求分析:查詢用戶表中相關的用戶。

發出相關的sq語句有:select * from user where username like "%張三%" and address= ?;

                                   select * from user;

                                   select * from user where id in(1,2,10);

如何才能讓這些語句在我們需要的時候就使用,不需要的時候就不適用。其實我們發現這三條語句有很多重復的地方,我們如果能做到讓重復的能夠重復使用,沒有重復的可以按我們需求使用的話就能減少我們寫很多sql語句。當然動態sql就是幫我們解決這些問題的。

映射文件:


   
   
   
           
  1. <!-- 定義sql片段,用於可重用的sql片段 -->
  2. <sql id="whereClause">
  3. <!-- if標簽:可以對輸入的參數進行判斷 -->
  4. <!-- test:指定判斷表達式 -->
  5. <if test="user!=null">
  6. <if test="user.username!=null and user.username!=''">
  7. AND username LIKE '%${user.username}%'
  8. </if>
  9. <if test="user.address!=null and user.address!=''">
  10. AND address=#{user.address}
  11. </if>
  12. </if>
  13. <if test="idList!=null">
  14. AND id IN
  15. <!-- foreach標簽: 可以循環傳入參數值 -->
  16. <!-- collenction:標示pojo中集合屬性的屬性名稱 -->
  17. <!-- item:每次遍歷出來的對象 -->
  18. <!--open開始遍歷時拼接的串-->
  19. <!--close結束遍歷時拼接的串-->
  20. <!--separator遍歷每個對象之間需要拼接字符-->
  21. <foreach collection="idList" item="item" open="(" close=")" separator=",">
  22. #{item}
  23. </foreach>
  24. </if>
  25. </sql>
  26. <select id="findUserList" parameterType="userVO" resultType="user">
  27. SELECT * FROM USER
  28. <!-- where標簽: 默認去掉第一個AND,如果沒有參數就去掉where自己-->
  29. <where>
  30. <!--引用sql語句片段-->
  31. <include refid="whereClause"> </include>
  32. </where>
  33. </select>

userVo類:


   
   
   
           
  1. public class UserVO {
  2. private User user;
  3. private List<Integer> idList;
  4. public List<Integer> getIdList() {
  5. return idList;
  6. }
  7. public void setIdList(List<Integer> idList) {
  8. this.idList = idList;
  9. }
  10. public User getUser() {
  11. return user;
  12. }
  13. public void setUser(User user) {
  14. this.user = user;
  15. }
  16. }


測試類:


   
   
   
           
  1. public class UserDao{
  2. @Override
  3. public void findUserList(){
  4. //全局配置文件路徑:
  5. String resource = "SqlMapConfig.xml";
  6. InputStream inputStream = Resources.getResourceAsStream(resource);
  7. //創建SqlSessionFactory
  8. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  9. SqlSession sqlSession = sqlSessionFactory.openSession();
  10. //測試foreach語句執行
  11.                 UserVO userVo = new UserVO();
  12.                 List<Integer> idList = new ArrayList<>();
  13.                 idList.add( 1);
  14.                 idList.add( 2);
  15.                 idList.add( 3);
  16.                 userVo.setIdList(idList);
  17.                  //測試select * from user where username like ? and address=?;
  18.                 //User user = new User();
  19.                 //user.setUsername("張三");
  20.                 //user.setAddress("武當山");
  21.                 //userVo.setUser(user);
  22.                 List<User> users = sqlSession.selectOne( "test.findUserList",userVo);
  23.                 System.out.println(users);
  24. sqlSession.close();
  25. }
  26. }

六、Mybatis之傳統Dao層的開發(該方式很少用)

6.1.開發環境准備:

        1.個人使用的jdk為1.7

        2.開發工具是使用的Eclipse4.5

        3.數據庫使用的MySQL5X

        4.導入mybatis所需要的jar包

        

        5.導入mysql數據庫驅動包

6.2.需求分析:

根據ID查詢查詢用戶、根據用戶名稱進行模糊查詢、添加用戶

6.3.代碼實現

創建用戶表對應pojo類User:


   
   
   
           
  1. public class User {
  2. private Integer id;
  3. private String username;
  4. private Date birthday;
  5. private String sex;
  6. private String address;
  7. //setter和get方法省略
  8. }

創建mybatis的全局配置文件SqlMapConfig.xml:用於配置數據源、事務、映射文件加載等信息


   
   
   
           
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE configuration
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  5. <configuration>
  6. <!-- 配置mybatis的環境信息 -->
  7. <environments default="developments">
  8. <environment id="developments">
  9. <!-- 配置JDBC事務控制,由mybatis進行管理 -->
  10. <transactionManager type="JDBC"> </transactionManager>
  11. <!-- 配置數據源,采用mybatis連接池 -->
  12. <dataSource type="POOLED">
  13. <property name="driver" value="com.mysql.jdbc.Driver"/>
  14. <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
  15. <property name="username" value="root"/>
  16. <property name="password" value="12345678"/>
  17. </dataSource>
  18. </environment>
  19. </environments>
  20. <!-- 加載映射文件 -->
  21. <mappers>
  22. <mapper resource="User.xml"/>
  23. </mappers>
  24. </configuration>

創建需求開發的映射文件User.xml配置文件:並在全局配置文件中添加該映射文件


   
   
   
           
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <!--
  6. namespace:命名空間,它的作用就是對SQL進行分類化管理,可以理解為SQL隔離
  7. 注意:使用mapper代理開發時,namespace有特殊且重要的作用
  8. -->
  9. <mapper namespace="test">
  10. <!-- 根據用戶ID查詢用戶信息 -->
  11. <!-- select:表示一個MappedStatement對象 -->
  12. <!-- id:statement的唯一標識 -->
  13. <!-- #{}:表示一個占位符?-->
  14. <!-- #{id}:里面的id表示輸入參數的參數名稱,如果該參數為簡單類型,那么#{}里面的參數可以任意 -->
  15. <!-- parameterType:輸入參數的java類型 -->
  16. <!-- resultType:輸出結果的所映射的java類型(單條結果所對應的java類型) -->
  17. <select id="findUserById" parameterType="java.lang.Integer" resultType="com.lc.mybatis.po.User">
  18. SELECT * FROM USER WHERE id = #{id}
  19. </select>
  20. <!-- 根據用戶名進行模糊查詢 -->
  21. <!-- ${}:表示一個sql連接符 -->
  22. <!-- ${value}:里面的 value表示輸入的名稱,如果該參數是簡單類型,那么${}里面的參數名稱必須是value-->
  23. <!-- ${}這種寫法存在sql注入的風險,所以需要 慎用!但是有些場景需要用到比如:排序,-->
  24. <select id="findUsersByName" parameterType="java.lang.String" resultType="com.lc.mybatis.po.User">
  25. SELECT * FROM USER WHERE username LIKE "%${value}%"
  26. </select>
  27. <!-- 添加用戶: -->
  28. <!--
  29. [selectKey標簽]:通過select查詢來生成主鍵
  30. [keyProperty]:指定存放生成主鍵的屬性
  31. [resultType]:生成主鍵所對應的Java類型
  32. [order]:指定該查詢主鍵SQL語句的執行順序,相對於insert語句
  33. [last_insert_id]:MySQL的函數,要配合insert語句一起使用,該函數在mysql中是執行在insert語句后。
  34. -->
  35. <insert id="insertUser" parameterType="com.lc.mybatis.po.User">
  36. <selectKey keyProperty="id" resultType="int" order="AFTER">
  37. SELECT LAST_INSERT_ID()
  38. </selectKey>
  39. INSERT INTO USER(username,sex,birthday,address) VALUES(#{username},#{sex},#{birthday},#{address})
  40. </insert>
  41. </mapper>

dao層接口:


   
   
   
           
  1. public interface UserDao {
  2. //根據用戶id查詢用戶
  3. public User findUserById(int id);
  4.         //根據用戶名進行模糊查詢
  5.         public List<User> findUsersByName(String name);
  6.          //添加用戶
  7.         public void addUser(User user);
  8.  }

dao層的實現:


   
   
   
           
  1. public class UserDaoImpl implements UserDao{
  2. //通過構造方法注入sqlSessionFactory
  3. private SqlSessionFactory sqlSessionFactory;
  4. public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
  5. this.sqlSessionFactory = sqlSessionFactory;
  6. }
  7. //根據id查詢用戶
  8. @Override
  9. public User findUserById(int id) {
  10. SqlSession sqlSession = sqlSessionFactory.openSession();
  11. User user = sqlSession.selectOne( "test.findUserById", id);
  12. System.out.println(user);
  13. sqlSession.close();
  14. return user;
  15. }
  16. //根據用戶名進行模糊查詢
  17. @Override
  18. public List<User> findUsersByName(String name){
  19. SqlSession sqlSession = sqlSessionFactory.openSession();
  20. List<User> users = sqlSession.selectList( "test.findUsersByName",name);
  21. System.out.println(users);
  22. sqlSession.close();
  23. return users;
  24. }
  25. //添加用戶
  26. public List<User> addUser(String name){
  27. SqlSession sqlSession = sqlSessionFactory.openSession();
  28. User user = new User();
  29. user.setUsername( "超哥2");
  30. user.setAddress( "成都市");
  31. //調用SqlSession的增刪改查方法
  32. //第一個參數:表示statement的唯一表示
  33. //第一個參數:表示占位符的
  34. sqlSession.insert( "test.insertUser", user);
  35. System.out.println(user.getId());
  36. //切記:增刪改操作需要提交事務。
  37. sqlSession.commit();
  38. //關閉資源
  39. sqlSession.close();
  40. }


測試類:這里就只通過根據id查找用戶進行測試


   
   
   
           
  1. public class UserDaoTest {
  2. private SqlSessionFactory sqlSessionFactory;
  3. @Before
  4. public void setUp() throws IOException {
  5. InputStream inputStream = Resources.getResourceAsStream( "SqlMapConfig.xml");
  6. sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  7. }
  8. @Test
  9. public void testFindUserById() {
  10. UserDao userDao = new UserDaoImpl(sqlSessionFactory);
  11. userDao.findUserById( 1);
  12. }
  13. }

七、Mybatis之Mapper接口的開發方式

該方式開發,不需要寫dao層的實現類,而是mybatis根據映射文件等信息對接口進行jdk動態代理生成代理類來實現接口中的方法,因此,采用這種方式,我們只需要編輯接口,而不需要去寫實現。

7.1.需求分析

根據id查詢用戶。

7.2.Mapper開發代理規范
1、mapper接口的全限定名要和mapper映射文件的namespace值一致。
2、mapper接口的方法名稱要和mapper映射文件的statement的id一致。
3、mapper接口的方法參數類型要和mapper映射文件的statement的parameterType的值一致,而且它的參數是一個。

4、mapper接口的方法返回值類型要和mapper映射文件的statement的resultType的值一致。

7.3.代碼實現

准備po類:


   
   
   
           
  1. public class User {
  2. private Integer id;
  3. private String username;
  4. private Date birthday;
  5. private String sex;
  6. private String address;
  7.         //getter和setter方法省略
  8.  }

Mapper接口:


   
   
   
           
  1. public interface UserMapper {
  2. public User findUserById(int id);
  3. }


UserMapper.xml配置文件:


   
   
   
           
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <!--
  6. namespace:命名空間,它的作用就是對SQL進行分類化管理,可以理解為SQL隔離
  7. 注意:使用mapper代理開發時,namespace有特殊且重要的作用
  8. -->
  9. <mapper namespace="com.lc.mybatis.mapper.UserMapper">
  10. <!-- 根據用戶ID查詢用戶信息 -->
  11. <!-- select:表示一個MappedStatement對象 -->
  12. <!-- id:statement的唯一標識 -->
  13. <!-- #{}:表示一個占位符?-->
  14. <!-- #{id}:里面的id表示輸入參數的參數名稱,如果該參數為簡單類型,那么#{}里面的參數可以任意 -->
  15. <!-- parameterType:輸入參數的java類型 -->
  16. <!-- resultType:輸出結果的所映射的java類型(單條結果所對應的java類型) -->
  17. <select id="findUserById" parameterType="java.lang.Integer" resultType="com.lc.mybatis.po.User">
  18. SELECT * FROM USER WHERE id = #{id}
  19. </select>
  20. </mapper>


在全局配置文件SqlMapperConfig中添加該映射文件

測試代碼:


   
   
   
           
  1. public class UserMapperTest {
  2. private SqlSessionFactory sqlSessionFactory ;
  3. @Before
  4. public void setUp() throws IOException {
  5. InputStream inputStream = Resources.getResourceAsStream( "SqlMapConfig.xml");
  6. sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  7. }
  8. @Test
  9. public void testFindUserById() {
  10. SqlSession sqlSession = sqlSessionFactory.openSession();
  11. //獲取UserMapper的代理類
  12. UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
  13. User user = userMapper.findUserById( 10);
  14. System.out.println(user);
  15. sqlSession.close();
  16. }
  17. }

八、Mybatis一級緩存

mybatis提供查詢緩存,如果緩存中有數據,就不用從數據庫中獲取,用於減輕數據壓力,提高系統性能


一級緩存是sqlSession級別的緩存,在操作數據庫的時候,需要構造sqlSession對象,在對象中有一個數據結構(HashMap)用於存儲緩存數據。不同的SqlSession的緩存區域(HashMap)是互相不受影響的。


mybatis默認是支持一級緩存的。

8.1.證明一級緩存的存在:

驗證方法:


   
   
   
           
  1. public void testOneLevelCache() {
  2. SqlSession sqlSession = sqlSessionFactory.openSession();
  3. //獲取UserMapper的代理類
  4. UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
  5. //第一次查詢
  6. User user = userMapper.findUserById( 10);
  7. System.out.println(user);
  8. //第二次查詢
  9. User user2 = userMapper.findUserById( 10);
  10. System.out.println(user2);
  11. sqlSes

通過執行該方法,查看打印日志可以看出就執行了一次sql語句的查詢,因此可以判斷第二次查詢是沒有從數據庫中進行查詢的。


那當什么時候一級緩存會被清空呢?

通過測試發現,當在第二次查詢數據庫之前對數據庫進行了寫的操作后,第二次查詢就不會從緩存中查詢結果,而是直接從數據中查詢結果。另一種就是在第一查詢結果后,手動的方式清空一級緩存(使用sqlSession.clearCache();方法。)

測試方法:


九、Mybatis二級緩存

二級緩存是Mapper級別的緩存。多個SqlSession去操作同一個Mapper的sql語句,多個SqlSession可以共用二級緩存,二級緩存是誇SqlSession的。(二級緩存Mybatis默認是關閉的,需要自己去手動配置開啟或可以自己選擇用哪個廠家的緩存來作為二級緩存)

9.1.開啟二級緩存

首先在全局配置文件中配置開啟二級緩存功能:


   
   
   
           
  1. <!-- 開啟二級緩存總開關 -->
  2. <setting name="cacheEnabled" value="true"/>

在映射文件中去選擇是否該映射文件使用二級緩存:

如果使用就進行以下配置,如果不是用,就不需要對映射文件做任何修改。


   
   
   
           
  1. <!-- 開啟本mapper下的namespace的二級緩存,默認使用的是mybatis提供的PerpetualCache -->
  2. <cache> </cache>

也可以設置選擇二級緩存提工商

以下是我選擇使用EhcacheCache緩存(注意:在使用EhcacheCache緩存需要導入jar包)



最后就是,在需要緩存的po類中去實現序列化:

驗證二級緩存是否開啟:

驗證方法如下:


   
   
   
           
  1. @Test
  2. //測試二級緩存是否開啟
  3. public void testTwoLevelCache() {
  4. SqlSession sqlSession1 = sqlSessionFactory.openSession();
  5. SqlSession sqlSession2 = sqlSessionFactory.openSession();
  6. SqlSession sqlSession3 = sqlSessionFactory.openSession();
  7. //獲取UserMapper的代理類
  8. UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
  9. UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
  10. UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);
  11. User user1 = userMapper1.findUserById( 10);
  12. System.out.println(user1);
  13. //當sqlSession1執行close()的時候,才把sqlSession1查詢的結果寫到二級緩存中去。
  14. sqlSession1.close();
  15. // User u = new User();
  16. // u.setUsername("小胖");
  17. // u.setAddress("成都");
  18. // u.setSex("2");
  19. // u.setBirthday(new Date());
  20. // userMapper3.insertUser(u);
  21. // //當其中任何一個sqlSession執行commit()方法后將刷新整個緩存區
  22. // sqlSession3.commit();
  23. // sqlSession3.close();
  24. //第二次查詢
  25. User user2 = userMapper2.findUserById( 10);
  26. System.out.println(user2);
  27. sqlSession2.close();
  28. }

測試結果:


同時通過測試,當在第二次查詢的時候,向數據庫提交數據后,就會對緩存進行刷新,這樣在第二次查詢的時候就沒有走緩存,而是走的數據庫。

9.2.禁用二級緩存

由於二級緩存默認是關閉的,如果不開啟就不會使用二級緩存。如果,我們開啟了二級緩存,而在有些查詢結果集中,不需要受到二級緩存影響,該怎么去做呢?

在select查詢中,默認是使用了二級緩存,如果不想使用二級緩存,就在select標簽中有一個useCache的屬性設置為false,就代表不使用二級緩存,每次進行查詢數據都不會從緩存總獲取,而是直接從數據庫中進行查詢。useCache的默認值是true,即代表statement使用二級緩存。


9.3.刷新二級緩存

在statement中設置flushCache=true,可以刷新二級緩存。默認情況下,select語句中的flushCache是false。如果是insert、update、delete語句,那么flushCache的默認值是true。如果將select語句中的flushCache值改為true,就意味着查詢語句的二級緩存失效,每次查詢都會從數據庫進行查詢。如果將select語句的flushCache值為false,就代表該查詢語句使用了二級緩存,如果在數據庫中修改了數據,而二級緩存中的數據還是原來的數據,那么這樣就會出現臟讀。

flushCache設置如下:




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM