文章目錄
- Mybatis概述
- 什么是Mybatis?
- Mybatis導入
- 知識補充
- 數據持久化
- 持久層
- 第一個Mybatis程序:數據的增刪改查查
- 創建環境
- 編寫代碼
- 1、目錄結構
- 2、核心配置文件:resources/mybatis-config.xml
- 3、mybatis工具類:Utils/MybatisUtils
- 4、Pojo:User
- 5、Dao接口:UserDao
- 6、Mapper配置文件:UserMapper.xml
- 測試
- 常見問題匯總
- 第一個Mybatis程序:完善
- 優化后的整體目錄結構
- 1、通過db.properties文件配置數據庫連接的基本設置
- 2、配置多套環境
- 3、起別名
- 4、映射器 mappers
- 第一個Mybatis程序:進階
- resultMap
- 問題描述
- 解決1:改變Sql語句,在sql中起別名
- 解決2:使用resultMap
- 注意事項!!!
- 模糊查詢
- 日志
- 日志工廠
- STDOUT_LOGGING使用
- LOG4J使用
- 分頁
- Limit分頁
- RowBounds分頁
- 分頁插件:PageHelper
- 注解開發實現
- 實現
- 關于 @Param(“”) 注解
- #{} 和 ${} 的區別
- Lombok
- 第二個Mybatis程序:基礎,多對一處理
- 案例背景
- 編寫代碼
- 1、Pojo
- 2、Utils
- 3、Dao:按照查詢嵌套處理
- 4、Dao:按照結果嵌套處理
- 5、結果
- 總結:association
- 第二個Mybatis程序:進階,一對多處理
- 案例背景
- 編寫代碼
- 1、Pojo
- 2、Utils
- 3、Dao:按照查詢嵌套處理
- 4、Dao:按照結果嵌套處理
- 5、結果
- 總結:collection
- 動態SQL
- 什么是動態SQL?
- 環境搭建
- 動態SQL-IF
- 動態SQL-choose、when、otherwise
- 動態SQL-Set
- 動態SQL-trim、sql片段
- 動態SQL-foreach
- 緩存
- 簡介
- Mybatis緩存
- 一級緩存
- 二級緩存
- Mybatis調用順序
- 自定義緩存-ehcache
- 介紹
Mybatis概述
什么是Mybatis?
- MyBatis 是一款優秀的持久層框架
- 它支持自定義 SQL、存儲過程以及高級映射
- MyBatis 免除了幾乎所有的 JDBC代碼以及設置參數和獲取結果集
- MyBatis 可以通過簡單的 XML 或注解來配置和映射原始類型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 對象)為數據庫中的記錄
Mybatis導入
-
Maven倉庫:https://mvnrepository.com/artifact/org.mybatis/mybatis
-
官方文檔(中文):https://mybatis.org/mybatis-3/zh/index.html
知識補充
數據持久化
- 持久化就是將程序的數據從瞬時狀態轉化為持久狀態的過程
- 生活結合:冰箱冷藏
- 內存中的數據:斷電即失
- 可以持久化存儲數據的媒介:數據庫(jdbc)、io文件
持久層
- 完成持久化工作的代碼塊
- Dao層,Service層,Controller層…
第一個Mybatis程序:數據的增刪改查查
創建環境
1、Maven項目創建
2、新建一個模塊
3、導入相關依賴
4、建立數據庫環境
-- 建表
CREATE TABLE `user`(
`id` INT(20) NOT NULL PRIMARY KEY,
`name` VARCHAR(30) DEFAULT NULL,
`pwd` VARCHAR(30) DEFAULT NULL
)ENGINE=INNODB DEFAULT CHARSET=utf8;-- 插入語句
INSERT INTO `user`(`id`, `name`, `pwd`) VALUES
(1, "狂神", "123456"),
(2, "張三", "1234567"),
(3, "李四", "1234568")
編寫代碼
1、目錄結構
后續按代碼編寫順序,貼出相關代碼
2、核心配置文件:resources/mybatis-config.xml
主要完成對數據庫的配置連接和Dao層xml文件的注冊
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//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="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/learn_mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8"/><property name="username" value="root"/><property name="password" value="123456"/></dataSource></environment></environments><!-- 每一個Mapper.xml都需要在MyBatis核心配置文件中注冊--><mappers><mapper resource="GSF/Example/Dao/UserMapper.xml"/></mappers></configuration>
- mappers標簽下的內容是在寫了Dao層代碼后,寫入的
3、mybatis工具類:Utils/MybatisUtils
每次連接數據庫之前,都需要通過sqlSessionFactory來獲取sqlSession對象,從而進行后續的數據庫連接、sql執行、關閉操作
將該獲取過程提取抽象,寫為工具類,方便每次調用使用
package GSF.Example.Utils;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.IOException;
import java.io.InputStream;public class MybatisUtils {private static SqlSessionFactory sqlSessionFactory;static {String resources = "mybatis-config.xml";InputStream inputStream = null;try {inputStream = Resources.getResourceAsStream(resources);sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);} catch (IOException e) {throw new RuntimeException(e);}}public static SqlSession getSqlsession(){return sqlSessionFactory.openSession();}
}
4、Pojo:User
和數據庫中數據表相對應的實體類對象
- 字段和數據表字段基本一一對應
- 如果不對應,也可以通過一個resultMap映射,完成不對應字段之間的關聯
set、get方法很關鍵,是執行sql語句完畢后,將查詢結果寫入實體類對象的關鍵
package GSF.Example.Pojo;public class User {private int id;private String name;private String pwd;public User(){}public User(int id, String name, String pwd) {this.id = id;this.name = name;this.pwd = pwd;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPwd() {return pwd;}public void setPwd(String pwd) {this.pwd = pwd;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +", pwd='" + pwd + '\'' +'}';}
}
5、Dao接口:UserDao
定義獲取數據庫對象的接口方法
package GSF.Example.Dao;import GSF.Example.Pojo.User;import java.util.List;
import java.util.Map;public interface UserDao {List<User> getUserList();// 根據id查詢用戶User getUserById(int id);//插入一個用戶int addUser(User user);// 用map的方式插入用戶int addUserByMap(Map<String, Object> map);//修改用戶int updateUser(User user);//刪除一個用戶int deleteUser(int id);
}
6、Mapper配置文件:UserMapper.xml
寫入接口方法的具體實現,需要寫入相應的sql語句
- 代替的是原來UserDaoImpl中的相關實現
- 寫完此配置文件,需要向 “2” 的核心配置文件中注冊該mapper
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace=綁定一個Dao/Mapper接口-->
<mapper namespace="GSF.Example.Dao.UserDao"><!-- select查詢語句,ID對應方法名--><select id="getUserList" resultType="GSF.Example.Pojo.User">select * from learn_mybatis.user</select><select id="getUserById" parameterType="int" resultType="GSF.Example.Pojo.User">select * from learn_mybatis.user where id=#{id}</select><insert id="addUser" parameterType="GSF.Example.Pojo.User">insert into learn_mybatis.user(id, name, pwd) values (#{id}, #{name}, #{pwd});</insert><insert id="addUserByMap" parameterType="map">insert into learn_mybatis.user(id, name, pwd) values (#{user_id}, #{user_name}, #{user_pwd});</insert><update id="updateUser" parameterType="GSF.Example.Pojo.User">update learn_mybatis.user set name=#{name}, pwd=#{pwd} where id=#{id};</update><delete id="deleteUser" parameterType="int">delete from learn_mybatis.user where id=#{id};</delete>
</mapper>
測試
1、測試:UserTest
package GSF.Example.Dao;import GSF.Example.Pojo.User;
import GSF.Example.Utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;import java.util.HashMap;
import java.util.List;public class UserTest {@Testpublic void GetUserList(){// 官方建議用try...catch包裹,可以不用SqlSession sqlsession = MybatisUtils.getSqlsession();try {UserDao mapper = sqlsession.getMapper(UserDao.class);List<User> userList = mapper.getUserList();for (User user : userList) {System.out.println(user);}}catch (Exception e){e.printStackTrace();}finally {sqlsession.close();}}@Testpublic void GetUserById(){SqlSession sqlsession = MybatisUtils.getSqlsession();UserDao mapper = sqlsession.getMapper(UserDao.class);User user = mapper.getUserById(2);System.out.println(user);sqlsession.close();}@Testpublic void AddUser(){SqlSession sqlsession = MybatisUtils.getSqlsession();UserDao mapper = sqlsession.getMapper(UserDao.class);// 插入成功,返回值為1int flag = mapper.addUser(new User(10, "GSF", "qwerty"));System.out.println(flag);sqlsession.commit();sqlsession.close();}@Testpublic void AddUserByMap(){SqlSession sqlsession = MybatisUtils.getSqlsession();UserDao mapper = sqlsession.getMapper(UserDao.class);// 插入成功,返回值為1HashMap<String, Object> map_obj = new HashMap<>();map_obj.put("user_id", 12);map_obj.put("user_name", "121212");map_obj.put("user_pwd", "zxcxvz");int flag = mapper.addUserByMap(map_obj);System.out.println(flag);sqlsession.commit();sqlsession.close();}@Testpublic void UpdateUser(){SqlSession sqlsession = MybatisUtils.getSqlsession();UserDao mapper = sqlsession.getMapper(UserDao.class);int flag = mapper.updateUser(new User(1, "123", "12345678"));System.out.println(flag);sqlsession.commit();sqlsession.close();}@Testpublic void DeleteUser(){SqlSession sqlsession = MybatisUtils.getSqlsession();UserDao mapper = sqlsession.getMapper(UserDao.class);int flag = mapper.deleteUser(1);System.out.println(flag);sqlsession.commit();sqlsession.close();}
}
常見問題匯總
第一次寫程序,可能遇到各種各樣錯誤,基本都涵蓋如下:
- Dao層Mapper.xml配置文件沒有在mybatis-config.xml中注冊
- maven導出資源問題【資源不放在resources文件夾下,正常情況下沒法輸出到target文件夾中】
- 通過配置資源導出的目錄解決該問題
<!-- 在項目的pom.xml文件中加入此配置 --><build><resources><resource><directory>src/main/resources</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes></resource><resource><directory>src/main/java</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes></resource></resources>
</build>
- src/main/resources和src/main/java目錄下的所有.xml文件和.properties文件,都會被識別為資源,從而在構建的時候輸出到target目錄
第一個Mybatis程序:完善
優化后的整體目錄結構
1、通過db.properties文件配置數據庫連接的基本設置
db.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/learn_mybatis?useUnicode=true&characterEncoding=utf-8
username=root
password=123456
- url中不需要轉義符了
- 原url內容:
jdbc:mysql://localhost:3306/learn_mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8
- 原url內容:
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><!--核心配置文件-->
<configuration><!-- properties標簽的位置有嚴格的限制,不能隨意位置更改--><properties resource="db.properties"/><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></dataSource></environment></environments>
</configuration>
- 刪除其他配置,方便理解當前改動
2、配置多套環境
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><!-- 核心配置文件 -->
<configuration>
<!-- properties標簽的位置有嚴格的限制,不能隨意位置更改 --><properties resource="db.properties"/><!-- 通過更改default的值,來實現不同環境的切換 --><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></dataSource></environment><environment id="test"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/learn_mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8"/><property name="username" value="root"/><property name="password" value="123456"/></dataSource></environment></environments>
</configuration>
3、起別名
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><!--核心配置文件-->
<configuration><!--properties標簽的位置有嚴格的限制,不能隨意位置更改--><properties resource="db.properties"/><typeAliases><!-- 給特定類名起別名,給出類的全路徑標識,給出別名--><typeAlias type="GSF.Example.Pojo.User" alias="User"/><!--導入包名,在類名上沒有注解的情況下,包內所有類的別名默認為類名的首字母小寫--><package name="GSF.Example.Pojo"/></typeAliases><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></dataSource></environment></environments>
</configuration>
4、映射器 mappers
方式1:將xml文件注冊進核心配置文件(mybatis-config.xml)【強烈推薦】
- 不需要注意xml配置文件和對應的Dao層java代碼的名字是否一致
<mappers><mapper resource="GSF/Example/Dao/UserDao.xml"/>
</mappers>
方式2:將接口類的完全限定名注冊進核心配置文件(mybatis-config.xml)
<mappers><mapper class="GSF.Example.Dao.UserDao"/>
</mappers>
- 需要保證:接口和其mapper配置文件同名
- 需要保證:接口和其mapper配置文件在同一個文件夾下
方式3:將包注冊進核心配置文件(mybatis-config.xml)
<mappers><package name="GSF.Example.Dao"/>
</mappers>
- 需要保證的內容跟方法2一樣
第一個Mybatis程序:進階
resultMap
解決pojo實體類中對應屬性名和數據庫中對應字段名不一致的問題
問題描述
當數據庫的字段和實體類的字段不一致的時候,進行訪問,會出現不一致的字段為空
數據庫字段
實體類字段
獲取id=1的數據庫數據
解決1:改變Sql語句,在sql中起別名
<select id="getUserById" parameterType="int" resultType="GSF.Example.Pojo.User">select id,name,pwd as password from mybatis.user where id =#{id}
</select>
解決2:使用resultMap
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!-- namespace=綁定一個Dao/Mapper接口-->
<mapper namespace="GSF.Example.Dao.UserDao"><resultMap id="UserMap" type="GSF.Example.Pojo.User"><!-- column:數據庫中的列名;property:實體類中的屬性名,一樣的就無需再配置進來(配置了也不影響)--><result column="pwd" property="password"/></resultMap><!--select查詢語句,ID對應方法名--><select id="getUserList" resultMap="UserMap">select id, name, pwd from learn_mybatis.user</select><select id="getUserById" parameterType="int" resultType="user">select id, name, pwd as password from learn_mybatis.user where id=#{id}</select>
</mapper>
- resultMap標簽下的result標簽定義不一致字段之間的對應關系
- 對應的select標簽:需要將resultType改為resultMap
注意事項!!!
- 當實體類沒有空參構造,即使有字段不一致,Mybatis會強制將實體類中的字段和數據庫中的字段進行屬性匹配
- 可能出現字段不一致,但是并沒有 字段=null 的情況出現
模糊查詢
等到了項目,理解的才能更深刻
現在暫時參考如下文章:https://blog.csdn.net/Adobe_java/article/details/118460709
日志
日志工廠
有代碼出問題了,日志就是最好的排錯手段
mybatis官方支持的7種實現日志的方式:
- 掌握:LOG4J(第三方jar包)、STDOUT_LOGGING(標準日志輸出)
STDOUT_LOGGING使用
mybatis-config.xml配置即可:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><!--核心配置文件-->
<configuration><!-- properties標簽的位置有嚴格的限制,不能隨意位置更改 --><properties resource="db.properties"/><!-- settings標簽依舊有嚴格的位置限制 --><settings><!-- name和value的一個字都不能和官方規定的不一致:不要字符不一致,不要有多余的空格 --><setting name="logImpl" value="STDOUT_LOGGING"/></settings><environments default="development">......</environments></configuration>
設置了日志后的控制臺輸出:
LOG4J使用
什么是log4j
- Log4j是Apache的一個開源項目,通過使用Log4j,我們可以控制日志信息輸送的目的地是控制臺、文件、GUI組件
- 我們也可以控制每一條日志的輸出格式
- 通過定義每一條日志信息的級別,我們能夠更加細致地控制日志的生成過程
- 通過一個配置文件來靈活地進行配置,而不需要修改應用代碼
log4j使用
1、導包
Maven:https://mvnrepository.com/artifact/log4j/log4j
2、log4j.properties配置(固定名字)【放在resources文件夾下】
### 配置根 ###
log4j.rootLogger = debug,console,file### 配置輸出到控制臺 ###
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold = debug
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern = %d{ABSOLUTE} %5p %c{1}:%L - %m%n### 配置輸出到文件 ###
log4j.appender.file = org.apache.log4j.FileAppender
log4j.appender.file.File = ./log/GSF.loglog4j.appender.file.Append = true
log4j.appender.file.Threshold = debuglog4j.appender.file.layout = org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n### 配置輸出到文件,并且每天都創建一個文件 ###
log4j.appender.dailyRollingFile = org.apache.log4j.DailyRollingFileAppender
log4j.appender.dailyRollingFile.File = logs/log.log
log4j.appender.dailyRollingFile.Append = true
log4j.appender.dailyRollingFile.Threshold = debug
log4j.appender.dailyRollingFile.layout = org.apache.log4j.PatternLayout
log4j.appender.dailyRollingFile.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n### 設置輸出sql的級別,其中logger后面的內容全部為jar包中所包含的包名 ###
log4j.logger.org.mybatis=debug
log4j.logger.java.sql=debug
log4j.logger.java.sql.Connection=debug
log4j.logger.java.sql.Statement=debug
log4j.logger.java.sql.PreparedStatement=debug
log4j.logger.java.sql.ResultSet=debug
3、mybatis-config.xml配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><!--核心配置文件-->
<configuration><!-- properties標簽的位置有嚴格的限制,不能隨意位置更改--><properties resource="db.properties"/><settings><setting name="logImpl" value="LOG4J"/></settings><environments default="development">......</environments></configuration>
前三個步驟完成后,訪問數據庫相關操作,就可以記錄到日志中
4、代碼中手動設置日志輸出
package GSF.Example.Dao;import GSF.Example.Pojo.User;
import GSF.Example.Utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import org.junit.Test;import java.util.HashMap;
import java.util.List;public class UserTest {static Logger logger = Logger.getLogger(UserTest.class);@Testpublic void GetUserList(){logger.info("info級別的日志,基本信息,該種日志打印出來,表示系統的正常運行痕跡");logger.debug("debug級別的日志,用于排查錯誤內容,該種日志打印出來,用于排除系統的錯誤");logger.error("error級別的日志,用于輸出錯誤信息,該種日志打印出來,往往是異常捕捉后的輸出");SqlSession sqlsession = MybatisUtils.getSqlsession();try {UserDao mapper = sqlsession.getMapper(UserDao.class);List<User> userList = mapper.getUserList();for (User user : userList) {System.out.println(user);}}catch (Exception e){e.printStackTrace();}finally {sqlsession.close();}}
}
- 類中導入包
- 定義對象
- 因為日志中可以記錄當前日志在什么文件中寫入,所以logger的定義需要綁定當前類的class文件
- 每個使用log4j的方法,都需要在其類中定義logger對象(自認為,待確認?)
分頁
Limit分頁
SELECT * FROM user limit startIndex,pageSize;
SELECT * FROM user limit 0,2;
SELECT * FROM user limit 3; #[0,3]
1、接口定義
//分頁
List<User> getUserByLimit(Map<String,Integer> map);
2、mapper.xml配置
<!-- 分頁-->
<select id="getUserByLimit" parameterType="map" resultMap="UserMap">select * from mybatis.user limit #{startIndex},#{pageSize}
</select>
3、測試
@Test
public void getUserByLimit(){SqlSession sqlSession = MybatisUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);HashMap<String, Integer> map = new HashMap<>();map.put("startIndex",1);map.put("pageSize",2);List<User> userList = mapper.getUserByLimit(map);for (User user : userList) {System.out.println(user);}sqlSession.close();
RowBounds分頁
不建議使用
1、接口定義
//分頁2
List<User> getUserByRowBounds();
2、mapper.xml配置
<!--分頁2-->
<select id="getUserByRowBounds" resultMap="UserMap">select * from mybatis.user
</select>
3、測試
@Test
public void getUserByRowBounds(){SqlSession sqlSession = MybatisUtils.getSqlSession();//RowBounds實現RowBounds rowBounds = new RowBounds(1, 2);//通過java代碼層面實現分頁List<User> userList = sqlSession.selectList("com.qjd.dao.UserMapper.getUserByRowBounds",null,rowBounds);for (User user : userList) {System.out.println(user);}sqlSession.close();
}
分頁插件:PageHelper
官方地址:https://pagehelper.github.io/docs/howtouse/
注解開發實現
本質:基于反射和動態代理實現
實現
1、接口上寫入注解
package GSF.Example.Dao;import GSF.Example.Pojo.User;
import org.apache.ibatis.annotations.*;import java.util.List;
import java.util.Map;public interface UserMapper {@Select("select * from learn_mybatis.user")List<User> getUserList();//方法存在多個參數,所有的參數前面前面必須加上 @Param("") 注解@Select("select * from learn_mybatis.user where id=#{id}")User getUserByID(@Param("id") int id);@Insert("insert into learn_mybatis.user(id,name,pwd) values(#{id},#{name},#{pwd})")int addUser(User user);@Insert("insert into learn_mybatis.user(id,name,pwd) values(#{user_id},#{user_name},#{user_pwd})")int addUserByMap(Map<String, Object> map);@Update("update learn_mybatis.user set name=#{name},pwd=#{password} where id=#{id}")int updateUser(User user);@Delete("delete from learn_mybatis.user where id=#{uid}")int deleteUser(@Param("uid") int id);
}
2、mybatis-config.xml核心配置文件的配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><!--核心配置文件-->
<configuration>......<!-- 注冊--><mappers><mapper class="GSF.Example.Dao.UserMapper"/></mappers></configuration>
3、測試
package GSF.Example.Dao;import GSF.Example.Pojo.User;
import GSF.Example.Utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;import java.util.HashMap;
import java.util.List;public class UserTest {@Testpublic void GetUserList() {// 官方建議用try...catch包裹,可以不用SqlSession sqlsession = MybatisUtils.getSqlsession();try {UserMapper mapper = sqlsession.getMapper(UserMapper.class);List<User> userList = mapper.getUserList();for (User user : userList) {System.out.println(user);}} catch (Exception e) {e.printStackTrace();} finally {sqlsession.close();}}@Testpublic void GetUserById() {SqlSession sqlsession = MybatisUtils.getSqlsession();UserMapper mapper = sqlsession.getMapper(UserMapper.class);User user = mapper.getUserByID(2);System.out.println(user);sqlsession.close();}@Testpublic void AddUser() {SqlSession sqlsession = MybatisUtils.getSqlsession();UserMapper mapper = sqlsession.getMapper(UserMapper.class);// 插入成功,返回值為1int flag = mapper.addUser(new User(20, "GSF", "qwerty"));System.out.println(flag);sqlsession.commit();sqlsession.close();}@Testpublic void AddUserByMap() {SqlSession sqlsession = MybatisUtils.getSqlsession();UserMapper mapper = sqlsession.getMapper(UserMapper.class);// 插入成功,返回值為1HashMap<String, Object> map_obj = new HashMap<>();map_obj.put("user_id", 21);map_obj.put("user_name", "121212");map_obj.put("user_pwd", "zxcxvz");int flag = mapper.addUserByMap(map_obj);System.out.println(flag);sqlsession.commit();sqlsession.close();}@Testpublic void UpdateUser() {SqlSession sqlsession = MybatisUtils.getSqlsession();UserMapper mapper = sqlsession.getMapper(UserMapper.class);int flag = mapper.updateUser(new User(1, "123", "12345678"));System.out.println(flag);sqlsession.commit();sqlsession.close();}@Testpublic void DeleteUser() {SqlSession sqlsession = MybatisUtils.getSqlsession();UserMapper mapper = sqlsession.getMapper(UserMapper.class);int flag = mapper.deleteUser(1);System.out.println(flag);sqlsession.commit();sqlsession.close();}}
關于 @Param(“”) 注解
- 基本類型的參數或者String需要加上
- 如果只有一個基本類型的話,可以忽略,但是建議加上
- 引用類型的參數不需要加該注解,比如:User、Map…
- 在sql中引用的就是@Param(“”)注解中設定的屬性名
#{} 和 ${} 的區別
#{} | ${} |
---|---|
預編譯處理 | 是字符串替換 |
處理#{} 時,會將sql中的#{} 整體替換為占位符(即:?),調用PreparedStatement的set方法來賦值 | 在處理 $ { } 時,就是把 ${ } 替換成變量的值 |
可有效防止SQL注入 | 無法防止SQL注入 |
預編譯的機制:
- 預編譯是提前對SQL語句進行預編譯,而后再調用SQL,注入的參數就不會再進行SQL編譯
- 而SQL注入是發生在編譯的過程中,因為惡意注入了某些特殊字符,最后被編譯為SQL時輕而易舉的通過,從而導致數據泄露
- 預編譯機制則可以很好的防止SQL注入
Lombok
Lombok項目是一個Java庫,他是一個插件,它會自動插入編輯器和構建工具中,Lombok提供了一組有用的注釋,用來消除Java類中的大量樣板代碼。僅五個字符@Data就可以替換數百行代碼從而產生干凈,簡潔且易于維護的Java類
使用步驟
- 在IDEA中安裝Lombok插件
- 在項目中導入Lombok的jar包
- 在實體類上加入注解
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {private int id;private String name;private String password;
}
注解 | 含義 |
---|---|
@Data | 提供屬性的set、get方法、無參構造 |
@AllArgsConstructor | 提供類的全參構造 |
@NoArgsConstructor | 提供類的無參構造 |
第二個Mybatis程序:基礎,多對一處理
案例背景
描述
- 多個學生對應一個老師
- 對于學生而言:多個學生關聯一個老師【多對一】
- 對于老師而言:一個老師集合對應多個學生【一對多】
要求
- 查詢所有的學生,及其關聯的老師信息
數據庫創建
-- 新建老師表
CREATE TABLE `teacher` (`id` INT(10) NOT NULL,`name` VARCHAR(30) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8-- 插入老師數據
INSERT INTO teacher(`id`, `name`) VALUES (1, '秦老師');-- 新建學生表
CREATE TABLE `student` (`id` INT(10) NOT NULL,`name` VARCHAR(30) DEFAULT NULL,`tid` INT(10) DEFAULT NULL,PRIMARY KEY (`id`),KEY `fktid` (`tid`),CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8-- 插入學生數據
INSERT INTO `student` (`id`, `name`, `tid`) VALUES
('1', '小明', '1'),
('2', '小紅', '1'),
('3', '小張', '1'),
('4', '小李', '1'),
('5', '小王', '1')
編寫代碼
1、Pojo
- 老師類
import lombok.Data;@Data
public class Teacher {private int id;private String name;
}
- 學生類
import lombok.Data;@Data
public class Student {private int id;private String name;//學生需要關聯一個老師private Teacher teacher;
}
2、Utils
- 寫法參照《第一個Mybatis程序:數據的增刪改查查》
3、Dao:按照查詢嵌套處理
思路:子查詢
- 查詢所有的學生信息
- 根據查詢出來的學生的tid,尋找對應的老師
Mapper.xml
<select id="getTeacher" resultType="GSF.Example.Pojo.Teacher">select * from learn_mybatis.teacher where id=#{id}
</select><!--根據查詢嵌套處理-->
<select id="getStudent" resultMap="getStudent">select id, name, tid from learn_mybatis.student;
</select><resultMap id="getStudent" type="GSF.Example.Pojo.Student"><result property="id" column="id"/><result property="name" column="name"/><association property="teacher" column="tid" javaType="GSF.Example.Pojo.Teacher" select="getTeacher"/>
</resultMap>
test.java
@Test
public void GetStudent() {// 官方建議用try...catch包裹,可以不用SqlSession sqlsession = MybatisUtils.getSqlsession();UserDao mapper = sqlsession.getMapper(UserDao.class);List<Student> students = mapper.getStudent();for (Student student : students) {System.out.println(student);}sqlsession.close();
}
4、Dao:按照結果嵌套處理
思路:子查詢
- 查詢所有的學生信息、老師信息
- 將結果嵌套處理
Mapper.xml
<select id="getStudent2" resultMap="getStudent2">select s.id s_id ,s.name s_name, t.id t_id, t.name t_name from learn_mybatis.student s, learn_mybatis.teacher twhere s.tid=t.id
</select><resultMap id="getStudent2" type="GSF.Example.Pojo.Student"><result property="id" column="s_id"/><result property="name" column="s_name"/><association property="teacher" javaType="GSF.Example.Pojo.Teacher"><result property="id" column="t_id"/><result property="name" column="t_name"/></association>
</resultMap>
test.java
@Test
public void GetStudent() {// 官方建議用try...catch包裹,可以不用SqlSession sqlsession = MybatisUtils.getSqlsession();UserDao mapper = sqlsession.getMapper(UserDao.class);List<Student> students = mapper.getStudent();for (Student student : students) {System.out.println(student);}sqlsession.close();
}
5、結果
Student(id=1, name=小明, teacher=Teacher(id=1, name=秦老師))
Student(id=2, name=小紅, teacher=Teacher(id=1, name=秦老師))
Student(id=3, name=小張, teacher=Teacher(id=1, name=秦老師))
Student(id=4, name=小李, teacher=Teacher(id=1, name=秦老師))
Student(id=5, name=小王, teacher=Teacher(id=1, name=秦老師))
總結:association
- association標簽,處理關聯關系,即多對一
標簽屬性 含義 javaType 集合對象的類型
第二個Mybatis程序:進階,一對多處理
案例背景
描述
- 多個學生對應一個老師
- 對于學生而言:多個學生關聯一個老師【多對一】
- 對于老師而言:一個老師集合對應多個學生【一對多】
要求
- 查詢對應id的老師信息,及其包含的所有學生
數據庫創建
- 同上
編寫代碼
1、Pojo
- 老師類
package GSF.Example.Pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.util.List;@NoArgsConstructor
@AllArgsConstructor
@Data
public class Teacher {private int id;private String name;private List<Student> students;
}
- 學生類
package GSF.Example.Pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@NoArgsConstructor
@AllArgsConstructor
@Data
public class Student {private int id;private String name;private int tid;
}
2、Utils
- 寫法參照《第一個Mybatis程序:數據的增刪改查查》
3、Dao:按照查詢嵌套處理
思路:子查詢
- 查詢對應id的老師信息
- 根據查詢出來的老師的tid,尋找對應的學生
Mapper.xml
<select id="getTeacher2" resultMap="TeacherStudent2">select * from learn_mybatis.teacher where id=#{id}
</select>
<resultMap id="TeacherStudent2" type="GSF.Example.Pojo.Teacher"><!--兩個地方用到id,這個result就得寫出來,不然不展示老師的id--><result property="id" column="id"/><result property="name" column="name"/><collection property="students" column="id" javaType="ArrayList" ofType="GSF.Example.Pojo.Student" select="getStudentByTeacherId"/>
</resultMap><select id="getStudentByTeacherId" resultType="GSF.Example.Pojo.Student">select * from learn_mybatis.student where tid =#{id}
</select>
test.java
@Test
public void GetTeacherById2() {// 官方建議用try...catch包裹,可以不用SqlSession sqlsession = MybatisUtils.getSqlsession();UserDao mapper = sqlsession.getMapper(UserDao.class);Teacher teacher = mapper.getTeacher2(1);System.out.println(teacher);sqlsession.close();
}
4、Dao:按照結果嵌套處理
思路:子查詢
- 查詢對應id的所有老師、學生信息
- 將結果嵌套處理
Mapper.xml
<select id="getTeacher" resultMap="getTeacher">select s.id s_id, s.name s_name, t.name t_name, t.id t_idfrom learn_mybatis.student s, learn_mybatis.teacher twhere s.tid = t.id and t.id=#{id}
</select><resultMap id="getTeacher" type="GSF.Example.Pojo.Teacher"><result property="id" column="t_id"/><result property="name" column="t_name"/><collection property="students" javaType="ArrayList" ofType="GSF.Example.Pojo.Student"><result property="id" column="s_id"/><result property="name" column="s_name"/><result property="tid" column="t_id"/></collection>
</resultMap>
test.java
@Test
public void GetTeacherById() {// 官方建議用try...catch包裹,可以不用SqlSession sqlsession = MybatisUtils.getSqlsession();UserDao mapper = sqlsession.getMapper(UserDao.class);Teacher teacher = mapper.getTeacher(1);System.out.println(teacher);sqlsession.close();
}
5、結果
Teacher(id=1, name=秦老師, students=[Student(id=1, name=小明, tid=1), Student(id=2, name=小紅, tid=1), Student(id=3, name=小張, tid=1), Student(id=4, name=小李, tid=1), Student(id=5, name=小王, tid=1)])
總結:collection
-
collection標簽,處理集合關系,即一對多
標簽屬性 含義 javaType 集合對象的類型 ofType 集合對象的類型
動態SQL
什么是動態SQL?
簡單來說,就是根據不同的判斷條件和需要,來動態拼接SQL語句。
在Mybatis之前,動態SQL的描述需要耗費很大精力。借助強大的OGNL表達式,Mybatis3替換了之前的大部分元素,使得動態SQL的描述變得簡單很多。
環境搭建
- 數據庫環境
--
CREATE TABLE `blog`(
`id` VARCHAR(50) NOT NULL COMMENT '博客id',
`title` VARCHAR(100) NOT NULL COMMENT '博客標題',
`author` VARCHAR(30) NOT NULL COMMENT '博客作者',
`create_time` DATETIME NOT NULL COMMENT '創建時間',
`views` INT(30) NOT NULL COMMENT '瀏覽量'
)ENGINE=INNODB DEFAULT CHARSET=utf8INSERT INTO `blog`(`id`,`title`,`author`,`create_time`,`views`) VALUES
(1, "如何學Python", "青", "2022-10-11", 300),
(2, "如何學Java", "劉", "2022-10-12", 400),
(3, "如何學Django", "郭", "2022-10-13", 700)
-
java項目環境及相關配置:參考前文
-
Dao:實體類
@Data
public class Blog {private int id;private String title;private String author;private Date createTime;private int views;
}
動態SQL-IF
public interface UserDao {List<Blog> getBlogIf(Map<String, Object> map);
}
<select id="getBlogIf" parameterType="map" resultType="GSF.Example.Pojo.Blog">select * from learn_mybatis.blog where 1=1<if test="title != null">and title=#{title}</if><if test="author != null">and author=#{author}</if>
</select>
-- 若傳入空的map,真實的sql語句:
select * from learn_mybatis.blog where 1=1-- 若傳入的map帶有title鍵,真實的sql語句:
select * from learn_mybatis.blog where 1=1 and title=?-- 若傳入的map帶有title鍵和author鍵,真實的sql語句:
select * from learn_mybatis.blog where 1=1 and title=? and author=?
- IF標簽不具備自動添加and的功能,每個拼接的子SQL語句,需要自行添加and
@Test
public void GetBlogIf() {SqlSession sqlsession = MybatisUtils.getSqlsession();UserDao mapper = sqlsession.getMapper(UserDao.class);Map<String, Object> objectMap = new HashMap<>();//注釋掉,就返回默認檢索的所有情況objectMap.put("title", "如何學Django");objectMap.put("author", "劉");List<Blog> blogIf = mapper.getBlogIf(objectMap);for (Blog blog : blogIf) {System.out.println(blog);}sqlsession.close();
}
動態SQL-choose、when、otherwise
public interface UserDao {List<Blog> getBlogChoose_When_Otherwise(Map<String, Object> map);
}
<select id="getBlogChoose_When_Otherwise" parameterType="map" resultType="GSF.Example.Pojo.Blog">select * from learn_mybatis.blog<!-- 這里用到了下一個查詢才講述的where標簽 --><where><choose><when test="title != null">and title = #{title}</when><when test="author !=null">and author = #{author}</when><otherwise>and id = 1</otherwise></choose></where>
</select>
-- 若傳入空的map,真實的sql語句:
select * from learn_mybatis.blog where id=1-- 若傳入的map帶有title鍵,真實的sql語句:
select * from learn_mybatis.blog where title=?-- 若傳入的map帶有title鍵和author鍵,真實的sql語句:
select * from learn_mybatis.blog where title=?
- choose、when、otherwisel類似java的switch用法
- 從上到下的判斷語句,遇到滿足的就用,即使后續有條件也滿足,也不會調用
- where標簽具備自動添加where字符和刪除首個子SQL語句and字符的功能
@Test
public void GetBlogChoose_When_Otherwise() {SqlSession sqlsession = MybatisUtils.getSqlsession();UserDao mapper = sqlsession.getMapper(UserDao.class);Map<String, Object> objectMap = new HashMap<>();//注釋掉,就返回默認檢索的所有情況//objectMap.put("title", "如何學Django");//objectMap.put("author", "劉");List<Blog> blogIf = mapper.getBlogChoose_When_Otherwise(objectMap);for (Blog blog : blogIf) {System.out.println(blog);}sqlsession.close();
}
動態SQL-Set
public interface UserDao {int updateBlogSet(Map<String, Object> map);
}
<update id="updateBlogSet" parameterType="map">update learn_mybatis.blog<set><if test="title != null">title = #{title},</if><if test="author != null">author = #{author},</if></set>where id = #{id}
</update>
-- 若傳入空的map或僅僅有id的map,真實的sql語句:
報錯-- 若傳入的map帶有title鍵,真實的sql語句:
update learn_mybatis.blog SET title = ? where id = ?-- 若傳入的map帶有title鍵和author鍵,真實的sql語句:
update learn_mybatis.blog SET title = ?, author = ? where id = ?
- set標簽具備補充set字符和刪除sql語句末尾“,”字符的功能
- if標簽中sql子句末尾的“,”需要寫入,不然sql語句報錯
@Test
public void UpdateBlogSet() {SqlSession sqlsession = MybatisUtils.getSqlsession();UserDao mapper = sqlsession.getMapper(UserDao.class);Map<String, Object> objectMap = new HashMap<>();objectMap.put("id", 1);objectMap.put("title", "如何學Python-修改");objectMap.put("author", "劉");int blogIf = mapper.updateBlogSet(objectMap);System.out.println(blogIf);sqlsession.commit();sqlsession.close();
}
動態SQL-trim、sql片段
public interface UserDao {int updateBlogTrim(Map<String, Object> map);
}
<sql id="if-title-author"><if test="title != null">title = #{title},</if><if test="author != null">author = #{author},</if>
</sql><update id="updateBlogTrim" parameterType="map">update learn_mybatis.blog<trim prefix="SET" suffixOverrides=","><include refid="if-title-author"></include></trim>where id = #{id}
</update>
-- 若傳入空的map或僅僅有id的map,真實的sql語句:
報錯-- 若傳入的map帶有title鍵,真實的sql語句:
update learn_mybatis.blog SET title = ? where id = ?-- 若傳入的map帶有title鍵和author鍵,真實的sql語句:
update learn_mybatis.blog SET title = ?, author = ? where id = ?
- trim標簽可以自定義待拼接sql語句的相關前綴、后綴的補充操作及去除操作
- 上述用trim標簽,實現set標簽的相關功能
trim標簽屬性 | 描述 |
---|---|
prefix | 給sql語句拼接的前綴 |
suffix | 給sql語句拼接的后綴 |
prefixOverrides | 去除sql語句前面的關鍵字或者字符,該關鍵字或者字符由prefixOverrides屬性指定,假設該屬性指定為"AND",當sql語句的開頭為"AND",trim標簽將會去除該"AND" |
suffixOverrides | 去除sql語句后面的關鍵字或者字符,該關鍵字或者字符由suffixOverrides屬性指定,假設該屬性指定為",“,當sql語句的結尾為”,“,trim標簽將會去除該”," |
// 使用trim標簽和SQL片段
@Test
public void UpdateBlogTrim_SQLFragment() {SqlSession sqlsession = MybatisUtils.getSqlsession();UserDao mapper = sqlsession.getMapper(UserDao.class);Map<String, Object> objectMap = new HashMap<>();objectMap.put("id", 1);objectMap.put("title", "如何學Python-修改");objectMap.put("author", "青-修改-修改");int blogIf = mapper.updateBlogTrim(objectMap);System.out.println(blogIf);sqlsession.commit();sqlsession.close();
}
動態SQL-foreach
public interface UserDao {List<Blog> getBlogForeach(Map<String, Object> map);
}
<select id="getBlogForeach" parameterType="map" resultType="GSF.Example.Pojo.Blog">select * from learn_mybatis.blog<where><foreach collection="ids" item="id" open="and (" close=")" separator="or">id=#{id}</foreach></where>
</select>
-- 若傳入空的map,真實的sql語句:
select * from learn_mybatis.blog-- 若傳入的map中的list帶有值1,真實的sql語句:
select * from learn_mybatis.blog WHERE ( id=? )-- 若傳入的map中的list帶有值1、2、3,真實的sql語句:
select * from learn_mybatis.blog WHERE ( id=? or id=? or id=? )
- 提供遍歷操作
- 還是傳入的map,只是map的鍵對應的值是一個list
@Test
public void GetBlogForeach() {SqlSession sqlsession = MybatisUtils.getSqlsession();UserDao mapper = sqlsession.getMapper(UserDao.class);ArrayList<Integer> ids = new ArrayList<>();ids.add(1);ids.add(2);ids.add(3);ids.add(4);HashMap<String, Object> map = new HashMap<>();map.put("ids", ids);List<Blog> blogIf = mapper.getBlogForeach(map);for (Blog blog : blogIf) {System.out.println(blog);}sqlsession.close();
}
緩存
簡介
什么是緩存?
- 存在內存中的臨時數據
- 將用戶經常查詢的數據放在緩存(內存)中,用戶去查詢數據就不用了從磁盤上(關系型數據庫數據文件)查詢,從緩存中查詢,從而提高查詢效率,解決了高并發系統的性能問題
為什么使用緩存?
- 減少和數據庫的交互次數,較少系統開銷,提高系統效率
什么樣的數據能使用緩存?
- 經常查詢而且不經常改變的數據
Mybatis緩存
MyBatis包含一個非常強大的查詢緩存特性,它可以非常方便地定制和配置緩存。緩存可以極大的提升查詢效率。
MyBatis系統中默認定義了兩級緩存:一級緩存和二級緩存
- 默認情況下,只有一級緩存開啟 (SqlSession級別的緩存,也稱為本地緩存)
- 二級緩存需要手動開啟和配置,他是基于namespace級別的緩存
- 為了提高擴展性,MyBatis定義了緩存接口Cache。我們可以通過實現Cache接口來自定義二級緩存
一級緩存
也稱為本地緩存
與數據庫同一次會話期間查詢到的數據會放在本地緩存中,以后如果需要獲取相同的數據,直接從緩存中拿,沒必須再去查詢數據庫
測試驗證一級緩存
@Test
public void test(){SqlSession sqlSession = MybatisUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);User user = mapper.queryUserById(1);System.out.println(user);System.out.println("=================================================================");User user2 = mapper.queryUserById(1);System.out.println(user2);System.out.println(user==user2);sqlSession.close();
}
- 返回結果為true,且只執行了一次sql語句
一級緩存失效條件
- 查詢不同的東西
- 增刪改操作,可能會改變原來的數據,所以必定會刷新緩存!
- 查詢不同的Mapper.xml
- 手動清理緩存!
@Test
public void test(){SqlSession sqlSession = MybatisUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);User user = mapper.queryUserById(1);System.out.println(user);// 更新數據,導致緩存時效//mapper.updateUser(new User(2,"niahoooo","309487"));// 手動清理緩存,導致緩存時效//sqlSession.clearCache();System.out.println("=================================================================");User user2 = mapper.queryUserById(1);System.out.println(user2);System.out.println(user==user2);sqlSession.close();
}
一級緩存生命周期
生命周期為一個特定mapper.xml的一次sqlsession會話
二級緩存
二級緩存也叫全局緩存,一級緩存作用域太低了,所以誕生了二級緩存
基于namespace級別的緩存,一個名稱空間,對應一個二級緩存
工作機制:
- 一個會話查詢一條數據,這個數據就會被放在當前會話的一級緩存中:
- 如果當前會話關閉了,這個會話對應的一級緩存就沒了,一級緩存中的數據被保存到二級緩存中;
- 新的會話查詢信息,就可以從二級緩存中獲取內容
- 不同的mapper.xml查出的數據會放在自己對應的緩存(map)中
測試驗證二級緩存
- 在全局開啟二級緩存:mybatis-config.xml
<setting name="cacheEnable" value="true"/>
- 在要開啟緩存的mapper.xml中開啟
<cache eviction="FIFO"flushInterval="60000"size="512"readOnly="true"/>
- 測試
@Test
public void test(){SqlSession sqlSession = MybatisUtils.getSqlSession();SqlSession sqlSession2 = MybatisUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);User user = mapper.queryUserById(1);System.out.println(user);UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);User user2 = mapper.queryUserById(1);System.out.println(user2);System.out.println(user==user2);sqlSession.close();sqlSession2.close();
}
注意
- 我們需要將實體類序列化(實現Serializable接口),否則就會報錯
- sqlsession關閉的時候一定要在最后關閉,不能先關閉sqlsession再關閉sqlsession2,這樣會導致Cause: org.apache.ibatis.executor.ExecutorException: Executor was closed
二級緩存的生命周期
在同一個Mapper.xml下的多次Sqlsession
只有當sqlsession關閉的時候,數據才會從一級緩存扔到二級緩存
Mybatis調用順序
- 先看二級緩存中有沒有
- 再看一級緩存中有沒有
- 查詢數據庫
- 一二級緩存都沒有,查詢數據庫,查詢后將數據放入一級緩存
自定義緩存-ehcache
介紹
- EhCache 是一個純Java的進程內緩存框架,具有快速、精干等特點,是Hibernate中默認的CacheProvider
- Ehcache是一種廣泛使用的開源Java分布式緩存。主要面向通用緩存
具體使用,用到再說,開發中常用Redis數據庫來做緩存