21.spring+redis+mysql做缓存

 

spring+redis+mysql做缓存

CacheUserAspect

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package com.test.redis.cache;

import com.alibaba.fastjson.JSONObject;
import com.test.redis.vo.User;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;


@Component
@Aspect
@EnableAspectJAutoProxy
public class CacheUserAspect {

private Log log = LogFactory.getLog(CacheUserAspect.class);

private static final String POINTCUT_INSERT = "execution(* com.test.redis.service.impl.UserServiceImpl.insertUser(..))";
private static final String POINTCUT_UPDATE = "execution(* com.test.redis.service.impl.UserServiceImpl.updateUser(..))";
private static final String POINTCUT_DELETE = "execution(* com.test.redis.service.impl.UserServiceImpl.deleteUserById(..))";
private static final String POINTCUT_GETONE = "execution(* com.test.redis.service.impl.UserServiceImpl.getUserById(..))";

// redis key profix
private static final String PROFIX = "user:";

@Autowired
private JedisPool jedisPool;

@Around(value = CacheUserAspect.POINTCUT_INSERT)
public User cacheInsertUser(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
// insert user into database
User user = (User) proceedingJoinPoint.proceed();
// insert user into redis
Jedis jedis = jedisPool.getResource();
String userJsonStr = JSONObject.toJSONString(user);
jedis.set(PROFIX + user.getId(), userJsonStr);
log.info(PROFIX + user.getId() + "-数据已存入Redis");
jedis.close();

return user;
}

@Around(value = CacheUserAspect.POINTCUT_UPDATE)
public User cacheUpdateUser(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
// update user in database
User user = (User) proceedingJoinPoint.proceed();
// update user in redis
Jedis jedis = jedisPool.getResource();
String userJsonStr = JSONObject.toJSONString(user);
jedis.set(PROFIX + user.getId(), userJsonStr);
log.info(PROFIX + user.getId() + "-数据已经更新到redis");
jedis.close();

return user;
}

@Around(value = CacheUserAspect.POINTCUT_DELETE)
public Integer cacheDeleteUser(ProceedingJoinPoint proceedingJoinPoint) {
Integer userId = (Integer) proceedingJoinPoint.getArgs()[0];
log.info(PROFIX + userId + "-数据库数据已删除");

Jedis jedis = jedisPool.getResource();
if (jedis.exists(PROFIX + userId)){
jedis.del(PROFIX + userId);
log.debug(PROFIX + userId + "已从redis中删除");
}
else {
log.debug(PROFIX + userId + "redis中不存在该key");
}
log.info(PROFIX + userId + "-数据已从Redis删除");
jedis.close();

return userId;
}

@Around(value = CacheUserAspect.POINTCUT_GETONE)
public User cacheGetOneUser(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Integer userId = (Integer) proceedingJoinPoint.getArgs()[0];
if (userId == null) {
return null;
}

User user;
Jedis jedis = jedisPool.getResource();
String userJsonStr = jedis.get(PROFIX + userId);
if (userJsonStr != null) {
log.info(PROFIX + userId + "-已从redis中查询得到数据");
user = JSONObject.parseObject(userJsonStr, User.class);

}
else {
log.info(PROFIX + userId + "-redis中没有该数据,从数据库中查询");
user = (User) proceedingJoinPoint.proceed();
if (user != null) {
userJsonStr = JSONObject.toJSONString(user);
jedis.set(PROFIX + user.getId(), userJsonStr);
log.debug(PROFIX + userId + "-数据已存入redis");
}
}

jedis.close();
return user;

}

}

UserMapper.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.test.redis.mapper;

import com.test.redis.vo.User;

import java.util.List;

public interface UserMapper {

public int deleteUserById(Integer id);

public int insertUser(User user);

public User getUserById(Integer id);

public int updateUser(User user);

public List<User> queryAllUser();
}

UserMapper.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?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.test.redis.mapper.UserMapper">
<resultMap id="BaseResultMap" type="com.test.redis.vo.User">
<id column="id" jdbcType="INTEGER" property="id"/>
<result column="name" jdbcType="VARCHAR" property="name"/>
<result column="age" jdbcType="INTEGER" property="age"/>
</resultMap>

<sql id="Base_Column_List">
id, `name`, age
</sql>

<select id="getUserById" parameterType="java.lang.Integer" resultMap="BaseResultMap">
select
<include refid="Base_Column_List"/>
from user
where id = #{id,jdbcType=INTEGER}
</select>

<delete id="deleteUserById" parameterType="java.lang.Integer">
delete from user
where id = #{id,jdbcType=INTEGER}
</delete>

<insert id="insertUser" keyColumn="id" keyProperty="id" parameterType="com.test.redis.vo.User" useGeneratedKeys="true">
insert into user (`name`, age)
values (#{name,jdbcType=VARCHAR}, #{age,jdbcType=INTEGER})
</insert>

<update id="updateUser" parameterType="com.test.redis.vo.User">
update user
<set>
<if test="name != null">
`name` = #{name,jdbcType=VARCHAR},
</if>
<if test="age != null">
age = #{age,jdbcType=INTEGER},
</if>
</set>
where id = #{id,jdbcType=INTEGER}
</update>

<select id="queryAllUser" resultMap="BaseResultMap">
select
<include refid="Base_Column_List"/>
from user
</select>
</mapper>

UserService

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.test.redis.service;

import com.test.redis.vo.User;

import java.util.List;

public interface UserService {

public int deleteUserById(Integer id);

public User insertUser(User user);

public User getUserById(Integer id);

public User updateUser(User user);

public List<User> queryAllUser();

}

UserServiceImpl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package com.test.redis.service.impl;

import com.test.redis.mapper.UserMapper;
import com.test.redis.service.UserService;
import com.test.redis.vo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserServiceImpl implements UserService {

@Autowired
private UserMapper userMapper;

@Override
public int deleteUserById(Integer id) {
int affectRows = this.userMapper.deleteUserById(id);
return affectRows;
}

@Override
public User insertUser(User user) {
this.userMapper.insertUser(user);
return user;
}

@Override
public User getUserById(Integer id) {
User user = this.userMapper.getUserById(id);
return user;
}

@Override
public User updateUser(User user) {
this.userMapper.updateUser(user);
return user;
}

@Override
public List<User> queryAllUser() {
List<User> userList = this.userMapper.queryAllUser();
return userList;
}
}

User

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package com.test.redis.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {

private Integer id;

private String name;

private Integer age;

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

}

application-cache.xml

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

<context:component-scan base-package="com.test.redis.cache"></context:component-scan>

</beans>

application-dao.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

<!-- 引入db.properties -->
<context:property-placeholder
location="classpath*:db.properties" system-properties-mode="FALLBACK" />

<!-- 声明dataSource -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!-- 注入连接属性 -->
<property name="driverClassName" value="${driverClassName}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${username}"></property>
<property name="password" value="${password}"></property>
</bean>
<!-- 声明sessionFactory 并注入mybatis.cfg.xml -->
<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 注入数据源 -->
<property name="dataSource" ref="dataSource"></property>
<!-- 注入mapper.xml -->
<property name="mapperLocations">
<array>
<value>classpath:mapper/*Mapper.xml</value>
</array>
</property>
</bean>

<!-- 扫描mapper接口 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 注入mapper接口所在的包 注意多个包的情况的配置 -->
<property name="basePackage">
<value>
com.test.redis.mapper
</value>
</property>
<!-- 注入sqlSessionFactory -->
<property name="sqlSessionFactoryBeanName"
value="sqlSessionFactory"></property>
</bean>
</beans>

application-redis.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<!--声明配置-->
<bean id="poolConfig" class="org.apache.commons.pool2.impl.GenericObjectPoolConfig">
<property name="maxTotal" value="100"></property>
<property name="maxIdle" value="80"></property>
<property name="minIdle" value="20"></property>
<property name="maxWaitMillis" value="2000"></property>
<property name="testOnBorrow" value="true"></property>
</bean>


<!--jedispool-->
<bean id="jedisPool" class="redis.clients.jedis.JedisPool">
<!--因为JedisPool没有属性 所以只能使用构造器的注入方式-->
<constructor-arg name="poolConfig" ref="poolConfig"></constructor-arg>
<constructor-arg name="host" value="192.168.168.130"></constructor-arg>
<constructor-arg name="port" value="6379"></constructor-arg>
<constructor-arg name="timeout" value="2000"></constructor-arg>
<!-- <constructor-arg name="password" value="123456"></constructor-arg>-->
</bean>

</beans>

application-service.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

<context:component-scan base-package="com.test.redis.service.impl"></context:component-scan>

<!-- 1,声明事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 启动注解事务 -->
<!-- <tx:annotation-driven/> -->
<!-- 2,声明事务的传播特性 也就是通知 -->
<tx:advice id="advise" transaction-manager="transactionManager">
<tx:attributes>
<!-- 以add开头的方法名需要事务 -->
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="insert*" propagation="REQUIRED"/>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="change*" propagation="REQUIRED"/>
<tx:method name="reset*" propagation="REQUIRED"/>
<tx:method name="get*" read-only="true"/>
<tx:method name="load*" read-only="true"/>
<tx:method name="*" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- 3进行AOP织入 -->
<aop:config>
<!-- 声明切面 -->
<aop:pointcut expression="execution(* com.test.redis.service.impl.*.*(..))" id="pc"/>
<!-- 织入 -->
<aop:advisor advice-ref="advise" pointcut-ref="pc"/>
</aop:config>
</beans>

applicationContext.xml

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


<import resource="classpath*:application-dao.xml"></import>
<import resource="classpath*:application-service.xml"></import>
<import resource="classpath*:application-redis.xml"></import>
<import resource="classpath*:application-cache.xml"></import>

</beans>

db.properties

1
2
3
4
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username=root
password=123456

log4j.properties

1
2
3
4
5
6
7
8
# Global logging configuration
log4j.rootLogger=INFO, stdout
# MyBatis logging configuration...
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.example</groupId>
<artifactId>redis-spring-mysql-demo</artifactId>
<version>1.0-SNAPSHOT</version>

<name>redis-spring-mysql-demo</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>

<mybatis.version>3.5.2</mybatis.version>
<mybatis-spring.version>2.0.2</mybatis-spring.version>
<spring.version>4.3.24.RELEASE</spring.version>
<druid.version>1.0.18</druid.version>
<mysql.version>8.0.22</mysql.version>
<fastjson.version>1.2.59</fastjson.version>
<!-- log4j注意只能使用2.0以下的版本 -->
<log4j.version>1.2.17</log4j.version>
<jedis.version>3.1.0</jedis.version>
<lombok.verison>1.18.10</lombok.verison>
</properties>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>

<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<!-- mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>${mybatis-spring.version}</version>
</dependency>
<!-- 导入spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- mysql数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!-- json -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!-- log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>${jedis.version}</version>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.verison}</version>
<scope>provided</scope>
</dependency>

</dependencies>

<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>

TestApp.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.test.redis.test;

import com.test.redis.service.UserService;
import com.test.redis.vo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestApp {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:ApplicationContext.xml");

UserService userService = applicationContext.getBean(UserService.class);

// insert
User user = new User();
user.setName("Kim");
user.setAge(10);
userService.insertUser(user);

// select
Integer userId = user.getId();
user = userService.getUserById(userId);
System.out.println("selectUser = " + user);

// update
user.setAge(15);
userService.updateUser(user);
user = userService.getUserById(userId);
System.out.println("updateUser = " + user);

// delete
userService.deleteUserById(2);

System.out.println("Finished!");
}
}

output:

1
2
3
4
5
6
7
8
9
 INFO [main] - user:1-数据已存入Redis
INFO [main] - user:1-已从redis中查询得到数据
selectUser = User(id=1, name=Kim, age=10)
INFO [main] - user:1-数据已经更新到redis
INFO [main] - user:1-已从redis中查询得到数据
updateUser = User(id=1, name=Kim, age=15)
INFO [main] - user:2-数据库数据已删除
INFO [main] - user:2-数据已从Redis删除
Finished!