SpringBoot2.0.4使用JPA和Redis

      近来研究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文件如下:

<?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>com.bonc</groupId>
	<artifactId>boot-hibernate</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>boot-hibernate</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.4.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid-spring-boot-starter</artifactId>
			<version>1.1.10</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.18.0</version>
			<scope>provided</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>


</project>

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<Student> 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<Student> findAll() {
        return studentRepository.findAll();
    }

    @Override
    public Page<Student> findBySepc(int page, int size) {
        PageRequest pageRequest = PageRequest.of(page,size);
        Page<Student> students = studentRepository.findAll(new Specification<Student>(){
            @Override
            public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                Path<String> 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<Student,Integer>,JpaSpecificationExecutor<Student> {

}

如果你没有用过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<Object, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        template.setKeySerializer(new GenericJackson2JsonRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashKeySerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        return template;
    }
}

这里的配置主要解决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<T> {

    private String code;

    private String msg;

    private T data;

    public static <T> GeneralResponse<T> failedResponse(String failedString) {
        GeneralResponse<T> response = new GeneralResponse<T>();
        response.setMsg(failedString);
        return response;
    }

    public static <T> GeneralResponse<T> successfulResponse(String successfulString) {
        GeneralResponse<T> response = new GeneralResponse<T>();
        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的新增,那么表不用自己建的

猜你喜欢

转载自blog.csdn.net/zab635590867/article/details/81915551