Spring缓存管理Demo:实现对用户信息CURD的缓存管理,上述理论的确枯燥无味,而且还容易让人头大,看了很多博客和分析,搭建一个测试Demo吧,好记性不如烂笔头。
1. User数据表创建
2. 基础SpringBoot项目环境搭建
3. Dao层
4. Service层
5. Controller层
6. 测试结果
1.数据表创建
CREATE TABLE `users` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`uuid` varchar(255) NOT NULL,
`name` varchar(255) NOT NULL,
`age` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
2.基础SpringBoot项目环境搭建
在IDEA中创建SpringBoot项目很简单,包括依赖的导入。
File - New Project - Springinitializr - default - https://start.spring.io/
配置项目中的相关参数,采用maven构建项目,可勾选依赖,根据个人需要,注意弹出框右上角有选择Springboot版本的按钮,默认2.0+,改成1.5即可。
Springboot2.0和Springboot1.0有些许差距,建议选择Springboot1.0版本
基础项目创建完成之后,需要添加cache方面的相关依赖。
<!--开启 cache 缓存-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!-- ehcache 缓存 -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<!--log4j2日志-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<!--Druid数据连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.20</version>
</dependency>
在resources目录下编辑application.properties文件:
# 数据库驱动配置信息
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.url = jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf-8
spring.datasource.username = root
spring.datasource.password = 1234
spring.datasource.driverClassName = com.mysql.jdbc.Driver
# Druid连接池的配置信息
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=20
spring.datasource.maxWait=60000
spring.datasource.timeBetweenEvictionRunsMillis=60000
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
spring.datasource.poolPreparedStatements=true
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
spring.datasource.filters=stat,wall,log4j
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
# Log4j2 配置
logging.config=classpath:log4j2.xml
resources添加配置文件:
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--启动项设置为 trace,加载 springboot 启动内部各种详细输出-->
<Configuration status="trace">
<Appenders>
<!--添加一个控制台追加器-->
<Console name="Console" target="SYSTEM_OUT" follow="true">
<PatternLayout>
<pattern>[%-5p] %d %c - %m%n</pattern>
</PatternLayout>
</Console>
<!--添加一个文本追加器,文件位于根目录下,名为log.log-->
<File name="File" fileName="log.log">
<PatternLayout>
<pattern>[%-5p] %d %c - %m%n</pattern>
</PatternLayout>
</File>
</Appenders>
<Loggers>
<Logger name="org.apache.catalina.util.LifecycleBase" level="error" />
<Logger name="org.apache.coyote.http11.Http11NioProtocol" level="warn" />
<Logger name="org.apache.tomcat.util.net.NioSelectorPool" level="warn" />
<Logger name="org.hibernate.validator.internal.util.Version" level="warn" />
<Logger name="org.springframework" level="warn" />
<Logger name="com.github" level="debug" />
<!--记录 qg.fangrui.boot 包及其子包 debug 及其以上的记录,并输出到文件中-->
<Logger name="qg.fangrui.boot" level="debug">
<!-- AppenderRef 可以控制文件输出对象-->
<AppenderRef ref="File" />
</Logger>
<!--根记录全部输出到控制台上-->
<Root level="debug">
<AppenderRef ref="Console" />
</Root>
</Loggers>
</Configuration>
ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false">
<defaultCache
eternal="false"
maxElementsInMemory="1000"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="0"
timeToLiveSeconds="600"
memoryStoreEvictionPolicy="LRU" />
<!-- 自定义缓存策略 通过name进行缓存策略的区分 这里的缓存策略名为users-->
<cache
name="users"
eternal="false"
maxElementsInMemory="100"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="0"
timeToLiveSeconds="300"
memoryStoreEvictionPolicy="LRU" />
</ehcache>
启动主类:Application.java添加@EnableCaching缓存开启注解
3.Dao层
mybatis3.0+后可以通过注解替代mapper文件。
@Mapper
public interface UserDao {
@Select("select * from users where uuid = #{uuid}")
User getUserByUuid(String uuid);
@Insert("insert into users (uuid, name, age) values (#{uuid}, #{name}, #{age})")
int addUser(User user);
@Update("update users set uuid = #{uuid}, name = #{name}, age = #{age} where uuid = #{uuid}")
int updateUser(User user);
@Delete("delete from users where uuid = #{uuid}")
void deleteUser(String uuid);
}
4.Service层
service层采用了接口+实现类的方式进行处理。缓存管理系列注解上述已经说明。
@Service
public class UserServiceImpl implements UserService{
//对应ehcache.xml中的缓存策略名称
private static final String CACHE_NAME = "users";
@Autowired
private UserDao userDao;
@Override
public int addUser(User user) {
return userDao.addUser(user);
}
@CacheEvict(value = CACHE_NAME, key = "'user_' + #uuid")
@Override
public void deleteUser(String uuid) {
userDao.deleteUser(uuid);
}
@Cacheable(value = CACHE_NAME, key = "'user_' + #uuid")
@Override
public User getUserByUuid(String uuid) {
System.out.println("此处查询了数据库:用户UUID为" + uuid);
return userDao.getUserByUuid(uuid);
}
@CacheEvict(value = CACHE_NAME, key = "'user_' + #user.getUuid()")
@Override
public int updateUser(User user) throws Exception {
User temp = userDao.getUserByUuid(user.getUuid());
if (null == temp) {
throw new Exception("未找到待修改对象");
}
temp.setName(user.getName());
temp.setAge(user.getAge());
return userDao.updateUser(temp);
}
}
5.Controller层:这里的添加、修改、删除后分别进行了三次数据查询。
@Controller
public class UserController {
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
//定义全局测试用户
User user = new User(UUID.randomUUID().toString(), "张三", 18);
@Autowired
private UserService userService;
@RequestMapping(value = "/ehcache")
@ResponseBody
public String ehcache() throws Exception {
System.out.println("构建测试用户");
if (userService.addUser(user) == 0) {
logger.debug("新建用户失败");
throw new Exception();
}
logger.debug("新建用户成功");
System.out.println(userService.getUserByUuid(user.getUuid()));
System.out.println(userService.getUserByUuid(user.getUuid()));
System.out.println(userService.getUserByUuid(user.getUuid()));
System.out.println("测试修改");
user.setName("张三改");
user.setAge(20);
if (userService.updateUser(user) == 0) {
logger.debug("修改用户失败");
throw new Exception();
}
logger.debug("修改用户成功");
System.out.println(userService.getUserByUuid(user.getUuid()));
System.out.println(userService.getUserByUuid(user.getUuid()));
System.out.println(userService.getUserByUuid(user.getUuid()));
System.out.println("测试删除");
userService.deleteUser(user.getUuid());
System.out.println(userService.getUserByUuid(user.getUuid()));
System.out.println(userService.getUserByUuid(user.getUuid()));
System.out.println(userService.getUserByUuid(user.getUuid()));
return "测试完毕";
}
}
6.测试结果
启动项目,测试请求:localhost:8080/ehcache
观察控制台打印的结果数据:
1. 构建测试用户
[DEBUG] 2018-08-09 11:39:28,553 org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession
[DEBUG] 2018-08-09 11:39:28,556 org.mybatis.spring.SqlSessionUtils - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4be30c72] was not registered for synchronization because synchronization is not active
[INFO ] 2018-08-09 11:39:28,585 com.alibaba.druid.pool.DruidDataSource - {dataSource-1} inited
[DEBUG] 2018-08-09 11:39:28,708 org.mybatis.spring.transaction.SpringManagedTransaction - JDBC Connection [com.mysql.jdbc.JDBC4Connection@4b6ca547] will not be managed by Spring
[DEBUG] 2018-08-09 11:39:28,711 com.jyf.ex.ehcache.dao.UserDao.addUser - ==> Preparing: insert into users (uuid, name, age) values (?, ?, ?)
[DEBUG] 2018-08-09 11:39:28,723 com.jyf.ex.ehcache.dao.UserDao.addUser - ==> Parameters: 6e790f91-e5ab-4a26-8b49-17d2816cd6ce(String), 张三(String), 18(Integer)
[DEBUG] 2018-08-09 11:39:28,725 com.jyf.ex.ehcache.dao.UserDao.addUser - <== Updates: 1
[DEBUG] 2018-08-09 11:39:28,726 org.mybatis.spring.SqlSessionUtils - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4be30c72]
[DEBUG] 2018-08-09 11:39:28,726 com.jyf.ex.ehcache.controller.UserController - 新建用户成功
2. 添加后查询:
此处查询了数据库:用户UUID为84bebbe5-b870-446f-96cc-39277e869aec
[DEBUG] 2018-08-09 12:47:28,638 org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession
[DEBUG] 2018-08-09 12:47:28,638 org.mybatis.spring.SqlSessionUtils - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2b1e955f] was not registered for synchronization because synchronization is not active
[DEBUG] 2018-08-09 12:47:28,639 org.mybatis.spring.transaction.SpringManagedTransaction - JDBC Connection [com.mysql.jdbc.JDBC4Connection@755d3205] will not be managed by Spring
[DEBUG] 2018-08-09 12:47:28,639 com.jyf.ex.ehcache.dao.UserDao.getUserByUuid - ==> Preparing: select * from users where uuid = ?
[DEBUG] 2018-08-09 12:47:28,639 com.jyf.ex.ehcache.dao.UserDao.getUserByUuid - ==> Parameters: 84bebbe5-b870-446f-96cc-39277e869aec(String)
[DEBUG] 2018-08-09 12:47:28,647 com.jyf.ex.ehcache.dao.UserDao.getUserByUuid - <== Total: 1
[DEBUG] 2018-08-09 12:47:28,648 org.mybatis.spring.SqlSessionUtils - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2b1e955f]
User{id=6, uuid='84bebbe5-b870-446f-96cc-39277e869aec', name='张三', age=18} //查询数据库并加入缓存
User{id=6, uuid='84bebbe5-b870-446f-96cc-39277e869aec', name='张三', age=18} //查询缓存
User{id=6, uuid='84bebbe5-b870-446f-96cc-39277e869aec', name='张三', age=18} //查询缓存
由于在数据查询service层业务逻辑中加入了打印标识。这里只出现了一条标识,说明访问数据库一次后,将查询结果放入缓存,第二三此查询均从缓存中进行查询。
3. 修改后查询
[DEBUG] 2018-08-09 12:47:28,652 org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession
[DEBUG] 2018-08-09 12:47:28,652 org.mybatis.spring.SqlSessionUtils - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1a69a910] was not registered for synchronization because synchronization is not active
[DEBUG] 2018-08-09 12:47:28,652 org.mybatis.spring.transaction.SpringManagedTransaction - JDBC Connection [com.mysql.jdbc.JDBC4Connection@755d3205] will not be managed by Spring
[DEBUG] 2018-08-09 12:47:28,652 com.jyf.ex.ehcache.dao.UserDao.updateUser - ==> Preparing: update users set uuid = ?, name = ?, age = ? where uuid = ?
[DEBUG] 2018-08-09 12:47:28,652 com.jyf.ex.ehcache.dao.UserDao.updateUser - ==> Parameters: 84bebbe5-b870-446f-96cc-39277e869aec(String), 张三改(String), 20(Integer), 84bebbe5-b870-446f-96cc-39277e869aec(String)
[DEBUG] 2018-08-09 12:47:28,654 com.jyf.ex.ehcache.dao.UserDao.updateUser - <== Updates: 1
[DEBUG] 2018-08-09 12:47:28,654 org.mybatis.spring.SqlSessionUtils - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1a69a910]
[DEBUG] 2018-08-09 12:47:28,658 com.jyf.ex.ehcache.controller.UserController - 修改用户成功
此处查询了数据库:用户UUID为84bebbe5-b870-446f-96cc-39277e869aec
[DEBUG] 2018-08-09 12:47:28,659 org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession
[DEBUG] 2018-08-09 12:47:28,659 org.mybatis.spring.SqlSessionUtils - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7b5c042d] was not registered for synchronization because synchronization is not active
[DEBUG] 2018-08-09 12:47:28,659 org.mybatis.spring.transaction.SpringManagedTransaction - JDBC Connection [com.mysql.jdbc.JDBC4Connection@755d3205] will not be managed by Spring
[DEBUG] 2018-08-09 12:47:28,659 com.jyf.ex.ehcache.dao.UserDao.getUserByUuid - ==> Preparing: select * from users where uuid = ?
[DEBUG] 2018-08-09 12:47:28,659 com.jyf.ex.ehcache.dao.UserDao.getUserByUuid - ==> Parameters: 84bebbe5-b870-446f-96cc-39277e869aec(String)
[DEBUG] 2018-08-09 12:47:28,660 com.jyf.ex.ehcache.dao.UserDao.getUserByUuid - <== Total: 1
[DEBUG] 2018-08-09 12:47:28,660 org.mybatis.spring.SqlSessionUtils - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7b5c042d]
User{id=6, uuid='84bebbe5-b870-446f-96cc-39277e869aec', name='张三改', age=20} //更新缓存,用数据库中的新数据替换缓存
User{id=6, uuid='84bebbe5-b870-446f-96cc-39277e869aec', name='张三改', age=20} //查询缓存
User{id=6, uuid='84bebbe5-b870-446f-96cc-39277e869aec', name='张三改', age=20} //查询缓存
修改数据后,需要更新缓存,于是第一次查询清除缓存后从数据库查询后放入更新后的数据。
4. 删除后查询
[DEBUG] 2018-08-09 12:47:28,660 org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession
[DEBUG] 2018-08-09 12:47:28,660 org.mybatis.spring.SqlSessionUtils - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@446ec5c4] was not registered for synchronization because synchronization is not active
[DEBUG] 2018-08-09 12:47:28,660 org.mybatis.spring.transaction.SpringManagedTransaction - JDBC Connection [com.mysql.jdbc.JDBC4Connection@755d3205] will not be managed by Spring
[DEBUG] 2018-08-09 12:47:28,660 com.jyf.ex.ehcache.dao.UserDao.deleteUser - ==> Preparing: delete from users where uuid = ?
[DEBUG] 2018-08-09 12:47:28,661 com.jyf.ex.ehcache.dao.UserDao.deleteUser - ==> Parameters: 84bebbe5-b870-446f-96cc-39277e869aec(String)
[DEBUG] 2018-08-09 12:47:28,663 com.jyf.ex.ehcache.dao.UserDao.deleteUser - <== Updates: 1
[DEBUG] 2018-08-09 12:47:28,663 org.mybatis.spring.SqlSessionUtils - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@446ec5c4]
此处查询了数据库:用户UUID为84bebbe5-b870-446f-96cc-39277e869aec
[DEBUG] 2018-08-09 12:47:28,663 org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession
[DEBUG] 2018-08-09 12:47:28,663 org.mybatis.spring.SqlSessionUtils - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1b6ce894] was not registered for synchronization because synchronization is not active
[DEBUG] 2018-08-09 12:47:28,663 org.mybatis.spring.transaction.SpringManagedTransaction - JDBC Connection [com.mysql.jdbc.JDBC4Connection@755d3205] will not be managed by Spring
[DEBUG] 2018-08-09 12:47:28,664 com.jyf.ex.ehcache.dao.UserDao.getUserByUuid - ==> Preparing: select * from users where uuid = ?
[DEBUG] 2018-08-09 12:47:28,664 com.jyf.ex.ehcache.dao.UserDao.getUserByUuid - ==> Parameters: 84bebbe5-b870-446f-96cc-39277e869aec(String)
[DEBUG] 2018-08-09 12:47:28,664 com.jyf.ex.ehcache.dao.UserDao.getUserByUuid - <== Total: 0
[DEBUG] 2018-08-09 12:47:28,665 org.mybatis.spring.SqlSessionUtils - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1b6ce894]
null //确认数据被删除,并更新缓存
null //查询缓存
null //查询缓存
删除数据后,应该同步更新缓存,先查询数据库确定数据已不存在,将缓存清空。因此后两次查询缓存均返回Null。