SpringDataJpa增删改查、分页以及批量操作

SpringDataJpa

  • 基本增删改查
  • 自定义查询与更新
  • jpa实现分页
  • 批量操作
    • 批量保存跟删除
    • 批量更新
  • 以上部分的完整代码

基本增删改查

每个Repository都需要实现JpaRepository,然后可根据标准化的操作方式以及实体字段来定义接口方法,优势在查询方面,支持多字段,多类型(大于、小于、等于、in、like、between and。。。)

@Repository
public interface UUserRepository extends JpaRepository {

	@Override
	UUser save(UUser user);
	
	@Override
	List findAll();
	
	UUser findByUserName(String userName);

	Optional findById(Integer id);

    void deleteById(Integer id);

	//删除表中所有数据,谨慎使用
	void deleteAll();
   }

自定义查询与更新

@Repository
public interface UUserRepository extends JpaRepository {

	/本地查询 nativeQuery=true 表示使用原生sql,表名、字段名跟数据库一致
	@Query(value="select * from u_user where nickname like %?1 and status =?2" ,nativeQuery=true)
	List findByUserNameAAndStatus(String name, Integer status);

	//@Query执行delete和update语句一样,需要添加@Modifying注解,使用时在Repository或者更上层需要@Transactional注解。
	/**
	 * 支持更新类的Query语句
	 *  使用 @Modifying 修改标识
	 * 返回值应该是int,表示更新语句所影响的行数
	 * @param id
	 * @param newName
	 * @return
	 */
	@Modifying
	@Transactional(rollbackFor = Exception.class)
	@Query(value="update UUser u set u.email=:newEmail where u.id =:nn")
	int updateUserEmail(@Param("nn") Integer id, @Param("newEmail") String newName);

 
   }

jpa实现分页

分页还需实现JpaSpecificationExecutor接口,只需在serviceImpl中传入所需参数即可SpringDataJpa增删改查、分页以及批量操作_第1张图片
service层具体实现代码如下:一个是无查询条件分页返回,一个是有限制条件的分页返回。其中*jpa的页面数量是从0开始的*,这里需要注意一下,或者写个工具类统一处理

@Service
public class UUserServiceImpl implements UUserService{

	@Autowired
	UUserRepository userRepository;


	@Override
	public Page findUserNoCriteria(Integer page, Integer size) {
		//springboot 2.0之前的写法设置排序字段为ID 降序
//		Pageable pageable = new PageRequest(page, size, Sort.Direction.DESC, "id");

		//springboot 2.0之后的推荐写法
		Sort sort = new Sort(Sort.Direction.ASC, "id");
		Pageable pageable = PageRequest.of(page-1, size, sort);
		return userRepository.findAll(pageable);

	}

	@Override
	public Page findUserCriteria(Integer page, Integer size, UUser userQuery) {

//		Specification specification1 = (Specification) (root, query, criteriaBuilder) -> {
//			List list = new ArrayList<>();
//			// 第一个userId为CloudServerDao中的字段,第二个userId为参数
//			Predicate p1 = criteriaBuilder.equal(root.get("userId"),userId);
//			list.add(p1);
//			if (!key.equals(null)) {
//				// 此处为查询serverName中含有key的数据
//				Predicate p2 = criteriaBuilder.like(root.get("serverName"),"%"+key+"%" );
//				list.add(p2);
//			}
//			return criteriaBuilder.and(list.toArray(new Predicate[0]));
//		};
		
		Specification specification = new Specification() {
			@Override
			public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
				List predicates = new ArrayList();
				if(!StringUtils.isEmpty(userQuery.getUserName())) {
					predicates.add(criteriaBuilder.like(root.get("nickName"), "%" + userQuery.getUserName() + "%"));
				}
				if(null != userQuery.getStatus()){
					predicates.add(criteriaBuilder.equal(root.get("status"), userQuery.getStatus()));
				}
				if(null != userQuery.getId()){
					predicates.add(criteriaBuilder.greaterThan(root.get("id"), userQuery.getId()));
				}
				return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
				}
			};
		//设置排序字段为ID 升序 页码从0开始
		Pageable pageable = PageRequest.of(page-1, size, Sort.Direction.ASC, "id");
		return userRepository.findAll(specification,pageable);
	}

批量操作

批量保存跟删除

批量保存和删除可直接传参调用,传入集合对象
SpringDataJpa增删改查、分页以及批量操作_第2张图片

也可在repository中自己实现批量删除

    //批量删除
	void deleteInBatch(Iterable userList);
   
    //sql实现批量删除
	@Modifying
	@Transactional
	@Query(value="delete from UUser u where u.id in (:ids) ")
	int deleteByIds(@Param("ids")List ids);
@Service
public class UUserServiceImpl implements UUserService{
  @Autowired
	UUserRepository userRepository;

   @Override
	public List saveAllUser(List userList) {
		return userRepository.saveAll(userList);
	}
	@Override
	public int deleteByIds(List ids) {
		return userRepository.deleteByIds(ids);
	}

	@Override
	public void deleteInBatch(List userList) {
		userRepository.deleteInBatch(userList);
	}
	}

批量更新

使用jdbcTemplet 来实现,JdbcTemplate,执行批处理操作,如batchUpdate方法
也可通过@PersistenceContext注解 注入EntityManager对象 然后自己写QL语句,用EntityManager对象来做持久化操作就好了
@PersistenceContext
private EntityManager em;
https://blog.csdn.net/wangshfa/article/details/27323297
整合如下
service层

/**
	 * 通过EntityManager来实现批量插入
	 * @param userList
	 */
	void batchInsert(List userList);
	/**
	 * 通过EntityManager来实现批量更新
	 * @param userList
	 */
    void batchUpdate(List userList);

serviceImpl层

@Transactional
	@Override
	public void batchInsert(List userList) {
		for (int i = 0; i < userList.size(); i++) {
			em.persist(userList.get(i));
			if (i % 30 == 0) {
				em.flush();
				em.clear();
			}
		}

		// jdbcTemplate批量插入操作
//		String sql = "insert u_user(nickname,email,status) values(?,?)";
//		jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
//			public void setValues(PreparedStatement ps, int i) throws SQLException {
//				String name = userList.get(i).getUserName();
//				String email = userList.get(i).getEmail();
//				int status = userList.get(i).getStatus();
//				ps.setString(1, name);
//				ps.setString(2, email);
//				ps.setInt(3, status);
//			}
//
//			public int getBatchSize() {
//				return userList.size();
//			}
//		});

	}


	@Transactional
	@Override
	public void batchUpdate(List userList) {
		for (int i = 0; i < userList.size(); i++) {
			em.merge(userList.get(i));
			if(i % 30 == 0){
				em.flush();
				em.clear();
			}
		}

		// jdbcTemplate批量更新操作
//		String sql = "update u_user set status=? where nickname=?";
//		jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
//			public void setValues(PreparedStatement ps, int i) throws SQLException {
//				int status = userList.get(i).getStatus();
//				String name = userList.get(i).getUserName();
//				ps.setInt(1, status);
//				ps.setString(2, name);
//			}
//			public int getBatchSize() {
//				return userList.size();
//			}
//		});
		
	}
	

待完善

以上部分的完整代码

service层

package com.fei.springboot.demo.service;

import com.fei.springboot.demo.entity.UUser;
import org.springframework.data.domain.Page;

import java.util.List;
import java.util.Optional;

/**
 * jpa的增删改查 分页等
 *   https://www.jianshu.com/p/14cd90f32d4d
 * @author hpf
 * @create 2019-05-18 16:15
 */

public interface UUserService {

	/**
	 * 没有查询条件的分页
	 * @param page
	 * @param size
	 * @return Page
	 */
	Page findUserNoCriteria(Integer page, Integer size);

	/**
	 * 带查询条件的分页
	 * @param page
	 * @param size
	 * @param userQuery
	 * @return Page
	 */
	Page findUserCriteria(Integer page, Integer size, UUser userQuery);

	/**
	 * 根据主键id查询
	 * @param id
	 * @return Optional
	 */
	Optional findByID(Integer id);

	/**
	 *  保存用户到数据库
	 * @param user
	 * @return user
	 */
	UUser saveUser(UUser user);

	/**
	 * 批量保存用户
	 * @param userList
	 * @return List
	 */
	List saveAllUser(List userList);

	/**
	 * 根据id来更新邮箱信息
	 * @param id
	 * @param newEmail
	 * @return 更新的数量
	 */
	int updateUserEmail(Integer id, String newEmail);

	/**
	 * 根据主键id来删除数据
	 * @param id
	 */
	void deleteUserById(Integer id);

	/**
	 *  根据主键id集合来批量删除
	 * @param ids
	 * @return
	 */
	int deleteByIds(List ids);

	/**
	 *  根据对象集合来批量删除
	 * @param userList
	 */
	void deleteInBatch(List userList);
	
	/**
	 * 通过EntityManager来实现批量插入
	 * @param userList
	 */
	void batchInsert(List userList);

	/**
	 * 通过EntityManager来实现批量更新
	 * @param userList
	 */
    void batchUpdate(List userList);

}

serviceImpl实现层

package com.fei.springboot.demo.service.impl;

import com.fei.springboot.demo.entity.UUser;
import com.fei.springboot.demo.repository.jpa.UUserRepository;
import com.fei.springboot.demo.service.UUserService;
import org.springframework.beans.factory.annotation.Autowired;
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.data.jpa.domain.Specification;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * @author hpf
 * 数据库连接中设置,批量速度会快点rewriteBatchedStatements=true
 * @date 2019-05-18 16:16
 */
@Service
public class UUserServiceImpl implements UUserService{

	@Autowired
	UUserRepository userRepository;

	@PersistenceContext
	private EntityManager em;

	@Autowired
	private JdbcTemplate jdbcTemplate;


	@Override
	public Page findUserNoCriteria(Integer page, Integer size) {
		//springboot 2.0之前的写法设置排序字段为ID 降序
//		Pageable pageable = new PageRequest(page, size, Sort.Direction.DESC, "id");

		//springboot 2.0之后的推荐写法
		Sort sort = new Sort(Sort.Direction.ASC, "id");
		Pageable pageable = PageRequest.of(page-1, size, sort);
		return userRepository.findAll(pageable);

	}

	@Override
	public Page findUserCriteria(Integer page, Integer size, UUser userQuery) {

//		Specification specification1 = (Specification) (root, query, criteriaBuilder) -> {
//			List list = new ArrayList<>();
//			// 第一个userId为CloudServerDao中的字段,第二个userId为参数
//			Predicate p1 = criteriaBuilder.equal(root.get("userId"),userId);
//			list.add(p1);
//			if (!key.equals(null)) {
//				// 此处为查询serverName中含有key的数据
//				Predicate p2 = criteriaBuilder.like(root.get("serverName"),"%"+key+"%" );
//				list.add(p2);
//			}
//			return criteriaBuilder.and(list.toArray(new Predicate[0]));
//		};
		
		Specification specification = new Specification() {
			@Override
			public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
				List predicates = new ArrayList();
				if(!StringUtils.isEmpty(userQuery.getUserName())) {
					predicates.add(criteriaBuilder.like(root.get("nickName"), "%" + userQuery.getUserName() + "%"));
				}
				if(null != userQuery.getStatus()){
					predicates.add(criteriaBuilder.equal(root.get("status"), userQuery.getStatus()));
				}
				if(null != userQuery.getId()){
					predicates.add(criteriaBuilder.greaterThan(root.get("id"), userQuery.getId()));
				}
				return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
				}
			};
		//设置排序字段为ID 升序 页码从0开始
		Pageable pageable = PageRequest.of(page-1, size, Sort.Direction.ASC, "id");
		return userRepository.findAll(specification,pageable);
	}

	@Override
	public Optional findByID(Integer id) {
		return userRepository.findById(id);
	}

	@Override
	public UUser saveUser(UUser user) {
		return userRepository.save(user);
	}

	@Override
	public List saveAllUser(List userList) {
		return userRepository.saveAll(userList);
	}

	@Override
	public int updateUserEmail(Integer id, String newEmail) {
		return userRepository.updateUserEmail(id,newEmail);
	}

	@Override
	public void deleteUserById(Integer id) {
		userRepository.deleteById(id);
	}

	@Override
	public int deleteByIds(List ids) {
		return userRepository.deleteByIds(ids);
	}

	@Override
	public void deleteInBatch(List userList) {
		userRepository.deleteInBatch(userList);
	}

	@Transactional
	@Override
	public void batchInsert(List userList) {
		for (int i = 0; i < userList.size(); i++) {
			em.persist(userList.get(i));
			if (i % 30 == 0) {
				em.flush();
				em.clear();
			}
		}

		// jdbcTemplate批量插入操作
//		String sql = "insert u_user(nickname,email,status) values(?,?)";
//		jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
//			public void setValues(PreparedStatement ps, int i) throws SQLException {
//				String name = userList.get(i).getUserName();
//				String email = userList.get(i).getEmail();
//				int status = userList.get(i).getStatus();
//				ps.setString(1, name);
//				ps.setString(2, email);
//				ps.setInt(3, status);
//			}
//
//			public int getBatchSize() {
//				return userList.size();
//			}
//		});

	}


	@Transactional
	@Override
	public void batchUpdate(List userList) {
		for (int i = 0; i < userList.size(); i++) {
			em.merge(userList.get(i));
			if(i % 30 == 0){
				em.flush();
				em.clear();
			}
		}

		// jdbcTemplate批量更新操作
//		String sql = "update u_user set status=? where nickname=?";
//		jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
//			public void setValues(PreparedStatement ps, int i) throws SQLException {
//				int status = userList.get(i).getStatus();
//				String name = userList.get(i).getUserName();
//				ps.setInt(1, status);
//				ps.setString(2, name);
//			}
//			public int getBatchSize() {
//				return userList.size();
//			}
//		});

	}


}

repository

package com.fei.springboot.demo.repository.jpa;

import com.fei.springboot.demo.entity.UUser;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

/**
 * 分页还需实现JpaSpecificationExecutor接口
 * @author hpf
 * @create 2019-05-10 21:32
 */
@Repository
public interface UUserRepository extends JpaRepository,JpaSpecificationExecutor {

	@Override
	UUser save(UUser user);

	@Override
	List findAll();

	UUser findByUserName(String userName);

	Optional findById(Integer id);

	//本地查询 nativeQuery=true 表示使用原生sql,表名、字段名跟数据库一致
	@Query(value="select * from u_user where nickname like %?1 and status =?2" ,nativeQuery=true)
	List findByUserNameAAndStatus(String name, Integer status);

	//@Query执行delete和update语句一样,需要添加@Modifying注解,使用时在Repository或者更上层需要@Transactional注解。
	/**
	 * 支持更新类的Query语句
	 *  使用 @Modifying 修改标识
	 * 返回值应该是int,表示更新语句所影响的行数
	 * @param id
	 * @param newName
	 * @return
	 */
	@Modifying
	@Transactional(rollbackFor = Exception.class)
	@Query(value="update UUser u set u.email=:newEmail where u.id =:nn")
	int updateUserEmail(@Param("nn") Integer id, @Param("newEmail") String newName);


	void deleteById(Integer id);

	//删除表中所有数据,谨慎使用
	void deleteAll();

	void deleteInBatch(Iterable userList);

	@Modifying
	@Transactional
	@Query(value="delete from UUser u where u.id in (:ids) ")
	int deleteByIds(@Param("ids")List ids);

}

entity类

package com.fei.springboot.demo.entity;

import com.alibaba.fastjson.annotation.JSONField;

import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
import java.util.List;

/**
 * 权限测试中用户类
 * JPA提供的四种标准用法为TABLE,SEQUENCE,IDENTITY,AUTO.
 *   TABLE:使用一个特定的数据库表格来保存主键。
 *   SEQUENCE:根据底层数据库的序列来生成主键,条件是数据库支持序列。 mysql不支持此种方式
 *   IDENTITY:主键由数据库自动生成(主要是自动增长型) oracle不支持此种方式
 *   AUTO:主键由程序控制。会在数据库中生成一张hibernate_sequence表
 * 在指定主键时,如果不指定主键生成策略,默认为AUTO。
 *
 * @author hpf
 * @date 2019-05-10 21:14
 */
@Table(name = "u_user")
@Entity
//@JSONType(ignores ={"id", "createTime"})
public class UUser implements Serializable {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "id")
	private Integer id;

	@JSONField(ordinal = 1)
	@Column(name = "nickname")
	private String userName;

	@Column(name = "email")
	private String email;

	//不会序列化到json
	@JSONField(name = "passWORD",serialize=false)
	@Column(name = "pswd")
	private String password;

	@Column(name = "create_time")
	private Date createTime;

	@Column(name = "last_login_time")
	private Date lastLoginTime;

	@Column(name = "status")
	private Integer status;

	//表示此字段不被序列化。不会被映射到数据库,也不会序列化到json
	@Transient
//	@ElementCollection(targetClass=String.class)
	private List roleList;

	//数据库中没有此字段
//	@ElementCollection(targetClass=String.class)  会在数据中多生成一张表
	@Transient
	private List permissionList;

	//get set 方法
}

test类

package com.fei.springboot.demo;

import com.fei.springboot.demo.entity.UUser;
import com.fei.springboot.demo.service.UUserService;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * @author hpf
 * @date 2019-05-18 16:55
 */
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest

public class UUserServiceTest {

	private static final Logger logger = LoggerFactory.getLogger(UUserServiceTest.class);

	@Autowired
	UUserService userService;

	private static UUser user;

	@BeforeClass
	public static void create(){
		user  = new UUser();
//		user.setId(1);
		user.setStatus(1);
		user.setUserName("inserttest");
		user.setEmail("111sdad@@");


	}

	@Test
	public void testCriteria() {
		Page userNoCriteria = userService.findUserNoCriteria(1, 3);
		logger.info("List user is :{}",userNoCriteria.getContent());
		logger.info("total element:{},total page:{},current page number:{},current size:{}",
				userNoCriteria.getTotalElements(),userNoCriteria.getTotalPages(),userNoCriteria.getPageable().getPageNumber(),userNoCriteria.getSize());

		Page userCriteria = userService.findUserCriteria(1, 2, user);
		logger.info("List user is :{}",userCriteria.getContent());

	}

//	@Transactional
	@Test
	public void testCurd() {
		Optional userOptional = userService.findByID(3);
		logger.info("findByID, userOptional is :{}",userOptional.get());
		//通过一个数据库不存在的id去获取数据
		Optional userOptional1 = userService.findByID(4);
//		Optional.ofNullable(userOptional1)
//				.map(user->user.get())
//				.orElse(null);
//		logger.info("findByID, userOptional is :{}",userOptional1.get());

		int i = userService.updateUserEmail(2, "fei@飞.com");
		logger.info("影响行数:{}",i);
		//未更新数据库 则返回值为0
		i = userService.updateUserEmail(4, "fei@飞.com");
		logger.info("影响行数:{}",i);

		UUser saveUser = userService.saveUser(user);
		logger.info("saveUser is :{}",saveUser);
		userService.deleteUserById(saveUser.getId());
	}

	@Test
	public void testBatch() {
		List saveUserList = new ArrayList<>();
		UUser uUser = new UUser();
		uUser.setUserName("test1");
		uUser.setEmail("delete1");
		UUser uUser2 = new UUser();
		uUser2.setUserName("test2");
		uUser2.setEmail("delete2");
		saveUserList.add(uUser);
		saveUserList.add(uUser2);
//		UUser saveUser = userService.saveUser(uUser);
//		UUser saveUser2 = userService.saveUser(uUser2);
		List saveAllUser = userService.saveAllUser(saveUserList);
		List deleteUserList = new ArrayList<>();
		List userIdS = new ArrayList<>();
		for (UUser uUser1 : saveAllUser) {
			deleteUserList.add(uUser1);
			userIdS.add(uUser1.getId());
		}

		//批量删除方法1
		logger.info("this is delete for:{}",deleteUserList);
//		userService.deleteInBatch(userList);
		//批量删除方法2
		logger.info("this is delete number:{}",userService.deleteByIds(userIdS));
	}

}

参考链接:jpa分页
批量保存效率对比
主键策略
主键策略

你可能感兴趣的:(Java)