spring data包含很多与数据库相关的内容,这里我们主要介绍spring data中的jparedissolr的内容。

JPA

简介

Jpa (Java Persistence API) 是 Sun 官方提出的 Java 持久化规范。它为 Java 开发人员提供了一种对象/关联映射工具来管理 Java 应用中的关系数据。它的出现主要是为了简化现有的持久化开发工作和整合 ORM 技术,结束现在 Hibernate,TopLink,JDO 等 ORM 框架各自为营的局面。

注意:Jpa 是一套规范,不是一套产品,那么像 Hibernate,TopLink,JDO 他们是一套产品,如果说这些产品实现了这个 Jpa 规范,那么我们就可以叫他们为 Jpa 的实现产品。

Spring Boot Jpa 是 Spring 基于 ORM 框架、Jpa 规范的基础上封装的一套 Jpa 应用框架,可使开发者用极简的代码即可实现对数据的访问和操作。它提供了包括增删改查等在内的常用功能,且易于扩展!学习并使用 Spring Data Jpa 可以极大提高开发效率!

Spring Boot Jpa 让我们解脱了 DAO 层的操作,基本上所有 CRUD 都可以依赖于它来实现

添加依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <!-- 如果你的是1.5.21版spring boot,或者你的MySQL是5.6及以上版本就可以不指定版本,否则可以指定一下版本,2.x系列spring boot指定的驱动是8.0版的,不指定版本会跟自己的MySQL数据库连接不上(版本不兼容) -->
    <!-- <version>5.1.47</version> -->
</dependency>

使用JPA

创建实体类

下面以我自己的数据库中的一个message表为例

import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.sql.Timestamp;

/**
 * 使用Spring Data JPA操作数据库,实体类上需要加@Entity注解、主键属性上需要加@Id注解.
 * 这个@Entity注解是JPA里提供的注解,标注此类是一个实体类
 *
 * @author bennett
 */

@Setter
@Getter
@Entity
@Table(name = "message")
public class Message {

    /**
     * 消息状态:已读状态
     */
    public static final int STATUS_READED = 1;
    /**
     * 消息状态:未读状态
     */
    public static final int STATUS_UNREAD = 2;
    /**
     * 消息状态:删除状态
     */
    public static final int STATUS_DELETE = 3;

    /**
     * 也是JPA里提供的注解,标注了此属性是主键ID
     */
    @Id
    @GeneratedValue
    private Integer id;

    /**
     * 这里如果用apache的dbutils查询的话,字段名称必须和数据库中完全一样。否则结果集封装不进来
     */
    @Column
    private Integer fromId;
    @Column
    private Integer toId;
    @Column
    private String subject;
    @Column
    private String content;
    @Column
    private Integer status;
    @Column
    private Timestamp createTime;
    @Column
    private String attachment;

    @Override
    public String toString() {
        return "Message{" + "id=" + id + ", fromId=" + fromId + ", toId=" + toId + ", subject='" + subject + '\'' + ", content='" + content + '\'' + ", status=" + status + ", createTime=" + createTime + ", attachment='" + attachment + '\'' + '}';
    }
}

自定义CRUD操作

使用spring data中的jpa就可以让我们自己的接口继承JpaRepository这个接口,这样我们就可以同时使用spring boot JPA提供的一些CRUD方法,也可以添加自定义的方法供我们使用。

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import javax.transaction.Transactional;
import java.util.List;

/**
 * 使用JPA完成数据库的CRUD操作
 *
 * @author bennett
 */

public interface MessageDao extends JpaRepository<Message, Integer> {

    /**
     * 按status字段查找
     *
     * @param status 状态
     * @return Message集合
     */
    List<Message> findMessageByStatus(Integer status);

    /**
     * 自定义SQL查询,此处写的不是标准的SQL语句,而是JPQL
     *
     * @return Message集合
     */
    @Query("select m from Message m")
    List<Message> findMessage();

    /**
     * 事务@Transactional注解必须加到update、save、delete这些修改数据操作上(否则会报没有可用事务异常)
     * 下面的@Query、@Modifying这俩注解是一组,适合于自定义SQL语句时配合使用。
     *
     * @param id
     */
    @Transactional(rollbackOn = java.lang.Exception.class)
    @Query("delete from Message where id = ?1")
    @Modifying
    @Override
    void deleteById(Integer id);
}

?1代表第一个占位符?,后续还有条件可以用?2?3....表示

配置Spring Boot

要想使用JPA还需要在SpringBoot中添加两个属性(1.5.21不需要第二个)

spring:
  jpa:
    show-sql: true
    hibernate:
      use-new-id-generator-mappings: false #这个属性在2.x系列的spring boot中默认是true,要改为false

Spring Boot JPA提供的方法

@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {

	List<T> findAll();

     /**
     * 返回所有的实体,根据Sort参数提供的规则排序。
     */
	List<T> findAll(Sort sort);

     /**
     * 根据给定的id集合查询所有对应的实体,返回实体集合。
     */
	List<T> findAllById(Iterable<ID> ids);

    /**
     * 保存提供的所有实体。
     */
	<S extends T> List<S> saveAll(Iterable<S> entities);

     /**
     * 将所有未决的更改刷新到数据库。
     */
	void flush();

    /**
     * 保存一个实体并立即将更改刷新到数据库。
     */
	<S extends T> S saveAndFlush(S entity);

    /**
     * 在一个批次中删除给定的实体集合,这意味着将产生一条单独的Query。
     */
	void deleteInBatch(Iterable<T> entities);

    /**
     * 在一个批次中删除所有的实体。
     */
	void deleteAllInBatch();
    
	T getOne(ID id);
    
    /**
    * 根据扩展的条件查询所有
    */
	@Override
	<S extends T> List<S> findAll(Example<S> example);
    
    /**
    * 根据扩展条件和排序规则查询所有并排序
    */
	@Override
	<S extends T> List<S> findAll(Example<S> example, Sort sort);
}

测试JPA的方法

下面仅测试了JPA中的查询方法和几个自定义的方法

import com.demo.springboot.bean.Message;
import com.demo.springboot.dao.MessageDao;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

/**
 * 测试JPA里面的方法
 *
 * @author bennett
 */

@RunWith(SpringRunner.class)
@SpringBootTest
public class JpaTest {

    @Autowired
    private MessageDao messageDao;

    /**
     * 调用JPA中原生的findAll方法
     */
    @Test
    public void testQueryMessage() {
        List<Message> messageList = messageDao.findAll();
        System.out.println("一共" + messageList.size() + "条数据");
        for (Message message : messageList) {
            System.out.println(message);
        }
    }

    /**
     * 调用自定义的按照status查询
     */
    @Test
    public void testQueryMessageByStatus() {
        List<Message> messageList = messageDao.findMessageByStatus(3);
        System.out.println("一共" + messageList.size() + "条数据");
        for (Message message : messageList) {
            System.out.println(message);
        }
    }

    /**
     * 调用Spring JPA原生 saveAndFlush修改数据(id存在则更新,否则执行插入)
     */
    @Test
    public void testUpdateMessage() {
        Message message = new Message();
        // message.setId(40);
        message.setContent("Bennett");
        messageDao.saveAndFlush(message);
    }

    /**
     * 调用自定义语句完成删除操作
     */
    @Test
    public void testDeleteMessageById() {
        messageDao.deleteById(29);
    }

    /**
     * 调用自定义语句完成查询
     */
    @Test
    public void testQueryMessageBySQL() {
        List<Message> messageList = messageDao.findMessage();
        System.out.println("一共" + messageList.size() + "条数据");
        for (Message message : messageList) {
            System.out.println(message);
        }
    }
}

JPA关键字

具体的关键字,使用方法和生产成SQL如下表所示

KeywordSampleJPQL snippet
AndfindByLastnameAndFirstname… where x.lastname = ?1 and x.firstname = ?2
OrfindByLastnameOrFirstname… where x.lastname = ?1 or x.firstname = ?2
Is,EqualsfindByFirstnameIs,findByFirstnameEquals… where x.firstname = ?1
BetweenfindByStartDateBetween… where x.startDate between ?1 and ?2
LessThanfindByAgeLessThan… where x.age < ?1
LessThanEqualfindByAgeLessThanEqual… where x.age ⇐ ?1
GreaterThanfindByAgeGreaterThan… where x.age > ?1
GreaterThanEqualfindByAgeGreaterThanEqual… where x.age >= ?1
AfterfindByStartDateAfter… where x.startDate > ?1
BeforefindByStartDateBefore… where x.startDate < ?1
IsNullfindByAgeIsNull… where x.age is null
IsNotNull,NotNullfindByAge(Is)NotNull… where x.age not null
LikefindByFirstnameLike… where x.firstname like ?1
NotLikefindByFirstnameNotLike… where x.firstname not like ?1
StartingWithfindByFirstnameStartingWith… where x.firstname like ?1 (parameter bound with appended %)
EndingWithfindByFirstnameEndingWith… where x.firstname like ?1 (parameter bound with prepended %)
ContainingfindByFirstnameContaining… where x.firstname like ?1 (parameter bound wrapped in %)
OrderByfindByAgeOrderByLastnameDesc… where x.age = ?1 order by x.lastname desc
NotfindByLastnameNot… where x.lastname <> ?1
InfindByAgeIn(Collection ages)… where x.age in ?1
NotInfindByAgeNotIn(Collection age)… where x.age not in ?1
TRUEfindByActiveTrue()… where x.active = true
FALSEfindByActiveFalse()… where x.active = false
IgnoreCasefindByFirstnameIgnoreCase… where UPPER(x.firstame) = UPPER(?1)

Redis

Redis 是目前业界使用最广泛的内存数据存储。相比 Mogodb,Redis 支持更丰富的数据结构,例如 hash, list, set ,zset等,同时支持数据持久化。本章主要是介绍redis在spring boot中的应用

添加依赖

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

SpringBoot redis的使用

下面只是给出了spring boot中使用redis的方式,redis的具体使用方式读者可以去看我写的另一篇关于Redis的一些使用方式和介绍👉Spring Boot中Redis的配置与使用

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

/**
 * 练习redis
 *
 * @author bennett
 */

@Service
public class RedisService {

    /**
     * SpringBoot会自动帮我们装配RedisConnectionFactory, StringRedisTemplate, RedisTemplate这几个类
     * 自动装配的属性可以直接注入到我们的类中使用
     */
    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 专门操作String类型的key\value
     */
    private StringRedisTemplate redisTemplateForString;

    /**
     * 添加键与值
     *
     * @param key   键
     * @param value 值
     */
    public void set(String key, String value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 获取指定键的值
     *
     * @param key 键
     * @return 值
     */
    public Object get(String key) {
        return redisTemplate.opsForValue().get(key);
    }
}

测试Redis的方法

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * 测试redis
 *
 * @author bennett
 */

@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisTest {

    @Autowired
    private RedisService redisService;

    /**
     * 测试Redis
     */
    @Test
    public void testSet() {
        redisService.set("springboot", "hello redis");
        Assert.assertEquals("没存进去", "hello redis", redisService.get("springboot"));
    }
}

介于篇幅问题,本篇文章就先介绍这么多,至于solr搜索引擎请关注下一篇博客。