准备测试环境
- 先定义一个简单的角色Pojo
/**
* 因为要序列化对象,所以需要实现Serializable 接口,表明它能够序列化
*/
public class Role implements Serializable {
private String note;
private long id;
private String roleName;
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
- 需要一个Mabatis角色接口
@Repository
public interface RoleMapper {
public int insertRole(Role role);
public int deleterRole(Long id);
public int updateRole(Role role);
public Role getRole(Long it);
public List<Role> findRoles(@Param("roleName")String roleName);
}
- 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" >
<mapper namespace = "com.ssm.chapter21.mapper.RoleMapper">
<!-- 主键回填 -->
<insert id="insertRole" parameterType="com.ssm.chapter21.pojo.Role" useGeneratedKeys="true" keyProperty="id">
insert into t_role(role_name,note) values(#{roleName},#{note})
</insert>
<delete id = "deleterRole" parameterType="long">
delete from t_role where id = #{id}
</delete>
<update id = "updateRole" parameterType="com.ssm.chapter21.pojo.Role">
update t_role set role_name = #{roleName},note = #{note} where id = #{id}
</update>
<select id = "getRole" parameterType = "long" resultType = "com.ssm.chapter21.pojo.Role">
select id,role_name as roleName,note from t_role where id = #{id}
</select>
<select id = "findRoles" parameterType = "string" resultType="com.ssm.chapter21.pojo.Role">
select id,role_name as roleName,note from t_role
where role_name like concat('%',#{roleName},'%')
</select>
</mapper>
- Mybatis配置文件-用于引入Mapper映射文件
<?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>
- 角色服务(Service层)接口
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);
}
- 配置数据库和扫描相关配置文件
@Configuration
//定义spring扫描的包
@ComponentScan("com.*")
//使用事务驱动管理器
@EnableTransactionManagement
public class RootConfig implements TransactionManagementConfigurer{
private DataSource dataSource = null;
/**
* 配置数据库
* @return 数据连接池
*/
@Bean(name="dataSource")
public DataSource initDataSource() {
if(dataSource != null) {
return dataSource;
}
Properties props = new Properties();
props.setProperty("dirverClassName", "com.mysql.jdbc.Driver");
props.setProperty("url", "jdbc:mysql://localhost:3306/ssm");
props.setProperty("username", "root");
props.setProperty("password", "mysql");
try {
dataSource = BasicDataSourceFactory.createDataSource(props);
}catch(Exception e) {
e.printStackTrace();
}
return dataSource;
}
/**
* 配置SqlSessionFactoryBean
* @return SqlSessionFactryBean
*/
@Bean(name="sqlSessionFactory")
public SqlSessionFactoryBean initSqlSessionFactory() {
SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
sqlSessionFactory.setDataSource(dataSource);
//配置Mybatis配置文件
Resource resource = new ClassPathResource("mybatis-config.xml");
sqlSessionFactory.setConfigLocation(resource);
return sqlSessionFactory;
}
/**
* 通过自动扫描,发现Mybatis Mapper接口
* @return
*/
@Bean
public MapperScannerConfigurer initMapperScannerConfigurer() {
MapperScannerConfigurer msc = new MapperScannerConfigurer();
//扫描包
msc.setBasePackage("com.*");
msc.setSqlSessionFactoryBeanName("sqlSessionFactory");
//区分注解扫描
msc.setAnnotationClass(Repository.class);
return msc;
}
/**
* 实现接口方法,注册注解事务,当@Transactional使用的时候产生数据库事务
*/
@Override
@Bean(name="annotationDrivenTransactionManager")
public PlatformTransactionManager annotationDrivenTransactionManager() {
DataSourceTransactionManager tranactionManaer = new DataSourceTransactionManager();
tranactionManaer.setDataSource(initDataSource());
return tranactionManaer;
}
}
配置Spring缓存管理器
在Spring项目中提供了接口CacheManager来定义缓存管理器,而在Spring-data-redis.jar包中实现CacheManager接口的是RedisCacheManager,以下配置类配置了RedisTemplate模板和RedisCacheManaer.
@Configuration
//表示spring Ioc容器启动了缓存机制
@EnableCaching
public class RedisConfig {
//配置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("qjmsystem.top");
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.setHashValueSerializer(jdkSerializationRedisSerializer);
return redisTemplate;
}
public CacheManager initRedisCacheManager(RedisTemplate redisTemplate) {
RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
//设置超时时间为10分钟
cacheManager.setDefaultExpiration(600);
//设置缓存名称
List<String> cacheNames = new ArrayList<String>();
cacheNames.add("redisCacheManager");
cacheManager.setCacheNames(cacheNames);
return cacheManager;
}
@Bean(name = "redisCacheManager")
public CacheManager createCacheManager() {
return initRedisCacheManager(initRedisTemplate());
}
}
缓存注解的使用
注解 | 描述 | 备注 |
@Cacheable | 如果有缓存,则使用缓存,不再执行方法 | 只能用于有返回值的方法中 |
@CachePut | 无论如何会执行方法,并把结果缓存到redis中 | 只能用于有返回值的方法中 |
@CacheEvict | 移除缓存中的key | 可以用于void方法上 |
注: 以上注解通常用于方法上。一般来说,对于查询,使用@Cacheable,对于插入和修改,使用@CachePut,对于删除,使用@CacheEvict
@Cacheable 和 @CacheEvict的注解属性
属性 | 配置类型 | 描述 |
value | string[] | 指定缓存管理器,可以指定多个 |
key | String | spring表达式,指定缓存的key |
condition | String | spring表达式,表达式为false,则不会缓存应用到方法上,true则会 |
unless | String | spring表达式,如果表达式为true,则不会将方法的结果放到缓存上 |
Sping表达式和缓存注解之间的约定
通过这些约定去引用方法的参数和返回值的内容,使得起注入key所定义的Spring表达式结果中。方便使用对应的参数或者返回值作为缓存的key
表达式 | 描述 | 备注 |
#result | 方法返回结果值,还可以使用Sping表达式进一步读取其属性 | 不能用于注解@Cacheable |
#Argument | 任意方法的参数 | 通过#+参数名称去引用 |
@Service
public class RoleServiceImpl implements RoleService {
@Autowired
private RoleMapper roleMapper =null;
/**
* 使用Cacheable定义缓存策略
* 当缓存中有值,则返回缓存数据,否则访问方法得到数据
* 通过value引用缓存管理器,通过key定义键
*
*/
@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);
}
/**
* 使用CacheEvict删除缓存对应的key
*
*/
@Override
@Transactional(isolation= Isolation.READ_COMMITTED,propagation = Propagation.REQUIRED)
@CacheEvict(value="redisCacheManager", key="'redis_role_'+#id")
public int deleteRole(Long id) {
return roleMapper.deleterRole(id);
}
/**
* 使用@CachePut则表示无路如何都会执行方法,最后讲方法的返回值再保存到缓存中
* 使用在插入数据的地方,则表示保存到数据库后,会同期插入Redis缓存中
*
*/
@Override
@Transactional(isolation=Isolation.READ_COMMITTED,propagation=Propagation.REQUIRED)
@CachePut(value="redisCacheManager", key = "'redis_role_'+#result.id")
public Role insertRole(Role role) {
roleMapper.insertRole(role);
return role;
}
/**
* 使用@CachePut,表示更新数据库同时,也会同步更新缓存
*/
@Override
@Transactional(isolation=Isolation.READ_COMMITTED,propagation=Propagation.REQUIRED)
@CachePut(value="redisCacheManager", key = "'redis_role_'+#role.id")
public int updateRole(Role role) {
roleMapper.updateRole(role);
return 0;
}
/**
* 该方法不适合做缓存
*/
@Override
public List<Role> findRoles(String roleName, String note) {
// TODO Auto-generated method stub
return null;
}
}
自此,使用了使用spring注解使用redis缓存