核心概念: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代码段 |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
关键词 | 样品 | JPQL代码段 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
还有一种就是自己自定义查询语句了
运用@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);
}
下面给大家介绍一下Example和ExampleMatcher的使用
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;
......