SpringDataJPA(二) 分页查询与动态条件
1、分页查询
Spring Data JPA 中 Pageable
是分页查询的抽象接口,其包含了基本分页信息(如页码、每页大小、排序等)。而PageRequest
则是 Pageable
接口的实现类,提供了具体的分页参数生成功能。常用的几种分页查询构造方法如下:
Return | Method | Description |
---|---|---|
static PageRequest |
of(int pageNumber, int pageSize) |
构造分页查询请求: - pageNumber :查询页码(起始页为0,不得为负数);- pageSize :查询页大小(必须大于0); |
static PageRequest |
of(int pageNumber, int pageSize, Sort sort) |
构造分页查询请求并对结果排序: - pageNumber :查询页码(起始页为0,不得为负数);- pageSize :查询页大小(必须大于0);- sort :排序规则(不能为空,默认以 Sort.unsorted() 代替); |
static PageRequest |
of(int pageNumber, int pageSize, Sort.Direction direction, String... properties) |
构造分页查询请求并对结果排序: - pageNumber :查询页码(起始页为0,不得为负数);- pageSize :查询页大小(必须大于0);- direction :排序方向(不可为空);- properties :排序属性(不可为空); |
// 第一种实例化 Pageable
Pageable pageable1 = PageRequest.of(1, 2);
//第二种实例化 Pageable
Sort sort = Sort.by(Sort.Direction.ASC, "age");
Pageable pageable2 = PageRequest.of(1, 2, sort);// 升序
//第三种实例化 Pageable
Pageable pageable3 = PageRequest.of(1, 2, Sort.Direction.DESC, "age");// 降序
在 Spring Data JPA 的查询方法中,要实现查询结果的分页,只需确保定义的 Repository 继承自 PagingAndSortingRepository 接口,并在 JPA 查询接口方法参数的最后追加构造好的 Pageable
分页参数即可,JPA 可以自动对分页参数进行解析和执行。返回结果包括以下两种类型:
(1)Slice<T>
Slice
提供了轻量级分页查询功能,其不包含总页数或总记录数信息,仅包含是否有下一页的信息。Slice
返回的数据和 Page
类似,但因为不需要执行 count
查询,因此性能开销较小,适用于数据量较大且不关心总数的场景,比如“加载更多”、“滚动加载”等。
Return | Method | Description |
---|---|---|
List<T> |
getContent() |
返回查询当前页的数据列表 |
int |
getNumber() |
返回查询当前页的页码 |
int |
getNumberOfElements() |
返回查询当前页的元素数量 |
int |
getSize() |
返回分页大小 |
boolean |
hasNext() |
判断是否有下一页 |
boolean |
hasPrevious() |
判断是否有上一页 |
(2)Page<T>
Page
接口继承自Slice
,其在Slice
基础之上还包含了总页数、总记录数等信息,适用于需要详细、完整、精确分页信息的场景,比如分页按钮、分页导航等。相比Slice
来说,其需要额外查询数据总数count
,所以在查询大数据集时性能开销较大、性能略低。
Return | Method | Description |
---|---|---|
long |
getTotalElements() |
返回查询元素总数 |
int |
getTotalPages() |
返回查询总页数 |
(3)代码示例
// 命名规则方法
public Slice<UserInfo> findByAgeGreaterThan(int age, Pageable pageable);
// JPQL查询
@Query("select u from UserInfo u where u.name like ?1%")
public Page<UserInfo> findByNameLike(String name, Pageable pageable);
// 1.保留方法: Page
PageRequest pageRequest = PageRequest.of(page, size);
Page<UserInfo> pageInfo = userInfoDao.findAll(pageRequest);
System.out.println(pageInfo.getTotalPages()); // 获取总页数
System.out.println(pageInfo.getTotalElements()); // 获取总元素数
System.out.println(pageInfo.getNumberOfElements()); // 获取当前页元素数
return pageInfo.getContent(); // 返回当前页的数据列表
// 2.命名规则方法: Slice
PageRequest pageRequest = PageRequest.of(page, size);
Slice<UserInfo> pageInfo = userInfoDao.findByAgeGreaterThan(18, pageRequest);
return pageInfo.getContent(); // 返回当前页的数据列表
// 3.JPQL查询: Page+Sort
PageRequest pageRequest = PageRequest.of(page, size, Sort.Direction.ASC, "age", "id");// 按照'age'与'id'升序
Page<UserInfo> pageInfo = userInfoDao.findByNameLike("test", pageRequest);
return pageInfo.getContent();
三种方式的查询结果如下:
// 1.保留方法: limit+count
Hibernate: select userinfo0_.id as id1_1_, userinfo0_.age as age2_1_, userinfo0_.des_info as des_info3_1_, userinfo0_.email as email4_1_, userinfo0_.name as name5_1_ from user_info userinfo0_ limit ?
Hibernate: select count(userinfo0_.id) as col_0_0_ from user_info userinfo0_
//2.命名规则方法: limit
Hibernate: select userinfo0_.id as id1_1_, userinfo0_.age as age2_1_, userinfo0_.des_info as des_info3_1_, userinfo0_.email as email4_1_, userinfo0_.name as name5_1_ from user_info userinfo0_ where userinfo0_.age>? limit ?
//3.JPQL查询: limit+count+order
Hibernate: select userinfo0_.id as id1_1_, userinfo0_.age as age2_1_, userinfo0_.des_info as des_info3_1_, userinfo0_.email as email4_1_, userinfo0_.name as name5_1_ from user_info userinfo0_ where userinfo0_.name like ? order by userinfo0_.age asc, userinfo0_.id asc limit ?
Hibernate: select count(userinfo0_.id) as col_0_0_ from user_info userinfo0_ where userinfo0_.name like ?
需要注意的是:
- 关于
nativeQuery
:基于nativeQuery = true
的本地SQL查询方法在使用分页查询时,JPA 可以基于主查询语句自动生成countQuery
,其查询过程与使用方法上述三种方式一致,但是在复杂查询场景下最好手动添加countQuery
(生成可能存在问题);
参考文章:
public interface UserRepository extends JpaRepository<User, Long> {
@Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1",
countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
nativeQuery = true)
Page<User> findByLastname(String lastname, Pageable pageable);
}
- 关于
countQuery
:countQuery
的目的是为Page
结果计算总记录数,若手动添加了countQuery
则会优先执行手动添加的countQuery
;注意若返回结果为Slice
,则不会执行countQuery
,即使手动加了countQuery
; - 关于分页小优化:在
Pageable
分页参数中,若当前查询页page
的剩余数据量 < 页大小size
,则不会再去执行countQuery
(恰好相等的话仍需执行);
2、动态条件
参考文章:
类似于 Mybatis 的动态SQL(比如、等),Spring Data JPA 也支持在运行时动态生成查询条件的能力,其提供了一套强大的面向对象的工具集,包括 Specification
、CriteriaBuilder
和 Predicate
等,可以帮助我们构建复杂的动态查询。JPA 2 引入了criteria API
来构建查询语句中的where
条件,这些查询条件通常用CriteriaBuilder
来构建,构建的每个条件元素都表示为Predicate
对象,而Specification
则是对条件元素Predicate
的封装(或者说是对JPA本身 Criteria 动态查询的包装)。
2.1 基本组件介绍
要实现动态查询,首先需要将 Repository 接口继承JpaSperiactionExecutor
接口,该接口提供了一系列支持Specification
动态查询的保留方法,而Specification
则提供了构建动态查询条件Predicate
的API。在实际应用中,我们只需要实现Specification
接口,并提供一个toPredicate
方法来定义我们的查询规则,Spring Data JPA就会自动地为我们执行查询。
(1)JpaSpecificationExecutor
public interface JpaSpecificationExecutor<T> {
// 查询单个对象
Optional<T> findOne(@Nullable Specification<T> spec);
// 查询全部列表
List<T> findAll(@Nullable Specification<T> spec);
// 查询分页列表(Pageable)
Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable);
// 查询排序列表(Sort)
List<T> findAll(@Nullable Specification<T> spec, Sort sort);
// 统计查询
long count(@Nullable Specification<T> spec);
}
(2)Specification
Specification
是一个基于JPA Criteria API
构建动态查询条件的抽象接口,用于封装和构建代表查询条件的Predicate
对象,其核心源码如下:
public interface Specification<T> extends Serializable {
// 非
static <T> Specification<T> not(@Nullable Specification<T> spec) {
return spec == null //
? (root, query, builder) -> null //
: (root, query, builder) -> builder.not(spec.toPredicate(root, query, builder));
}
// 与
default Specification<T> and(@Nullable Specification<T> other) {
return SpecificationComposition.composed(this, other, CriteriaBuilder::and);
}
// 或
default Specification<T> or(@Nullable Specification<T> other) {
return SpecificationComposition.composed(this, other, CriteriaBuilder::or);
}
// 构建WHERE动态查询条件对象 Predicate
@Nullable
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder);
}
可以看出,Specification
通过实现抽象方法Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder)
来构建动态查询条件(多个Predicate
支持通过逻辑谓词连接成一个查询条件Predicate
),当然Specification
本身也提供了逻辑谓词not
、and
、or
方法来实现多个Specification
动态条件的连接和组合。
(3) toPredicate 方法
toPredicate
方法接收三个参数Root
、CriteriaQuery
和CriteriaBuilder
,并返回一个Predicate
,其中参数含义如下:
-
Root
:Root接口代表查询根对象,可以通过Root获取实体中的查询属性,比如root.get("lastName")
; -
CriteriaQuery
:代表顶层查询对象,可以用来自定义查询方式(查询结构),一般使用较少;- 比如:
query.distinct(true).select(...).where(...).groupBy(...).having(...).getRestriction()
,最后需要通过getRestriction()
方法获得一个Predicate
对象返回;
- 比如:
-
CriteriaBuilder
:构建查询条件(WHERE中的条件元素)的构造器,即用于构建Predicate
对象。其内部封装有很多查询条件构造方法,常用方法如下:Method Description Example Predicate equal(Expression<?> x, Object y)
构建等于条件 Predicate predicate = cb.equal(root.get("propertyName"), "Example");
Predicate notEqual(Expression<?> x, Object y)
构建不等于条件 Predicate predicate = cb.notEqual(root.get("propertyName"), "Example");
Predicate like(Expression<String> x, String pattern)
构建模糊查询条件 Predicate predicate = cb.like(root.get("propertyName"), "%Example%")
Predicate greaterThanOrEqualTo(Expression<? extends Y> x, Y y)
构建大于等于条件 Predicate predicate = cb.greaterThanOrEqualTo(root.get("propertyId"), 1)
Predicate lessThanOrEqualTo(Expression<? extends Y> x, Y y)
构建小于等于条件 Predicate predicate = cb.lessThanOrEqualTo(root.get("propertyId"), 2)
Predicate between(Expression<? extends Y> v, Y x, Y y)
构建范围条件 Predicate predicate = cb.between(root.get("propertyId"), 1, 10)
Predicate and(Expression<Boolean> x, Expression<Boolean> y)
构建两个条件的and逻辑与表达式 Predicate and = cb.and(predicate1, predicate2)
Predicate and(Predicate... restrictions)
构建多个条件的and逻辑与表达式,支持可变参数或数组 Predicate and = cb.and(predicateList.toArray(new Predicate[0]))
Predicate or(Expression<Boolean> x, Expression<Boolean> y)
构建两个条件的or逻辑或表达式 Predicate or = cb.or(predicate1, predicate2)
Predicate or(Predicate... restrictions)
构建多个条件的or逻辑或表达式,支持可变参数或数组 Predicate or = cb.or(predicateList.toArray(new Predicate[predicateList.size()]))
Predicate not(Expression<Boolean> restriction)
构建条件的not逻辑否表达式 Predicate not = cb.not(predicate)
2.2 单条件查询
背景: 前端向后端服务提交POST表单请求(form-data),其请求参数包括分页数据(page、size)、查询条件(id、name、age、email)等,需要注意各查询条件均是可选项,若同时存在多个条件则按照顺序为优先级进行单条件查询。
(1)Controller
@RestController
@RequestMapping("/userinfo")
public class UserInfoController {
@Autowired
UserInfoService userInfoService;
/**
* accessToken: 接收URL中的查询参数,可不传递
* page: 接收POST表单中的分页数据,按参数名称映射
* request: 接收POST表单中的查询数据,按参数名称映射
*/
@RequestMapping("/queryByPriority")
public List<UserInfo> queryByPriority(@RequestParam(value = "accessToken", required = false) String accessToken, CommonPage page, CommonRequest request) {
System.out.println(accessToken);
System.out.println(page);
System.out.println(request);
return userInfoService.queryBySingleCondition(page,request);
}
}
(2)Service
@Service
public class UserInfoService {
@Autowired
IUserInfoDao userInfoDao;
public List<UserInfo> queryBySingleCondition(CommonPage page, CommonRequest request){
// 构造动态查询条件
Specification<UserInfo> specification = new Specification<UserInfo>() {
@Override
public Predicate toPredicate(Root<UserInfo> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
if(request != null){
// equal
if(request.getId() != -1){
Predicate predicate = criteriaBuilder.equal(root.get("id"), request.getId());
return predicate;
}
// like
if(StringUtils.isNotEmpty(request.getName())){
Predicate predicate = criteriaBuilder.like(root.get("name"), "%" + request.getName() + "%");
return predicate;
}
// greaterThanOrEqualTo
if(request.getAge() > 0){
Predicate predicate = criteriaBuilder.greaterThanOrEqualTo(root.get("age"), request.getAge());
return predicate;
}
// in
if(StringUtils.isNotEmpty(request.getEmail())){
Predicate predicate = root.get("email").in(Arrays.asList("[email protected]","[email protected]","[email protected]"));
return predicate;
}
}
// null: 表示查询所有
return null;
}
};
// 构造分页参数
Pageable pageable = PageRequest.of(page.getPage(), page.getSize());
// JpaSpecificationExecutor.findAll
Page<UserInfo> pageResult = userInfoDao.findAll(specification, pageable);
// 返回查询结果
return pageResult.getContent();
}
}
(3)查询结果
accesstoken_test_20241130
CommonPage(page=0, size=5)
CommonRequest(id=-1, name=user, age=25, email=null, description=null)
Hibernate: select userinfo0_.id as id1_1_, userinfo0_.age as age2_1_, userinfo0_.des_info as des_info3_1_, userinfo0_.email as email4_1_, userinfo0_.name as name5_1_ from user_info userinfo0_ where userinfo0_.name like ? limit ?
2.3 多条件查询
背景: 前端向后端服务提交POST表单请求(form-data),其请求参数包括分页数据(page、size)、查询条件(id、name、age、email)等,需要注意各查询条件均是可选项,若同时存在多个条件则需保证查询结果要同时满足所有条件。
多条件查询的关键在于多条件的连接,常见的条件连接方式包括两种:
- 基于
CriteriaBuilder
:通过CriteriaBuilder
的逻辑谓词and
、or
等来实现多个Predicate
条件对象的连接和组合; - 基于
Specification
:通过Specification
接口提供的not
、and
、or
方法来实现多个Specification
动态条件的连接和组合
(1)Controller
@RestController
@RequestMapping("/userinfo")
public class UserInfoController {
@Autowired
UserInfoService userInfoService;
@RequestMapping("/queryByCombination")
public List<UserInfo> queryByCombination(@RequestParam(value = "accessToken", required = false) String accessToken, CommonPage page, CommonRequest request) {
System.out.println(accessToken);
System.out.println(page);
System.out.println(request);
return userInfoService.queryByConditions(page,request);
}
}
(2)Service
- 基于
CriteriaBuilder
@Service
public class UserInfoService {
@Autowired
IUserInfoDao userInfoDao;
public List<UserInfo> queryByConditions(CommonPage page, CommonRequest request){
// 构造动态查询条件
Specification<UserInfo> specification = new Specification<UserInfo>() {
@Override
public Predicate toPredicate(Root<UserInfo> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
// 收集查询条件的列表
List<Predicate> predicateList = new ArrayList<>();
// equal
if(request.getId() != -1){
Predicate predicate = criteriaBuilder.equal(root.get("id"), request.getId());
predicateList.add(predicate);
}
// like
if(StringUtils.isNotEmpty(request.getName())){
Predicate predicate = criteriaBuilder.like(root.get("name"), "%" + request.getName() + "%");
predicateList.add(predicate);
}
// greaterThanOrEqualTo
if(request.getAge() > 0){
Predicate predicate = criteriaBuilder.greaterThanOrEqualTo(root.get("age"), request.getAge());
predicateList.add(predicate);
}
// 多条件and组合方式
// 1). criteriaBuilder.and 返回 predicate
Predicate predicate = criteriaBuilder.and(predicateList.toArray(new Predicate[predicateList.size()]));// where 1=1
return predicate;
// 2). query.where.getRestriction 返回 predicate
//Predicate predicate = query.where(predicateList.toArray(new Predicate[predicateList.size()])).getRestriction();
//return predicate;
// 3). query.where 可以返回 null
//query.where(predicateList.toArray(new Predicate[predicateList.size()]))
//return null;
}
};
// 构造分页参数
Pageable pageable = PageRequest.of(page.getPage(), page.getSize());
// JpaSpecificationExecutor.findAll
Page<UserInfo> pageResult = userInfoDao.findAll(specification, pageable);
// 返回查询结果
return pageResult.getContent();
}
}
accesstoken_test_20241130
CommonPage(page=0, size=3)
CommonRequest(id=-1, name=user, age=25, email=null, description=null)
Hibernate: select userinfo0_.id as id1_1_, userinfo0_.age as age2_1_, userinfo0_.des_info as des_info3_1_, userinfo0_.email as email4_1_, userinfo0_.name as name5_1_ from user_info userinfo0_ where (userinfo0_.name like ?) and userinfo0_.age>=25 limit ?
注意: 若and
连接的PredicateList
条件列表为空,则查询语句会追加 where 1=1
的恒成立条件;若or
连接的PredicateList
条件列表为空,则查询语句会追加 where 0=1
的恒成立条件;若直接返回null
则不会追加where
条件。
- 基于
Specification
@Service
public class UserInfoService {
@Autowired
IUserInfoDao userInfoDao;
public List<UserInfo> queryBySpecifications(CommonPage page, CommonRequest request){
// 构造多动态查询条件 Specification 的组合
Specification<UserInfo> specification = new Specification<UserInfo>() {
@Override
public Predicate toPredicate(Root<UserInfo> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
// 收集查询条件
List<Predicate> predicateList = new ArrayList<>();
// equal
if(request.getId() != -1){
Predicate predicate = criteriaBuilder.equal(root.get("id"), request.getId());
predicateList.add(predicate);
}
// like
if(StringUtils.isNotEmpty(request.getName())){
Predicate predicate = criteriaBuilder.like(root.get("name"), "%" + request.getName() + "%");
predicateList.add(predicate);
}
// 多条件 or 组合
Predicate predicate = criteriaBuilder.or(predicateList.toArray(new Predicate[predicateList.size()]));
return predicate;
}
}.and(new Specification<UserInfo>() {
@Override
public Predicate toPredicate(Root<UserInfo> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
// greaterThanOrEqualTo
if(request.getAge() > 0){
Predicate predicate = criteriaBuilder.greaterThanOrEqualTo(root.get("age"), request.getAge());
return predicate;
}
return null;
}
});
// 构造分页参数
Pageable pageable = PageRequest.of(page.getPage(), page.getSize());
// JpaSpecificationExecutor.findAll
Page<UserInfo> pageResult = userInfoDao.findAll(specification, pageable);
// 返回查询结果
return pageResult.getContent();
}
}
accesstoken_test_20241130
CommonPage(page=0, size=3)
CommonRequest(id=6, name=user, age=25, email=null, description=null)
Hibernate: select userinfo0_.id as id1_1_, userinfo0_.age as age2_1_, userinfo0_.des_info as des_info3_1_, userinfo0_.email as email4_1_, userinfo0_.name as name5_1_ from user_info userinfo0_ where (userinfo0_.id=6 or userinfo0_.name like ?) and userinfo0_.age>=25 limit ?
Hibernate: select count(userinfo0_.id) as col_0_0_ from user_info userinfo0_ where (userinfo0_.id=6 or userinfo0_.name like ?) and userinfo0_.age>=25
2.4 关系优先级
关系型运算符的优先级由高到低分别为:not
、and
、or
,CriteriaQuery
构建查询语句时会自动根据优先级进行优化,决定是否需要加()
来组合子条件。
public List<UserInfo> queryByMerge(CommonPage page, CommonRequest request){
// 构造动态查询条件
Specification<UserInfo> specification = new Specification<UserInfo>() {
@Override
public Predicate toPredicate(Root<UserInfo> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
// or_1
Predicate predicate_id = criteriaBuilder.equal(root.get("id"), request.getId());
Predicate predicate_name = criteriaBuilder.like(root.get("name"), "%" + request.getName() + "%");
Predicate orP_1 = criteriaBuilder.or(predicate_id, predicate_name);
// or_2
Predicate predicate_age = criteriaBuilder.greaterThanOrEqualTo(root.get("age"), request.getAge());
Predicate predicate_email = criteriaBuilder.like(root.get("email"), "%" + request.getEmail() + "%");
Predicate orP_2 = criteriaBuilder.or(predicate_age, predicate_email);
// and
Predicate andP = criteriaBuilder.and(orP_1, orP_2);
return andP;
}
};
// JpaSpecificationExecutor.findAll
List<UserInfo> findResult = userInfoDao.findAll(specification);
// 返回查询结果
return findResult;
}
CommonPage(page=0, size=3)
CommonRequest(id=6, name=user, age=25, [email protected], description=null)
Hibernate: select userinfo0_.id as id1_1_, userinfo0_.age as age2_1_, userinfo0_.des_info as des_info3_1_, userinfo0_.email as email4_1_, userinfo0_.name as name5_1_ from user_info userinfo0_ where (userinfo0_.id=6 or userinfo0_.name like ?) and (userinfo0_.age>=25 or userinfo0_.email like ?)
2.5 复杂查询
构建复杂查询(比如子查询、多表连接等)需要使用 CriteriaQuery<?> query
构建查询结构;以子查询为例,其需要使用CriteriaQuery.subquery(Class<U> type)
方法来构建子查询:
public void testSubSpecification() {
Specification<RetPrdInfo> specification = (root, query, cb) -> {
// 1.父查询条件
Predicate parentPredicate = cb.equal(root.get("crToolRunMode"), "CLN");
// 2.子查询 Params: type – the subquery result type
Subquery<RetPrdAbn> subQuery = query.subquery(RetPrdAbn.class);
// 1) 子查询对象 subRoot 及子查询 SELECT 参数
Root<RetPrdAbn> subRoot = subQuery.from(RetPrdAbn.class);
subQuery = subQuery.select(subRoot.get("prdSeqIdFk"));
// 2) 子查询条件 WHERE
Predicate subPredicate1 = cb.equal(subRoot.get("lotIdFk"), "LW0001");
Predicate subPredicate2 = cb.equal(subRoot.get("lotSpltIdFk"), "00");
subQuery.where(cb.and(subPredicate1, subPredicate2));
// 3.将父查询条件和子查询合并 IN
Predicate parentAndSubConjunctPredicate = root.get("prdSeqId").in(subQuery);
// 4.最终查询语句
return query.where(parentPredicate, parentAndSubConjunctPredicate).getRestriction();
};
// ...
}
select
...
from
ret_prd_info
where
cr_tool_run_mode = ?
and (prd_seq_id in
(
select prd_seq_id_fk
from ret_prd_abn
where lot_id_fk = ? and retprdabn1_.lot_splt_id_fk = ?
)
)
3、批处理
参考文章:
- https://www.cnblogs.com/blog5277/p/10661096.html
- https://blog.csdn.net/JingAi_jia917/article/details/138284510
@Service
public class ProductServiceImpl implements ProductService {
@Resource
private EntityManager entityManager;
/**
* 批量插入数据
*/
@Transactional
@Override
public int batchInsert(List<ProductEntity> list) {
int batchSize = 2000;
if(list.isEmpty()) {
return 0;
}
// 单次批量插入条数
StringBuffer sb = new StringBuffer();
String insertSql = "insert into tb_product(name, delivery_no, customer, security_code, create_time, validate_num) values ";
sb.append(insertSql);
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
int index = 0;
for(ProductEntity entity : list) {
index ++;
// 拼接sql字符串
sb.append("('").append(entity.getName()).append("','").append(entity.getDeliveryNo()).append("','")
.append(entity.getCustomer()).append("','").append(entity.getSecurityCode()).append("','")
.append(format.format(entity.getCreateTime())).append("', 0),");
if(index % batchSize == 0) {
Query query = entityManager.createNativeQuery(sb.substring(0, sb.length() - 1) + ";");
int rs = query.executeUpdate();
if(rs != batchSize) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
return 0;
}
sb = sb.replace(0, sb.length(), insertSql);
index = 0;
}
}
if(index > 0) {
Query query = entityManager.createNativeQuery(sb.substring(0, sb.length() - 1) + ";");
int rs = query.executeUpdate();
if(rs != list.size() % batchSize) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
return 0;
}
}
return list.size();
}
/**
* 批量修改
*/
@Transactional
@Override
public int batchUpdate3(List<ProductEntity> list) {
if(list.isEmpty()) {
return 0;
}
StringBuffer sb = new StringBuffer();
String updateSql = "update tb_product set ";
for(int i = 0 ; i < list.size() ; i ++) {
ProductEntity entity = list.get(i);
sb.append(updateSql).append("name = '").append(entity.getName()).append("', customer = '")
.append(entity.getCustomer()).append("' where pid = ").append(entity.getPid()).append(";");
if(i > 0 && i % 2000 == 0) {
Query query = entityManager.createNativeQuery(sb.toString());
int rs = query.executeUpdate();
if(rs <= 0) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
return 0;
}
sb = sb.replace(0, sb.length(), Strings.EMPTY);
}
}
if(sb.length() > 0) {
Query query = entityManager.createNativeQuery(sb.toString());
int rs = query.executeUpdate();
if(rs <= 0) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
return 0;
}
}
return list.size();
}
}