目錄
- 1. 簡介
- 1.1什么是Mybatis
- 1.2 如何獲得Mybatis
- 1.3 使用Mybatis的好處:
- 2.初涉Mybatis
- 2.1環境搭建
- 2.2、創建一個模塊(專案)
- 2.3、使用Mybatis的三個重要類
- 3.Mybatis的CRUD簡單實作
- 3.1、通過id查找用戶:
- 3.2、插入用戶:
- 3.3、根據id更改用戶名字:
- 3.4、 根據id洗掉用戶:
- 3.5、好用的Map
- 3.6、模糊查詢
- 4.配置決議
- 4.1、environments 環境配置
- 4.2、properties(屬性)
- 4.3、typeAliases(型別別名)
- 4.4、settings(設定)
- 4.5、mappers(映射器)
- 4.6、其他(暫時了解)
- 5.拓展:當屬性名和列名不一致
- 6.日志
- 6.1、日志工廠
- 6.2、Log4j
- 7.分頁
- 7.1、 limit分頁:
- 7.2、 RowBounds分頁(不推薦使用)
- 7.3、分頁插件
- 8.注解開發
- 8.1、常用的注解
- 8.2、使用注解開發
- 8.3、關于#{}和${}的比較
- 8.4、當注解開發和xml開發同時使用
- 9.Lombok
- 10.復雜查詢
- 10.1、模擬場景環境搭建
- 10.2、多對一實際應用:關聯
- 10.2.1、嵌套查詢
- 10.2.2、嵌套結果
- 10.3、一對多實際應用:集合
- 10.3.1、嵌套查詢
- 10.3.2、嵌套結果
- 10.4、小結
- 11.動態SQL
- 11.1、簡單介紹
- 11.2、實體專案的搭建
- 11.3動態SQL的使用
- 11.3.1、if
- 11.3.2、choose (when, otherwise)
- 11.3.3、trim (where, set)
- 11.3.4、foreach
- 11.3.5、sql片段
- 11.3.6、小結
- 12.Mybatis快取
- 12.1、簡介
- 12.2、Mybatis快取
- 12.3、一級快取
- 12.4、二級快取
- 12.5、快取原理
- 12.6、自定義快取(了解)
1. 簡介
1.1什么是Mybatis
- MyBatis 是一款優秀的持久層框架
- 它支持自定義 SQL、存盤程序以及高級映射,
- MyBatis 免除了幾乎所有的 JDBC 代碼以及設定引數和獲取結果集的作業,
- MyBatis 可以通過簡單的 XML 或注解來配置和映射原始型別、介面和 Java POJO(Plain Old Java Objects,普通老式 Java 物件)為資料庫中的記錄,
1.2 如何獲得Mybatis
-
獲得maven倉庫:
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.9</version> </dependency> -
Github:https://github.com/mybatis/mybatis-3
-
中文檔案:https://mybatis.net.cn/getting-started.html
1.3 使用Mybatis的好處:
- 使用簡單,傳統的JDBC代碼太復雜
- 簡單易學:沒有任何第三方依賴,最簡單安裝只要兩個jar檔案+配置幾個sql映射檔案,
- 靈活
- 解除sql與程式代碼的耦合
- 提供映射標簽,支持物件與資料庫的orm欄位關系映射,
- 提供物件關系映射標簽,支持物件關系組建維護,
- 提供xml標簽,支持撰寫動態sql,
2.初涉Mybatis
2.1環境搭建
-
使用navicat創建一個資料庫

-
新建專案
-
匯入依賴
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.9</version> </dependency>
2.2、創建一個模塊(專案)
-
撰寫mybatis的核心組態檔
<?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> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="https://www.cnblogs.com/xiaoye-Blog/p/com.mysql.cj.jdbc.Driver"/> <property name="url" value="https://www.cnblogs.com/xiaoye-Blog/p/jdbc:mysql://localhost:3306/mybatis?&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai"/> <property name="username" value="https://www.cnblogs.com/xiaoye-Blog/p/root"/> <property name="password" value="https://www.cnblogs.com/xiaoye-Blog/p/18227022334a"/> </dataSource> </environment> </environments> <mappers> <mapper resource="Mapper/UserMapper.xml"/> </mappers> </configuration> <!--注:xml檔案中使用&符號需要改成使用 & 代替--> -
撰寫mybatis工具類(封裝):
public class MybatisUtils { private static SqlSessionFactory sqlSessionFactory; //第一步:獲取SqlSessionFactory物件 static { try { String resource = "mybatis-config.xml";//路徑寫對 InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } //通過SqlSessionFactory物件獲取SqlSession物件 //SqlSession:SqlSession 提供了在資料庫執行 SQL 命令所需的所有方法,你可以通過 SqlSession 實體來直接執行已映射的 SQL 陳述句, public static SqlSession getSqlSession(){return sqlSessionFactory.openSession();}//當傳遞一個true引數時表示自動提交事務 } -
撰寫
-
撰寫物體類
//注;物體類的屬性名必須與資料庫的列名一致,否則無法進行匹配從而出現資料為空的現象,當然也可以在Mapper.xml配置中通過撰寫一個resultMap來進行映射,此時名字可以不相同 public class User { private int id; private String username; private String password; public User() { } public User(int id, String username, String password) { this.id = id; this.username = username; this.password = password; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } } -
撰寫Mapper介面(Dao)
public interface UserMapper { public List<User> getUser(); } -
撰寫Mapper組態檔
//注:每個Mapper檔案都需要在mybatis-config.xml檔案中去注冊 //<mapper resource="Mapper/UserMapper.xml"/> //相當于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"> //namespace:命名空間,指定要實作的Mapper介面,路徑映射 <mapper namespace="com.study.dao.UserMapper"> //id:唯一匹配于Mapper介面的方法名 //resultType:回傳型別,必須寫全限定名稱 <select id="getUser" resultType="com.study.pojo.User"> select * from user; </select> </mapper>
-
-
測驗
public class UserMapperTest { @Test public void test(){ //獲得sqlSession物件 SqlSession sqlSession = MybatisUtils.getSqlSession(); //獲取UserMapper的物件以呼叫介面內的方法 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //呼叫方法 List<User> users = userMapper.getUser(); //遍歷結果集 for (User user : users) { System.out.println(user.getId() + " " + user.getUsername() + " " + user.getPassword()); } //關閉sqlSessoin sqlSession.close(); } }
2.3、使用Mybatis的三個重要類
-
SqlSessionFactoryBuilder:
可以重用 SqlSessionFactoryBuilder 來創建多個 SqlSessionFactory 實體,但最好還是不要一直保留著它,以保證所有的 XML 決議資源可以被釋放給更重要的事情
-
SqlSessionFactory:
SqlSessionFactory 一旦被創建就應該在應用的運行期間一直存在,沒有任何理由丟棄它或重新創建另一個實體,最簡單的就是使用單例模式或者靜態單例模式
-
SqlSession:
SqlSession 的實體不是執行緒安全的,因此是不能被共享的,每次打開一個 SqlSession,記得關閉它, 這個關閉操作很重要
3.Mybatis的CRUD簡單實作
3.1、通過id查找用戶:
-
介面:
public User getUserById(int id); -
Mapper組態檔
<select id="getUserById" resultType="com.study.pojo.User"> select * from user where id=#{id}; </select> -
測驗
SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); User user = userMapper.getUserById(1); sqlSession.close();
3.2、插入用戶:
-
介面:
public void insertUser(User user); -
Mapper組態檔
<insert id="insertUser"> insert into user values (#{id},#{username},#{password}); </insert> -
測驗
SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); userMapper.insertUser(new User(5,"老六","1234")); sqlSession.commit(); sqlSession.close(); //注:在Mybatis中增刪改查找都需要使用事務,必須手動提交事務如果沒有配置自動管理事務的情況下
3.3、根據id更改用戶名字:
-
介面:
public void insertUser(User user); -
Mapper組態檔
<insert id="insertUser"> insert into user values (#{id},#{username},#{password}); </insert> -
測驗
//當有多個引數的時候,可以使用@Param()注解指定名字 //public void updateName(@Param("id") int id,@Param("username") String username); SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); userMapper.updateName(3,"王五"); sqlSession.commit(); sqlSession.close();
3.4、 根據id洗掉用戶:
-
介面:
public void insertUser(User user); -
Mapper組態檔
<insert id="insertUser"> insert into user values (#{id},#{username},#{password}); </insert> -
測驗
SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); userMapper.deleteUserById(5); sqlSession.commit(); sqlSession.close();
3.5、好用的Map
當介面中傳遞的物件有多個的時候,除了可以使用·@Param()注解之外,我們常常使用一個不算規范但是特別好用的方式,那就是傳遞Map
-
介面:
public void updateNameById(Map<String,Object> map); -
mapper組態檔:
<update id="updateNameById" > update user set username=#{username} where id=#{id}; </update> -
呼叫:
SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); Map<String,Object> map=new HashMap(); map.put("username","戰三"); map.put("id",2); userMapper.updateNameById(map); sqlSession.commit(); sqlSession.close();
總結:
- 當介面只傳遞一個引數的時候:可以直接在mapper檔案使用,且不需要與引數名字對應
- 當需要多個引數的時候:
- 如果有一個物體類正好與之對應,那么可以傳遞一個物件,然后在mapper檔案中通過#{物件.屬性}呼叫
- 通過使用注解的方式@Param()指定名字
- 通過傳遞一個Map
3.6、模糊查詢
-
方式一:在java代碼在傳遞“%”
userMapper.getUserLike("%張%"); -
方式二:在mapper檔案的sql陳述句中實作
<select id="getUserLike" resultType="com.study.pojo.User"> select * from user where username like "%"#{name}"%" ; </select>
4.配置決議
MyBatis 的組態檔包含了會深深影響 MyBatis 行為的設定和屬性資訊, 配置檔案的頂層結構如下:
- configuration(配置)
- properties(屬性)
- settings(設定)
- typeAliases(型別別名)
- typeHandlers(型別處理器)
- objectFactory(物件工廠)
- plugins(插件)
- environments(環境配置)
- environment(環境變數)
- transactionManager(事務管理器)
- dataSource(資料源)
- environment(環境變數)
- databaseIdProvider(資料庫廠商標識)
- mappers(映射器)
4.1、environments 環境配置
MyBatis 可以配置成適應多種環境,不過要記住:盡管可以配置多個環境,但每個 SqlSessionFactory 實體只能選擇一種環境,
environments 元素定義了如何配置環境,
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="..." value="https://www.cnblogs.com/xiaoye-Blog/p/..."/>
</transactionManager>
<dataSource type="POOLED">
<property name="driver" value="https://www.cnblogs.com/xiaoye-Blog/p/${driver}"/>
<property name="url" value="https://www.cnblogs.com/xiaoye-Blog/p/${url}"/>
<property name="username" value="https://www.cnblogs.com/xiaoye-Blog/p/${username}"/>
<property name="password" value="https://www.cnblogs.com/xiaoye-Blog/p/${password}"/>
</dataSource>
</environment>
<!--如果要切換環境只需要更改環境default,改成需要使用的環境的id-->
<environment id="test">
</environment>
</environments>
注意點:
- 默認使用的環境 ID(比如:default="development"),
- 每個 environment 元素定義的環境 ID(比如:id="development"),
- 事務管理器的配置(比如:type="JDBC"),
- 資料源的配置(比如:type="POOLED"),
4.2、properties(屬性)
可以從外部的資源環境讀取,也可以在內部定義,可以動態的替換環境中的配置資訊
-
外部資源檔案引入:
-
db.properties
driver=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai username=root password=11111111 -
引入:
<properties resource="db.properties"> </properties>
-
-
內部使用property定義:
<properties resource="org/mybatis/example/config.properties"> <property name="username" value="https://www.cnblogs.com/xiaoye-Blog/p/dev_user"/> <property name="password" value="https://www.cnblogs.com/xiaoye-Blog/p/F2Fa3!33TYyg"/> </properties>
設定好的屬性可以動態替換:
<dataSource type="POOLED">
<property name="driver" value="https://www.cnblogs.com/xiaoye-Blog/p/${driver}"/>
<property name="url" value="https://www.cnblogs.com/xiaoye-Blog/p/${url}"/>
<property name="username" value="https://www.cnblogs.com/xiaoye-Blog/p/${username}"/>
<property name="password" value="https://www.cnblogs.com/xiaoye-Blog/p/${password}"/>
</dataSource>
注:如果同時使用了外部資源檔案和內部定義的方式那么會使用外部資源檔案,
4.3、typeAliases(型別別名)
型別別名可為 Java 型別設定一個縮寫名字,降低冗余的全限定類名書寫
-
方式一:使用具體的全限定類名
<typeAliases> <typeAlias alias="Author" type="domain.blog.Author"/> <typeAlias alias="Blog" type="domain.blog.Blog"/> </typeAliases>注:設定之后在其他使用domain.blog.Author的地方就可以使用Author代替
-
方式二:使用物體類包名
<typeAliases> <package name="domain.blog"/> </typeAliases>注:通過這種方式設定之后,在該包下所有的物體類的全限定類名可以使用該類名的首字母小寫來代替,比如User使用user代替
總結:兩種方式各有優劣,當類比較少的時候可以使用第一種方式,當類比較多的時候可以使用第二種方式,如果想在使用第二種方式的同時給特點的類設定指定名字,可以使用注解的方式,且如果同時使用了第一種方式和第二種方式那么使用兩個別名都正確,
@Alias("author")
public class Author {}
4.4、settings(設定)
1.常用的一些設定:
| 設定名 | 描述 | 有效值 | 默認值 |
|---|---|---|---|
| cacheEnabled | 全域性地開啟或關閉所有映射器組態檔中已配置的任何快取, | true | false | true |
| lazyLoadingEnabled | 延遲加載的全域開關,當開啟時,所有關聯物件都會延遲加載, 特定關聯關系中可通過設定 fetchType 屬性來覆寫該項的開關狀態, |
true | false | false |
| useGeneratedKeys | 允許 JDBC 支持自動生成主鍵,需要資料庫驅動支持,如果設定為 true,將強制使用自動生成主鍵,盡管一些資料庫驅動不支持此特性,但仍可正常作業(如 Derby), | true | false | False |
| mapUnderscoreToCamelCase | 是否開啟駝峰命名自動映射,即從經典資料庫列名 A_COLUMN 映射到經典 Java 屬性名 aColumn, | true | false | False |
| logImpl | 指定 MyBatis 所用日志的具體實作,未指定時將自動查找, | SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING | 未設定 |
日志:
- STDOUT_LOGGING (mybatis默認)
- LOG4J (掌握)
- LOG4J2
- JDK_LOGGING
- COMMONS_LOGGING
- SLF4J
- NO_LOGGING:
4.5、mappers(映射器)
-
作用:告訴 MyBatis 到哪里去找映射檔案
-
實作方式:
-
方式一:resource(推薦)
<!-- 使用相對于類路徑的資源參考 --> <mappers> <mapper resource="org/mybatis/builder/AuthorMapper.xml"/> <mapper resource="org/mybatis/builder/BlogMapper.xml"/> <mapper resource="org/mybatis/builder/PostMapper.xml"/> </mappers> -
方式二:url(極不推薦)
<!-- 使用完全限定資源定位符(URL) --> <mappers> <mapper url="file:///var/mappers/AuthorMapper.xml"/> <mapper url="file:///var/mappers/BlogMapper.xml"/> <mapper url="file:///var/mappers/PostMapper.xml"/> </mappers> -
方式三:class
<!-- 使用映射器介面實作類的完全限定類名 --> <mappers> <mapper /> <mapper /> <mapper /> </mappers>注:
- 介面必須和mapper組態檔在同一個包下
- 介面和mapper組態檔的名字必須相同
-
方式四:name
<!-- 將包內的映射器介面實作全部注冊為映射器 --> <mappers> <package name="org.mybatis.builder"/> </mappers>注:
- 介面必須和mapper組態檔在同一個包下
- 介面和mapper組態檔的名字必須相同
-
4.6、其他(暫時了解)
- typeHandlers(型別處理器)
- objectFactory(物件工廠)
- plugins(插件)(有用)
- Mybatis PageHelper分頁插件
- Mybatis通用Mapper插件
- Mybatis Plus插件
- 代碼生成插件mybatis-generator
5.拓展:當屬性名和列名不一致
假設存在一個資料庫user表,欄位如下:

一個User物體類如下:
public class User {
private int id;
private String username;
private String password;
}
那么當查詢結果集為User型別的時候,會出現姓名為空的問題,
解決方式:
-
方式一:在sql陳述句中使用別名
select id ,name as usernaem,password from user; -
方式二:resultMap結果映射
<resultMap id="userMap" type="user"> <id property="id" column="id"/> <result property="username" column="name"></result> <result property="password" column="password"></result> </resultMap> <select id="getUserAll" resultMap="userMap"> select * from user ; </select>-
resultMap元素是 MyBatis 中最重要最強大的元素, -
ResultMap 的設計思想是,對簡單的陳述句做到零配置,對于復雜一點的陳述句,只需要描述陳述句之間的關系就行了,
-
ResultMap的優秀之處——你完全可以不用顯式地配置它們,如上面的resultMap可以改為
<resultMap id="userMap" type="user"> <result property="username" column="name"></result> </resultMap>即只需要顯示的配置不匹配的情況即可,
注:其實第一種方法使用別名的本質上還是使用了resultMap的映射,因為在這些情況下,MyBatis 會在幕后自動創建一個
ResultMap,再根據屬性名來映射列到 JavaBean 的屬性上, -
6.日志
6.1、日志工廠
-
當我們操作資料庫出現錯誤時,需要借助一些手段進行排錯
- 之前:sout,debug
- 現在:日志
-
日志類別:
- STDOUT_LOGGING(掌握)(默認的標準日志工廠)
- LOG4J(掌握)
- LOG4J2
- SLF4J
- JDK_LOGGING
- COMMONS_LOGGING
- NO_LOGGING
-
配置日志:
<settings> <setting name="logImpl" value="https://www.cnblogs.com/xiaoye-Blog/p/STDOUT_LOGGING"/> </settings>使用了日志之后,我們就可以查看到非常多的資訊

6.2、Log4j
-
介紹:
- Log4j是Apache的一個開源專案,通過使用Log4j,我們可以控制日志資訊輸送的目的地是控制臺、檔案、GUI組件等
- 我們也可以控制每一條日志的輸出格式;
- 通過定義每一條日志資訊的級別,我們能夠更加細致地控制日志的生成程序,
- 可以通過一個組態檔來靈活地進行配置,而不需要修改應用的代碼,
-
log4j:
-
匯入log4j依賴
<dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> -
log4j.properties
#將等級為debug的日志資訊輸出到console和file,其中console為控制臺,名字可以自己定義,file相同 log4j.rootLogger=DEBUG,console,file #控制臺輸出的相關設定 log4j.appender.console=org.apache.log4j.ConsoleAppender log4j.appender.console.Target=System.out log4j.appender.console.layout=org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern=%p:%c%n%m%l%n%m #檔案輸出的相關設定 log4j.appender.file=org.apache.log4j.FileAppender log4j.appender.file.File=d:/log4jFile/mybatis.log log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %l %F %p %m%n log4j.appender.file.MaxFileSize=10mb #控制日志的輸出鑒別 log4j.logger.org.mybatis=DEBUG log4j.logger.java.sql.ResultSet=DEBUG log4j.logger.java.sql=DEBUG log4j.logger.java.sql.Statement=DEBUG log4j.logger.java.sql.PreparedStatement=DEBUG -
在mybatis-config中配置log4j的使用
<settings> <setting name="logImpl" value="https://www.cnblogs.com/xiaoye-Blog/p/LOG4J"/> </settings>
-
7.分頁
思考:為什么要分頁
- 減少資料的處理量
7.1、 limit分頁:
select * from user limit startIndex,pagesize;
select *from user limit pagesize; -- 當只有一個引數的時候,從第一個資料開始
7.2、 RowBounds分頁(不推薦使用)
-
介面:
public List<User> getUser(); -
mapper.xml:
<select id="getUser" resultType="com.study.pojo.User"> select * from user ; </select> -
實作:
SqlSession sqlSession = MybatisUtils.getSqlSession(); RowBounds rowBounds=new RowBounds(1,2); List<User> list = sqlSession.selectList("com.study.dao.UserMapper.getUser", null, rowBounds); for (Object user : list) { System.out.println(user.toString()); }
7.3、分頁插件
使用PageHelper分頁插件,https://pagehelper.github.io/,了解一下即可,如有需要再看使用檔案,
8.注解開發
- 使用注解來映射簡單陳述句會使代碼顯得更加簡潔
- 但對于稍微復雜一點的陳述句,Java 注解不僅力不從心,還會讓你本就復雜的 SQL 陳述句更加混亂不堪
- 如果需要做一些很復雜的操作,最好用 XML 來映射陳述句,
使用建議:除非是很簡單的操作,否則盡量建議使用xml方式完成,一般而言我們都會使用xml,
8.1、常用的注解
-
@Insert:
插入記錄的時候麻煩的一點是主鍵如何生成,對此基本上有三種方案,分別是手動指定(應用層)、自增主鍵(資料層單表)、選擇主鍵(資料層多表),(如想了解可以查)
@Insert("insert into user values (#{id},#{username},null)") -
@Delete:
@Delete("delete from user where id=#{id};") -
@Updata:
@Update(" update user set username=#{username} where id=#{id};") -
@select:
@Select("select * from user") -
@Param:
在介面中傳遞多個引數的時候可以指定
public void updateName(@Param("id") int id,@Param("username") String username);注:
- 基本型別或者String型別需要加上
- 參考型別不需要加
- 如果只有一個基本型別的引數可以不加
- 在mapper.xml中使用的就是它指定的名字
-
@Results, @Result:
當使用select標簽時,如果查詢的欄位與當前物體類不能進行很好的匹配那么需要我們進行一個映射
@Results(id = "userMap", value = https://www.cnblogs.com/xiaoye-Blog/p/{ @Result(id=true, column ="id", property = "id"), @Result(column = "username", property = "username"), @Result(column = "passwd", property = "passwd"), }) @Select("SELECT * FROM t_user WHERE id=#{id}") User loadByIdResultMap(Long id); -
@ResultMap:
如果以及存在一個@Results,那么可以通過@ResultMap指定id名字去參考它
@ResultMap("userMap") @Select("SELECT * FROM t_user WHERE id=#{id}") User loadByIdResultMapReference(Long id);
8.2、使用注解開發
-
介面:
public interface UserMapper { @Select("select * from user") public List<User> getUser(); @Update(" update user set username=#{username} where id=#{id};") public void updateName(@Param("id") int id,@Param("username") String username); @Insert("insert into user values (#{id},#{username},null)") public void insertUser(User user); @Delete("delete from user where id=#{id};") public void deleteUserById(int id); } -
mybatis-config.xml注冊介面:
<mappers> <mapper /> </mappers> -
測驗:
SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> user = userMapper.getUser(); //userMapper.insertUser(new User(6,"隨便","123123")); //userMapper.updateName(2,"還行"); //userMapper.deleteUserById(1); for (User user1 : user) { System.out.println(user1); } sqlSession.commit(); sqlSession.close();
本質:反射機制實作
底層:動態代理
8.3、關于#{}和${}的比較
- 前者是占位,在使用時會將傳入的字串加上引號當做一個整體,${}是拼接,在使用的時候會將傳入的字串不做處理直接拼接
- 使用#{}時會進行預編譯可以防止sql注入,使用${}不會預編譯不可以防止sql注入
- 使用時#{}是編譯好SQL后陳述句再去取值,${}取值以后再去編譯SQL陳述句
- 建議:一般能用#{}就不用${}
8.4、當注解開發和xml開發同時使用
注:雖然注解和xml組態檔可以同時使用,但是如果在介面中的同一個方法上既使用了注解,有在xml檔案中進行了配置,也就是對同一個方法同時使用了注解組態檔兩種方式,那么程式會報錯,
9.Lombok
Lombok專案是一個java庫,它可以自動插入到編輯器和構建工具中,增強java的性能,不需要再寫getter、setter或equals方法,只要有一個注解,你的類就有一個功能齊全的構建器、自動記錄變數等等.
-
常用注解:
- Data:整合了Getter、Setter、ToString、EqualsAndHashCode、無參建構式注解,
- Getter:快速構建Getter方法,
- Setter:快速構建Setter方法,
- ToString:快速將當前物件轉換成字串型別,便于log
- EqualsAndHashCode:快速進行相等判斷
- NonNull:判斷變數(物件)是否為空,
- AllArgsConstructor:快速構建全部引數的建構式
- NoArgsConstructor:快速構建無參建構式
-
Lombok的使用:
-
在IDEA中安裝Lombok插件
-
在專案中匯入lombok的jar包
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.16</version> </dependency> -
使用:
@Data @AllArgsConstructor @NoArgsConstructor public class Persosn { private String name; private int age; }注:由于使用@Data只含有無參建構式,使用要結合@AllArgsConstructor使用,但是使用了@AllArgsConstructor之后@Data的無參建構式就會消失,使用需要再搭配@NoArgsConstructor使用,
-
注:缺點:無法承載有各種引數的建構式,但是我們可以手動的去添加,
10.復雜查詢
10.1、模擬場景環境搭建
- 新建專案,匯入相關依賴
- 組態檔的撰寫
- 新建物體類Student和Teacher
- 建立對應的Mapper介面
- 建立對應的Mapper組態檔
- 注冊組態檔
- 測驗環境搭建是否成功
10.2、多對一實際應用:關聯
比如多個學生對應一個老師,就是多對一
物體類如下:
@Data
public class Student {
private int id;
private String name;
private Teacher teacher;//多個學生一個老師
}
@Data
public class Teacher {
private int id;
private String name;
}
實作關鍵:association
10.2.1、嵌套查詢
<resultMap id="Student_t" type="student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<association property="teacher" column="tid" javaType="teacher" select="getTeacher"/>
</resultMap>
<select id="getStudent" resultMap="Student_t">
select * from student ;
</select>
<select id="getTeacher" resultType="teacher">
select * from teacher where id=#{id}
</select
通過嵌套一個子查詢的方式,通過學生的tid去找到對應的老師
10.2.2、嵌套結果
<resultMap id="Student_t2" type="student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
</association>
</resultMap>
<select id="getStudent2" resultMap="Student_t2">
select s.id sid,s.name sname,t.id tid ,t.name tname from student s,teacher t where s.tid=t.id;
</select>
通過對結果集直接進行映射
10.3、一對多實際應用:集合
比如一個老師有多個學生,對于老師而言就是一對多
物體類如下:
@Data
public class Student {
private int id;
private String name;
private int tid;
}
@Data
public class Teacher {
private int id;
private String name;
private List<Student> students;
}
實作關鍵:collection
10.3.1、嵌套查詢
<resultMap id="teacher_s1" type="teacher">
<result property="id" column="id"/>
<result property="name" column="name"/>
<collection property="students" ofType="student" column="id" select="getStudent" javaType="ArrayList"/>
</resultMap>
<select id="getTeacher" resultMap="teacher_s1">
select * from teacher t;
</select>
<select id="getStudent" resultType="student">
select * from student where tid=#{id};
</select>
10.3.2、嵌套結果
<resultMap id="teacher_s2" type="teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<collection property="students" ofType="student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result column="tid" property="tid"/>
</collection>
</resultMap>
<select id="getTeacher1" resultMap="teacher_s2">
select s.id sid,s.name sname,t.id tid ,t.name tname from student s,teacher t where s.tid=t.id;
</select>
10.4、小結
- 關聯:association
- 集合:collection
- javaType:用來指定物體類中的屬性的型別
- ofType:用來指定映射到List或者集合中的pojo型別,泛型中的約束型別
附:面試高頻問題;
- MySql引擎
- InnoDB底層原理
- 索引
- 索引優化
11.動態SQL
11.1、簡單介紹
動態 SQL 是 MyBatis 的強大特性之一,如果你使用過 JDBC 或其它類似的框架,你應該能理解根據不同條件拼接 SQL 陳述句有多痛苦,例如拼接時要確保不能忘記添加必要的空格,還要注意去掉串列最后一個列名的逗號,利用動態 SQL,可以徹底擺脫這種痛苦,
種類:
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
11.2、實體專案的搭建
-
在資料庫中根據以下物體類創建blog表
@Data public class Blog { private String id; private String title; private String author; private Date createTime; private int views; }拓展:物體類中的id型別是String,在具體的一個專案中其實我們可以使用UUID這個類來隨機生成一個唯一的ID,工具類簡單封裝如下:
public class IDUtils { public static String getId(){ return UUID.randomUUID().toString().replace("-",""); } } -
新建專案,匯入相關依賴
-
組態檔的撰寫
<settings> <setting name="mapUnderscoreToCamelCase" value="https://www.cnblogs.com/xiaoye-Blog/p/true"/> </settings>注:開啟這個設定可以自動將資料庫的下劃線映射到物體類的駝峰命名屬性
-
新建物體類Blog
-
建立對應的Mapper介面
-
建立對應的Mapper組態檔
-
注冊組態檔
-
測驗環境搭建是否成功
11.3動態SQL的使用
11.3.1、if
- if提供了條件判斷的功能,可以根據情況決定是否要追加陳述句,
<select id="queryBlog" resultType="blog">
select * from blog where 1=1
<if test="id != null">
and id=#{id}
</if>
<if test="title != null">
and title =#{title}
</if>
<if test="author!='李四'">
and author =#{author}
</if>
<if test="views > 800 ">
and views>#{views}
</if>
</select>
注:第一個where條件后面加一個1=1是為了方便后面的每一個判斷條件追加sql的第一個能寫and
11.3.2、choose (when, otherwise)
- 有時候,我們不想使用所有的條件,而只是想從多個條件中選擇一個使用,針對這種情況,MyBatis 提供了 choose 元素,它有點像 Java 中的 switch 陳述句,
<select id="queryBlog" resultType="blog">
select * from blog
<where>
<choose>
<when test="id != null">
id=#{id}
</when>
<when test="title != null">
and title =#{title}
</when>
<when test="author!='李四'">
and author =#{author}
</when>
<otherwise>
and views>#{views}
</otherwise>
</choose>
</where>
</select>
- 注:當同時滿足多個when的時候,按照順序選擇拼接,比如第一個when滿足那么即是后面的滿足了也不會拼接,然后都不滿足那么拼接otherwise里面的內容,另外otherwise不是必須的
11.3.3、trim (where, set)
-
where:where 元素只會在子元素回傳任何內容的情況下才插入 “WHERE” 子句,而且,若子句的開頭為 “AND” 或 “OR”,where 元素也會將它們去除,
-
set:set 元素可以用于動態包含需要更新的列,忽略其它不更新的列
<update id="updateAuthorIfNecessary"> update Author <set> <if test="author != null">author=#{author},</if> <if test="title != null">title=#{title},</if> <if test="views >= 0">views=#{views}</if> </set> </update> -
trim:
-
trim包含的屬性;
- prefix:自定義前綴
- prefixOverrides:需要被移除的前綴
- suffix:自定義后綴
- suffixOverrides:需要被移除的后綴
-
可以自定義標簽的替換方式,比如與where等同效果的格式如下:
<trim prefix="WHERE" prefixOverrides="AND |OR "> ... </trim>prefixOverrides 屬性會忽略通過管道符分隔的文本序列(注意此例中的空格是必要的),上述例子會移除所有 prefixOverrides 屬性中指定的內容,并且插入 prefix 屬性中指定的內容,
-
與set等同效果的格式如下:
<trim prefix="SET" suffixOverrides=","> ... </trim>
-
11.3.4、foreach
-
foreach 元素的功能非常強大,它允許你指定一個集合,宣告可以在元素體內使用的集合項(item)和索引(index)變數,它也允許你指定開頭與結尾的字串以及集合項迭代之間的分隔符,
-
可以將任何可迭代物件(如 List、Set 等)、Map 物件或者陣列物件作為集合引數傳遞給 foreach,當使用可迭代物件或者陣列時,index 是當前迭代的序號,item 的值是本次迭代獲取到的元素,當使用 Map 物件(或者 Map.Entry 物件的集合)時,index 是鍵,item 是值,
<select id="queryBlog" resultType="blog"> select * from blog <where> <foreach collection="names" item="name" open="author in (" close=")" separator=","> #{name} </foreach> </where> </select>測驗:
@Test public void test() { SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class); ArrayList<String> names = new ArrayList<>(); names.add("張三"); names.add("李四"); Map<String,List> map=new HashMap<>(); map.put("names",names); List<Blog> blogs = blogMapper.queryBlog(map); for (Blog blog : blogs) { System.out.println(blog); } sqlSession.close(); }
11.3.5、sql片段
sql片段的作用就是可以將一部分sql代碼抽取出來,然后可以對他進行一個復用,
<select id="queryBlog" resultType="blog">
select * from blog
<where>
<include refid="choose"></include>
</where>
</select>
<sql id="choose">
<choose>
<when test="id != null">
id=#{id}
</when>
<when test="title != null">
and title =#{title}
</when>
<when test="author!='李四'">
and author =#{author}
</when>
</choose>
</sql>
注意事項:
- 盡量不要使sql片段太過復雜
11.3.6、小結
動態sql本質上就是拼接sql陳述句
建議:
- 我們可以在mysql中去寫寫出我們需要的sql陳述句,然后再去拼接
12.Mybatis快取
12.1、簡介
- 什么是快取
- 存盤在記憶體中的臨時資料
- 將經常查詢的資訊從記憶體中復制一份到快取,當再次查找時就直接從快取中查找,從而提高效率,解決高并發的性能問題
- 使用快取的好處
- 減少資料庫的互動次數,減小系統的開銷,提高效率
- 什么樣的資料庫可以使用快取
- 查詢比較頻繁并且不經常改動的資料庫
12.2、Mybatis快取
mybatis本身有兩種快取,分別為一級快取和二級快取
-
一級快取:
- MyBatis默認開啟了一級快取,一級快取是在 SqlSession 層面進行快取的,即,同一個 SqlSession ,多次呼叫同一個 Mapper 和同一個方法的同一個引數,只會進行一次資料庫查詢,然后把資料快取到緩沖中,以后直接先從快取中取出資料,不會直接去查資料庫,
-
二級快取:
- 二級快取需要手動開啟,他是基于namespce級別的快取
- 為了提高拓展性,mybatis定義了快取介面Cache,我們可以通過該介面自定義二級快取
12.3、一級快取
- 一級快取也叫本地快取:SqlSession
- 在同一個SqlSession之間查詢到的資料會放到本地的快取中
- 之后如果想要獲取資料自己從本地快取中取
測驗步驟:
-
開啟日志
<settings> <setting name="logImpl" value="https://www.cnblogs.com/xiaoye-Blog/p/STDOUT_LOGGING"/> </settings> -
測驗在同一個SqlSession期間查詢相同的資料
-
查看日志輸出

快取失效的情況:
-
查詢不一樣的資料
-
增刪改操作,由于可能會改變原來的資料,所有快取也會失效

-
查詢不同的Mapper.xml
-
手動清除快取
sqlSession.clearCache();
-
快取會使用最近最少使用演算法(LRU, Least Recently Used)演算法來清除不需要的快取,
-
快取不會定時進行重繪(也就是說,沒有重繪間隔)
小結:一級快取是默認開啟的,也關閉不掉,只能手動清理或者設定,一級快取其實就相當于一個Map
12.4、二級快取
- 二級快取也叫全域快取,它的出現是為了解決一級快取的作用域太低
- 它是基于namespace級別的快取,一個命名空間,對應一個二級快取
- 機制:
- 一個SqlSession查詢一條資料,這個資料會被放到一級快取中;
- 當這個SqlSession斷開的時候,一級快取就會消失,為了能夠繼續保存,我們就產生了二級快取
- 當其他的SqlSession查詢資料時,就可以先從二級快取中查詢
- 不同的mapper.xml檔案查出的資料會放到自己的快取(map)之中
測驗步驟:
-
開啟二級快取設定;
<setting name="cacheEnabled" value="https://www.cnblogs.com/xiaoye-Blog/p/true"/> <!--注:二級快取是默認開啟的,但是我們一般會顯示的寫出來--> -
在要使用二級快取的mapper.xml組態檔中開啟快取:
<!--直接開啟--> <cache/> <!--當然還可以給快取設定一些屬性--> <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/> <!--該快取的 清除快取策略:FIFO(最近最少使用) 重繪間隔:60s 最多存盤:結果物件或串列的 512 個參考 回傳的物件被認為是只讀的 --> -
測驗
小結:
-
在使用二級快取的時候可能會報錯:
Error serializing object. Cause: java.io.NotSerializableException解決:原因是沒有將物體類序列化,所以直接將類序列化即可
-
在mapper.xml檔案中,對于查找標簽都可以手動設定是否開啟快取
useCache="true" -
快取清除的策略:
LRU– 最近最少使用:移除最長時間不被使用的物件,FIFO– 先進先出:按物件進入快取的順序來移除它們,SOFT– 軟參考:基于垃圾回收器狀態和軟參考規則移除物件,WEAK– 弱參考:更積極地基于垃圾收集器狀態和弱參考規則移除物件,
-
所有的資料都會先存到一級快取,只有當會話提交或者關閉才會提交到二級快取
12.5、快取原理

12.6、自定義快取(了解)
注:一般可以采用redis來做快取!!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/500503.html
標籤:Java
