mybatis
Mybatis
MyBatis是什么,有什么用
-
MyBatis 是一个 Java 持久层框架(用于操作数据库的工具),它简化了数据库的增删改查(CRUD)操作。你可以把它理解成一个帮你“翻译”和“跑腿”的助手:你写 SQL 语句,它帮你自动处理 Java 代码和数据库之间的繁琐对接。
-
持久化
就是把瞬时数据变为永久数据
存数据到数据库,io存到文件,都是持久化
-
MyBatis 就像一个“SQL 执行管家”,帮你把 Java 对象和数据库之间的操作变得简单、清晰,适合需要灵活控制 SQL 的中小型项目。
-
导入方法
- maven 依赖导入
- github 下载jar包
-
前提
- JDBC
- Mysql
- java基础
- maven
- junit(测试用)
第一个Mybatis
-
共七步,从左往右
-
配置maven依赖,建立子maven模块
<dependencies> <!--mysql驱动--> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!--mybatis--> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.19</version> </dependency> <!--junit--> <!-- https://mvnrepository.com/artifact/junit/junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> </dependency> </dependencies><!--解决资源导出问题--> <build> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </build> -
写工具类获取SqlSessionFactory,返回SqlSession
package com.zhm.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; // 此工具类为了获取SqlSession public class MybatisUtils { static SqlSessionFactory sqlSessionFactory = null; static { try { // mybatis配置,配置jdbc连接信息 String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); // SqlSessionFactoryBuilder获取SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { throw new RuntimeException(e); } } public static SqlSession getSqlSession(){ SqlSession sqlSession = sqlSessionFactory.openSession(true); return sqlSession; } } -
写mybatis配置,SqlSessionFactory的配置(连接mysql数据库)
<?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="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <!--每一个mapper.xml都要注册mapper--> <mappers> <mapper resource="com/zhm/dao/UserMapper.xml"></mapper> </mappers> </configuration> -
写实体类
package com.zhm.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; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", pwd='" + pwd + '\'' + '}'; } } -
写UserMapper接口
package com.zhm.dao; import com.zhm.pojo.User; import java.util.List; public interface UserDao { List<User> getUserList(); } -
写实现类,用xml文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!--绑定接口名--> <mapper namespace="com.zhm.dao.UserDao"> <!--方法名,返回值--> <select id="getUserList" resultType="com.zhm.pojo.User"> select * from mybatis.user; </select> </mapper> -
测试(新建完全相同文件夹测试,@test),最后记得关闭sqlsession,释放资源
package com.zhm.dao; import com.zhm.pojo.User; import com.zhm.utils.MybatisUtils; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; public class UserDaoTest { @Test public void test(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserDao mapper = sqlSession.getMapper(UserDao.class); List<User> userList = mapper.getUserList(); for (User user : userList) { System.out.println(user); } sqlSession.close(); } }
-
CRUD
-
我们经常会听到CRUD,但是自己不知道,增删改查
c create 创建
r read 阅读
u update 更改
d delete 删除 -
配置好环境后,实现增删改查只用3步
- 增加UserDao(mapper)接口方法,要什么加什么
- 在usermapper.xml绑定接口,绑定方法,绑定方法返回类型,参数,编写sql代码
- 测试类测试,获取UserDao对象,直接调用方法,传入参数,获取返回
-
注意点:
namespace 绑定接口位置
id 方法名
resultType 返回值类型
parameterType 参数类型
#{id}为占位符,跟接口方法里面参数一样
增删改记得commit提交事务,不如数据库数据不会更新
-
<?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 namespace="com.zhm.dao.UserDao"> <!--id方法名,resultType返回值类型--> <select id="getUserList" resultType="com.zhm.pojo.User"> select * from mybatis.user; </select> <!--parameterType参数类型,#{id}为占位符,跟接口方法里面参数一样--> <select id="getUserById" resultType="com.zhm.pojo.User" parameterType="int"> select * from mybatis.user where id = #{id}; </select> <insert id="addUser" parameterType="com.zhm.pojo.User"> insert into mybatis.user(id, name, pwd) values (#{id},#{name},#{pwd}); </insert> <update id="updateUser" parameterType="com.zhm.pojo.User"> update mybatis.user set name = #{name},pwd = #{pwd} where id = #{id}; </update> <delete id="deleteUser" parameterType="int"> delete from mybatis.user where id=#{id}; </delete> </mapper> -
不变的测试代码
@Test public void deleteUser(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); // 此处选择调用方法,commit看情况 // sqlSession.commit(); sqlSession.close(); }
出现错误,java报错,从下面往上面看
万能Map
-
在实体类数据库属性过多可以使用map
类似修改情况,假如属性过多,但修改只修改某个属性,就可以用这个方法
-
首先在usermapper参数改为map
-
在mybatismapper.xml里编写sql,修改参数列表parameterType=map,
sql语句的#{随意填写k},调用时存入随意填写k与v就行
-
-
int updateUser2(Map<String,Object> map);<update id="updateUser2" parameterType="map"> update mybatis.user set pwd = #{newpwd} where id = #{getid}; </update>public void updateUser2(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); // 万能map键值对,实现类里面写k,调用时,写k和对应v Map<String, Object> map = new HashMap<String, Object>(); map.put("newpwd","135792"); map.put("getid",6); int i = mapper.updateUser2(map); if (i>0){ System.out.println("修改成功"); } sqlSession.commit(); sqlSession.close(); } -
模糊查询,安全写法
<select id="getUserById" resultType="com.zhm.pojo.User" parameterType="String"> select * from mybatis.user where name like #{String}; </select>@Test public void getUserByName(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.getUserByName("%李%"); System.out.println(user); sqlSession.close(); }
优化配置文件mybatis-config
XML(可扩展标记语言)文件是一种用于存储和传输数据的文本文件
配置顺序,必须按着顺序来,标的是重要的
// 属性
properties
// 设置
settings
// 别名
typeAliases
typeHandlers
objectFactory
objectWrapperFactory
reflectorFactory
plugins
// 环境
environments
databaseIdProvider
// mapper注册
mappers
属性优化
<!--属性标签,可以从外面导入外部配置文件-->
<properties resource="db.properties">
<!--可以自己配置属性-->
<property name="pwd" value="123456"/>
</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="${pwd}"/>
</dataSource>
</environment>
</environments>
别名优化
<typeAliases>
<!--第一种,自定义别名-->
<typeAlias type="com.zhm.pojo.User" alias="User"></typeAlias>
<!--第二种,传包定义系统帮你首字母小写定义别名,自定义可以用注解-->
<package name="com.zhm.pojo"/>
</typeAliases>
// 第二种的注解
@Alias("hello")
public class User {}
- 一般实体类少用第一种,多就第二种
设置优化
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。 下表描述了设置中各项设置的含义、默认值等。
配置_MyBatis中文网直接看链接
映射器Mappers优化(重要)
-
每一个mapper.xml文件,都需要在mybatis-config中映射注册,否则报错
Type interface com.zhm.dao.UserMapper is not known to the MapperRegistry.
-
三种
- 映射xml资源
- 映射xml资源对应的类(类和xml资源要同名同包)
- 映射xml资源的包(类和xml资源要同名同包)
-
<mappers> <!-- <!–第一种,直接映射Mapeer.xml资源地址–>--> <mapper resource="com/zhm/dao/UserMapper.xml"/> <!--第二种,映射Mapeer.xml对应的类,要求xml和对应类同名同包--> <!-- <mapper class="com.zhm.dao.UserMapper"/>--> <!--第三种,映射Mapeer.xml所在包,要求xml和对应类同名同包--> <!-- <package name="com.zhm.dao"/>--> </mappers>
补充,sqlsessionfactory相对于连接池
解决属性名和字段名不一致
-
数据库列字段和实体类属性不一致
-
类似数据库pwd,实体类password
-
用resultmap映射解决
<!--column代表数据库列名,property代表实体类属性--> <resultMap id="gUL" type="User"> <result column="pwd" property="password"/> </resultMap> <!--gUL代表resultMap的id--> <select id="getUserList" resultMap="gUL"> select * from mybatis.user; </select>
日志工厂
- mybatis-config.xml里配置
- 设置加上logImpl属性
STDOUT_LOGGING
-
标准日志输出
-
<!--设置--> <settings> <!--日志工厂,注意键值的空格和大小写,要跟官网一致--> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings>日志输出 F:\Environment\java\jdk1.8\bin\java.exe -ea -Didea.test.cyclic.buffer.size=1048576 "... Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter. PooledDataSource forcefully closed/removed all connections. PooledDataSource forcefully closed/removed all connections. PooledDataSource forcefully closed/removed all connections. PooledDataSource forcefully closed/removed all connections. Opening JDBC Connection Created connection 1891546521. Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@70beb599] ==> Preparing: select * from mybatis.user; ==> Parameters: <== Columns: id, name, pwd <== Row: 1, xiaohong, 123456 <== Row: 2, xiaolan, 12345 <== Row: 3, xiaohuang, 1234 <== Row: 6, xax, 135792 <== Total: 4 User{id=1, name='xiaohong', password='123456'} User{id=2, name='xiaolan', password='12345'} User{id=3, name='xiaohuang', password='1234'} User{id=6, name='xax', password='135792'} Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@70beb599] Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@70beb599] Returned connection 1891546521 to pool. 进程已结束,退出代码0
LOG4J
-
可以输出到文件,可以自定义格式,方便,一般用这个
用法
-
先导依赖到pom.xml,mybatis-config.xml的setting设置配置
<!--设置--> <settings> <!--日志工厂,注意键值的空格和大小写,要跟官网一致--> <setting name="logImpl" value="LOG4J"/> </settings> -
配置log4j的配置文件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.Threshold=DEBUG log4j.appender.console.layout = org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern=[%c]-%m%n #文件输出的相关设置 log4j.appender.file = org.apache.log4j.RollingFileAppender log4j.appender.file.File=./log/kuang.log log4j.appender.file.MaxFileSize=10mb log4j.appender.file.Threshold=DEBUG log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n #日志输出级别 log4j.logger.org.mybatis=DEBUG log4j.logger.java.sql=DEBUG log4j.logger.java.sql.Statement=DEBUG log4j.logger.java.sql.ResultSet=DEBUG log4j.logger.java.sql.PreparedStatement=DEBUG -
使用,导包名
import org.apache.log4j.Logger;
import org.apache.log4j.Priority;package com.zhm.dao; import com.zhm.pojo.User; import com.zhm.utils.MybatisUtils; import org.apache.ibatis.session.SqlSession; import org.apache.log4j.Logger; import org.apache.log4j.Priority; import org.junit.Test; import java.util.HashMap; import java.util.List; import java.util.Map; public class UserDaoTest { public static Logger logger = Logger.getLogger(UserDaoTest.class); @Test public void test(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); // 打印sqlSession logger.info(sqlSession); UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> userList = mapper.getUserList(); for (User user : userList) { System.out.println(user); } sqlSession.close(); } @Test public void testLog4j(){ // 可以放在程序中用于打印测试 logger.info("进入info"); logger.debug("进入debug"); logger.error("进入error"); } }
-
注解开发
-
一般简单的用注解,mapper.xml配置更全能,注解更简单
-
注解不能用resultmap解决属性名和字段名不一致
-
本质就是通过注解获取类的信息,获取到方法信息(参数,返回,注解),通过注解自动实现
-
过程
-
在接口里面写新方法,加上@注解,编写sql,注意sql不能错
@Select("select * from user;") List<User> getUserList2(); -
mybatis-config.xml(mybatis配置文件)配置注册mapper,用class=的方式
<mappers> <!--注解开发也要注册mapper,用class来注册--> <mapper class="com.zhm.dao.UserMapper"/> </mappers> -
测试
@Test public void getUserList2(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> userList2 = mapper.getUserList2(); for (User user : userList2) { System.out.println(user); } sqlSession.close(); }
-
-
自动提交
修改mybatis.utils工具类
本质是重载方法里面,不写autocommit默认false
public static SqlSession getSqlSession(){ // 设置自动提交为true,增删改就不用手动commit SqlSession sqlSession = sqlSessionFactory.openSession(true); return sqlSession; } -
增删改查
// @Param 多个参数,基本类型或者String,要使用@param注解 // 否则会MyBatis 会将参数封装成map对象 // {param1=id, param2=name} @Select("select * from user where id = #{uid} and name = #{uname};") User getUserByIdAndName(@Param("uid") int id, @Param("uname") String name); @Insert("insert into user(id,name,pwd) values (#{id},#{name},#{password})") int addUser(User user); // password sql引用要用实体类定义的变量名 @Update("update user set name=#{name},pwd=#{password} where id=#{id}") int updateUser(User user); // @param注解 sql里引用要用注解里定义的 @Delete("delete from user where id=#{uid}") int deleteUser(@Param("uid") int id); -
关于@Param
尽量多用
- 基本参数和string要加上
- 引用类型不需要
- 只有单个参数不需要,但是尽量多用
- sql里面的引用#{x},传入要写设定的@Param("x")
Lombok
-
简化代码,主要简化实体类的构造器,getset,tostring等等
-
package com.zhm.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.apache.ibatis.type.Alias; /* @Data 无参,getset,tostring,hash等等 @AllArgsConstructor 全参构造器 @NoArgsConstructor 无参构造器 其他的见名知意 */ @Data @AllArgsConstructor @NoArgsConstructor public class User { private int id; private String name; private String password; }
重新配置复杂情况环境
步骤
- pom.xml导入lombok依赖
- 复制配置mybatis-config.xml文件,db.properties,log4j.properties配置文件
- 复制utils工具类
- 新建java pojo文件夹实体类student teacher,@Data注解
- 新建dao层,写studentmapper接口 teachermapper接口
- resources新建对应studentmapper.xml和teachermapper.xml配置,要和dao层对应
- 在dao层编写注解测试
- 测试环境
一对多和多对一复杂情况
- 多个学生对一个老师 associate
- 一个老师对多个学生 collection
- 本质是多表查询
- 连表查询
- 子查询
多对一
- student实体类有list
teacher - association处理复杂属性teacher
<mapper namespace="com.zhm.dao.StudentMapper">
<!--连表查询-->
<select id="getStudent" resultMap="StudentTeacher">
select s.id sid,s.name sname,t.name tname,t.id tid
from student s,teacher t
where s.tid=t.id;
</select>
<resultMap id="StudentTeacher" type="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<!--复杂属性单独处理 -->
<association property="teacher" javaType="Teacher">
<result property="name" column="tname"/>
<result property="id" column="tid"/>
</association>
</resultMap>
<!--子查询-->
<select id="getStudent2" resultMap="StudentTeacher2">
select * from student;
</select>
<resultMap id="StudentTeacher2" type="Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<!--复杂属性单独处理 -->
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="teacher">
select * from teacher where id=#{tid};
</select>
</mapper>
一对多
- teachrt实体类有list
students - collection 处理复杂属性student
- ofType 跟集合有关,设置为集合内的泛型类型,javatype是arraylist
<mapper namespace="com.zhm.dao.TeacherMapper">
<select id="getTeacherById" parameterType="int" resultMap="getTeacher">
select t.id tid,t.name tname,s.id sid,s.name sname
from student s,teacher t
where s.tid=t.id and t.id=#{tid};
</select>
<resultMap id="getTeacher" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<collection property="students" ofType="Student">
<result property="name" column="sname"/>
<result property="id" column="sid"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
<!-------------------------------------------------------------------------------->
<select id="getTeacherById2" parameterType="int" resultMap="getTeacher2">
select * from teacher where id=#{tid};
</select>
<resultMap id="getTeacher2" type="Teacher">
<!--一样的可以省略,mybatis会能帮你匹配-->
<!-- <result property="id" column="id"/>-->
<!-- <result property="name" column="name"/>-->
<!--column="id"传给下面查询语句老师的id-->
<collection property="students" column="id" javaType="ArrayList" ofType="Student" select="TeacherStudent"/>
</resultMap>
<select id="TeacherStudent" resultType="student">
select * from student where tid=#{id};
</select>
</mapper>
总结
动态sql
环境搭建
- 导依赖
- 配置资源文件
- sqlsession工具类
- 工具数据库创pojo实体类Blog
- BlogMapper接口和BlogMapper.xml实现类,记得在mybatis-config.xml注册
- 注意点 驼峰命名自动映射,在 mybatis-config.xml里面配置
<!--mapUnderscoreToCamelCase是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
if
- 如果test为true,则执行后面
<select id="queryBlogIf" parameterType="map" resultType="blog">
select * from mybatis.blog where 1=1
<if test="title!=null">and title=#{title}</if>
<if test="author!=null">and author=#{author}</if>
</select>
choose(when,otherwise)
- 跟switch一样,otherwise就是default
<!--跟java switch一样,从上到下when的条件满足就执行条件后sql,然后结束,都不满足就执行最后otherwise的sql-->
<!--where标签可以帮你忽略首句and,如果where内没有满足的,就会忽略where-->
<select id="queryBlogChoose" parameterType="map" resultType="blog">
select * from mybatis.blog
<where>
<choose>
<when test="title!=null">
title=#{title}
</when>
<when test="author!=null">
and author=#{author}
</when>
<otherwise>
and views=#{views}
</otherwise>
</choose>
</where>
</select>
trim(where,set)
- 本质就是帮助写sql,帮你忽略and和,的工具
<!--where标签可以帮你忽略首句and,如果where内没有满足的,就会忽略where-->
<select id="queryBlogChoose" parameterType="map" resultType="blog">
select * from mybatis.blog
<where>
<choose>
<when test="title!=null">
title=#{title}
</when>
<when test="author!=null">
and author=#{author}
</when>
<otherwise>
and views=#{views}
</otherwise>
</choose>
</where>
</select>
<!--set会帮你忽略最后一个逗号-->
<update id="updateBlogSet" parameterType="map">
update mybatis.blog
<set>
<if test="title!=null">
title=#{title},
</if>
<if test="author!=null">
author=#{author}
</if>
</set>
<where>
<if test="views!=null">
views=#{views}
</if>
</where>
</update>
sql片段和foreach
-
sql片段就是复用sql代码,打包重复的sql,写id,调用时用include标签
-
foreach执行迭代遍历集合
<!--select * from blog where (views=1000 or views=2000 or views=3000)--> <!--迭代,传入list集合,collection对应k,item为sql#{}内引用--> <!--当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。 当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。--> <select id="queryBlogForeach" parameterType="map" resultType="blog"> select * from mybatis.blog <where> <include refid="myForeach"></include> </where> </select> <sql id="myForeach"> <foreach collection="viewss" item="views" open="(" separator="or" close=")"> views=#{views} </foreach> </sql>
总结
- 动态sql就算在sql里面进行逻辑运算,用的最多的是if
- 动态sql编写,先写静态sql,再根据静态来编写动态
缓存
- 减少并发,每次查询一样数据都要重新执行sql很消耗资源
- 一般缓存作用于多读少改的数据,存入缓存(内存),相反,多改少读的数据存磁盘
一级缓存
-
作用域在sqlsession存活时间内
-
一级缓存,一般只在读同一数据才生效
-
几种一级缓存无效情况
-
清除一级缓存
sqlSession.clearCache(); -
执行增删改
后可能影响数据,缓存数据可能改变,所以要重新查询
mapper.updateUser(new User(2,"xiaoer","axxaa"));
-
-
一级缓存就是Map
-
package com.zhm.dao; import com.zhm.pojo.User; import com.zhm.utils.MybatisUtils; import org.apache.ibatis.session.SqlSession; import org.junit.Test; public class UserMapperTest { @Test public void test(){ // 一级缓存只在sqlSession开启关闭内,且查询同一数据有效, // 查询同一记录执行一次查询 SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.queryUser(1); System.out.println(user); System.out.println("==============================="); // 清除一级缓存,重新执行sql // sqlSession.clearCache(); // 执行增删改后可能影响数据,缓存数据可能改变,所以要重新查询 // mapper.updateUser(new User(2,"xiaoer","axxaa")); User user2 = mapper.queryUser(2); System.out.println(user2); User user3 = mapper.queryUser(1); System.out.println(user3); sqlSession.close(); } }
二级缓存
-
作用于整个mapper
-
mybatis-config.xml setting 开启全局缓存(默认就是开启)
-
mapper配置
<cache/> <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/> -
测试
@Test public void test2(){ // 二级缓存,整个mapper都有效果UserMapper.class // 开启二级缓存后,当会话提交或者关闭,一级缓存会继承给二级缓存 SqlSession sqlSession1 = MybatisUtils.getSqlSession(); UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class); User user1 = mapper1.queryUser(1); System.out.println(user1); sqlSession1.close(); System.out.println("------------------------------------------------------"); SqlSession sqlSession2 = MybatisUtils.getSqlSession(); UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class); User user2 = mapper2.queryUser(1); System.out.println(user2); sqlSession2.close(); }
-
-
注意点
readOnly 默认为false,实体类记得实现Serializable接口,序列化
- 序列化就是把对象转换成一种通用的格式,方便存储、传输和共享。
- MyBatis 二级缓存需要序列化实体类,因为缓存数据可能被多个会话共享,或者存储到不同的地方(如硬盘、远程缓存)。
- 如果实体类不序列化,MyBatis 就无法正确存储和读取缓存数据。
缓存查询顺序
- 用户从上面进来,先看二级,再一级,都没有再执行连接数据库查询sql
浙公网安备 33010602011771号