一、Redis和数据库的结合

  使用Redis可以优化性能,但是存在Redis的数据和数据库同步的问题。

  例如,T1时刻以将 key1 保存数据到 Redis,T2时刻刷新进入数据库,但是T3时刻发生了其他业务需要改变数据库同一条记录的数据,但是采用了 key2 保存到Redis中,然后又写入了更新数据到数据库中,这就导致 Redis 中key1 的数据是脏数据,和数据库中的数据不一致。

  

  1.Redis和数据库读操作

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

  

  1. public DataObject readMethod(args) {
  2. DataObject data = getRedis(key);
  3. if(data != null){
  4. data = getFromDataBase();
  5. writeRedis(key, data);
  6. setRedisExpire(key, 5);
  7. }
  8. return data;
  9. }

  2. Redis 和数据库写操作

  写操作要考虑数据一致的问题,尤其是那些重要的业务数据,所以首先应该考虑从数据库中读取最新的数据,然后对数据进行操作,最后把数据写入 Redis 缓存中。

  

  写入业务数据时,应该先从数据库中读取最新数据,然后进行业务操作,更新业务数据到数据库后,再将数据刷新到 Redis 缓存中,这样就能避免将脏数据写入数据库中。

  1. public DataObject writeMethod(args) {
  2. DataObject data = getFromDataBase(args);
  3. ExecLogic(data);
  4. updateDataBase(data);
  5. updateRedisData(data);
  6. }

  二、使用Spring缓存机制整合Redis

  

  

  1.定义一个POJO类和Mybatis

  1. package com.ssm.chapter21.pojo;
  2.  
  3. import java.io.Serializable;
  4.  
  5. public class Role implements Serializable {
  6.  
  7. private static final long serialVersionUID = -1194462093889377366L;
  8.  
  9. private Long id;
  10. private String roleName;
  11. private String note;
  12.  
  13. /**** setter and getter ****/
  14. }

POJO

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  5. <configuration>
  6. <mappers>
  7. <mapper resource="com/ssm/chapter21/mapper/RoleMapper.xml"/>
  8. </mappers>
  9. </configuration>

Mybatis-config.xml

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.ssm.chapter21.dao.RoleDao">
  6.  
  7. <select id="getRole" resultType="com.ssm.chapter21.pojo.Role">
  8. select id, role_name as
  9. roleName, note from t_role where id = #{id}
  10. </select>
  11.  
  12. <delete id="deleteRole">
  13. delete from t_role where id=#{id}
  14. </delete>
  15.  
  16. <insert id="insertRole" parameterType="com.ssm.chapter21.pojo.Role"
  17. useGeneratedKeys="true" keyProperty="id">
  18. insert into t_role (role_name, note) values(#{roleName}, #{note})
  19. </insert>
  20.  
  21. <update id="updateRole" parameterType="com.ssm.chapter21.pojo.Role">
  22. update t_role set role_name = #{roleName}, note = #{note}
  23. where id = #{id}
  24. </update>
  25. <select id="findRoles" resultType="com.ssm.chapter21.pojo.Role">
  26. select id, role_name as roleName, note from t_role
  27. <where>
  28. <if test="roleName != null">
  29. role_name like concat('%', #{roleName}, '%')
  30. </if>
  31. <if test="note != null">
  32. note like concat('%', #{note}, '%')
  33. </if>
  34. </where>
  35. </select>
  36. </mapper>

RoleMapper.xml

  1. package com.ssm.chapter21.dao;
  2.  
  3. import java.util.List;
  4.  
  5. import org.apache.ibatis.annotations.Param;
  6. import org.springframework.stereotype.Repository;
  7.  
  8. import com.ssm.chapter21.pojo.Role;
  9.  
  10. /**** imports ****/
  11. @Repository
  12. public interface RoleDao {
  13.  
  14. public Role getRole(Long id);
  15.  
  16. public int deleteRole(Long id);
  17.  
  18. public int insertRole(Role role);
  19.  
  20. public int updateRole(Role role);
  21.  
  22. public List<Role> findRoles(@Param("roleName") String roleName, @Param("note") String note);
  23. }

RoleDao.java

  1. package com.ssm.chapter21.service;
  2.  
  3. import java.util.List;
  4.  
  5. import com.ssm.chapter21.pojo.Role;
  6.  
  7. public interface RoleService {
  8. public Role getRole(Long id);
  9.  
  10. public int deleteRole(Long id);
  11.  
  12. public Role insertRole(Role role);
  13.  
  14. public int updateRole(Role role);
  15.  
  16. public List<Role> findRoles(String roleName, String note);
  17.  
  18. public int insertRoles(List<Role> roleList);
  19. }

RoleService

  

  2.通过Java配置Spring

  RootConfig.java的定义,其中包含了4个部分

  1. package com.ssm.chapter21.config;/**** imports ****/
  2. @Configuration
  3. // 定义Spring扫描的包
  4. @ComponentScan("com.*")
  5. // 使用事务驱动管理器
  6. @EnableTransactionManagement
  7. // 实现接口TransactionManagementConfigurer,这样可以配置注解驱动事务
  8. public class RootConfig implements TransactionManagementConfigurer {
    private DataSource dataSource = null;
    ...
    }

  (1)配置数据库

  1. /**
  2. * 配置数据库
  3. *
  4. * @return 数据连接池
  5. */
  6. @Bean(name = "dataSource")
  7. public DataSource initDataSource() {
  8. if (dataSource != null) {
  9. return dataSource;
  10. }
  11. Properties props = new Properties();
  12. props.setProperty("driverClassName", "com.mysql.jdbc.Driver");
  13. props.setProperty("url", "jdbc:mysql://localhost:3306/chapter6?useSSL=false");
  14. props.setProperty("username", "root");
  15. props.setProperty("password", "bjtungirc");
  16. try {
  17. dataSource = BasicDataSourceFactory.createDataSource(props);
  18. } catch (Exception e) {
  19. e.printStackTrace();
  20. }
  21. return dataSource;
  22. }

  (2)配置SqlSessionFactoryBean

  1. /**
  2. * * 配置SqlSessionFactoryBean
  3. *
  4. * @return SqlSessionFactoryBean
  5. */
  6. @Bean(name = "sqlSessionFactory")
  7. public SqlSessionFactoryBean initSqlSessionFactory() {
  8. SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
  9. sqlSessionFactory.setDataSource(initDataSource());
  10. // 加载Mybatis配置文件
  11. Resource resource = new ClassPathResource("mybatis/mybatis-config.xml");
  12. sqlSessionFactory.setConfigLocation(resource);
  13. return sqlSessionFactory;
  14. }

  (3)配置Mybatis Mapper

  1. /**
  2. * * 通过自动扫描,发现Mybatis Mapper映射器
  3. *
  4. * @return Mapper映射器
  5. */
  6. @Bean
  7. public MapperScannerConfigurer initMapperScannerConfigurer() {
  8. MapperScannerConfigurer msc = new MapperScannerConfigurer();
  9. // 定义扫描包
  10. msc.setBasePackage("com.*");
  11. msc.setSqlSessionFactoryBeanName("sqlSessionFactory");
  12. // 区分注解扫描
  13. msc.setAnnotationClass(Repository.class);
  14. return msc;
  15. }

  (4)配置注解驱动,使得@Transactional可以触发事务

  1. /**
  2. * 实现接口方法,注册注解事务,当@Transactional使用的时候产生数据库事务
  3. */
  4. @Override
  5. @Bean(name = "annotationDrivenTransactionManager")
  6. public PlatformTransactionManager annotationDrivenTransactionManager() {
  7. DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
  8. transactionManager.setDataSource(initDataSource());
  9. return transactionManager;
  10. }

  3.通过Java配置RedisTemplate和Redis缓存管理器

  RedisConfig.java,其中包含两个部分,RedisTemplate和Redis缓存管理器

  其中@EnableCaching 表示Spring IoC 容器启动了缓存机制。

  1. package com.ssm.chapter21.config;/**** imports ****/
  2. @Configuration
  3. @EnableCaching
  4. public class RedisConfig {...}

  (1)RedisTemplate配置

  1. @Bean(name = "redisTemplate")
  2. public RedisTemplate initRedisTemplate() {
  3. JedisPoolConfig poolConfig = new JedisPoolConfig();
  4. // 最大空闲数
  5. poolConfig.setMaxIdle(50);
  6. // 最大连接数
  7. poolConfig.setMaxTotal(100);
  8. // 最大等待毫秒数
  9. poolConfig.setMaxWaitMillis(20000);
  10. // 创建 Jedis 连接工厂
  11. JedisConnectionFactory connectionFactory = new JedisConnectionFactory(poolConfig);
  12. connectionFactory.setHostName("localhost");
  13. connectionFactory.setPort(6379);
  14. // 调用后初始化方法,没有它将抛出异常
  15. connectionFactory.afterPropertiesSet();
  16. // 自定义两个Redis序列化器
  17. RedisSerializer jdkSerializationRedisSerializer = new JdkSerializationRedisSerializer();
  18. RedisSerializer stringRedisSerializer = new StringRedisSerializer();
  19. // 定义RedisTemplate对象,并设置连接工程
  20. RedisTemplate redisTemplate = new RedisTemplate();
  21. redisTemplate.setConnectionFactory(connectionFactory);
  22. // 设置序列化器
  23. redisTemplate.setDefaultSerializer(stringRedisSerializer);
  24. redisTemplate.setKeySerializer(stringRedisSerializer);
  25. redisTemplate.setValueSerializer(jdkSerializationRedisSerializer);
  26. redisTemplate.setHashKeySerializer(stringRedisSerializer);
  27. redisTemplate.setHashValueSerializer(jdkSerializationRedisSerializer);
  28. return redisTemplate;
  29. }

  (2)配置Redis缓存管理器

  定义默认超时时间为10分钟,这样就可以在一定的时间间隔后重新从数据库中读取数据了。另外redisCacheManager名称在之后的业务方法中也会用到。

  1. @Bean(name = "redisCacheManager")
  2. public CacheManager initRedisCacheManager(@Autowired RedisTemplate redisTempate) {
  3. RedisCacheManager cacheManager = new RedisCacheManager(redisTempate);
  4. // 设置默认超时时间,为10分钟
  5. cacheManager.setDefaultExpiration(600);
  6. // 设置缓存管理器名称
  7. List<String> cacheNames = new ArrayList<String>();
  8. cacheNames.add("redisCacheManager");
  9. cacheManager.setCacheNames(cacheNames);
  10. return cacheManager;
  11. }

  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接口的实现类中的方法的定义为:

  1. package com.ssm.chapter21.service.impl;/**** imports ****/
  2. @Service
  3. public class RoleServiceImpl implements RoleService {
  4. // 角色DAO,方便执行SQL
  5. @Autowired
  6. private RoleDao roleDao = null;
       ...
    }

  (1)使用@Cacheable注解的getRole方法

  在Spring的调用中,会先查询Redis中看是否存在key为redis_role_id的键值对,如果有,就返回结果。如果没有,就访问getRole方法,从数据库中查询到数据,返回给调用者,然后将键值对redis_role_id---roleDao.getRole(id)保存到Redis中。

  1. /**
  2. * 使用@Cacheable定义缓存策略 当缓存中有值,则返回缓存数据,否则访问方法得到数据 通过value引用缓存管理器,通过key定义键
  3. * @param id 角色编号
  4. * @return 角色对象
  5. */
  6. @Override
  7. @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
  8. @Cacheable(value = "redisCacheManager", key = "'redis_role_'+#id")
  9. public Role getRole(Long id) {
  10. return roleDao.getRole(id);
  11. }

  (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缓存管理器定义的过程。

  1. /**
  2. * 使用@CachePut则表示无论如何都会执行方法,最后将方法的返回值再保存到缓存中
  3. * 使用在插入数据的地方,则表示保存到数据库后,会同期插入到Redis缓存中
  4. *
  5. * @param role 角色对象
  6. * @return 角色对象(会回填主键)
  7. */
  8. @Override
  9. @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
  10. @CachePut(value = "redisCacheManager", key = "'redis_role_'+#result.id")
  11. public Role insertRole(Role role) {
  12. roleDao.insertRole(role);
  13. return role;
  14. }
  15.  
  16. /**
  17. * 使用@CachePut,表示更新数据库数据的同时,也会同步更新缓存
  18. *
  19. * @param role 角色对象
  20. * @return 影响条数
  21. */
  22. @Override
  23. @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
  24. @CachePut(value = "redisCacheManager", key = "'redis_role_'+#role.id")
  25. public int updateRole(Role role) {
  26. return roleDao.updateRole(role);
  27. }

  (3)使用@CacheEvict注解的deleteRole方法在方法,可以执行完成后会移除对应的缓存,

  1. /**
  2. * 使用@CacheEvict删除缓存对应的key
  3. *
  4. * @param id 角色编号
  5. * @return 返回删除记录数
  6. */
  7. @Override
  8. @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
  9. @CacheEvict(value = "redisCacheManager", key = "'redis_role_'+#id")
  10. public int deleteRole(Long id) {
  11. return roleDao.deleteRole(id);
  12. }

  (4)测试@CachePut注解、@Cacheable和@CacheEvict注解:

  1. package com.ssm.chapter21.main;
  2. public class Chapter21Main {
  3.  
  4. public static void main(String[] args) {
  5. //使用注解Spring IoC容器
  6. ApplicationContext ctx = new AnnotationConfigApplicationContext(RootConfig.class, RedisConfig.class);
  7. //获取角色服务类
  8. RoleService roleService = ctx.getBean(RoleService.class);
  9. Role role = new Role();
  10. role.setRoleName("role_name_1");
  11. role.setNote("role_note_1");
  12. //插入角色
  13. roleService.insertRole(role);
  14. //获取角色
  15. Role getRole = roleService.getRole(role.getId());
  16. getRole.setNote("role_note_1_update");
  17. //更新角色
  18. roleService.updateRole(getRole);
  19. //删除角色
  20. roleService.deleteRole(getRole.getId());
  21. }
  22.  
  23. }

  输出日志:

  在第二部分getRole部分可以看到,只出现了两次Opening RedisConnection和Closing Redis Connection而没有出现任何SQL执行,因为在Redis中已经先查找到了对应的数据。

  1. 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
  2. Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@71e2843b]
  3. JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] will be managed by Spring
  4. ==> Preparing: insert into t_role (role_name, note) values(?, ?)
  5. ==> Parameters: role_name_1(String), role_note_1(String)
  6. <== Updates: 1Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@71e2843b]
  7. Opening RedisConnection
  8. Closing Redis Connection
  9. Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@71e2843b]
  10. Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@71e2843b]
  11. Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@71e2843b]
  12. Initiating transaction commit
  13. Committing JDBC transaction on Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver]
  14. Resetting isolation level of JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] to 4
  15. Releasing JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] after transaction
  16. Returning JDBC Connection to DataSource
  17. 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']
  18. 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
  19. Changing isolation level of JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] to 2
  20. Switching JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] to manual commit
  21. Opening RedisConnection
  22. Closing Redis Connection
  23. Opening RedisConnection
  24. Closing Redis Connection
  25. Initiating transaction commit
  26. Committing JDBC transaction on Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver]
  27. Resetting isolation level of JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] to 4
  28. Releasing JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] after transaction
  29. Returning JDBC Connection to DataSource
  30.  
  31. 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='']
  32. 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
  33. DChanging isolation level of JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] to 2
  34. Switching JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] to manual commitCreating a new SqlSession
  35. Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6636448b]
  36. JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] will be managed by Spring
  37. ==> Preparing: update t_role set role_name = ?, note = ? where id = ? ==> Parameters: role_name_1(String), role_note_1_update(String), 7(Long)
  38. <== Updates: 1Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6636448b]
  39. Opening RedisConnection
  40. Closing Redis Connection
  41. Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6636448b]
  42. Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6636448b]
  43. Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6636448b]
  44. Initiating transaction commit
  45. Committing JDBC transaction on Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver]
  46. Resetting isolation level of JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] to 4
  47. Releasing JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] after transaction
  48. Returning JDBC Connection to DataSource
  49.  
  50. 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]
  51. 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
  52. Changing isolation level of JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] to 2
  53. Switching JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] to manual commitCreating a new SqlSession
  54. Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1c681761]
  55. JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] will be managed by Spring
  56. ==> Preparing: delete from t_role where id=?==> Parameters: 7(Long)
  57. <== Updates: 1Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1c681761]
  58. Opening RedisConnection
  59. Closing Redis Connection
  60. Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1c681761]
  61. Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1c681761]
  62. Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1c681761]
  63. Initiating transaction commit
  64. Committing JDBC transaction on Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver]
  65. Resetting isolation level of JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] to 4
  66. Releasing JDBC Connection [jdbc:mysql://localhost:3306/chapter6?useSSL=false, UserName=root@, MySQL-AB JDBC Driver] after transaction
  67. Returning JDBC Connection to DataSource

  (4)findRoles方法

  使用缓存的前提是----高命中率。由于这里根据角色名称和备注查找角色信息,该方法的返回值会根据查询条件而多样化,导致其不确定和命中率低下,这种情况下使用缓存并不能有效提高性能,所以findRoles方法就不必使用缓存注解来进行标注了。

  1. @Override
  2. @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
  3. public List<Role> findRoles(String roleName, String note) {
  4. return roleDao.findRoles(roleName, note);
  5. }

  (5)insertRoles方法

  insertRoles方法中调用了insertRole方法,而insertRole方法本身带有注解@CachePut,这时如果要执行insertRoles方法,会发现缓存失效了。

  这里失效的原因是和之前讨论过的数据库事务失效的情况一样,由于缓存注解也是使用了Spring AOP 来实现,而Spring AOP使用了动态代理,即只有代理对象的相互调用,AOP才具有拦截功能。而这里的自调用是没有代理对象存在的,因此注解功能失效。

  1. @Override
  2. @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
  3. public int insertRoles(List<Role> roleList) {
  4. for (Role role : roleList) {
  5. //同一类的方法调用自己方法,产生自调用[插入:失效]问题
  6. this.insertRole(role);
  7. }
  8. return roleList.size();
  9. }

  

Spring(五)Spring缓存机制与Redis的结合的更多相关文章

  1. net core Webapi基础工程搭建(五)——缓存机制

    目录 前言 Cache Session Cookie 小结 补充 前言 作为WebApi接口工程,性能效率是必不可少的,每次的访问请求,数据库读取,业务逻辑处理都或多或少耗费时间,偶尔再来个各种花式f ...

  2. hbase 学习(十五)缓存机制以及可以利用SSD作为存储的BucketCache

    下面介绍Hbase的缓存机制: a.HBase在读取时,会以Block为单位进行cache,用来提升读的性能 b.Block可以分类为DataBlock(默认大小64K,存储KV).BloomBloc ...

  3. 15 hbase 学习(十五)缓存机制以及可以利用SSD作为存储的BucketCache

    下面介绍Hbase的缓存机制:  a.HBase在读取时,会以Block为单位进行cache,用来提升读的性能 b.Block可以分类为DataBlock(默认大小64K,存储KV).BloomBlo ...

  4. 缓存机制总结(JVM内置缓存机制,MyBatis和Hibernate缓存机制,Redis缓存)

    一.JVM内置缓存(值存放在JVM缓存中) 我们可以先了解一下Cookie,Session,和Cache Cookie:当你在浏览网站的时候,WEB 服务器会先送一小小资料放在你的计算机上,Cooki ...

  5. Spring Boot集成EHCache实现缓存机制

    SpringBoot 缓存(EhCache 2.x 篇) SpringBoot 缓存 在 Spring Boot中,通过@EnableCaching注解自动化配置合适的缓存管理器(CacheManag ...

  6. (35)Spring Boot集成Redis实现缓存机制【从零开始学Spring Boot】

    [本文章是否对你有用以及是否有好的建议,请留言] 本文章牵涉到的技术点比较多:Spring Data JPA.Redis.Spring MVC,Spirng Cache,所以在看这篇文章的时候,需要对 ...

  7. Spring Boot从入门到精通(六)集成Redis实现缓存机制

    Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言 ...

  8. Spring Cache 抽象(缓存抽象) Redis 缓存

        积少成多 ----  仅以此致敬和我一样在慢慢前进的人儿 相关内容: https://blog.51cto.com/14230003/2369413?source=dra           ...

  9. Redis整合Spring结合使用缓存实例

    林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 摘要:本文介绍了如何在Spring中配置redis,并通过Spring中AOP的思想,将缓存的 ...

随机推荐

  1. (java实现)单向循环链表

    什么是单向循环链表 单向循环链表基本与单向链表相同,唯一的区别就是单向循环链表的尾节点指向的不是null,而是头节点(注意:不是头指针). 因此,单向循环链表的任何节点的下一部分都不存在NULL值. ...

  2. Java 内存模型与内存结构

    Java内存模型 一.简介 Java内存模型(JMM)主要是为了规定线程和内存之间的一些关系:根据JMM的设计,系统存在一个主内存(Main Memory)和工作内存(Work Memory),Jav ...

  3. element取表格对应id数据

    <el-button size="mini" type="danger" @click="editor(scope.row)"> ...

  4. IBM MQ8.0常用操作

    一.创建队列管理器 1.创建队列管理器QM1:crtmqm -q QM1 2.删除队列管理器QM1:dltmqm QM1 3.启动队列管理器QM1:strmqm QM1 4.停止队列管理器QM1:en ...

  5. [ASP.NET Core 3框架揭秘] 跨平台开发体验: Docker

    对于一个 .NET Core开发人员,你可能没有使用过Docker,但是你不可能没有听说过Docker.Docker是Github上最受欢迎的开源项目之一,它号称要成为所有云应用的基石,并把互联网升级 ...

  6. 对BFC规范的理解

    什么是BFC? BFC 全称为 块级格式化上下文(Block Fromatting Context),是Web页面的可视化CSS渲染出的一部分.它是块级盒布局出现的区域,也是浮动层元素进行交互的区域. ...

  7. laravel学习之旅

    前言:之前写了二篇YII2.0的基本mvc操作,所以,打算laravel也来这一下 *安装现在一般都用composer安装,这里就不讲述了* 一.熟悉laravel (1)如果看到下面这个页面,就说明 ...

  8. for循环练习题1——水仙花数

    /*输出所有的水仙花数,所谓水仙花数是指一个3位数,其各个位上数 字立方和等于其本身. 例如: 153 = 1*1*1 + 3*3*3 + 5*5*5 */class ForTest3{ public ...

  9. python 安装pyqt

    ---恢复内容开始--- 一.安装 1.官网:www.riverbankcomputing.com 2.使用命令安装,可以自动去官网查找与Python版本号相同的程序进行下载,比较方便,如果不是这样也 ...

  10. HTML innerHTML、textContext、innerText

    网址 : https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML 1.innerHTML : 获得.修改元素的用HTML语 ...