Spring(五)Spring缓存机制与Redis的结合
一、Redis和数据库的结合
使用Redis可以优化性能,但是存在Redis的数据和数据库同步的问题。
例如,T1时刻以将 key1 保存数据到 Redis,T2时刻刷新进入数据库,但是T3时刻发生了其他业务需要改变数据库同一条记录的数据,但是采用了 key2 保存到Redis中,然后又写入了更新数据到数据库中,这就导致 Redis 中key1 的数据是脏数据,和数据库中的数据不一致。

1.Redis和数据库读操作
数据缓存往往会在 Redis 上设置超时时间,当设置 Redis 的数据超时后,Redis 就没法读出数据了,这个时候就会触发程序读取数据库,然后将读取数据库数据写入 Redis,并给数据重设超时时间,这样程序在读取的过程中就能按一定的时间间隔刷新数据了。

public DataObject readMethod(args) {
DataObject data = getRedis(key);
if(data != null){
data = getFromDataBase();
writeRedis(key, data);
setRedisExpire(key, 5);
}
return data;
}
2. Redis 和数据库写操作
写操作要考虑数据一致的问题,尤其是那些重要的业务数据,所以首先应该考虑从数据库中读取最新的数据,然后对数据进行操作,最后把数据写入 Redis 缓存中。

写入业务数据时,应该先从数据库中读取最新数据,然后进行业务操作,更新业务数据到数据库后,再将数据刷新到 Redis 缓存中,这样就能避免将脏数据写入数据库中。
public DataObject writeMethod(args) {
DataObject data = getFromDataBase(args);
ExecLogic(data);
updateDataBase(data);
updateRedisData(data);
}
二、使用Spring缓存机制整合Redis

1.定义一个POJO类和Mybatis
package com.ssm.chapter21.pojo;
import java.io.Serializable;
public class Role implements Serializable {
private static final long serialVersionUID = -1194462093889377366L;
private Long id;
private String roleName;
private String note;
/**** setter and getter ****/
}
POJO
<?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>
<mappers>
<mapper resource="com/ssm/chapter21/mapper/RoleMapper.xml"/>
</mappers>
</configuration>
Mybatis-config.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.ssm.chapter21.dao.RoleDao"> <select id="getRole" resultType="com.ssm.chapter21.pojo.Role">
select id, role_name as
roleName, note from t_role where id = #{id}
</select> <delete id="deleteRole">
delete from t_role where id=#{id}
</delete> <insert id="insertRole" parameterType="com.ssm.chapter21.pojo.Role"
useGeneratedKeys="true" keyProperty="id">
insert into t_role (role_name, note) values(#{roleName}, #{note})
</insert> <update id="updateRole" parameterType="com.ssm.chapter21.pojo.Role">
update t_role set role_name = #{roleName}, note = #{note}
where id = #{id}
</update>
<select id="findRoles" resultType="com.ssm.chapter21.pojo.Role">
select id, role_name as roleName, note from t_role
<where>
<if test="roleName != null">
role_name like concat('%', #{roleName}, '%')
</if>
<if test="note != null">
note like concat('%', #{note}, '%')
</if>
</where>
</select>
</mapper>
RoleMapper.xml
package com.ssm.chapter21.dao; import java.util.List; import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository; import com.ssm.chapter21.pojo.Role; /**** imports ****/
@Repository
public interface RoleDao { public Role getRole(Long id); public int deleteRole(Long id); public int insertRole(Role role); public int updateRole(Role role); public List<Role> findRoles(@Param("roleName") String roleName, @Param("note") String note);
}
RoleDao.java
package com.ssm.chapter21.service;
import java.util.List;
import com.ssm.chapter21.pojo.Role;
public interface RoleService {
public Role getRole(Long id);
public int deleteRole(Long id);
public Role insertRole(Role role);
public int updateRole(Role role);
public List<Role> findRoles(String roleName, String note);
public int insertRoles(List<Role> roleList);
}
RoleService
2.通过Java配置Spring
RootConfig.java的定义,其中包含了4个部分
package com.ssm.chapter21.config;/**** imports ****/
@Configuration
// 定义Spring扫描的包
@ComponentScan("com.*")
// 使用事务驱动管理器
@EnableTransactionManagement
// 实现接口TransactionManagementConfigurer,这样可以配置注解驱动事务
public class RootConfig implements TransactionManagementConfigurer {
private DataSource dataSource = null;
...
}
(1)配置数据库
/**
* 配置数据库
*
* @return 数据连接池
*/
@Bean(name = "dataSource")
public DataSource initDataSource() {
if (dataSource != null) {
return dataSource;
}
Properties props = new Properties();
props.setProperty("driverClassName", "com.mysql.jdbc.Driver");
props.setProperty("url", "jdbc:mysql://localhost:3306/chapter6?useSSL=false");
props.setProperty("username", "root");
props.setProperty("password", "bjtungirc");
try {
dataSource = BasicDataSourceFactory.createDataSource(props);
} catch (Exception e) {
e.printStackTrace();
}
return dataSource;
}
(2)配置SqlSessionFactoryBean
/**
* * 配置SqlSessionFactoryBean
*
* @return SqlSessionFactoryBean
*/
@Bean(name = "sqlSessionFactory")
public SqlSessionFactoryBean initSqlSessionFactory() {
SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
sqlSessionFactory.setDataSource(initDataSource());
// 加载Mybatis配置文件
Resource resource = new ClassPathResource("mybatis/mybatis-config.xml");
sqlSessionFactory.setConfigLocation(resource);
return sqlSessionFactory;
}
(3)配置Mybatis Mapper
/**
* * 通过自动扫描,发现Mybatis Mapper映射器
*
* @return Mapper映射器
*/
@Bean
public MapperScannerConfigurer initMapperScannerConfigurer() {
MapperScannerConfigurer msc = new MapperScannerConfigurer();
// 定义扫描包
msc.setBasePackage("com.*");
msc.setSqlSessionFactoryBeanName("sqlSessionFactory");
// 区分注解扫描
msc.setAnnotationClass(Repository.class);
return msc;
}
(4)配置注解驱动,使得@Transactional可以触发事务
/**
* 实现接口方法,注册注解事务,当@Transactional使用的时候产生数据库事务
*/
@Override
@Bean(name = "annotationDrivenTransactionManager")
public PlatformTransactionManager annotationDrivenTransactionManager() {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(initDataSource());
return transactionManager;
}
3.通过Java配置RedisTemplate和Redis缓存管理器
RedisConfig.java,其中包含两个部分,RedisTemplate和Redis缓存管理器
其中@EnableCaching 表示Spring IoC 容器启动了缓存机制。
package com.ssm.chapter21.config;/**** imports ****/
@Configuration
@EnableCaching
public class RedisConfig {...}
(1)RedisTemplate配置
@Bean(name = "redisTemplate")
public RedisTemplate initRedisTemplate() {
JedisPoolConfig poolConfig = new JedisPoolConfig();
// 最大空闲数
poolConfig.setMaxIdle(50);
// 最大连接数
poolConfig.setMaxTotal(100);
// 最大等待毫秒数
poolConfig.setMaxWaitMillis(20000);
// 创建 Jedis 连接工厂
JedisConnectionFactory connectionFactory = new JedisConnectionFactory(poolConfig);
connectionFactory.setHostName("localhost");
connectionFactory.setPort(6379);
// 调用后初始化方法,没有它将抛出异常
connectionFactory.afterPropertiesSet();
// 自定义两个Redis序列化器
RedisSerializer jdkSerializationRedisSerializer = new JdkSerializationRedisSerializer();
RedisSerializer stringRedisSerializer = new StringRedisSerializer();
// 定义RedisTemplate对象,并设置连接工程
RedisTemplate redisTemplate = new RedisTemplate();
redisTemplate.setConnectionFactory(connectionFactory);
// 设置序列化器
redisTemplate.setDefaultSerializer(stringRedisSerializer);
redisTemplate.setKeySerializer(stringRedisSerializer);
redisTemplate.setValueSerializer(jdkSerializationRedisSerializer);
redisTemplate.setHashKeySerializer(stringRedisSerializer);
redisTemplate.setHashValueSerializer(jdkSerializationRedisSerializer);
return redisTemplate;
}
(2)配置Redis缓存管理器
定义默认超时时间为10分钟,这样就可以在一定的时间间隔后重新从数据库中读取数据了。另外redisCacheManager名称在之后的业务方法中也会用到。
@Bean(name = "redisCacheManager")
public CacheManager initRedisCacheManager(@Autowired RedisTemplate redisTempate) {
RedisCacheManager cacheManager = new RedisCacheManager(redisTempate);
// 设置默认超时时间,为10分钟
cacheManager.setDefaultExpiration(600);
// 设置缓存管理器名称
List<String> cacheNames = new ArrayList<String>();
cacheNames.add("redisCacheManager");
cacheManager.setCacheNames(cacheNames);
return cacheManager;
}
4.缓存注解说明
- @Cacheable:表明在进入方法之前,Spring会先去缓存服务器中查找对应key的缓存值,如果找打缓存值,那么Spring将不会再调用方法,而是将缓存值读出,返回给调用者;如果没有找到缓存值,那么Spring就会执行自定义的方法,将最后的结果通过key保存到缓存服务器中
- @CachaPut:Spring 会将该方法返回的值缓存到缓存服务器中,Spring不会事先去缓存服务器中查找,而是直接执行方法,然后缓存。就该方法始终会被Spring所调用
- @CacheEvict:移除缓存对应的key的值
- @Caching:分组注解,能够同时应用于其他缓存的注解
上面的注解都能标注到类或者方法上,如果放到类上,则对所有的方法都有效;如果放在方法上,则只是对方法有效。在大部分情况下,会放置到方法上。
一般而言,对于查询,可以使用@Cacheable;对于插入和修改,可以使用@CachePut;对于删除操作,可以使用@CacheEvict
@Cacheable和@CachaPut的配置属性为:
- value(String[]):使用缓存管理器的名称
- condition(String):Spring表达式,如果返回值为false,则不会将缓存应用到方法上
- key(String):Spring表达式,通过它来计算对应缓存的key
- unless(String):Spring表达式,如果表达式的返回值为true,则不会将方法的结果放到缓存上
RoleService接口的实现类中的方法的定义为:
package com.ssm.chapter21.service.impl;/**** imports ****/
@Service
public class RoleServiceImpl implements RoleService {
// 角色DAO,方便执行SQL
@Autowired
private RoleDao roleDao = null;
...
}
(1)使用@Cacheable注解的getRole方法
在Spring的调用中,会先查询Redis中看是否存在key为redis_role_id的键值对,如果有,就返回结果。如果没有,就访问getRole方法,从数据库中查询到数据,返回给调用者,然后将键值对redis_role_id---roleDao.getRole(id)保存到Redis中。
/**
* 使用@Cacheable定义缓存策略 当缓存中有值,则返回缓存数据,否则访问方法得到数据 通过value引用缓存管理器,通过key定义键
* @param id 角色编号
* @return 角色对象
*/
@Override
@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
@Cacheable(value = "redisCacheManager", key = "'redis_role_'+#id")
public Role getRole(Long id) {
return roleDao.getRole(id);
}
(2)使用@CachePut注解的insertRole方法和updateRole方法
由于需要先执行insertRole把对应的信息更新到数据库,然后才能刷新Redis。因此,Spring会先执行roleDao.insertRole(role);,然后根据return得到的role,将redis_role_role.id---role保存到Redis中。而updateRole方法也是同理,先执行updateRole方法更新对象,然后将redis_role_role.id---role保存到Redis中。保存到Redis中的过程都遵循redisCacheManager缓存管理器定义的过程。
/**
* 使用@CachePut则表示无论如何都会执行方法,最后将方法的返回值再保存到缓存中
* 使用在插入数据的地方,则表示保存到数据库后,会同期插入到Redis缓存中
*
* @param role 角色对象
* @return 角色对象(会回填主键)
*/
@Override
@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
@CachePut(value = "redisCacheManager", key = "'redis_role_'+#result.id")
public Role insertRole(Role role) {
roleDao.insertRole(role);
return role;
} /**
* 使用@CachePut,表示更新数据库数据的同时,也会同步更新缓存
*
* @param role 角色对象
* @return 影响条数
*/
@Override
@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
@CachePut(value = "redisCacheManager", key = "'redis_role_'+#role.id")
public int updateRole(Role role) {
return roleDao.updateRole(role);
}
(3)使用@CacheEvict注解的deleteRole方法在方法,可以执行完成后会移除对应的缓存,
/**
* 使用@CacheEvict删除缓存对应的key
*
* @param id 角色编号
* @return 返回删除记录数
*/
@Override
@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
@CacheEvict(value = "redisCacheManager", key = "'redis_role_'+#id")
public int deleteRole(Long id) {
return roleDao.deleteRole(id);
}
(4)测试@CachePut注解、@Cacheable和@CacheEvict注解:
package com.ssm.chapter21.main;
public class Chapter21Main { public static void main(String[] args) {
//使用注解Spring IoC容器
ApplicationContext ctx = new AnnotationConfigApplicationContext(RootConfig.class, RedisConfig.class);
//获取角色服务类
RoleService roleService = ctx.getBean(RoleService.class);
Role role = new Role();
role.setRoleName("role_name_1");
role.setNote("role_note_1");
//插入角色
roleService.insertRole(role);
//获取角色
Role getRole = roleService.getRole(role.getId());
getRole.setNote("role_note_1_update");
//更新角色
roleService.updateRole(getRole);
//删除角色
roleService.deleteRole(getRole.getId());
} }
输出日志:
在第二部分getRole部分可以看到,只出现了两次Opening RedisConnection和Closing Redis Connection而没有出现任何SQL执行,因为在Redis中已经先查找到了对应的数据。
Creating new transaction with name [com.ssm.chapter21.service.impl.RoleServiceImpl.insertRole]: PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED; ''
Acquired Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] for JDBC transaction
Changing isolation level of JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] to 2
Switching JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] to manual commitCreating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@71e2843b]
JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] will be managed by Spring
==> Preparing: insert into t_role (role_name, note) values(?, ?)
==> Parameters: role_name_1(String), role_note_1(String)
<== Updates: 1Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@71e2843b]
Opening RedisConnection
Closing Redis Connection
Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@71e2843b]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@71e2843b]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@71e2843b]
Initiating transaction commit
Committing JDBC transaction on Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver]
Resetting isolation level of JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] to 4
Releasing JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] after transaction
Returning JDBC Connection to DataSource
Adding transactional method 'RoleServiceImpl.getRole' with attribute: PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED; ''Adding cacheable method 'getRole' with attribute: [Builder[public com.ssm.chapter21.pojo.Role com.ssm.chapter21.service.impl.RoleServiceImpl.getRole(java.lang.Long)] caches=[redisCacheManager] | key=''redis_role_'+#id' | keyGenerator='' | cacheManager='' | cacheResolver='' | condition='' | unless='' | sync='false']
Creating new transaction with name [com.ssm.chapter21.service.impl.RoleServiceImpl.getRole]: PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED; ''Acquired Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] for JDBC transaction
Changing isolation level of JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] to 2
Switching JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] to manual commit
Opening RedisConnection
Closing Redis Connection
Opening RedisConnection
Closing Redis Connection
Initiating transaction commit
Committing JDBC transaction on Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver]
Resetting isolation level of JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] to 4
Releasing JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] after transaction
Returning JDBC Connection to DataSource Adding transactional method 'RoleServiceImpl.updateRole' with attribute: PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED; ''Adding cacheable method 'updateRole' with attribute: [Builder[public int com.ssm.chapter21.service.impl.RoleServiceImpl.updateRole(com.ssm.chapter21.pojo.Role)] caches=[redisCacheManager] | key=''redis_role_'+#role.id' | keyGenerator='' | cacheManager='' | cacheResolver='' | condition='' | unless='']
Creating new transaction with name [com.ssm.chapter21.service.impl.RoleServiceImpl.updateRole]: PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED; ''Acquired Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] for JDBC transaction
DChanging isolation level of JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] to 2
Switching JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] to manual commitCreating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6636448b]
JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] will be managed by Spring
==> Preparing: update t_role set role_name = ?, note = ? where id = ? ==> Parameters: role_name_1(String), role_note_1_update(String), 7(Long)
<== Updates: 1Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6636448b]
Opening RedisConnection
Closing Redis Connection
Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6636448b]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6636448b]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6636448b]
Initiating transaction commit
Committing JDBC transaction on Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver]
Resetting isolation level of JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] to 4
Releasing JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] after transaction
Returning JDBC Connection to DataSource Adding transactional method 'RoleServiceImpl.deleteRole' with attribute: PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED; ''Adding cacheable method 'deleteRole' with attribute: [Builder[public int com.ssm.chapter21.service.impl.RoleServiceImpl.deleteRole(java.lang.Long)] caches=[redisCacheManager] | key=''redis_role_'+#id' | keyGenerator='' | cacheManager='' | cacheResolver='' | condition='',false,false]
Creating new transaction with name [com.ssm.chapter21.service.impl.RoleServiceImpl.deleteRole]: PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED; ''Acquired Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] for JDBC transaction
Changing isolation level of JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] to 2
Switching JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] to manual commitCreating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1c681761]
JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] will be managed by Spring
==> Preparing: delete from t_role where id=?==> Parameters: 7(Long)
<== Updates: 1Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1c681761]
Opening RedisConnection
Closing Redis Connection
Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1c681761]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1c681761]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1c681761]
Initiating transaction commit
Committing JDBC transaction on Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver]
Resetting isolation level of JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] to 4
Releasing JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] after transaction
Returning JDBC Connection to DataSource
(4)findRoles方法
使用缓存的前提是----高命中率。由于这里根据角色名称和备注查找角色信息,该方法的返回值会根据查询条件而多样化,导致其不确定和命中率低下,这种情况下使用缓存并不能有效提高性能,所以findRoles方法就不必使用缓存注解来进行标注了。
@Override
@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
public List<Role> findRoles(String roleName, String note) {
return roleDao.findRoles(roleName, note);
}
(5)insertRoles方法
insertRoles方法中调用了insertRole方法,而insertRole方法本身带有注解@CachePut,这时如果要执行insertRoles方法,会发现缓存失效了。
这里失效的原因是和之前讨论过的数据库事务失效的情况一样,由于缓存注解也是使用了Spring AOP 来实现,而Spring AOP使用了动态代理,即只有代理对象的相互调用,AOP才具有拦截功能。而这里的自调用是没有代理对象存在的,因此注解功能失效。
@Override
@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
public int insertRoles(List<Role> roleList) {
for (Role role : roleList) {
//同一类的方法调用自己方法,产生自调用[插入:失效]问题
this.insertRole(role);
}
return roleList.size();
}
Spring(五)Spring缓存机制与Redis的结合的更多相关文章
- net core Webapi基础工程搭建(五)——缓存机制
目录 前言 Cache Session Cookie 小结 补充 前言 作为WebApi接口工程,性能效率是必不可少的,每次的访问请求,数据库读取,业务逻辑处理都或多或少耗费时间,偶尔再来个各种花式f ...
- hbase 学习(十五)缓存机制以及可以利用SSD作为存储的BucketCache
下面介绍Hbase的缓存机制: a.HBase在读取时,会以Block为单位进行cache,用来提升读的性能 b.Block可以分类为DataBlock(默认大小64K,存储KV).BloomBloc ...
- 15 hbase 学习(十五)缓存机制以及可以利用SSD作为存储的BucketCache
下面介绍Hbase的缓存机制: a.HBase在读取时,会以Block为单位进行cache,用来提升读的性能 b.Block可以分类为DataBlock(默认大小64K,存储KV).BloomBlo ...
- 缓存机制总结(JVM内置缓存机制,MyBatis和Hibernate缓存机制,Redis缓存)
一.JVM内置缓存(值存放在JVM缓存中) 我们可以先了解一下Cookie,Session,和Cache Cookie:当你在浏览网站的时候,WEB 服务器会先送一小小资料放在你的计算机上,Cooki ...
- Spring Boot集成EHCache实现缓存机制
SpringBoot 缓存(EhCache 2.x 篇) SpringBoot 缓存 在 Spring Boot中,通过@EnableCaching注解自动化配置合适的缓存管理器(CacheManag ...
- (35)Spring Boot集成Redis实现缓存机制【从零开始学Spring Boot】
[本文章是否对你有用以及是否有好的建议,请留言] 本文章牵涉到的技术点比较多:Spring Data JPA.Redis.Spring MVC,Spirng Cache,所以在看这篇文章的时候,需要对 ...
- Spring Boot从入门到精通(六)集成Redis实现缓存机制
Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言 ...
- Spring Cache 抽象(缓存抽象) Redis 缓存
积少成多 ---- 仅以此致敬和我一样在慢慢前进的人儿 相关内容: https://blog.51cto.com/14230003/2369413?source=dra ...
- Redis整合Spring结合使用缓存实例
林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 摘要:本文介绍了如何在Spring中配置redis,并通过Spring中AOP的思想,将缓存的 ...
随机推荐
- 第八届蓝桥杯java b组第五题
标题:取数位 求1个整数的第k位数字有很多种方法.以下的方法就是一种. 对于题目中的测试数据,应该打印5. 请仔细分析源码,并补充划线部分所缺少的代码. 注意:只提交缺失的代码,不要填写任何已有内容或 ...
- word2vec之tensorflow(skip-gram)实现
关于word2vec的理解,推荐文章https://www.cnblogs.com/guoyaohua/p/9240336.html 代码参考https://github.com/eecrazy/wo ...
- Ubuntu18.04直接安装python3.7或者升级自带的python3.6版本之后导致终端无法打开的解决办法
安装ptyhon3.7 sudo apt-get update sudo apt-get install python3.7 安装成后的目录在/usr/bin/python3.7,同时将其设置成默认 ...
- 基于计算机操作系统的Linux的进程管理
一.实验目的 1.熟悉和理解进程和进程树的概念,掌握有关进程的管理机制. 2.了解进程与程序.并行与串行执行的区别. 3.掌握使用Linux命令管理和操作进程的方法 二.实验内容 1. 用ps命令观察 ...
- python学习笔记之zipfile模块
为什么学习: 在做自动化测试平台的apk上传功能部分时候,涉及到apk上传后提取apk的icon图标,通过aapt解析apk,获取对应icon在apk中的地址,通过python的zipfile模块来解 ...
- 聚类算法之K-means
想想常见的分类算法有决策树.Logistic回归.SVM.贝叶斯等.分类作为一种监督学习方法,要求必须事先明确知道各个类别的信息,并且断言所有待分类项都有一个类别与之对应.但是很多时候上述条件得不到满 ...
- Lxde添加触摸板双击功能、防误触
前言 本文链接:https://www.cnblogs.com/hellxz/p/linux_touchpad_settings.html 这时简单记录一下最近两天折腾Lxde的触摸板功能的设置,留待 ...
- .Net Core 微服务容器系列基础目录篇
1.开场白 HI,各位老铁,大家端午好,之前写了些关于.net core商城系列的文章,有点乱,今天心血来潮想着整理一下(今天只是先把目录列出来,后面的每篇文章这两天会进行重新修改的,目前先将就看下) ...
- VisualStudio自定义调试工具(GIS)
闲言 偶尔分享技术,对,这次就是偶尔,几年一次(技术自卑).上周末竟然有人催更,也是受宠...若惊.以后会主动定期更的,可能. 前言 Visual Studio 调试器自带很多调试工具,调 ...
- IDEA 学习笔记之 1.5已经过时问题
1.5已经过时问题: apache-maven-3.5.0\conf\settings.xml添加: <profile> <id>jdk-1.8</id> < ...