Spring Data JPA 总结

核心概念:Spring Data 存储库抽象中的中央接口是Repository【存储库的意思】,它将域类以及域类的ID类型作为类型参数进行管理,此接口用作标记接口,它就是爸爸,下面展示一下接口结构图

里面印象最深的就是CurdRepository接口,只要是入门基本上都是从这个接口入门的,就是进行简单的增删改查的操作。

注意点得话应该就是其中得save()方法 和JpaRepository接口中得saveAndFlush()方法了这两个区别:

  • save() :保存之前会判断数据库中是否已经存在该数据,存在就直接更新,不存在就插入
  • saveAndFlush():这个是保存并强制刷新,但是这个好像挺耗性能的,save()应该是保存到内存中 然后执行commit的时候在进行提交【??以后再探究】

其中还有 PageingAndSortingRepository接口:毋庸置疑得是分页得,但是我们工作中得分页查询会是【多条件指定查询+多条件模糊查询】,这个时候我们就需要使用ExampleMatcher接口构造多条件模糊查询 使用Example构造多条件指定查询。过一会我再来讲这两个方法得使用。

然后就是 JpaRepository接口了,它继承了PagingAndSortingRepository QueryByExampleExecutor接口 【里面有两个查询方法,参数就是Example<S> example

SimpleJpaRepository实现了JpaRepository接口 和JpaSpecificationExecutor【这个接口我觉得使用起来比较复杂的平常我不用这个,这个有点类似 Mybatis-Plus中的EntityWrapper条件构造器=-=】接口

你会发现貌似最底层的就是JpaRepository,所以继承这个就行了,基本需要的业务实现的也就都实现了

自定义创建查询:

这就是Jpa的快捷便利之处,内置的查询构建器机制,但是也要根据规范来,最基本的就是遇见下划线驼峰命名法了。比如 根据user_id 和 user_name进行查询

findByUserIdAndUserName(String userId,Stirng userName);

来讲一下他们的规范:

  • 查询的话一般有 find...By、read...By、query...By、count...By和get...By,当然我们也可以使用or and like将多个条件连接起来 注意like后面的参数需要自己加 %%【findBy+参数名+Like(参数)】
  • find 中还可以查询前几条数据 比如:
    User findFirstByOrderByLastnameAsc();
    
    User findTopByOrderByAgeDesc();
    
    Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);
    
    Slice<User> findTop3ByLastname(String lastname, Pageable pageable);
    
    List<User> findFirst10ByLastname(String lastname, Sort sort);
    
    List<User> findTop10ByLastname(String lastname, Pageable pageable);
  •  其实修改操作和删除操作也是可以像查询这样的规则定义的,只是实际中查询的业务条件多变这里就多列举一下了

 

关键词样品JPQL代码段

And

findByLastnameAndFirstname

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

Or

findByLastnameOrFirstname

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

Is,Equals

findByFirstnamefindByFirstnameIsfindByFirstnameEquals

… 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(附加参数绑定%

EndingWith

findByFirstnameEndingWith

… where x.firstname like ?1(与前置绑定的参数%

Containing

findByFirstnameContaining

… where x.firstname like ?1(包含参数绑定%

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)

关键词样品JPQL代码段

And

findByLastnameAndFirstname

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

Or

findByLastnameOrFirstname

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

Is,Equals

findByFirstnamefindByFirstnameIsfindByFirstnameEquals

… 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(附加参数绑定%

EndingWith

findByFirstnameEndingWith

… where x.firstname like ?1(与前置绑定的参数%

Containing

findByFirstnameContaining

… where x.firstname like ?1(包含参数绑定%

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)

还有一种就是自己自定义查询语句了

运用@Query注解自定义sql语句

使用命名查询来声明实体查询是一种有效的方法,适用于少量的查询。由于查询本身与执行它们的java方法关联,因此也可以使用@Query注解直接绑定他们。这种查询方法优先于使用@NameQuery或再其中生命的查询定义的查询orm.xml查询。【官方话语】DELETE和UPDATE操作的时候必须加上@modifying注解并配合着 @Transactional 告诉他这是一个事务操作   新增不需要,他不支持

直接上代码普通的 查询

public interface UserRepository extends JpaRepository<User, Long> {

  @Query("select u from User u where u.emailAddress = ?1")
  User findByEmailAddress(String emailAddress);
}

like方式

public interface UserRepository extends JpaRepository<User, Long> {

  @Query("select u from User u where u.firstname like %?1")
  List<User> findByFirstnameEndsWith(String firstname);
}

 还可以进行原生sql进行查询,在@Query中添加 nativeQuery=true即可

public interface UserRepository extends JpaRepository<User, Long> {

  @Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery = true)
  User findByEmailAddress(String emailAddress);
}

 还有一种就是使用命名参数【=-= 刚接触这个的时候我就喜欢这么写】

public interface UserRepository extends JpaRepository<User, Long> {

  @Query("select u from User u where u.firstname = :firstname or u.lastname = :lastname")
  User findByLastnameOrFirstname(@Param("lastname") String lastname,
                                 @Param("firstname") String firstname);
}

 下面给大家介绍一下ExampleExampleMatcher的使用

Example:如果是null将忽略具有值得字段,并使用特定的默认值进行匹配字符串,所以不用担心自己查询的条件是null了,这个是指定条件查询

Person person = new Person();                        1 
person.setFirstname("Dave");                         2 

Example<Person> example = Example.of(person);        3

1:创建对象实例

2:设置要查询的属性

3:创建example

然后调用QueryByExampleExecutor接口中的查询方法即可:

public interface QueryByExampleExecutor<T> {

  <S extends T> S findOne(Example<S> example);

  <S extends T> Iterable<S> findAll(Example<S> example);

  // … more functionality omitted.
}

 ExampleMatcher 这个时候构造模糊查询条件的

Person person = new Person();                          1
person.setFirstname("Dave");                           2

ExampleMatcher matcher = ExampleMatcher.matching()     3
  .withIgnorePaths("lastname")                         4
  .withIncludeNullValues()                             5
  .withStringMatcherEnding();                          6

Example<Person> example = Example.of(person, matcher); 7

1:创建对象的新实例 

2:设置属性【你有需要查询的条件就创建设置,没有就直接创建个对象便可】

3:创建ExampleMatcher

4:创建需要模糊查询的字段

5:可忽略属性路径并包含空值

6:忽略属性路径,包含空值,并执行后缀字符串匹配。

包含查询也可以使用       .withMatcher("scriptName",ExampleMatcher.GenericPropertyMatchers.contains())

插播一下我实际中的引用

ExampleMatcher matcher = ExampleMatcher.matching()
				.withMatcher("scriptName",ExampleMatcher.GenericPropertyMatchers.contains());
		script.setUser((User) session.getAttribute("sessionUser"));
		Example<Script> example = Example.of(script, matcher);

你也可以使用java8的新特性lambdas

ExampleMatcher matcher = ExampleMatcher.matching()
  .withMatcher("firstname", match -> match.endsWith())
  .withMatcher("firstname", match -> match.startsWith());
}

 同样也是使用QueryByExampleExecutor接口中的方法,其实现类是SimpleJpaRepository【之所以它实现 是因为他实现了jpaRepository接口,jpaRepository 的爸爸是 QueryByExampleExecutor】

下面直接上一个我的条件查询分页代码:

/**
	 * 查询脚本列表
	 * 
	 * @author zhangxuewei
	 */
	@Override
	public Page<Script> findIndicatorsPage(Integer pageNum, Integer pageSize, Script script, HttpSession session) {
		ExampleMatcher matcher = ExampleMatcher.matching().withMatcher("scriptName",
				ExampleMatcher.GenericPropertyMatchers.contains());
		script.setUser((User) session.getAttribute("sessionUser"));
		Example<Script> example = Example.of(script, matcher);
		Pageable pageable = PageRequest.of(pageNum, pageSize, Sort.Direction.DESC, "createTime");
		Page<Script> scriptPage = scriptDao.findAll(example, pageable);
		return scriptPage;
	}

还有注意的一点便是实体层了,多表查询配置个注解即可,我使用的是oracle数据库  sequenceName = "SEQ_SCRIPT"这个是我声明的序列名称 后面 initialValue = 1 是初始值为 , allocationSize = 1 自增长大小为1  属性上的@Transient注解是:不是数据库中的字段就需要加这个注解

package com.befery.oams.entity;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Transient;

@Entity
@Table(name = "OAMS_SCRIPT")
public class Script implements Serializable{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	@Id
	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "GEN_SCRIPT")
	@SequenceGenerator(name = "GEN_SCRIPT", sequenceName = "SEQ_SCRIPT", initialValue = 1, allocationSize = 1)
	private Long id;
	private String scriptName;
	private String scriptUuidName;
	private Date createTime;
	private Date updateTime;

	@OneToOne
	@JoinColumn(name="USER_ID",referencedColumnName="ID")
	private User user;
	
	@Transient
	private String scriptDesc;
......

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值