3-Mybatis

文章目錄

  • 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、目錄結構

后續按代碼編寫順序,貼出相關代碼

image-20231123184114305

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&amp;useUnicode=true&amp;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程序:完善

優化后的整體目錄結構

image-20231208111915039

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&amp;useUnicode=true&amp;characterEncoding=UTF-8

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&amp;useUnicode=true&amp;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配置文件在同一個文件夾下

image-20231123192121045

方式3:將包注冊進核心配置文件(mybatis-config.xml)

<mappers><package name="GSF.Example.Dao"/>
</mappers>
  • 需要保證的內容跟方法2一樣

第一個Mybatis程序:進階

resultMap

解決pojo實體類中對應屬性名和數據庫中對應字段名不一致的問題

問題描述

當數據庫的字段和實體類的字段不一致的時候,進行訪問,會出現不一致的字段為空

數據庫字段

image-20231123192619522

實體類字段

image-20231123192645402

獲取id=1的數據庫數據

image-20231123192659620

解決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種實現日志的方式:

image-20231123194424229

  • 掌握: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>

設置了日志后的控制臺輸出:

image-20231123194722180

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調用順序

  1. 先看二級緩存中有沒有
  2. 再看一級緩存中有沒有
  3. 查詢數據庫

image-20231129103125446

  • 一二級緩存都沒有,查詢數據庫,查詢后將數據放入一級緩存

自定義緩存-ehcache

介紹

  • EhCache 是一個純Java的進程內緩存框架,具有快速、精干等特點,是Hibernate中默認的CacheProvider
  • Ehcache是一種廣泛使用的開源Java分布式緩存。主要面向通用緩存

具體使用,用到再說,開發中常用Redis數據庫來做緩存

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/206777.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/206777.shtml
英文地址,請注明出處:http://en.pswp.cn/news/206777.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

ALNS的MDP模型| 還沒整理完12-08

有好幾篇論文已經這樣做了&#xff0c;先擺出一篇&#xff0c;然后再慢慢更新 第一篇 該篇論文提出了一種稱為深增強ALNS&#xff08;DR-ALNS&#xff09;的方法&#xff0c;它利用DRL選擇最有效的破壞和修復運營商&#xff0c;配置破壞嚴重性參數施加在破壞算子上&#xff0c…

請簡要介紹一下HTML的發展史?

問題&#xff1a;什么是池化思想&#xff1f; 回答&#xff1a; 池化思想是一種資源管理的策略&#xff0c;通過事先創建并維護一組已經初始化好的資源對象池&#xff0c;以便在需要時快速獲取資源并在用完后歸還給池&#xff0c;以減少資源的創建和銷毀開銷&#xff0c;提高資…

第二十一章網絡通信總結

21.1 網絡程序設計基礎 Java網絡程序設計基礎涉及使用Java編程語言創建網絡應用程序。這通常涉及到使用Java的網絡API&#xff0c;如java.net包&#xff0c;以建立客戶端和服務器之間的通信。 基本步驟包括&#xff1a; 1.創建服務器&#xff1a; 使用ServerSocket類創建服務…

常見的中間件--消息隊列中間件測試點

最近刷題&#xff0c;看到了有問中間件的題目&#xff0c;于是整理了一些中間件的知識&#xff0c;大多是在小破站上的筆記&#xff0c;僅供大家參考~ 主要分為七個部分來分享&#xff1a; 一、常見的中間件 二、什么是隊列&#xff1f; 三、常見消息隊列MQ的比較 四、隊列…

用戶管理 --匯總

一、第一節課 1.1 本人寫的 前端&#xff1a; 魚皮 --&#xff1e; 用戶中心 第1節課-CSDN博客 中期&#xff1a; 一、用戶管理 第1節課中間-CSDN博客 后端&#xff1a; 一、用戶管理-CSDN博客 其他的鏈接 億圖腦圖MindMaster 1.2 優秀球友&#xff0c;推薦 Docs 另…

12_企業架構之Tomcat部署使用

Tomcat 學習目標和內容 1、能夠描述Tomcat的使用場景 2、能夠簡單描述Tomcat的工作原理 3、能夠實現部署安裝Tomcat 4、能夠實現配置Tomcat的service服務和自啟動 5、能夠實現Tomcat的Host的配置 6、能夠實現Nginx反向代理Tomcat 7、能夠實現Nginx負載均衡到Tomcat 一、Tomcat介…

Abaqus許可證配置文件問題

在使用Abaqus工程設計和仿真軟件時&#xff0c;您可能會遇到許可證配置文件問題。這些問題可能會影響軟件的正常運行和工作效率。為了幫助您解決這些問題&#xff0c;我們特別撰寫了這篇文章&#xff0c;以提供全面、有效的解決方案。 一、Abaqus許可證配置文件問題及原因 許…

力扣labuladong一刷day32天二叉樹

力扣labuladong一刷day32天二叉樹 一、297. 二叉樹的序列化與反序列化 題目鏈接&#xff1a;https://leetcode.cn/problems/serialize-and-deserialize-binary-tree/ 思路&#xff1a;關于序列化與反序列化&#xff0c;題目不要求序列化的方式&#xff0c;只要求樹經過序列化…

linux的定時任務Corntab

安裝crontab # yum安裝crontab yum install -y crontab# 開機自啟crond服務并現在啟動 systemctl enable --now crondcron系統任務調度 系統任務調度&#xff1a; 系統周期性所要執行的工作&#xff0c;比如寫緩存數據到硬盤、日志清理等。 在/etc/crontab文件&#xff0c;這…

機器學習之全面了解回歸學習器

我們將和大家一起探討機器學習與數據科學的主題。 本文主要討論大家針對回歸學習器提出的問題。我將概要介紹&#xff0c;然后探討以下五個問題&#xff1a; 1. 能否將回歸學習器用于時序數據&#xff1f; 2. 該如何縮短訓練時間&#xff1f; 3. 該如何解釋不同模型的結果和…

No suitable driver found for jdbc:mysql://localhost:3306(2023/12/7更新)

有兩種情況&#xff1a; 壓根沒安裝下載了但沒設為庫或方法不對 大多數為第一種情況&#xff1a; 一. 下載jdbc 打開網址選擇一個版本進行下載 https://nowjava.com/jar/version/mysql/mysql-connector-java.html 二.安裝jdbc 在項目里建一個lib文件夾 在把之前下載的jar文…

優化 SQL 日志記錄的方法

為什么 SQL 日志記錄是必不可少的 SQL 日志記錄在數據庫安全和審計中起著至關重要的作用&#xff0c;它涉及跟蹤在數據庫上執行的所有 SQL 語句&#xff0c;從而實現審計、故障排除和取證分析。SQL 日志記錄可以提供有關數據庫如何訪問和使用的寶貴見解&#xff0c;使其成為確…

JNPF低代碼平臺詳解 -- 系統架構

目錄 一、技術介紹 技術架構 二、設計原理 三、界面展示 1.代碼生成器 2.工作流程 3.門戶設計 4.大屏設計 5.報表設計 6.第三方登錄 7.多租戶實現 8.分布式調度 9.消息中心 四、功能框架 JNPF低代碼是一款新奇、實用、高效的企業級軟件開發工具&#xff0c;支持企…

Qt/C++音視頻開發58-逐幀播放/上一幀下一幀/切換播放進度/實時解碼

一、前言 逐幀播放是近期增加的功能&#xff0c;之前也一直思考過這個功能該如何實現&#xff0c;對于mdk/qtav等內核組件&#xff0c;可以直接用該組件提供的接口實現即可&#xff0c;而對于ffmpeg&#xff0c;需要自己處理&#xff0c;如果有緩存的數據的話&#xff0c;可以…

Rust的eBFP框架Aya(一) - Linux內核網絡基礎

前言 在我的Rust入門及實戰系列文章中已經說明&#xff0c; Rust是一門內存安全的高性能編程語言&#xff0c;從它的這些優秀特性來看&#xff0c;就是一門專為系統開發而誕生的語言。至于很多使用Rust來進行web開發的行為&#xff0c;不能說它們不好&#xff0c;只能說是殺雞…

2017下半年軟工(橋接模式)

題目——橋接模式&#xff08;抽象調用實現部分&#xff09; package org.example.橋接模式;/*** 橋接模式的核心思想是將抽象部分與它的實現部分分離&#xff0c;使它們可以獨立變化&#xff0c;就是說你在實現部分&#xff1a;WinImp、LinuxImp基礎上還能加上RedHatImp&#…

03-微服務架構構建之微服務拆分

文章目錄 前言一、微服務拆分的原則二、微服務拆分的時機三、微服務拆分的方法總結 前言 微服務架構是將一個單體應用程序拆分為一個個獨立且保持松耦合的服務的一種架構方式&#xff0c;每個服務有著獨立的數據庫并且能獨立運行部署。微服務架構的構建過程中&#xff0c;第一…

偷竊別人的密碼

在工作中都用到virtual machine吧&#xff0c;同事之間還互相借用機器&#xff0c;或者不借用但憑借自己的域賬號能登錄任意機器&#xff0c;而且每個域賬號都有sudo權限&#xff1f; 那你要小心了&#xff01; 因為我可以輕易記錄下每個ssh登錄到我機器&#xff0c;或者我在…

uniapp 輸入框輸入時,會將內容頂上去的解決方案

// 設置頁面最小高度 export const setPageMinHeight () > {return {position: relative,min-height: uni.getSystemInfoSync().windowHeight px} }頁面使用&#xff1a; import {setPageMinHeight} from "/utils/uniUtil";data() {return {minHeight: setPag…

Unity 狀態系統

狀態系統 原理食用方法Demo 原理 #mermaid-svg-lUbxJ8eMP3KqrEhY {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-lUbxJ8eMP3KqrEhY .error-icon{fill:#552222;}#mermaid-svg-lUbxJ8eMP3KqrEhY .error-text{fill:#55…