了解Spring Data(一)
spring data包含很多与数据库相关的内容,这里我们主要介绍spring data中的jpa
、redis
、solr
的内容。
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如下表所示
Keyword | Sample | JPQL snippet |
---|---|---|
And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 |
Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
Is,Equals | 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 ages) | … where x.age in ?1 |
NotIn | findByAgeNotIn(Collection age) | … 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) |
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搜索引擎请关注下一篇博客。