作用域
取值有两个:SqlSession和Statement
文档:https://mybatis.org/mybatis-3/configuration.html#settings
Mybatis plus 基于springboot的配置为:
mybatis-plus:
configuration:
local-cache-scope: statement
或者
mybatis-plus:
configuration:
local-cache-scope: session
SqlSession
每个SqlSession中持有了Executor,每个Executor中有一个LocalCache
执行SQL语句的过程中,首次执行它时从数据库获取的所有数据会被存储在一段高速缓存中,今后执行这条语句时就会从高速缓存中读取结果,而不是再次查询数据库。MyBatis提供了默认下基于HashMap的缓存实现。
类图如下:
SqlSessionConfig
package com.example.demo.config;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.plugin.Interceptor;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;
/**
* @author liuteng
*/
@Configuration
public class SqlSessionConfig {
private Logger logger = LoggerFactory.getLogger(SqlSessionConfig.class);
@Bean("sqlSessionFactoryBean")
public MybatisSqlSessionFactoryBean createSqlSessionFactory(@Qualifier("dataSource") DataSource dataSource,
@Qualifier("paginationInterceptor") PaginationInterceptor paginationInterceptor) {
// MybatisSqlSessionFactory
MybatisSqlSessionFactoryBean sqlSessionFactoryBean = null;
try {
// 实例SessionFactory
sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
// 配置数据源
sqlSessionFactoryBean.setDataSource(dataSource);
// 设置 MyBatis-Plus 分页插件
Interceptor [] plugins = {paginationInterceptor};
sqlSessionFactoryBean.setPlugins(plugins);
// 加载MyBatis配置文件
PathMatchingResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
sqlSessionFactoryBean.setMapperLocations(resourcePatternResolver.getResources("classpath*:mapper/*.xml"));
} catch (Exception e) {
logger.error("创建SqlSession连接工厂错误:{}", e.getMessage());
}
return sqlSessionFactoryBean;
}
@Bean("dataSource")
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource(){
return DataSourceBuilder.create().build();
}
@Bean
public MapperScannerConfigurer myGetMapperScannerConfigurer() {
MapperScannerConfigurer myMapperScannerConfigurer = new MapperScannerConfigurer();
myMapperScannerConfigurer.setBasePackage("com.example.demo.mapper");
myMapperScannerConfigurer.setSqlSessionFactoryBeanName("mySqlSessionFactoryBean");
return myMapperScannerConfigurer;
}
}
UserServiceImpl
package com.example.demo.service.impl;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.example.demo.mapper.User1Mapper;
import com.example.demo.mapper.UserMapper;
import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class UserServiceImpl implements UserService {
@Resource
DefaultSqlSessionFactory sqlSessionFactoryBean;
@Override
public int updateById(User user) {
try {
SqlSession sqlSession1 = sqlSessionFactoryBean.openSession();
SqlSession sqlSession2 = sqlSessionFactoryBean.openSession();
UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
User firstUser = userMapper1.selectById(user.getId());
log.debug("=========SqlSession1查询======== User:{}", JSON.toJSONString(firstUser));
userMapper2.updateById(user);
log.debug("=========SqlSession2修改======== User:{}", JSON.toJSONString(user));
User secondUser = userMapper2.selectById(user.getId());
log.debug("=========SqlSession2查询======== User:{}", JSON.toJSONString(secondUser));
User thirdUser = userMapper1.selectById(user.getId());
log.debug("=========SqlSession1查询======== User:{}", JSON.toJSONString(thirdUser));
} catch (Exception e) {
log.error(e.getMessage());
}
return 1;
}
}
数据库预先录入数据,然后测试修改用户名
执行结果
2020-05-26 14:52:21.869 DEBUG 3992 --- [nio-8080-exec-7] o.s.jdbc.datasource.DataSourceUtils : Fetching JDBC Connection from DataSource
o.m.s.t.SpringManagedTransaction : JDBC Connection [HikariProxyConnection@1725242542 wrapping com.mysql.cj.jdbc.ConnectionImpl@7bd24a07] will not be managed by Spring
c.e.demo.mapper.UserMapper.selectById : ==> Preparing: SELECT id,name,sex,phone,create_time,enable,version FROM user WHERE id=? AND enable=1
c.e.demo.mapper.UserMapper.selectById : ==> Parameters: 12121212(Long)
c.e.demo.mapper.UserMapper.selectById : <== Total: 1
c.e.demo.service.impl.UserServiceImpl : =========SqlSession1查询======== User:{"createTime":1590475920000,"enable":true,"id":12121212,"name":"wangwu","phone":"18111111111","sex":"MAN","version":1}
o.s.jdbc.datasource.DataSourceUtils : Fetching JDBC Connection from DataSource
o.m.s.t.SpringManagedTransaction : JDBC Connection [HikariProxyConnection@691008575 wrapping com.mysql.cj.jdbc.ConnectionImpl@4a631491] will not be managed by Spring
c.e.demo.mapper.UserMapper.updateById : ==> Preparing: UPDATE user SET name=?, phone=?, create_time=? WHERE id=? AND enable=1
c.e.demo.mapper.UserMapper.updateById : ==> Parameters: lisi(String), 18111111111(String), 2020-05-26 14:52:21.869(Timestamp), 12121212(Long)
c.e.demo.mapper.UserMapper.updateById : <== Updates: 1
c.e.demo.service.impl.UserServiceImpl : =========SqlSession2修改======== User:{"createTime":1590475941869,"enable":false,"id":12121212,"name":"lisi","phone":"18111111111"}
c.e.demo.mapper.UserMapper.selectById : ==> Preparing: SELECT id,name,sex,phone,create_time,enable,version FROM user WHERE id=? AND enable=1
c.e.demo.mapper.UserMapper.selectById : ==> Parameters: 12121212(Long)
c.e.demo.mapper.UserMapper.selectById : <== Total: 1
c.e.demo.service.impl.UserServiceImpl : =========SqlSession2查询======== User:{"createTime":1590475942000,"enable":true,"id":12121212,"name":"lisi","phone":"18111111111","sex":"MAN","version":1}
c.e.demo.service.impl.UserServiceImpl : =========SqlSession1查询======== User:{"createTime":1590475920000,"enable":true,"id":12121212,"name":"wangwu","phone":"18111111111","sex":"MAN","version":1}
由执行结果可知,同一个Session中,相同查询会使用缓存,不同Session之间互不影响。当有多个SqlSession或者分布式的环境下,数据库写操作会引起脏数据
设置一级缓存级别为Statement
修改SqlSessionConfig配置,新增如下
MybatisConfiguration configuration = new MybatisConfiguration();
configuration.setLocalCacheScope(LocalCacheScope.STATEMENT);
sqlSessionFactoryBean.setConfiguration(configuration);
执行结果:
com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@a4a722
com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
o.m.s.t.SpringManagedTransaction : JDBC Connection [HikariProxyConnection@1748010355 wrapping com.mysql.cj.jdbc.ConnectionImpl@a4a722] will not be managed by Spring
c.e.demo.mapper.UserMapper.selectById : ==> Preparing: SELECT id,name,sex,phone,create_time,enable,version FROM user WHERE id=? AND enable=1
c.e.demo.mapper.UserMapper.selectById : ==> Parameters: 12121212(Long)
com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Pool stats (total=1, active=1, idle=0, waiting=0)
c.e.demo.mapper.UserMapper.selectById : <== Total: 1
c.e.demo.service.impl.UserServiceImpl : =========SqlSession1查询======== User:{"createTime":1590489590000,"enable":true,"id":12121212,"name":"关羽","phone":"12345678910","sex":"MAN","version":1}
o.s.jdbc.datasource.DataSourceUtils : Fetching JDBC Connection from DataSource
com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@6eac3382
o.m.s.t.SpringManagedTransaction : JDBC Connection [HikariProxyConnection@1875164390 wrapping com.mysql.cj.jdbc.ConnectionImpl@6eac3382] will not be managed by Spring
c.e.demo.mapper.UserMapper.updateById : ==> Preparing: UPDATE user SET name=?, phone=?, create_time=? WHERE id=? AND enable=1
c.e.demo.mapper.UserMapper.updateById : ==> Parameters: 赵云(String), 12345678910(String), 2020-05-26 18:40:20.098(Timestamp), 12121212(Long)
c.e.demo.mapper.UserMapper.updateById : <== Updates: 1
c.e.demo.service.impl.UserServiceImpl : =========SqlSession2修改======== User:{"createTime":1590489620098,"enable":false,"id":12121212,"name":"赵云","phone":"12345678910"}
c.e.demo.mapper.UserMapper.selectById : ==> Preparing: SELECT id,name,sex,phone,create_time,enable,version FROM user WHERE id=? AND enable=1
c.e.demo.mapper.UserMapper.selectById : ==> Parameters: 12121212(Long)
c.e.demo.mapper.UserMapper.selectById : <== Total: 1
c.e.demo.service.impl.UserServiceImpl : =========SqlSession2查询======== User:{"createTime":1590489620000,"enable":true,"id":12121212,"name":"赵云","phone":"12345678910","sex":"MAN","version":1}
c.e.demo.mapper.UserMapper.selectById : ==> Preparing: SELECT id,name,sex,phone,create_time,enable,version FROM user WHERE id=? AND enable=1
c.e.demo.mapper.UserMapper.selectById : ==> Parameters: 12121212(Long)
c.e.demo.mapper.UserMapper.selectById : <== Total: 1
c.e.demo.service.impl.UserServiceImpl : =========SqlSession1查询======== User:{"createTime":1590489620000,"enable":true,"id":12121212,"name":"赵云","phone":"12345678910","sex":"MAN","version":1}
总结:Mybatis作为ORM框架,为了避免存在的脏读问题,建议修改一级缓存作用域为:Statement