Spring快取機制和Redis的結合
阿新 • • 發佈:2018-12-15
- 這裡使用reids作為快取。
- 使用Mybatis來操作資料庫。
- 並使用Spring的@Cacheable,@CachePut,@CacheEvict註解來操作redis快取。
1 準備環境
包結構
1 Spring配置 RootConfig.java
@Configuration @ComponentScan(basePackages="cn.wu") @EnableTransactionManagement public class RootConfig { // 配置資料來源 @Bean public DataSource initDataSource() { DataSource dataSource = null; Properties properties = new Properties(); properties.setProperty("driverClassName", "com.mysql.jdbc.Driver"); properties.setProperty("url", "jdbc:mysql://localhost:3306/ssm?useSSL=false"); properties.setProperty("username", "root"); properties.setProperty("password", "資料庫連線密碼"); try { dataSource = BasicDataSourceFactory.createDataSource(properties); } catch (Exception e) { e.printStackTrace(); } return dataSource; } // 配置mybatis的SqlSession的工廠 @Bean(name="sqlSessionFactory") public SqlSessionFactoryBean initSqlSessionFactoryBean() { SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(initDataSource()); // 設定dataSource Resource resource = new ClassPathResource("mybatis-config.xml"); sqlSessionFactoryBean.setConfigLocation(resource); // 設定mybatis配置檔案 return sqlSessionFactoryBean; } // 配置mybatis對映器的掃描器 @Bean public MapperScannerConfigurer initMapperScannerConfigurer() { MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer(); mapperScannerConfigurer.setBasePackage("cn.wu.mapper"); mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory"); mapperScannerConfigurer.setAnnotationClass(Repository.class); return mapperScannerConfigurer; } // 配置事務管理器 @Bean public PlatformTransactionManager initTransactionManager() { DataSourceTransactionManager transactionManage = new DataSourceTransactionManager(); transactionManage.setDataSource(initDataSource()); return transactionManage; } }
mybatis-config.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>
</configuration>
2 使用Redis作為快取的相關配置RedisConfig.java
@Configuration @EnableCaching // 讓Spring IOC容器啟動快取機制 public class RedisConfig { @Bean public RedisConnectionFactory initRedisConnectionFactory() { JedisPoolConfig poolConfig = new JedisPoolConfig(); poolConfig.setMaxIdle(50); poolConfig.setMaxTotal(100); poolConfig.setMaxWaitMillis(20000); JedisConnectionFactory connectionFactory = new JedisConnectionFactory(poolConfig); connectionFactory.setHostName("localhost"); connectionFactory.setPort(6379); return connectionFactory; } @Bean public RedisTemplate initRedisTemplate() { RedisTemplate redisTemplate = new RedisTemplate(); redisTemplate.setConnectionFactory(initRedisConnectionFactory()); StringRedisSerializer stringSerializer = new StringRedisSerializer(); JdkSerializationRedisSerializer jdkSSerializer = new JdkSerializationRedisSerializer(); redisTemplate.setKeySerializer(stringSerializer); redisTemplate.setValueSerializer(jdkSSerializer); redisTemplate.setDefaultSerializer(stringSerializer); redisTemplate.setHashKeySerializer(stringSerializer); redisTemplate.setHashValueSerializer(jdkSSerializer); return redisTemplate; } /* * 配置Spring快取管理器 * 這裡的快取管理器是RedisCacheManager。 * RedisCacheManager實現了Spring的CacheManager介面 */ @Bean(name = "redisCacheManager") public CacheManager initRedisCacheManager(@Autowired RedisTemplate redisTemplate) { RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate); // 設定鍵的超時時間為10分鐘 redisCacheManager.setDefaultExpiration(600L); // 設定快取名稱 List<String> cacheNames = new ArrayList<>(); cacheNames.add("redisCacheManager"); redisCacheManager.setCacheNames(cacheNames); return redisCacheManager; } }
2 Mybatis對映器程式碼與配置
1 Role.java
public class Role implements Serializable{
private static final long serialVersionUID = -4295925571801283375L;
private Long id;
private String roleName;
private String note;
// getter setter
}
2 RoleMapper.java
@Repository public interface RoleMapper { Role getRole(Long id); int deleteRole(Long id); int insertRole(Role role); int updateRole(Role role); List<Role> findRoles(@Param("roleName")String roleName, @Param("note")String note); }
3 RoleMapper.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="cn.wu.mapper.RoleMapper">
<select id="getRole" parameterType="long"
resultType="cn.wu.domain.Role">
select id, role_name as roleName, note from t_role where id
= #{id}
</select>
<delete id="deleteRole" parameterType="long">
delete from t_role where
id = #{id}
</delete>
<insert id="insertRole" parameterType="cn.wu.domain.Role"
useGeneratedKeys="true" keyProperty="id">
insert into t_role(role_name,
note) values(#{roleName}, #{note})
</insert>
<update id="updateRole" parameterType="cn.wu.domain.Role">
update t_role set
role_name = #{roleName}, note = #{note} where id = #{id}
</update>
<select id="findRoles" resultType="cn.wu.domain.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>
3 使用對映器的Service程式碼
RoleService.java
public interface RoleService {
Role getRole(Long id);
int deleteRole(Long id);
Role insertRole(Role role);
Role updateRole(Role role);
List<Role> findRoles(String roleName, String note);
}
RoleServiceImpl.java
@Service
public class RoleServiceImpl implements RoleService {
@Autowired
private RoleMapper roleMapper;
/**
* value = "redisCacheManager"表示使用的快取名稱(這裡使用的是RedisConfig中配置的快取管理器名稱)
* key = "'redis_role_'+#id" 表示快取到redis時的key
*
* @Cacheable 表示在執行getRole()程式碼前,先到redis查詢對應key的快取,
* 若存在快取則直接返回快取;
* 若快取不存在,則執行資料庫查詢程式碼,然後將結果快取到redis,其key為"'redis_role_'+#id"。
* 所以@Cacheable 適合放在查詢命中率高的方法上
*/
@Override
@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
@Cacheable(value = "redisCacheManager", key = "'redis_role_'+#id")
public Role getRole(Long id) {
return roleMapper.getRole(id);
}
/**
* @CachePut , 不管有沒有快取,insertRole()程式碼都會去執行,然後將返回的結果快取到redis中。
* 所以@CachePut 適合放在插入和更新資料庫的方法上。
*/
@Override
@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
@CachePut(value="redisCacheManager",key="'redis_role_'+#role.id")
public Role insertRole(Role role) {
roleMapper.insertRole(role);
return role;
}
/**
* @CacheEvict 表示刪除redis中的快取,這裡刪除的時key="'redis_role_'+#id"的快取
*/
@Override
@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
@CacheEvict(value="redisCacheManager", key="'redis_role_'+#id")
public int deleteRole(Long id) {
return roleMapper.deleteRole(id);
}
@Override
@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
@CachePut(value="redisCacheManager", key="'redis_role_'+#role.id")
public Role updateRole(Role role) {
roleMapper.updateRole(role);
return role;
}
@Override
public List<Role> findRoles(String roleName, String note) {
return roleMapper.findRoles(roleName, note);
}
}
4 測試
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(RootConfig.class, RedisConfig.class);
RoleService roleService = context.getBean(RoleService.class);
Role role = new Role();
role.setRoleName("李華");
role.setNote("好人");
roleService.insertRole(role); // reids中快取了key=redis_role_67,值為role物件
System.out.println(role); // Role [id=67, roleName=李華, note=好人]
Role role2 = roleService.getRole(role.getId()); // 沒有執行資料庫查詢語句,而是直接返回了redis中的快取
role2.setNote("備註好人");
roleService.updateRole(role2);// 更新了資料庫中的記錄和reids中的快取
}
}