一、mybatis基础知识和使用
1.什么是mybatis框架
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射实体类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
持久层:与数据库交互的一层。-- 用于操作数据表记录的
框架:别人写好的一个半成品。-- 我们需要加入自己的配置以及代码
ORM框架:Object Relative Mapping(对象关系映射)。表--实体类——一条记录实体类的对象。
表的字段--java实体类的属性
2.为什么使用Mybatis
3.如何使用mybatis(步骤)
3.1创建maven的java工程
3.2引入依赖--pom.xml
第一种方式:下载在本地的依赖资源(老师给的maven架包)
第二种方式:mvnrepository.com在线网站搜索选择依赖资源
<dependencies>
<!--数据库-->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<!--unit单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!-- lombok小辣椒插件:实体类中get、set和toString方法,有/无参构造方法-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
<!--引入log4j的jar-------必须引入log4j.properties日志属性文件:打印sql语句-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!--pageHelper:分页查询的依赖-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>6.1.0</version>
</dependency>
</dependencies>
3.3log4j.properties日志属性文件:打印sql语句
log4j.rootLogger=DEBUG, Console
#Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
log4j.logger.java.sql.ResultSet=INFO
log4j.logger.org.apache=INFO
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
3.4引入数据源文件--db.properties
企业开发中,习惯把数据源的信息放入属性文件中。在mybatis配置文件中引入该属性文件
#数据源信息
jdbc.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=root
jdbc.driverClassName=com.mysql.cj.jdbc.Driver
3.5编写配置文件Mybatis.xml--配置数据源信息
内容无需背--知道意思
<?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>
<!-- 引入数据源属性文件-->
<properties resource="db.properties"/>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<!--name是固定的 value改为数据源中设置的内容-->
<property name="driver" value="${jdbc.driverClass}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<!--引入对应的映射文件注意:改为自己的映射文件-->
<mappers>
<mapper resource="mapper/RoleMybatis.xml"/>
</mappers>
</configuration>
3.5.1为实体类起别名
之前我们在映射文件中resultType中返回的实体类类型,全部都是全路径
3.6创建一个实体类
package com.wjy.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @program: mybatis03
* @description:
* @author: 王佳瑶
* @create: 2024-05-20 17:27
**/
@Data//get、set、toString
// 有/无参构造方法
@NoArgsConstructor
@AllArgsConstructor
public class Role {
private Integer id;
private String name;
private String code;
private String description;
}
3.7创建一个接口
package com.wjy.dao;
import com.wjy.entity.Role;
import org.apache.ibatis.annotations.Param;
import java.util.List;
//定义实现功能和制定规范
public interface RoleDao {
public int insert(Role role);//增加--结果影响一行,以stu类提交数据
public int del(int id);//根据id删除--结果影响一行
public int update(Role role);//修改--结果影响一行,以stu类提交数据
public Role selById(int id);//根据id查找数据--返回一个stu类一行的数据
public List<Role> selAll();//查询所有的信息--返回一个集合容器,泛型为Role类
//传递多个参数的情况
//多个参数查询的情况--根据id和姓名查找
/*如果不使用mybatis为参数起的名称--默认的情况[param1,param2...]
* 可以使用@Param(" ")的方式
* 习惯使用@Param为每个参数起名称,在映射文件中#{使用名称}*/
public Role selByIdAndName(@Param("id") int id,@Param("name") String role_name);
//--模糊查询
public List<Role> selByName(String name);//根据姓名查找:返回的是一个集合容器
}
//其他情况 根据年龄查询-- 会存在特殊符号的情况,使用<![CDATA[sql语句]]>
public List<Stu> selectByAge(@Param("max") int max,@Param("min") int min);
3.8配置映射文件--在resources包下创建一个mapper包
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace:命名空间
以后需要跟dao接口相同
-->
<mapper namespace="com.wjy.dao.RoleDao">
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace:命名空间
以后需要跟dao接口相同
-->
<mapper namespace="com.wjy.dao.RoleDao">
<!--增加 userGeneratedKeys="true":是否使用生成的主键
keyProperty:生成后的主键赋给哪个属性
-->
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
insert into t_role values (null,#{name},#{code},#{description})
</insert>
<!--修改-->
<update id="update">
update t_role set role_name=#{name},role_code=#{code},description=#{description} where id=#{id}
</update>
<!--删除-->
<delete id="del">
delete from t_role where id=#{id}
</delete>
<!--由于数据库中的列名和属性名不一致-->
<!--第一种起别名的方式-->
<!--<select id="selById" resultType="com.wjy.entity.Role">
select id,role_name as name,role_code as code,description from t_role where id=#{id}
</select>-->
<!--第二种使用ResultMapper属性
定义映射关系
id:标识
type:执行查询后返回的数据类型
property:类中定义的属性名
column:数据库中的列名-->
<resultMap id="myMap" type="com.wjy.entity.Role">
<id property="id" column="id"/>
<result property="name" column="role_name"/>
<result property="code" column="role_code"/>
<result property="description" column="description"/>
</resultMap>
<!--查询所有信息-->
<select id="selAll" resultMap="myMap">
select * from t_role
</select>
<!--根据id查找:使用resultMap就不能使用-->
<select id="selById" resultMap="myMap">
select * from t_role where id=#{id}
</select>
<!--根据id和名字查找--多个参数需设置在定义接口时使用@Param("#{}中填写的")注解-->
<select id="selByIdAndName" resultMap="myMap">
select * from t_role where id=#{id} and role_name=#{name}
</select>
<!--模糊查询-->
<select id="selByName" resultMap="myMap">
select * from t_role where role_name like concat('%',#{name},'%')
</select>
<!--根据年龄的范围筛选出对应的数据
存在特殊字符-处理方式<![CDATA[sql语句]]>
-->
<select id="selectByAge" resultMap="myMap">
<![CDATA[select * from t_student where age > #{min} and age < #{max}]]>
</select>
</mapper>
3.8.1列名和属性名不一致的情况
查询列无法给对应的属性赋值。
第一种: 查询时为列起别名
让别名与属性名一致
第二种: 使用ResultMapper属性--推荐使用(联表查询时也会用到)
3.8.2传递多个参数--接口定义查询时
3.8.3<![CDATA[sql语句]]>--在xml文件中处理特殊符号
使用第二种:<![CDATA[sql语句]]>
3.8.5模糊查询--concat()
3.8.6添加时获取递增的主键值
userGeneratedKeys="true":是否使用生成的主键
keyProperty:生成后的主键赋给哪个属性
3.9单元测试
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.wjy.dao.RoleDao;
import com.wjy.entity.Role;
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 org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import java.util.List;
/**
* @program: mybatis05
* @description:
* @author: 王佳瑶
* @create: 2024-05-21 08:42
**/
public class RoleUnit {
InputStream resourceAsStream =null;
SqlSessionFactory sessionFactory =null;
SqlSession sqlSession =null;
RoleDao roleDao =null;
//在测试之前加载的注解方法
@Before
public void before()throws Exception{
resourceAsStream=Resources.getResourceAsStream("mybatis.xml");
sessionFactory=new SqlSessionFactoryBuilder().build(resourceAsStream);
sqlSession=sessionFactory.openSession();
roleDao = sqlSession.getMapper(RoleDao.class);
}
//增加
@Test
public void insert(){
Role role = new Role(null,"元","student","学生");
System.out.println("添加前:"+role);
roleDao.insert(role);
System.out.println("添加后:"+role);
sqlSession.commit();
}
//修改
@Test
public void update(){
Role role = new Role(13,"佳瑶","student","学生");
roleDao.update(role);
sqlSession.commit();
}
//删除
@Test
public void del(){
roleDao.del(13);
sqlSession.commit();
}
//根据id查询
@Test
public void selById(){
Role role = roleDao.selById(12);
System.out.println(role);
}
//根据id和姓名查询
@Test
public void selByIdAndName(){
Role role = roleDao.selByIdAndName(12,"王佳瑶");
System.out.println(role);
}
//根据姓名模糊查询
@Test
public void selByName(){
List<Role> roles = roleDao.selByName("w");
for (Role r:roles) {
System.out.println(r);
}
}
//查询全部
@Test
public void selAll(){
List<Role> roles = roleDao.selAll();
for (Role r:roles) {
System.out.println(r);
}
}
//查询全部--分页版
@Test
public void selAllAndLimit(){
//开启分页功能--起始页1,一页3条数据
PageHelper.startPage(1,2);
List<Role> roles = roleDao.selAll();//调用自己的方法--会自动在后面给补全分页sql语句
//把查询到的结果封装到PageInfo类中--包含总条数和当前页的记录
PageInfo<Role> pageInfo = new PageInfo<Role>(roles);
//将来会给前端pageInfo
System.out.println("总条数:"+pageInfo.getTotal());
System.out.println("总页数:"+pageInfo.getPages());
System.out.println("当前页的记录:"+pageInfo.getList());
sqlSession.commit();
}
}
4.mybatis的注解(了解)
上面完成crud操作时,通过的都是映射文件来写sql语句完成的。 mybatis也提供了注解模式
5.mybatis分页插件
自己写分页sql. [select * from 表名 where 条件 limit 起始记录,每页显示的条数] [select count(*) from 表名 where 条件] ---使用PageHelper
5.1pageHelper的依赖(前面依赖中有)
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>6.1.0<</version>
</dependency>
5.2引入拦截器--在mybatis配置文件中
写在environments的上方
<plugins>
<!-- com.github.pagehelper为PageHelper类所在包名 -->
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!-- 使用下面的方式配置参数,后面会有所有的参数介绍 -->
<property name="param1" value="value1"/>
</plugin>
</plugins>
5.3测试分页查询
6.总结
步骤:
1.创建maven工程
2.在pox.xml中引入依赖(复制查找)
3.在resources资源包下创建数据源文件---1.db.properties关于数据库的连接(复制查找)
2.log4j.properties日志属性文件(复制查找)
4.编写配置Mybatis.xml文件(复制查找)--在这里面有引入资源文件,设置value的值
--最后引入映射文件(mapper包下的关于具体类的操作实现)
5.在entity包下创建对应的实体类--使用注解设置get、set、toString方法等
6.在dao包下创建对应的接口实现类(制定规范)
7.配置对应的映射文件--<!--namespace:命名空间
必须和接口名一致
#{类中的对应的数据中的属性名}-->
<!--增加 userGeneratedKeys="true":是否使用生成的主键
keyProperty:生成后的主键赋给哪个属性
-->
<!--查询 列表和属性要对应
1.使用ResultMap定义映射关系
2.替换查询里的resultType属性
-->
<!--查询所有信息
考虑分页查询的情况:1.引入依赖
2.引入拦截器
3.测试:开启分页PageHelper、把查询到的数据封装到PageInfo中
-->
<!--根据id和姓名-多参-查找
在StuDao中多参传值的时候注解定义了,默认的会有[param1,...]不方便书写
-->
<!--根据年龄的范围筛选出对应的数据
存在特殊字符-处理方式<![CDATA[sql语句]]>
-->
<!--查找名字中有某个字符的所有信息:模糊查询:like 使用concat()方法
-->
7.mybatis实现联表查询
class[cid cname] student(id,name,age, class_id)
回顾: mysql联表的sql语句: select * from student s inner join class c on s.class_id=c.cid
表与表之间的关系: 外键。
mybatis中如何封装联表查询的结果。
7.1mybatis完成多对一
从多的一方查询一的一方的信息
1.根据id查询员工的信息及所在部门信息
2.根据部门名查询改部门下的所有员工
7.2mybatis动态sql标签
public List<Emp> selByNameAndJob(@Param("name") String name,@Param("job") String job);//测试if动态sql语句
public List<Emp> selByNameOrJobOrSal(@Param("name") String name,@Param("job") String job);//测试choose when otherwise动态sql语句
public int delById(@Param("id") int[] id);//根据id删除、批量选择性删除
public int insert(@Param("emps") List<Emp> emps);//批量增加
public int update(Emp emp);//根据id修改--set
7.2.1if标签
根据条件查询:1.传递员工名不为null,
按照name条件查询 如果name为null则查询所有
2.传递职位job
<select id="selByNameAndJob" resultMap="myMap">
select * from emp where 1=1
<if test="name!=null and name!=''">
and e_name like concat('%',#{name},'%')
</if>
<if test="job!=null and job!=''">
and JOB like concat('%',#{job},'%')
</if>
</select>
7.2.2choose when otherwise标签:
相当于switch或者if else...
<select id="selByNameOrJobOrSal" resultMap="myMap">
select * from emp where 1=1
<choose>
<when test="name!=null and name!=''">
and E_NAME like concat('%',#{name},'%')
</when>
<when test="job!=null and job!=''">
and JOB =#{job}
</when>
<otherwise>
and SAL > 5000
</otherwise>
</choose>
</select>
7.2.3where
where它可以自动处理条件语句的前缀
当条件满足时自动保证符合sql语法的条件格式
条件都不满足时查询全部内容,也就是where标签之前的完整sql语句
上面测试的都不符合正常规范,这种推荐使用
<select id="selByNameAndJob" resultMap="myMap">
select * from emp
<where>
<if test="name!=null and name!=''">
and e_name like concat('%',#{name},'%')
</if>
<if test="job!=null and job!=''">
and JOB like concat('%',#{job},'%')
</if>
</where>
</select>
7.2.4foreacch:遍历集合或数组
批量删除/增加等操作:例如:delete from user where id in (1,2,4)
collection: 要遍历的集合元素
item: 遍历时赋予的变量
open: 以。。开头
close: 以。。关闭
separator:分隔符
<delete id="delById">
delete from emp
<foreach collection="id" item="id" open="where empno in(" close=")" separator=",">
#{id}
</foreach>
</delete>
<insert id="insert">
insert into emp values
<foreach collection="emps" item="e" separator=",">
(null,#{e.name},#{e.job},#{e.salary},#{e.deptno})
</foreach>
</insert>
7.2.5set用于修改元素
<update id="update">
update emp
<set>
<if test="name!=null and name!=''">
e_name=#{name}
</if>
<if test="job!=null and job!=''">
job=#{job}
</if>
<if test="salary!=null and salary!=''">
sal=#{salary}
</if>
<if test="deptno!=null and deptno!=''">
deptno=#{deptno}
</if>
where empno = #{id}
</set>
</update>
//if
@Test
public void selByNameAndJob(){
List<Emp> emps = empDao.selByNameAndJob("", "");
System.out.println(emps);
}
//choose when otherwise--只会满足一个条件,相当于case语句中每条都有break,或者if-if else...
@Test
public void selByNameOrJobOrSal(){
List<Emp> emps = empDao.selByNameOrJobOrSal("", "销售经理");
System.out.println(emps);
}
//foreach:批量操作--遍历集合或数组
@Test
public void delById(){
int [] id = {2,3};
int i = empDao.delById(id);
sqlSession.commit();
}
@Test
public void insert(){
List<Emp> emps = new ArrayList<>();
emps.add(new Emp(null, "wjy", "boss", 9999,40));
emps.add(new Emp(null, "gyh", "boss", 9999,40));
int insert = empDao.insert(emps);
System.out.println(insert);
sqlSession.commit();
}
//set修改
@Test
public void update(){
Emp emp = new Emp(9,"王佳瑶",null,null,null);
empDao.update(emp);
sqlSession.commit();
}
7.2.6trim标签
它的功能更加强大,它可以替换where和set标签
<!--
trim:
prefix:前缀使用set
suffixOverrides: 后缀覆盖 ,
-->
<update id="update">
update emp
<trim prefix="set" suffixOverrides=",">
<if test="name!=null and name!=''">
e_name=#{name},
</if>
<if test="job!=null and job!=''">
job=#{job},
</if>
<if test="salary!=null and salary!=''">
sal=#{salary},
</if>
<if test="deptno!=null and deptno!=''">
deptno=#{deptno},
</if>
where empno = #{id}
</trim>
</update>
<!--根据条件查询-->
<select id="selectByCondition01" resultType="com.aaa.entity.User">
select * from user
<trim prefix="where" prefixOverrides="and |or">
<if test="name!=null and name!=''">
or name like concat('%',#{name},'%')
</if>
<if test="email!=null and email!=''">
and email=#{email}
</if>
</trim>
</select>
//where set 替换 trim
7.2.7联表条件分页查询
//接口处
public List<Emp> selectByNameAndSal(EmpMessage empMessage);
// 可以把条件封装到实体类中vo [view object] 视图对象
@Data
@AllArgsConstructor
@NoArgsConstructor
public class EmpMessage {
private String name;
private Integer maxMoney;
private Integer minMoney;
}
//sql查询,映射文件
<resultMap id="myMap" type="com.wjy.entity.Emp">
<id property="id" column="empno"/>
<result property="name" column="e_name"/>
<result property="job" column="job"/>
<result property="money" column="sal"/>
<result property="deptNo" column="deptno"/>
<association property="dept" javaType="com.wjy.entity.Dept">
<id property="id" column="deptno"/>
<result property="name" column="dname"/>
<result property="loc" column="loc"/>
</association>
</resultMap>
<select id="selectByNameAndSal" resultMap="myMap">
select * from emp e join dept d on d.deptno = e.DEPTNO
<trim prefix="where" prefixOverrides="and">
<if test="name!=null and name!=''">
and E_NAME like concat('%',#{name},'%')
</if>
<if test="minMoney!=null">
and SAL>=#{minMoney}
</if>
<if test="maxMoney!=null">
and SAL<=#{maxMoney}
</if>
</trim>
</select>
//测试--分页查找,根据名字模糊查找,新资在某个范围段的
@Test
public void selByNamAndSal(){
//打开分页
PageHelper.startPage(1,1);
//调用方法查找
EmpMessage empMessage = new EmpMessage();
empMessage.setName("佳");
empMessage.setMinMoney(8000);
empMessage.setMaxMoney(10000);
List<Emp> emps = empDao.selectByNameAndSal(empMessage);
PageInfo<Emp> pageInfo = new PageInfo<Emp>(emps);
System.out.println("总条数:"+pageInfo.getTotal());
System.out.println("总页数:"+pageInfo.getPages());
System.out.println("当前页的信息:");
List<Emp> list = pageInfo.getList();
for (Emp e :
list) {
System.out.println(e);
}
}
8. mybatis代码生成器--适用于简单的crud操作
实体类,dao接口,mapper映射文件无需自己写了。
先连接数据库
可以选择需要的数据库表
老的版本需要加上时区:
选择构建的表
设置生成的位置、包名(基础包名、实体类名包名)、忽略的前后缀、父类等
根据需要
选中default-all生成的资源
9.缓存--查询才有
缓存:把磁盘中的数据放入到内存中,减少数据库的压力
数据库存储:存放到磁盘
缓存的数据:存放在内存
对比:内存的速度要比磁盘速度快,电脑重启后内存的数据会丢失。
原理:
什么样的数据适合放入缓存:
1.查询频率高的数据且修改频率低的
2.安全系数低
mybatis默认支持缓存操作
提供了两个缓存模式:
1.一级缓存(默认开启的)基于sqlSession完成
2.二级缓存(默认不开启)基于Mapper(namespace)
9.1mybatis一级缓存
根据运行结果发现查询三次,但是只执行了一次sql语句:说明其他两次都是从缓存中读取的。
@Test
public void test01()throws Exception{
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sessionFactory.openSession();
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
Emp emp = empMapper.selectByPrimaryKey(11L);
System.out.println("第一次查询:"+emp);
Emp emp1 = empMapper.selectByPrimaryKey(11L);
System.out.println("第二次查询:"+emp1);
Emp emp2 = empMapper.selectByPrimaryKey(11L);
System.out.println("第三次查询:"+emp2);
}
根据运行结果得出,使用不同的sqlSession对象,发送了两次sql语句:说明一级缓存是基于sqlSession存放的
@Test
public void test02()throws Exception{
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession1 = sessionFactory.openSession();
EmpMapper empMapper1 = sqlSession1.getMapper(EmpMapper.class);
Emp emp1 = empMapper1.selectByPrimaryKey(11L);
System.out.println("第一次查询:"+emp1);
SqlSession sqlSession2 = sessionFactory.openSession();
EmpMapper empMapper2 = sqlSession2.getMapper(EmpMapper.class);
Emp emp2 = empMapper2.selectByPrimaryKey(11L);
System.out.println("第二次查询:"+emp2);
}
9.2mybatis二级缓存
基于mapper实现的,默认情况不开启,多个sqlSession可以共享二级缓存中的数据
1.第一次执行sql并写入到二级缓存中
2.第二次直接从缓存去读取
3.当执行插入、更新和删除操作时清空缓存区域
1.开启二级缓存--mybatis.xml文件中
<!--开启二级缓存-->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
2.使用二级缓存--在映射文件中使用
<!--使用二级缓存 表示映射文件中所有的查询都使用二级缓存-->
<cache/>
<cache
eviction="FIFO" //回收策略为先进先出
flushInterval="60000" //自动刷新时间
60ssize="1M" //最多缓存 512 个引用对象
readOnly="true"/> //只读
<!--在标签中单独设置二级缓存-->
useCache="true/false"
第一次sqlSession1关闭之前会先提交到缓存区域,然后第二吃sqlSession2执行时会直接从缓存区读取
使用不同的sqlSession对象只发生一条sql语句
@Test
public void test02()throws Exception{
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession1 = sessionFactory.openSession();
EmpMapper empMapper1 = sqlSession1.getMapper(EmpMapper.class);
Emp emp1 = empMapper1.selectByPrimaryKey(11L);
System.out.println("第一次查询:"+emp1);
sqlSession1.close();//关闭sqlSession1--会先执行commit()提交,再关闭资源
sqlSession1.commit();
SqlSession sqlSession2 = sessionFactory.openSession();
EmpMapper empMapper2 = sqlSession2.getMapper(EmpMapper.class);
Emp emp2 = empMapper2.selectByPrimaryKey(11L);
System.out.println("第二次查询:"+emp2);
}
如果中间执行了增删改操作,会清空缓存中的数据(一级二级都是)
@Test
public void test02()throws Exception{
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession1 = sessionFactory.openSession();
EmpMapper empMapper1 = sqlSession1.getMapper(EmpMapper.class);
Emp emp1 = empMapper1.selectByPrimaryKey(11L);
System.out.println("第一次查询:"+emp1);
//sqlSession1.close();//关闭sqlSession1--会先执行commit()提交,再关闭资源
sqlSession1.commit();
SqlSession sqlSession2 = sessionFactory.openSession();
EmpMapper empMapper2 = sqlSession2.getMapper(EmpMapper.class);
//修改
SqlSession sqlSession3 = sessionFactory.openSession();
EmpMapper empMapper3 = sqlSession3.getMapper(EmpMapper.class);
Emp emp3 = new Emp(10,"s","boss",6000.0,20);
empMapper3.updateByPrimaryKey(emp3);
sqlSession3.commit();
Emp emp2 = empMapper2.selectByPrimaryKey(11L);
System.out.println("第二次查询:"+emp2);
}