Spring Boot数据访问

Spring Boot数据访问概述

Spring Data是Spring提供了一个用于简化数据库访问、支持云服务的开源框架。它是一个伞形项目,包含了大量关系型数据库及非关系型数据库的数据访问解决方案,其设计目的是使我们可以快速且简单地使用各种数据访问技术。Spring Boot默认采用整合Spring Data地方式统一处理数据访问层,通过添加大量自动配置,引入各种数据访问模板xxxTemplate以及统一的Repository接口,从而达到简化数据访问层的操作。
Spring Data提供了多种类型数据库支持,Spring Boot对Spring Data支持的数据库进行了整合管理,提供了各种依赖启动器。

名称

描述

spring-boot-starter-data-jpa

Spring Data JPA与Hibernate的启动器

spring-boot-start-data-mongodb

MongoDB和Spring Data MongoDB的启动器

spring-boot-start-data-neo4

Neo4j图数据库和Spring Data Neo4j的启动器

spring-boot-start-redis

Redis键值数据存储与Spring Data Redis和Jedis客户端的启动器

Spring Boot没有提供MyBatis场景依赖,但是MyBatis开发团队自己适配了Spring Boot,提供了mybatis-spring-boot-starter依赖启动器实现数据访问操作。

Spring Boot整合MyBatis

基础环境搭建

因为Spring Boot框架开发很便利,所以实现Spring Boot与数据访问层框架的整合非常简单,主要是引入对应的依赖启动器,并进行数据库相关参数设置即可。
1、数据准备
在MySQL中,创建一个名为springbootdata的数据库,在该数据库中创建两个表t_article和t_comment,并预先插入几条测试数据
springbootdata.sql

create database springbootdata;
use springbootdata;
drop table if exists `t_article`;
create table `t_article` (
	`id` int(20) not null auto_increment comment '文章id',
	`title` varchar(200) default null comment '文章标题',
	`content` longtext comment '文章内容',
	primary key (`id`)
) engine=InnoDB auto_increment=2 default charset=utf8;
insert into `t_article` values ('1','Spring Boot 基础入门','从入门到精通讲解...');
insert into `t_article` values ('2','Spring Cloud基础入门','从入门到精通讲解...');
drop table if exists `t_comment`;
create table `t_comment` (
	`id` int(20) not null auto_Increment comment '评论id',
	`content` longtext comment '评论内容',
	`author` varchar(200) default null comment '评论作者',
	`a_id` int(20) default null comment '关联的文章id',
	primary key (`id`)
) engine=InnoDB auto_increment=3 default charset=utf8;
insert into `t_comment` values ('1','123','tom1','1');
insert into `t_comment` values ('2','123','tom2','1');
insert into `t_comment` values ('3','123','tom3','1');
insert into `t_comment` values ('4','123','tom4','1');
insert into `t_comment` values ('5','123','tom5','2');

2、创建项目,引入相应的启动器

1)创建Spring Boot项目。创建一个名为chapter03的Spring Boot项目,在Dependencies依赖中选中SQL模块中的Mysql和MyBatis依赖,并根据后续提示完成项目创建。

springboot 搜索计数功能 springboot获取数据_spring boot


2)编写数据库对应的实体类。在chapter03项目中创建名为com.example.chapter03的包,并在该包中编写与数据库表对应的实体类Comment和Article

Comment.java

package com.example.chapter03;

public class Comment {
    private Integer id;
    private String content;
    private String author;
    private Integer aId;
    //省略属性getter和setter方法
    //省略toString()方法
}

Article.java

package com.example.chapter03;

import java.util.List;

public class Article {
    private Integer id;
    private String title;
    private String content;
    private List<Comment> commentList;
    //省略属性getter和setter方法
    //省略toString()方法
}

3、编写配置文件
1)在application.properties配置文件中进行数据库连接配置。
application.properties

spring.datasource.url=jdbc:mysql://localhost:3306/springbootdata?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456

2)数据源类型选择配置。Spring Boot 1.x版本默认使用的使tomcat.jdbc数据源,Spring Boot 2.x版本默认使用的是hikari数据源。如果使用其他数据源,还需要进行额外配置。
这里选择使用阿里巴巴的Druid数据源。在pom.xml文件中添加Druid数据源启动器。

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

上述引入的依赖druid-spring-boot-starter,同样是阿里巴巴为了迎合Spring Boot项目而适配的Druid数据源启动器,当在pom.xml中引入该启动器后,不需要再进行其他额外配置,Spring Boot项目会自动识别配置Druid数据源。
需要说明的是,上述配置的Druid数据源启动器内部已经初始化了一些运行参数,如果开发过程中需要修改第三方Druid的运行参数,则必须在全局配置文件中修改。
application.properties

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.initialSize=20
spring.datasource.minIdle=10
spring.datasource.maxActive=100

修改了Druid数据源的类型、初始化连接数、最小空闲数和最大连接数
注:配置完之后会发现spring.datasource.initialSize、spring.datasource.minIdle、spring.datasource.maxActive属性底纹为黄色,这是因为Spring Boot提供的数据源自动配置类org.springframework.boot.autoconfigure.jdbc.DataSourceProperties中,没有与这些参数对应的默认属性,所以这些设置的属性值无法识别和生效。为此我们需要编写一个自定义配置类,将配置文件中的属性注入到Druid数据源属性中。
在chapter03项目中创建名为com.example.chapter03.config的包,并在该包下创建一个自定义配置类对Druid数据源属性值进行注入
DataSourceConfig.java

package com.example.chapter03.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
public class DataSourceConfig {
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource getDruid(){
        return new DruidDataSource();
    }
}

注:在pom.xml中添加第三方数据源Druid依赖时,本书直接选了适配Spring Boot开发Druid启动器druid-spring-boot-starter,所以可以不需要再进行其他配置,项目就会自动识别该数据源,而有些读者可能会使用独立的Druid依赖文件,这时就必须在全局配置中额外添加"spring.datasource.type=com.alibaba.druid.pool.DruidDataSource"配置,这样项目才能识别配置的Druid数据源。

使用注解的方式整合MyBatis

相比Spring与Mybatis的整合,Spring Boot与MyBatis的整合会使项目开发更加简便,同时还支持XML和注解两种配置方式。
1)创建Mapper接口文件。在chapter03项目中创建名为com.example.chapter03.mapper的包,并在该包下创建一个用于对数据库表t_comment数据操作的接口CommentMapper

package com.example.chapter03.mapper;

import com.example.chapter03.Comment;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

@Repository
@Mapper
public interface CommentMapper {
    @Select("select * from t_comment where id=#{id}")
    public Comment findById(Integer id);
    @Select("insert into t_comment(context,author,a_id)")
    public int insertComment(Comment comment);
    @Select("update t_comment set content=#{content} where id=#{id}")
    public int updataComment(Comment comment);
    @Select("delete from t_comment where id=#{id}")
    public int deleteComment(Integer id);
}

注:这里不进行@Repository注解程序依然可以正确执行,@Mapper可以将CommentMapper注册为Bean,但是开发工具不识别,这里额外使用@Repository可以令开发工具在运行前认为CommentMapper注入了Spring Boot。(和@Repository效果相同的还有,@Service、@Controller 和 @Component。不过它们有各自特殊的作用,这里应当使用 @Repository)

@Mapper注解表示该类是一个MyBatis接口文件,并保证能够被Spring Boot自动扫描到Spring容器中;在该接口内部,分别通过@Select、@Insert、@Update、@Delete注解配合SQL语句完成了对数据库表t_comment数据的增删改查操作。
注:在对应的接口类上添加了@Mapper注解,如果编写的Mapper接口过多时,需要重复为每一个接口文件添加@Mapper注解。为了避免这种麻烦,可以直接在Spring Boot项目启动类上添加@MapperScan(“xxx”)注解,不需要再逐个添加@Mapper注解。@MapperScan(“xxx”)注解的作用和@Mapper注解类似,但是它必须指定需要扫描的具体包名,例如@MapperScan(“com.example.mapper”)。
2)编写单元测试进行接口方法测试。打开chapter03项目的测试类Chapter03ApplicationTest,在该测试类中引入CommentMapper接口,并对接口方法进行测试。
Chapter03ApplicationTest.java

package com.example.chapter03;

import com.example.chapter03.mapper.CommentMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class Chapter03ApplicationTests {

    @Autowired
    private CommentMapper commentMapper;

    @Test
    public void selectComment(){
        Comment comment=commentMapper.findById(1);
        System.out.println(comment);
    }
}

springboot 搜索计数功能 springboot获取数据_spring_02


查找时aId没有正确输出,这是因为表中的字段a_id被我们在类中映射成了aId,命名法的不同造成了Spring Boot没有正确识别并映射,可以在全局配置文件中添加开启驼峰命名匹配映射。

mybatis.configuration.map-underscore-to-camel-case=true

springboot 搜索计数功能 springboot获取数据_java_03


可以看到aId正确的输出了。

使用配置文件的方式整合MyBatis

Spring Boot与MyBatis整合使用时,不仅支持注解方式,还支持XML配置文件的方式
1)创建Mapper接口文件。在chapter03项目的com.example.chapter03.mapper包下,创建一个操作t_article数据表的接口ArticleMapper

package com.example.chapter03.mapper;

import com.example.chapter03.Article;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

@Repository
@Mapper
public interface ArticleMapper {
    public Article selectArticle(Integer id);
    public int updateArticle(Article article);
}

2)创建XML映射文件。在chapter03项目的resources目录下,创建一个统一管理映射文件的包mapper,并在该包下编写与ArticleMapper接口对应的映射文件ArticleMapper.xml

<?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.example.chapter03.mapper.ArticleMapper">
    <select id="selectArticle" resultMap="articleWithComment">
        select a.*,c.id c_id,c.content c_content,c.author
        from t_article a,t_comment c
        where a.id=c.a_id AND a.id=#{id}
    </select>
    <resultMap id="articleWithComment" type="Article">
        <id property="id" column="id"/>
        <result property="title" column="title"/>
        <collection property="commentList" ofType="Comment">
            <id property="id" column="c_id"/>
            <result property="content" column="c_content"/>
            <result property="author" column="author"/>
        </collection>
    </resultMap>
    <update id="updateArticle" parameterType="Article">
        update t_article
        <set>
            <if test="title != null and title != ''">
                title=#{title},
            </if>
            <if test="content != null and content != ''">
                content=#{content}
            </if>
        </set>

    </update>
</mapper>

<mapper>标签的namespace属性值对应的是ArticleMapper接口文件的全路径名称,在映射文件中根据AritcleMapper接口文件中的方法,编写两个对应的SQL语句;同时配置数据类型映射时,没有使用类的全路径名称,而是是用来类的别名(例如,com.example.chapter03.Article的别名为Article)
关于MyBatis映射文件中的SQL语句具体语法可以查看之前Java Web学习专栏中动态SQL的内容。
3)配置XML映射文件路径。我们在项目中编写的XML映射文件,Spring Boot并无从知晓,所以无法扫描到该自定义编写的XML配置文件,还需要在全局配置文件中添加MyBatis映射文件路径的配置,同时需要添加实体类别名映射路径。

mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.type-aliases-package=com.example.chapter03

4)编写单元测试类。打开项目的测试类Chapter03ApplicationTests

package com.example.chapter03;

import com.example.chapter03.mapper.ArticleMapper;
import com.example.chapter03.mapper.CommentMapper;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class Chapter03ApplicationTests {

    @Autowired
    private CommentMapper commentMapper;

    public void selectComment(){
        Comment comment=commentMapper.findById(1);
        System.out.println(comment);
    }

    @Autowired
    private ArticleMapper articleMapper;
    @Test
    public void selectArticle(){
        Article article=articleMapper.selectArticle(1);
        System.out.println(article);
    }
}

springboot 搜索计数功能 springboot获取数据_spring boot_04

Spring Boot整合JPA

JPA(Java Persistence API,Java持久化API)是Sun公司提出的Java持久化规范,它为Java开发者提供了一种对象/关系映射的工具管理Java中的关系型数据,其主要目的是简化现有的持久化开发工作和整合ORM(Object Relational Mapping,对象/关系映射)技术,Spring Data在JPA规范的基础上,充分利用其优点,提出了Spring Data JPA模块对具有ORM关系数据进行持久化操作。

Spring Data JPA介绍

Spring Data API是ORM框架、JPA规范的基础上封装的一套JPA应用框架,提供了增删改查等常用功能,使开发者可以用较少的代码实现数据操作,同时还易于扩展。

编写ORM实体类

引入相关包

<dependency>
            <groupId>javax.persistence</groupId>
            <artifactId>persistence-api</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

Spring Data JPA框架是针对具有ORM关系的数据进行操作,所以在使用Spring Data JPA时,首先需要编写一个实体类与数据表进行映射,并且配置好映射关系

package com.example.chapter03;

import javax.persistence.*;

@Entity(name = "t_comment")
public class Discuss {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    @Column(name = "a_id")
    private Integer aId;
    //省略getXXX()和setXXX()
}

上述代码定义了一个Spring Data JPA 实体类Discuss,并将该类与数据表t_comment进行映射。
1)@Entity:标注要与数据库做映射的实体类,默认情况下,数据表的名称就是首字母小写的类名。当然,还可以使用name属性指定映射的表名。
2)@Id:标注在类属性或者getter方法上,表示某一个属性对应表中的主键。
3)@GeneratedValue:与@Id注解标注在同一位置,用于表示属性对应主键的生成策略,可省略。Spring Data JPA支持的主键生成策略包括有TABLE(使用一个特定的数据库表格来保存主键)、SEQUENCE(不支持主键自增长的数据库主键生成策略)、IDENTITY(主键自增)和AUTO(JPA自主选择前面三种合适的策略,默认选项)。

编写Repository接口

下面我们针对不同的表数据操作编写各自对应的Repository接口,并根据需要编写对应的数据操作方法

package com.example.chapter03;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.transaction.annotation.Transactional;

import java.awt.print.Pageable;
import java.util.List;

public interface DiscussRepository extends JpaRepository<Discuss,Integer> {
    public List<Discuss> findByAutorNotNull();
    @Query("select c from t_comment c where c.aId = ?1")
    public List<Discuss> getDiscussPaged(Integer aid, Pageable pageable);
    @Query(value = "select * from t_comment where a_Id = ?1",nativeQuery = true)
    public List<Discuss> getDiscussPaged2(Integer aid,Pageable pageable);
    @Transactional
    @Modifying
    @Query("update t_comment c set c.author = ?1 where c.id = ?2")
    public int updateDiscuss(String author,Integer id);
    @Transactional
    @Modifying
    @Query("delete t_comment c where c.id = ?1")
    public int deleteDiscuss(Integer id);
}

1)findByAuthorNotNull()方法:该方法是一个基本的查询方法,上方没有任何注释,属于JPA支持的方法名关键字查询方式;同时通过定义的方法名可以猜测出,该方法的作用是查询author非空的Discuss评论信息。
2)getDiscussPaged()方法:该方法上方通过@Query注解引入了一个SQL语句,用于通过文章分页ID查询Discuss评论信息。
3)getDiscussPaged2()方法:该方法的功能与getDiscussPaged()基本类似,区别是该方法上方的@Query注解将nativeQuery属性设置为true,用来编写原生SQL语句。
4)updateDiscuss()方法和deleteDiscuss()方法:这两个方法同样使用@Query注解配置了对应的SQL语句,这两个方法分别对应数据的更新和删除操作;需要说明的是,数据更新或者删除操作的方法上还使用了@Modifying和@Transactional注解,其中,@Modifying表示支持数据变更,@Transactional表示支持事务管理。

1)使用Spring Data JPA自定义Repository接口,必须继承XXRepository<T,ID>接口,其中的T代表要操作的实体类,ID代表实体类主键数据类型。

  • Repository是Spring Data JPA提供的用于自定义Reposity接口的顶级父接口,该接口中没有声明任何方法。
  • CrudRepository接口是Repository的继承接口之一,包含了一些基本的CRUD方法。
  • PagingAndSortingRepository接口继承CrudRepository接口的同时,提供了分页和排序两个方法。
  • QueryByExampleExecutor接口是进行条件封装查询的顶级父接口,允许通过Example实例执行复杂条件查询。

JpaRepository接口同时继承了PagingAndSortingRepository接口和QueryByExampleExecutor接口,并额外提供了一些数据操作方法。自定义Repository接口文件时,通常会直接选择JpaRepository接口。
2)在使用Spring Data JPA进行数据操作时,可以有多种实现方式,主要方式

  • 如果自定义接口继承了JpaRepository接口,则默认包含了一些常用的CRUD方法。
  • 自定义Repository接口中,可以使用@Query注解配合SQL语句进行数据的查、改、删操作。
  • 自定义Repository接口中,可以直接使用方法名关键字进行查询操作。
    其中,Spring Data JPA中支持的方法名关键字及对应的SQL片段说明。

关键字

方法名示例

对应的SQL片段

And

findByLastnameAndFirstname

where x.lastname = ?1 and x.firstname = ?2

Or

findByLastnameOrFirstname

where x.lastname = ?1 or x.firstname = ?2

Is,Equals

findByFirstname,findByFirstnameIs,findByFirstnameEquals

where x.firstname = ?1

Between

findByStartDateBetween

where x.startDate between ?1 and ?2

LessThan

findByAgeLessThan

where x.age < ?1

LessThanEqual

findByAgeLessThanEqual

where x.age <= ?1

GreaterThan

findByAgeGreaterThan

where x.age > ?1

GreaterThanEqual

findByAgeGreaterThanEqual

where x.age >= ?1

After

findByStartDateAfter

where x.startDate > ?1

Before

findByStartDateBefore

where x.startDate < ?1

IsNull

findByAgeIsNull

where x.age is null

IsNotNull,NotNull

findByAge(Is)NotNull

where x.age not null

Like

findByFirstnameLike

where x.firstname like ?1

NotLike

findByFirstnameNotLike

where x.firstname not like ?1

StartingWith

findByFirstnameStartingWith

where x.firstname like ?1 (parameter bound with appended %)

EndingWith

findByFirstnameEndingWith

where x.firstname like ?1 (parameter bound with prepended%)

Containing

findByFirstnameContaining

where x.firstname like ?1 (parameter bound wrapped in %)

OrderBy

findByAgeOrderByLastnameDesc

where x.age = ?1 order by x.lastname desc

Not

findByLastnameNot

where x.lastname <> ?1

In

findByAgeIn(Collection<Age> ages)

where x.age in ?1

NotIn

findByAgeNotIn(Collection<Age> ages)

where x.age not in ?1

True

findByActiveTrue()

where x.active = true

False

findByActiveFalse()

where x.active = false

IgnoreCase

findByFirstnameIgnoreCase

where UPPER(x.firstame) = UPPER(?1)

3)在自定义的Repository接口中,针对数据的变更操作(修改、删除),无论是否是用了@Query注解,都必须在方法上方添加@Transactional注解进行事务管理,否则程序执行就会出现InvalidDataAccessApiUsageException异常。如果在调用Repository接口方法的业务层Service类上已经添加了@Transactional注解进行事务管理,那么Repository接口文件中就可以省略@Transactional注解。
4)在自定义的Repository接口中,使用@Query注解方式执行数据变更操作(修改、删除),除了要使用@Query注解,还必须添加@Modifying注解表示数据变更。
5)JPA还支持使用Example实例进行负责条件查询。例如,针对JpaRepository接口中已存在的findAll(Example<S> var1)方法进行查询

//用example精确匹配查询条件
        Discuss discuss=new Discuss();
        discuss.setAuthor("123");
        Example<Discuss> example=Example.of(discuss);
        List<Discuss> list=repository.findAll(example);
        //用exampleMatcher模糊匹配查询条件
        Discuss discuss1=new Discuss();
        discuss.setAuthor("1");
        ExampleMatcher matcher=ExampleMatcher.matching().withMatcher("author",startsWith());
        Example<Discuss> example1=Example.of(discuss,matcher);
        List<Discuss> list=repository.findAll(example);

使用Spring Boot整合JPA

1)添加Spring Data JPA依赖启动器。在项目的pom.xml文件中添加Spring Data JPA依赖启动器。

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

上述代码中,并没有编写Spring Data JPA对应的版本号,这是因为Spring Boot对Spring Data JPA的版本号进行了统一管理。
2)编写ORM实体类。为了方便操作,我们以之前创建的数据库表t_comment为例编写对应的实体类,将之前创建的Comment类复制一份并重命名为Discuss
Discuss.java

package com.example.chapter03;

import javax.persistence.*;

@Entity(name = "t_comment")
public class Discuss {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String author;
    private String content;
    @Column(name = "a_id")
    private Integer aId;
    //省略getXXX()和setXXX()方法
    //省略toString()方法
}

3)编写Repository接口。在chapter03项目中创建名为com.example.chapter03.repository的包,该包下创建一个用于对数据库表t_comment进行操作的Repository接口DiscussRepository。

package com.example.chapter03.repository;

import com.example.chapter03.Discuss;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.transaction.annotation.Transactional;

import java.awt.print.Pageable;
import java.util.List;

public interface DiscussRepository extends JpaRepository<Discuss,Integer> {
    public List<Discuss> findByAutorNotNull();
    @Query("select c from t_comment c where c.aId = ?1")
    public List<Discuss> getDiscussPaged(Integer aid, Pageable pageable);
    @Query(value = "select * from t_comment where a_Id = ?1",nativeQuery = true)
    public List<Discuss> getDiscussPaged2(Integer aid,Pageable pageable);
    @Transactional
    @Modifying
    @Query("update t_comment c set c.author = ?1 where c.id = ?2")
    public int updateDiscuss(String author,Integer id);
    @Transactional
    @Modifying
    @Query("delete t_comment c where c.id = ?1")
    public int deleteDiscuss(Integer id);
}

自定义一个DiscussRepository接口文件,并编写了对数据表t_comment进行查、改、删操作的方法。
4)编写单元测试进行接口方法测试。将Chapter03ApplicationTests测试类在当前位置复制一份并重命名为JpaTests,用来编写Jpa相关的单元测试,并对内容稍微修改后编写DiscussRepository接口对应的测试方法。

@Autowired
    private DiscussRepository repository;
    //使用JpaRepository内部方法进行数据操作
    @Test
    public void selectComment(){
        Optional<Discuss> optional=repository.findById(1);
        if(optional.isPresent()){
            System.out.println(optional.get());
        }
    }

springboot 搜索计数功能 springboot获取数据_springboot 搜索计数功能_05

@Test
    public void selectCommentByKeys(){
        List<Discuss> list=repository.findByAuthorNotNull();
        System.out.println(list);
    }

springboot 搜索计数功能 springboot获取数据_spring_06

@Test
    public void selectCommentPaged(){
        Pageable pageable= PageRequest.of(0,3);
        List<Discuss> allPaged = repository.getDiscussPaged(1,pageable);
        System.out.println(allPaged);
    }

springboot 搜索计数功能 springboot获取数据_spring boot_07

//使用Example封装参数进行数据查询操作
    @Test
    public void selectCommentByExample(){
        Discuss discuss=new Discuss();
        discuss.setAuthor("tom1");
        Example<Discuss> example=Example.of(discuss);
        List<Discuss> list=repository.findAll(example);
        System.out.println(list);
    }

springboot 搜索计数功能 springboot获取数据_spring boot_08

@Test
    public void selectCommentByExampleMatcher(){
        Discuss discuss=new Discuss();
        discuss.setAuthor("tom");
        ExampleMatcher matcher=ExampleMatcher.matching().withMatcher("author",startsWith());
        Example<Discuss> example=Example.of(discuss,matcher);
        List<Discuss> list=repository.findAll(example);
        System.out.println(list);
    }

springboot 搜索计数功能 springboot获取数据_spring_09

Spring Boot整合Redis

Redis介绍

Redis是一个开源(BSD许可)的、内存中数据结构存储系统,它可以用作数据库、缓存和消息中间件,并提供多种语言的API。Redis支持多种类型的数据结构,例如字符串(String)、散列(hashes)、列表(lists)、集合(sets)等。同时,Redis内部内置了复本(replication)、LUA脚本(Lua scripting)、LRU驱动事件(LRU eviction)、事务(Transaction) 和不同级别的磁盘持久化(persistence),并通过Redis Sentinel和自动分区提供高可用性(high avaliability)。
相较于其他的key-value键值存储系统而言,Redis主要有以下优点。
1)存放速度快LRedis速度非常快,每秒可执行大约110 000次的设置操作,或者执行81 000次的读取操作。
2)支持丰富的数据类型:Redis支持开发人员常用的大多数数据类型,例如列表、集合、排序集和散列等。
3)操作具有原子性:所有Redis操作都是原子操作,这确保如果两个客户端并发访问,Redis服务器能接受更新后的值。
4)提供多种功能:Redis提供了多种功能特性,可用作非关系型数据库、缓存中间件、消息中间件等。

Redis下载安装

使用非关系型数据库Redis,必须先进行安装配置并开启Redis服务器,然后使用对应客户端连接使用。Redis支持多种方式的安装配置,例如Windows、Linux系统安装,Docker镜像安装等,不同安装方式的安装过程也不相同。为了方便操作,此处选择在Windows平台下进行Redis安装。
限制GitHub上下载Windows平台下的Redis安装包,在下载列表中找到对应版本的Redis,并选择对应的安装包下载即可。
Redis3.2.100下载地址 这里使用的是Redis3.2.100版本(当前Spring Boot 2.1.3版本与Redis进行了自动化配置,需要使用Redis 3.2及以上版本进行使用连接)。

Redis服务开启与连接配置

完成Redis的下载安装后,启动Redis服务,并使用可视化客户端工具连接对应的Redis服务进行效果测试

1)开启Redis服务

先进入到Redis安装包的解压目录,其对应目录文件内容

springboot 搜索计数功能 springboot获取数据_spring_10


解压过后会有多个目录文件,包括两个可执行文件:

  • redis-cli.exe 用于开启客户端工具
  • redis-server.exe 用于开启redis服务
    这里双击redis-server.exe指令即可开启Redis服务

springboot 搜索计数功能 springboot获取数据_spring_11


从图中可以看出,Redis服务正常启动,同时在终端窗口显示了当前Redis版本为3.2.100和默认启动端口号为6379.

2)Redis可视化客户端工具安装连接

Redis解压目录下的redis-cli.exe指令用于开启客户端工具,不过双击这个指令打开的是终端操作界面,对于Redis的可视化操作和查看并不方便。这里推荐使用一个Redis客户端可视化管理工具Redis Desktop Manage连接服务进行管理

使用Spring Boot整合Redis

我们对Redis进行了简单介绍,并完成了Redis服务的安装配置,接下来重点讲解Spring Boot与Redis的整合使用
1)添加Spring Data Redis依赖启动器。先在项目的pom.xml文件中添加Redis依赖启动器。

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

上述添加的Redis依赖启动器代码中,也没有编写对应的版本号信号,这是因为Spring Boot为Redis实现了自动配置,所以会统一管理版本号信息。
2)编写实体类。此处为了延时Spring Boot与Redis数据库的整合使用,在chapter03项目的com.example.chapter03包下编写几个对应的实体类。
Person.java

package com.example.chapter03;

import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash;
import org.springframework.data.redis.core.index.Indexed;

import java.util.List;

@RedisHash("persons")
public class Person {
    @Id
    private String id;
    @Indexed
    private String lastname;
    private Address address;
    private List<Family> familyList;
    //省略getter和setter
    //省略有参和无参构造方法
    //省略toString()方法
}

Address.java

package com.example.chapter03;

import org.springframework.data.redis.core.index.Indexed;

public class Address {
    @Indexed
    private String city;
    @Indexed
    private String country;
    //省略getter和setter
    //省略有参和无参构造方法
    //省略toString()方法
}

Family.java

package com.example.chapter03;

import org.springframework.data.redis.core.index.Indexed;

public class Family {
    @Indexed
    private String type;
    @Indexed
    private String username;
    //省略getter和setter
    //省略有参和无参构造方法
    //省略toString()方法
}

@RedisHash(“persons”):用于指定操作实体类对象在Redis数据库中的存储空间,此处表示针对Person实体类的数据操作都存储在Redis数据库中名为persons的存储空间下。
@Id:用于标识实体类主键。在Redis数据库中会默认生成字符串形式的HashKey表示唯一的实体对象id,当然也可以在数据存储时手动指定id。
@indexed:用于标记对应属性在Redis数据库中生成二级索引。使用该注解后会在Redis数据库中生成属性对应的二级索引,索引名称就是属性名,可以方便地进行数据条件查询。
3)编写Repository接口。Spring Boot针对包括Redis在内地一些常用数据库提供了自动化配置,可以通过实现Repository接口简化对数据库中地数据进行地增删改查操作,这些操作方法通Spring Data JPA操作数据地使用方法基本相同,可以使用方法名关键字进行数据操作。这里我们在com.example.chapter03.repository包下创建操作Person实体类的PersonRepository接口
PersonRepository.java

package com.example.chapter03.repository;

import com.example.chapter03.Person;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.CrudRepository;

import java.util.List;

public interface PersonRepository extends CrudRepository<Person,String> {
    List<Person> findByLastname(String lastname);
    Page<Person> findPersonByLastname(String lastname, Pageable page);
    List<Person> findByFirstnameAndLastname(String firstname,Pageable pageable);
    List<Person> findByAddress_City(String city);
    List<Person> findByFamilyList_Username(String username);
}

PersonRepository接口继承自CrudRepositoty接口,该接口定义了若干查询方法。
需要说明的是,在操作Redis数据库时编写的Repository接口文件需要继承CrudRepository接口,而不是继承JpaRepository,这是因为JpaRepository是Spring Boot整合JPA特有的。当然,也可以在项目pom.xml文件中同时导入Spring Boot整合的JPA依赖和Redis依赖,这样就可以编写一个继承JpaRepository的接口操作数据库了。
4)Redis数据库连接配置。在项目的全局配置文件application.properties中添加Redis数据库的连接配置。

spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=

上述代码中,在Spring Boot项目的全局配置文件application.properties中额外添加了Redis数据库的相关配置信息。
注:上述配置中如果不进行配置,则使用默认配置localhost:6379
5)编写单元测试进行接口方法测试。将Chapter03ApplicationTests测试类在当前位置复制一份并重命名为RedisTests,并对内容稍稍修改后编写PersonRepository接口对应的测试方法。

@Autowired
    private PersonRepository repository;
    @Test
    public void savePerson(){
        Person person=new Person("张","有才");
        Person person2=new Person("James","Harden");
        Address address=new Address("北京","China");
        person.setAddress(address);
        List<Family> list=new ArrayList<>();
        Family dad=new Family("父亲","张三");
        Family mom=new Family("母亲","李四");
        list.add(dad);
        list.add(mom);
        person.setFamilyList(list);
        Person save=repository.save(person);
        Person save2=repository.save(person2);
        System.out.println(save);
        System.out.println(save2);
    }

springboot 搜索计数功能 springboot获取数据_java_12


springboot 搜索计数功能 springboot获取数据_spring boot_13

@Test
    public void selectPerson(){
        List<Person> list=repository.findByAddress_City("北京");
        System.out.println(list);
    }

springboot 搜索计数功能 springboot获取数据_spring_14

@Test
    public void updatePerson(){
        Person person=repository.findByFirstnameAndLastname("张","有才").get(0);
        person.setLastname("小明");
        Person update=repository.save(person);
        System.out.println(update);
    }

springboot 搜索计数功能 springboot获取数据_spring_15


springboot 搜索计数功能 springboot获取数据_java_16

@Test
    public void deletePerson(){
        Person person=repository.findByFirstnameAndLastname("张","小明").get(0);
        repository.delete(person);
    }

springboot 搜索计数功能 springboot获取数据_springboot 搜索计数功能_17


springboot 搜索计数功能 springboot获取数据_springboot 搜索计数功能_18