我们在开发后台系统,在前台需要展示报表数据时一般是通过调用后台数据接口,数据接口就去按条件查询数据库并将结果返回给前台人员。通常在数据表数据较少时,查询效率是可以的,然而一般在高用户量系统中数据库数据量是十分庞大的,通过数据表建立索引虽然能够加快查询效率,但是速度还是会显得缓慢。这时我们就可以考虑使用集群、分布式和缓存等后端技术进行解决。下面我就介绍一种常用的缓存中间件Redis,我们项目结合redis作缓存做一个简单的demo。当然其实还有其他主流的缓存中间件,如MemCached,有新兴趣的朋友可以去网上找资料。
如果只想知道整合方式,那可以看完这节就可以了,有兴趣的朋友可以跟着继续看下去。
import com.hui.pojo.Department;
import com.hui.pojo.Employee;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Autowired
private RedisConnectionFactory redisConnectionFactory;
/**
* 缓存key生成规则,可自己定义
* @return
*/
@Bean(name = "empKeyGen")
public KeyGenerator empkeyGenerator() {
//java8+写法
return (target, method, params) -> {
StringBuilder sb = new StringBuilder();
sb.append("emp-");
sb.append(params[0]);
return sb.toString();
};
}
@Bean(name = "deptKeyGen")
public KeyGenerator deptkeyGenerator() {
return (target, method, params) -> {
StringBuilder sb = new StringBuilder();
sb.append("dept-");
sb.append(params[0]);
return sb.toString();
};
}
/**
* 我这里定义了两个cacheManager(缓存管理器),然后第一个缓存管理器创建了两个Cache,
* 分别用于缓存员工和部门,并且两个Cache各自有自己的json序列化方式,
* 大家也可以只用一个json序列化类,将泛型具体类改成Object就行
* @return
*/
@Bean(name = "cacheManager")
@Primary
public CacheManager CacheManager() {
//配置value序列化
Jackson2JsonRedisSerializer serializer1 = new Jackson2JsonRedisSerializer(Employee.class);
Jackson2JsonRedisSerializer serializer2 = new Jackson2JsonRedisSerializer(Department.class);
RedisCacheConfiguration config1 = RedisCacheConfiguration.defaultCacheConfig()
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer1));
RedisCacheConfiguration config2 = RedisCacheConfiguration.defaultCacheConfig()
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer2));
// 配置多个cache(缓存空间),每个缓存空间对应不同的配置(这里只做序列化区分设置)
Map<String, RedisCacheConfiguration> configMap = new HashMap<>();
configMap.put("emp", config1);
configMap.put("dept", config2);
RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory)
.withInitialCacheConfigurations(configMap)
.build();
return cacheManager;
}
/**
* 自定义cacheManager2,此案例没有用到,只用作区分,可以删除
* @return
*/
@Bean(name="otherCacheManager")
public CacheManager deptCacheManager() {
Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(String.class);
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer));
RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(redisCacheConfiguration).build();
return cacheManager;
}
}
<dependencies>
<!--redis 要用到的包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
(1)员工表 emp
CREATE TABLE `emp` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`sex` varchar(255) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
(2)部门表 dept
CREATE TABLE `dept` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
3.创建相关包和类(service、pojo、mapper、controller)
(1)实体类
@Data
public class Employee implements Serializable {
private Integer id;
private String name;
private String sex;
private Integer age;
}
@Data
public class Department {
private Integer id;
private String name;
}
(2) mapper
@Mapper
public interface EmpMapper {
@Select("select * from emp where id = #{id}")
Employee findEmpById(Integer id);
@Update("update emp set name=#{name},age=#{age} where id=#{id}")
int updateEmp(Employee e);
@Delete("delete from emp where id=#{id}")
int delEmpById(Integer id);
}
@Mapper
public interface DeptMapper {
@Select("select * from dept where id=#{id}")
Department findById(Integer id);
@Update("update dept set name=#{name} where id=#{id}")
int updateDept(Department dept);
@Delete("delete from dept where id=#{id}")
int delDept(Integer id);
}
(3) service
@Service
@CacheConfig(cacheManager = "cacheManager", cacheNames = "dept", keyGenerator = "deptKeyGen")
public class DeptService {
@Autowired
private DeptMapper deptMapper;
@Cacheable
public Department findById(Integer id) {
System.out.println("数据库操作查找部门");
return deptMapper.findById(id);
}
@CachePut
public Department updateDept(Department dept) {
System.out.println("数据库操作更新部门");
int row = deptMapper.updateDept(dept);
if (row > 0) {
return dept;
} else {
return null;
}
}
@CacheEvict
public int delDept(Integer id) {
System.out.println("数据库操作删除部门");
return deptMapper.delDept(id);
}
}
@CacheConfig(cacheManager = "cacheManager", cacheNames = "emp", keyGenerator = "empKeyGen")
@Service
public class EmpService {
@Autowired
private EmpMapper empMapper;
@Cacheable()
public Employee findEmpById(Integer id) {
System.out.println("数据库查找用户");
Employee emp = empMapper.findEmpById(id);
return emp;
}
@CachePut
public Employee updateEmp(Employee e) {
System.out.println("数据库更新用户");
int row = empMapper.updateEmp(e);
if (row > 0) {
return e;
} else {
return null;
}
}
@CacheEvict
public int delEmpById(Integer id) {
int res = empMapper.delEmpById(id);
return res;
}
}
(4) controller
@RestController
public class TestController {
@Autowired
private EmpService empService;
@Autowired
private DeptService deptService;
@RequestMapping("/emp/{id}")
public Employee getEmpById(@PathVariable("id") int id) {
return empService.findEmpById(id);
}
@RequestMapping("/updateEmp")
public Employee updateEmp(int id, String name,int age) {
Employee e = new Employee();
e.setAge(age);
e.setId(id);
e.setName(name);
Employee emp = empService.updateEmp(e);
return emp;
}
@RequestMapping("/delemp/{id}")
public String delEmpById(@PathVariable("id") int id) {
if (empService.delEmpById(id) > 0) {
return "del success";
} else {
return "del fail";
}
}
@RequestMapping("/dept/{id}")
public Department getDeptById(@PathVariable("id") int id) {
return deptService.findById(id);
}
@RequestMapping("/updateDept")
public Department updateDept(int id, String name) {
Department d = new Department();
d.setId(id);
d.setName(name);
Department dept = deptService.updateDept(d);
return dept;
}
@RequestMapping("/delDept/{id}")
public String delDeptById(@PathVariable("id") int id) {
if (deptService.delDept(id) > 0) {
return "del success";
} else {
return "del fail";
}
}
}
springboot是自带缓存功能的(实现了JSR107规范)实现,但是它好像是直接将缓存数据存在类似hashMap的一个地方,这样并不安全。我们整合redis作缓存,大家知道redis是一个高性能的内存数据库,就将相当于将缓存数据存在内存中,其速度肯定是快。下面图是JSR107规范图和解析:
1.CachingProvider定义了创建、配置、获取、管理和控制多个CacheManager。一个应用可以在运行期访问多个CachingProvider。
2.CacheManager定义了创建、配置、获取、管理和控制多个唯一命名的Cache,这些Cache存在于 CacheManager的上下文中。一个CacheManager仅被一个CachingProvider所拥有。
3. Cache是一个类似Map的数据结构并临时存储以Key为索引的值。一个Cache仅被一个CacheManager所拥有。
4.Entry是一个存储在Cache中的key-value对.
5.Expiry:每一个存储在Cache中的条目有一个定义的有效期。一旦超过这个时间,条目为过期的状态。一旦过期,条目将不可访问、更新和删除。缓存有效期可以通过ExpiryPolicy设置。
(1)@CacheConfig:用于配置该类中会用到的一些共用的缓存配置
(2)@Cacheable:用于方法返回值加入缓存。同时在查询时,会先从缓存中取,若不存在才再发起对数据库的访问。
(3)@CachePut:配置于方法上,能够根据参数定义条件进行缓存,与@Cacheable不同的是,每次回真实调用函数,所以主要用于数据新增和修改操作上。
(4)@CacheEvict:配置于函数上,通常用在删除方法上,用来从缓存中移除对应数据
(5)@Caching:配置于函数上,组合多个Cache注解使用。
1.查询1号员工
结果:第一次查询是直接查数据库,第二次查缓存
以上就是全部内容,各位大佬有什么指点的地方欢迎留言。