近来研究SpringBoot持久化与缓存的问题,搜集资料做了一个Demo。
环境:Win10、JDK1.8、IDEA、Redis、Mysql5.7、Redis3.2、SpringBoot2.0.4Release版
第一步建立一个学生表:
CREATE TABLE `student` (
`sid` int(11) DEFAULT NULL,
`sname` varchar(32) DEFAULT NULL,
`sage` int(11) DEFAULT NULL,
`ssex` varchar(8) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `student` VALUES ('1', '刘一', '18', '男');
INSERT INTO `student` VALUES ('2', '钱二', '19', '女');
INSERT INTO `student` VALUES ('3', '张三', '17', '男');
INSERT INTO `student` VALUES ('4', '李四', '18', '女');
INSERT INTO `student` VALUES ('5', '王五', '17', '男');
INSERT INTO `student` VALUES ('6', '赵六', '19', '女');
第二步用IDEA搭建一个SpringBoot的web项目,SQL项勾选JPA、Mysql、JDBC,NoSQL项勾选Redis,把需要的类都写上
项目搭好整体结构如图:
application.yml配置如下,选用阿里的Druid连接池
spring:
datasource:
url: jdbc:mysql://localhost:3306/testmb4
type: com.alibaba.druid.pool.DruidDataSource
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
redis:
database: 0
host: 127.0.0.1
port: 6379
pom.xml文件如下:
4.0.0
com.bonc
boot-hibernate
0.0.1-SNAPSHOT
jar
boot-hibernate
Demo project for Spring Boot
org.springframework.boot
spring-boot-starter-parent
2.0.4.RELEASE
UTF-8
UTF-8
1.8
org.springframework.boot
spring-boot-starter-data-jpa
org.springframework.boot
spring-boot-starter-jdbc
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-data-redis
mysql
mysql-connector-java
runtime
org.springframework.boot
spring-boot-starter-test
test
com.alibaba
druid-spring-boot-starter
1.1.10
org.projectlombok
lombok
1.18.0
provided
org.springframework.boot
spring-boot-maven-plugin
StudentController代码如下:
package com.bonc.boothibernate.web;
import com.bonc.boothibernate.common.GeneralResponse;
import com.bonc.boothibernate.entity.Student;
import com.bonc.boothibernate.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/stu")
public class StudentController {
@Autowired
private StudentService studentService;
//单查
@PostMapping("/getInfo")
public GeneralResponse getStudent(@RequestParam Integer sid) {
GeneralResponse generalResponse = new GeneralResponse();
generalResponse.setData(studentService.getOne(sid));
return generalResponse;
}
//全查
@PostMapping("/getAll")
public GeneralResponse getStudents() {
GeneralResponse generalResponse = new GeneralResponse();
generalResponse.setData(studentService.findAll());
return generalResponse;
}
//分页功能
@PostMapping("/findBySepc")
public GeneralResponse findBySepc(@RequestParam int page, @RequestParam int size) {
GeneralResponse generalResponse = new GeneralResponse();
generalResponse.setData(studentService.findBySepc(page,size));
return generalResponse;
}
@PostMapping("/findBySepcLessThan")
public GeneralResponse findBySepcLessThan(@RequestParam int sid) {
GeneralResponse generalResponse = new GeneralResponse();
generalResponse.setData(studentService.findBySidLessThan(sid));
return generalResponse;
}
}
StudentServiceImpl代码如下:
package com.bonc.boothibernate.service.impl;
import com.bonc.boothibernate.entity.Student;
import com.bonc.boothibernate.repository.StudentRepository;
import com.bonc.boothibernate.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import javax.persistence.criteria.*;
import java.util.List;
@Service
public class StudentServiceImpl implements StudentService {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private StudentRepository studentRepository;
@Override
public Student getOne(Integer sid) {
Student student = (Student)redisTemplate.opsForValue().get(sid);
if(student==null){
System.out.println("redis没存好了"+sid);
Student student1 = studentRepository.getOne(sid);
redisTemplate.opsForValue().set(sid,student1);
return student1;
}
System.out.println("redis存好了"+sid);
return student;
}
@Override
public List findAll() {
return studentRepository.findAll();
}
@Override
public Page findBySepc(int page, int size) {
PageRequest pageRequest = PageRequest.of(page,size);
Page students = studentRepository.findAll(new Specification(){
@Override
public Predicate toPredicate(Root root, CriteriaQuery> query, CriteriaBuilder cb) {
Path snamePath = root.get("sname");
//这里可以设置任意条查询条件
query.where(cb.like(snamePath, "张%"));
//这种方式使用JPA的API设置了查询条件,所以不需要再返回查询条件Predicate给Spring Data Jpa,故最后return null;即可。
return null;
}
},pageRequest);
return students;
}
}
StudentService接口代码可以推断,这里就不贴了。
StudentRepository代码如下:(这里啰嗦一句,传统喜欢叫-Dao,MyBatis用-Mapper,SpringBoot-data-jpa则用-Repository)
package com.bonc.boothibernate.repository;
import com.bonc.boothibernate.entity.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface StudentRepository extends JpaRepository,JpaSpecificationExecutor {
}
如果你没有用过SpringBoot JPA,那么你可能会怀疑这个Repository没有东西是不是错了,事实上,简单查询就是这么简单。
复杂应用参见:https://blog.csdn.net/zab635590867/article/details/81775086
Student代码如下:
package com.bonc.boothibernate.entity;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
@Entity
@Data
@JsonIgnoreProperties(value={"hibernateLazyInitializer","handler","fieldHandler"})
public class Student implements Serializable{
private static final long serialVersionUID = -509438491019594820L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer sid;
@Column(length = 20)
private String sname;
@Column(length = 20)
private Integer sage;
@Column(length = 10)
private String ssex;
}
@JsonIgnoreProperties(value={"hibernateLazyInitializer","handler","fieldHandler"}) 本来常规是不需要的,报了异常,网上搜到的用法,挺管用的。大神如有更好的解决方法,欢迎留言。
RedisConfig的代码:
package com.bonc.boothibernate.config;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
@Configuration
@EnableCaching
public class RedisConfig {
@Bean
public RedisTemplate
这里的配置主要解决redis缓存对象用。不配置,对象存到redis中就会报各种类型转换异常。
GeneralResponse是一个普通的响应类,前后端分离的项目,大多数的响应类都长这个样子,用了一个常用的插件lombok,主要省点getter和setter,如果报错请在IDEA中下载lombok插件后使用:
package com.bonc.boothibernate.common;
import lombok.Data;
/**
* @author Jackson Zhang
* @Date 2018/08/21
* @desc 通用响应
*/
@Data
public class GeneralResponse {
private String code;
private String msg;
private T data;
public static GeneralResponse failedResponse(String failedString) {
GeneralResponse response = new GeneralResponse();
response.setMsg(failedString);
return response;
}
public static GeneralResponse successfulResponse(String successfulString) {
GeneralResponse response = new GeneralResponse();
response.setMsg(successfulString);
return response;
}
}
第三步用postman测试接口情况
多次调用http://localhost:8080/stu/getInfo,可以看到第一次获取学生张三的信息通过mysql数据库,后面的都是从redis中取出的数据,这里最好设置一个过期时间。
调用http://localhost:8080/stu/findBySepc,可以获取姓张的所有学生的分页显示结果,表中只有一个。
总结:
1、redis想要实现对象的缓存,RedisConfig配置一定得配上,并且实体类要可序列化
2、springboot JPA简单查询持久层代码真的太简单
3、如果使用springboot JPA的新增,那么表不用自己建的