前言
Spring Data是一个非常大的伞形项目,由多个子项目组成,其中大多数子项目都关注对不同的数据库类型进行数据持久化。比较流行的几个Sprig Data项目包括:
Spring Data JPA:基于关系型数据库进行JPA持久化。
Spring Data MongoDB:持久化到Mongo文档数据库。
Spring Data Neo4j:持久化到Neo4j图数据库。
Spring Data Redis:持久化到Redis key-value存储。
Spring Data Cassandra:持久化到Cassandra数据库。
Spring Data 为所有项目提供了-项最有趣且最有用的特性,就是基于repository规范接口自动生成repository的功能。
我们就来了解一下Spring Data JPA :
JPA :Java Persistence API(Java 持久层 API):用于对象持久化的 API.
导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
Spring Boot应用可以通过JPA starter来添加Spring Data JPA。这个starter依赖不仅会引人Spring Data JPA,还会传递性地将Hibernate(开放源代码的对象关系映射框架)作为JPA的实现引入进来。
配置数据源信息
spring:
datasource:
url: jdbc:mysql://localhost:3306/Text
username: root
password: ********
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
database-platform: org.hibernate.dialect.MySQL5Dialect
定义实体对象
package sia.tacocloud.DAO;
import com.sun.istack.NotNull;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import javax.persistence.*;
import java.util.Arrays;
import java.util.Collection;
@Entity
@Table(name="boss")//表名
public class Boss {
private String name;
private String password;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
}
@Entity注解为了声明为JPA实体,他的id使用@Id注解,同时还设置了自动增长。
Spring 接口继承结构
声明JPA repository(继承CrudRepository)
CrudRepository定义了很多用于CRUD (创建、读取、更新、删除)操作的方法。注意,它是参数化的,第一个参数是repository要持久化的实体类型,第二个参数是实体ID属性的类型。对于BossRepository来说,参数应该是Boss和Integer。我们可以非常简单地定义BossCrudRepository
package sia.tacocloud.DAO;
import org.springframework.data.repository.CrudRepository;
import java.util.List;
public interface BossCrudRepository extends CrudRepository<Boss,Integer> {
}
现在,我们有了repository。你可能会想,我们应该需要编写它们的实现类,包括每个实现类所需的十多个方法。但是,Spring Data JPA带来的好消息是,我们根本就不用编写实现类!当应用启动的时候,Spring Data JPA会在运行期自动生成实现类。这意味着,我们现在就可以使用这些repository 了。我们只需要像使用基于JDBC的实现那样将它们注人控制器中就可以了,如下我们来测试一下。
测试类
@RunWith(SpringRunner.class)
@SpringBootTest
public class CrudTest {
@Autowired
private BossCrudRepository bossCrudRepository;
/**
* 添加单个用户
*/
@Test
public void testAddBoss(){
Boss boss = new Boss();
boss.setName("王七");
boss.setPassword("123");
bossCrudRepository.save(boss);
}
/**
* 批量添加用户
*/
@Test
public void test2(){
Boss boss = new Boss();
boss.setName("张二");
boss.setPassword("12333");
Boss boss1 = new Boss();
boss1.setName("申六");
boss1.setPassword("12222");
List<Boss> list= new ArrayList<>();
list.add(boss);
list.add(boss1);
bossCrudRepository.save(list);
}
/**
* 根据ID查询单条数据
*/
@Test
public void test3(){
Boss boss = bossCrudRepository.findOne(13);
System.out.println(boss);
}
/**
* 查询全部数据
*/
@Test
public void test4(){
List<Boss> list = (List<Boss>)bossCrudRepository.findAll();
System.out.println(list.toString());
}
/**
* 删除数据
*/
@Test
public void test5(){
bossCrudRepository.delete(13);
}
/**
* 更新数据 方式一
*/
@Test
public void test6(){
Boss boss = bossCrudRepository.findOne(12);
boss.setName("王五");
bossCrudRepository.save(boss);
}
/**
* 更新数据 方式二
*/
@Test
@Transactional//在测试类对于事务提交方式默认的是回滚。
@Rollback(false)//取消自动回滚
public void test7(){
Boss boss = bossCrudRepository.findOne(12);//持久化状态的
boss.setName("李四");
}
}
声明JPA repository(继承 PagingAndSortingRepository)
package sia.tacocloud.DAO;
import org.springframework.data.repository.PagingAndSortingRepository;
public interface BossPageAndSortJPARepository extends PagingAndSortingRepository<Boss, Integer> {
}
测试类
package sia.tacocloud.Control;
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.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.test.context.junit4.SpringRunner;
import sia.tacocloud.Configuration.ConfigurationProps;
import sia.tacocloud.DAO.Boss;
import sia.tacocloud.DAO.BossPageAndSortJPARepository;
import java.util.List;
import java.util.function.Consumer;
@RunWith(SpringRunner.class)
@SpringBootTest
public class BossPageText {
@Autowired//自定义配置属性,用来获取每页多少数据
private ConfigurationProps configurationProps;
@Autowired
private BossPageAndSortJPARepository bossPageAndSortJPARepository;
/**
* 分页
*/
@Test
public void testPage(){
int page = 2; //page:当前页的索引。注意索引都是从0开始的。
//PageSize显示每页多少条数据,这里使用自定义配置属性,属性源是应用配置文件
//数据库页数从0开始
//获取PageRequest的新方法,新版本
Pageable pageable= PageRequest.of(page-1,configurationProps.getPageSize());
Page<Boss> p = this.bossPageAndSortJPARepository.findAll(pageable);
System.out.println("数据的总条数:"+p.getTotalElements());
System.out.println("总页数:"+p.getTotalPages());
//获取当前页的数据
List<Boss> list = p.getContent();
for (Boss boss : list) {
System.out.println(boss.getId()+" "+boss.getPassword());
}
}
@Test
public void textPageAndSort(){
//获取Sort的新方法,新版本,对password先排序,在进行分页,如果不分页就直接传入sort就行,依情况而定
Sort password = Sort.by(Sort.Direction.DESC, "password");
Pageable of = PageRequest.of(0, 3, password);
Iterable<Boss> all = bossPageAndSortJPARepository.findAll(of);
all.forEach(boss -> System.out.println(boss.getId()+" "+boss.getPassword()));
}
}
上述Repository所提供的方法对于实体的通用持久化是非常有用的。但是,如果我们的需求并不局限于基本持久化,那又该怎么办呢?接下来,我们看一下如何自定义repositry来执行特定领域的查询。
自定义 JPA repository
Spring Data JPA 中为我们提供了两种查询方式的支持
1)基于方法名称命名规则查询
2)基于@Query 注解查询
方法名称命名规则查询
规则:
findBy(关键字)+属性名称(属性名称的首字母大写)+查询条件(首字母大写)
复制
关键字 | 方法命名 | sql where 字句 |
---|---|---|
And | findByNameAndPwd | where name= ? and pwd =? |
Or | findByNameOrSex | where name= ? or sex=? |
Between | findByIdBetween | where id between ? and ? |
LessThan | findByIdLessThan | where id < ? |
LessThanEqual | findByIdLessThanEquals | where id <= ? |
GreaterThan | findByIdGreaterThan | where id > ? |
GreaterThanEqual | findByIdGreaterThanEquals | where id > = ? |
After | findByIdAfter | where id > ? |
Before | findByIdBefore | where id < ? |
IsNull | findByNameIsNull | where name is null |
isNotNull,Not Null | findByNameNotNull | where name is not |
Like | findByNameLike | where name like ? |
NotLike | findByNameNotLike | where name not like ? |
StartingWith | findByNameStartingWith | where name like ‘?%’ |
EndingWith | findByNameEndingWith | where name like ‘%?’ |
Containing | findByNameContaining | where name like ‘%?%’ |
OrderBy | findByIdOrderByXDesc | where id=? order by x desc |
Not | findByNameNot | where name <> ? |
In | findByIdIn(Collection<?> c) | where id in (?) |
NotIn | findByIdNotIn(Collection<?> c) | where id not in (?) |
True | findByAaaTue | where aaa = true |
False | findByAaaFalse | where aaa = false |
IgnoreCase | findByNameIgnoreCase | where UPPER(name)=UPPER(?) |
创建接口
public interface BossRepository extends Repository<Boss, Integer> {
//方法名称命名规则
List<Users> findByNameLike(String name);
List<Users> findByNameAndIdGreaterThanEqual(String name,Integer id);
}
测试类
@RunWith(SpringRunner.class)
@SpringBootTest
public class RepositoryTest {
@Autowired
private BossRepository bossRepository;
/**
* 需求:根据用户姓名做Like处理
*/
@Test
public void test1(){
List<Boss> list = bossRepository.findByNameLike("%申%");
System.out.println(list.toString());
}
/**
* 需求:查询名称为王五,并且他的年龄大于等于17岁
*/
@Test
public void test2(){
List<Boss> list = this.usersDao.findByNameAndIdGreaterThanEqual("王五", 17);
System.out.println(list.toString());
}
}
尽管方法名称约定对于相对简单的查询非常有用,但是,不难想象,对于更为复杂的查询,方法名可能会面临失控的风险。在这种情况下,可以将方法定义为任何你想要的名称,并为其添加@Query注解从而明确指明方法调用时要执行的查询,如下面的样例所示:
2)基于@Query 注解查询
创建接口
public interface BossQueryRepository extends Repository<Boss,Integer> {
//启用SQL查询
@Query(value ="select * from boss where name like ? or ID > ? ",nativeQuery=true)
List<Boss> byNameOrIdUseSQL(String name,int id);
@Query(value="select * from boss where name like ? and Id = 9",nativeQuery=true)
List<Boss> byLikeNameAndIdUseSQL(String name,int id);
测试类
@RunWith(SpringRunner.class)
@SpringBootTest
public class RepositoryTest {
@Autowired
private BossQueryRepository bossQueryRepository;
/**
* 需求:根据用户姓名like申%或者Id>21
*/
@Test
public void test1(){
List<Boss> sc = bossQueryRepository.byNameOrIdUseSQL("申%",21);
System.out.println(list.toString());
}
/**
* 需求:查询名称like%王%,并且他的ID等于17
*/
@Test
public void test2(){
List<Boss> list = bossQueryRepository.byLikeNameAndIdUseSQL("%王%", 17);
System.out.println(list.toString());
}
}
来源:Spring实战5
https://www.cnblogs.com/chenglc/p/11226693.html