方式类总:
方式一、方式二、方式五:
面向对象的查法,用JPA底层提供的方法 (不需要写SQL,JPQL)
JPA对方式一二提供的支持有限,只能实现一些简单的CRUD;如果要实现复杂的功能,则使用方式五
方式五的思路,类似于mybatis逆向工程。设计理念:可以让不懂SQL的人,写出复杂的SQL语句
方式三、方式四:
自己需要写SQL,JPQL
jpa使用方式一
dao层中自己不用写任何方法,只调用父接口中的方法。
缺点:父接口中提供的方法有限
jpa使用方式二
可以编写自己的方法,并不写SQL。前提根据约定写方法名字
jpa使用方式三
面向对象SQL语句:JPQL
按形参位置写法
@Query("select p from People p where id=?1 and age=?2")
publish List<People> findByIdAndAge(int id, int age);
具名参数写法
@Query("select p from People p where id=:id and age=:age")
publish List<People> findByIdAndAge(@Param("id") int id, @Param("age") int age);
方式三基础加分页功能:
Pageable(PageRequest)
jpa使用方式四:
面向SQL(原生的SQL语句),推荐
原生sql增
@Modifying
@Query(nativeQuery=true, value="insert into tb_address(id,name) values(?,?) ")
publish List<People> addAddress(Integer id, String name);
原生sql删
@Modifying
@Query(nativeQuery=true, value="delete from tb_address where id=? ")
publish List<People> delAddress(Integer id);
原生sql改
@Modifying
@Query(nativeQuery=true, value="update tb_address a set a.name=? where a.id=?")
publish List<People> updateAddress(String name, Integer id);
原生sql查
问号形式
@Query(nativeQuery=true, value="select * from tb_people where name=? and age=?")
publish List<People> findByNameAndAge(string name, int age);
具名参数形式
@Query(nativeQuery=true, value="select * from tb_people where age in (:ages)")
publish List<People> findByAges(@Param("ages") int age);
:age 具名参数,说明是一个变量而不是普通的字段
方式四基础加分页功能:
Pageable(PageRequest)
jpa使用方式五:
面向对象查法
方式五实现步骤:
类似方式一,不用在dao中自定义任何方法(要写dao,只是不用写dao中的方法)
如findAll(实现Specification接口) 使用Predicate构造查询条件
实现service, controller
在动态查询Specifications有详细说明
动态查询:
QueryByExample
QBE是一种通用的查询机制,它允许您根据示例对象的属性值进行查询。您可以创建一个示例对象,设置其中的属性值作为查询条件,然后通过执行QBE查询来获取匹配的结果。QBE机制一般是通过使用动态查询构建器(如Criteria API)或自定义查询方法实现的。
- 只能针对字符串开头/包含/结尾/正则的匹配
- 不支持嵌套条件 ,如 or
Example
Example是JPA的一种特定实现,它是基于JPA的标准规范的一部分。它提供了一个Example类和ExampleMatcher类,用于根据示例对象的属性创建查询条件。可以创建一个示例对象,设置其中的属性值和匹配规则,然后使用Example对象作为查询条件,执行JPA查询方法,JPA会自动生成相应的查询语句来获取匹配的结果。Example适用于简单的查询场景,对于复杂的查询需求可能不够灵活。
具体来说,JPA的Example机制提供了以下功能:
- 创建示例对象:您可以创建一个具有特定属性值的实体对象,作为查询的示例。
- 匹配规则:您可以定义属性之间的匹配规则,如忽略大小写、模糊匹配等。
- 查询条件:使用Example对象作为查询条件,JPA会自动生成相应的查询语句。
使用Example时,您可以根据需要设置以下内容:
- 示例对象:创建一个具有特定属性值的实体对象,用作查询的示例。
- 匹配器(ExampleMatcher):定义属性之间的匹配规则,如忽略大小写、模糊匹配等。
- 示例选项(ExampleOptions):定义查询选项,如是否忽略Null值属性等。
通过使用Example,您可以在不编写原生SQL或JPQL查询语句的情况下,根据实体对象的属性值进行动态查询。
以下是一个基本示例,展示了如何使用JPA的Example机制:
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.jpa.repository.JpaRepository;
// 实体类
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
// 其他属性和方法...
}
// Repository接口
public interface UserRepository extends JpaRepository<User, Long> {
}
// 使用Example进行查询
public class ExampleUsage {
private UserRepository userRepository;
public List<User> findByExample(User user) {
ExampleMatcher matcher = ExampleMatcher.matching()
.withIgnoreCase()
.withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING);
Example<User> example = Example.of(user, matcher);
return userRepository.findAll(example);
}
}
Specifications
Specification机制提供了更高级的动态查询功能,是Spring Data JPA提供的一种机制。它允许您根据特定的查询条件创建查询规范,这些查询条件可以基于实体属性、关联关系、逻辑运算符等。通过编写自定义的Specification实现类,您可以定义复杂的查询逻辑,并将其应用于JPA查询方法中。Specification提供了更大的灵活性和自定义能力,适用于更复杂的查询需求。
普通条件动态查询
dao层代码实现
@Repository
public interface TGtSampleDao extends JpaRepository<TGtSample, String>, JpaSpecificationExecutor<TGtSample> {
}
service层依赖包引入
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
service层方法代码实现
public R list(TGtSampleDto dto) {
List<TGtSample> list = dao.findAll(new Specification<TGtSample>() {
@Override
public Predicate toPredicate(Root<TGtSample> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
// 查询条件
List<Predicate> predicates = new ArrayList<>();
if(dto.getType() != null){ // 是否where子句中有id
predicates.add(criteriaBuilder.equal(root.get("type").as(Integer.class), dto.getType()));
}
if(dto.getRailwayBureau()!=null && dto.getRailwayBureau()!=""){ // 是否where子句中有railwayBureau
predicates.add(criteriaBuilder.like(root.get("railwayBureau").as(String.class), "%"+dto.getRailwayBureau()+"%"));
}
if(dto.getMinUploadTime()!=null){ // 是否where子句中有uploadTime
predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("uploadTime").as(LocalDateTime.class), dto.getMinUploadTime()));
}
if(dto.getMaxUploadTime()!=null){ // 是否where子句中有uploadTime
predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("uploadTime").as(LocalDateTime.class), dto.getMaxUploadTime()));
}
criteriaQuery.orderBy(criteriaBuilder.desc(root.get("uploadTime").as(Date.class)));
return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
}
});
return R.ok(list);
}
分页条件动态查询
dao层代码实现
@Repository
public interface TGtSampleDao extends JpaRepository<TGtSample, String>, JpaSpecificationExecutor<TGtSample> {
}
service层依赖包引入
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
service层方法代码实现
public R list(TGtSampleDto dto) {
Page<TGtSample> page = dao.findAll(new Specification<TGtSample>() {
@Override
public Predicate toPredicate(Root<TGtSample> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
// 查询条件
List<Predicate> predicates = new ArrayList<>();
if(dto.getType() != null){ // 是否where子句中有id
predicates.add(criteriaBuilder.equal(root.get("type").as(Integer.class), dto.getType()));
}
if(dto.getRailwayBureau()!=null && dto.getRailwayBureau()!=""){ // 是否where子句中有railwayBureau
predicates.add(criteriaBuilder.like(root.get("railwayBureau").as(String.class), "%"+dto.getRailwayBureau()+"%"));
}
if(dto.getMinUploadTime()!=null){ // 是否where子句中有uploadTime
predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("uploadTime").as(LocalDateTime.class), dto.getMinUploadTime()));
}
if(dto.getMaxUploadTime()!=null){ // 是否where子句中有uploadTime
predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("uploadTime").as(LocalDateTime.class), dto.getMaxUploadTime()));
}
criteriaQuery.orderBy(criteriaBuilder.desc(root.get("uploadTime").as(Date.class)));
return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
}
}, PageRequest.of(dto.getCurrentPage(), dto.getSize()));
return R.ok(page);
}
Querydsl
第三方通用查询框架
获取分页查询结果参数
在Spring Data JPA中,执行分页查询时,可以通过Page
对象获取分页结果参数。Page
对象提供了一些方法来访问分页信息和查询结果。
以下是一些常用的Page
对象的方法:
getContent()
: 返回当前页的查询结果列表。getTotalElements()
: 返回查询结果的总数量。getTotalPages()
: 返回查询结果的总页数。getNumber()
: 返回当前页的页码。getSize()
: 返回每页的大小(每页显示的结果数量)。hasNext()
: 检查是否有下一页。hasPrevious()
: 检查是否有上一页。
下面是一个示例代码,演示如何执行分页查询并获取分页结果参数:
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
// 在您的Repository接口中定义方法
Pageable pageable = PageRequest.of(pageNumber, pageSize);
Page<YourEntity> page = yourRepository.findAll(specification, pageable);
// 获取分页结果参数
List<YourEntity> content = page.getContent(); // 当前页的查询结果列表
long totalElements = page.getTotalElements(); // 查询结果的总数量
int totalPages = page.getTotalPages(); // 查询结果的总页数
int currentPage = page.getNumber(); // 当前页的页码
int pageSize = page.getSize(); // 每页的大小
// 检查是否有下一页和上一页
boolean hasNextPage = page.hasNext();
boolean hasPreviousPage = page.hasPrevious();
在上述代码中,首先使用PageRequest
来创建Pageable
对象,然后在yourRepository
上调用findAll()
方法执行分页查询,传入specification
和pageable
作为参数。返回的Page
对象可以通过调用相应的方法来获取分页结果参数。
请注意,pageNumber
从0开始,表示第一页;pageSize
表示每页的大小(每页显示的结果数量)。
通过使用Page
对象,您可以轻松获取分页查询的结果和相关信息。
SQL小知识:
1.在使用group by时, select后的字段,要么是聚合函数,要么在group by后面
2.待更新