转载

SpringBoot整合Spring-data-jpa

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<!--mysql驱动-->
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
</dependency>

<!-- 添加数据库连接池 druid -->
<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>druid-spring-boot-starter</artifactId>
	<version>1.1.9</version>
</dependency>

主键生成策略

  • @GeneratedValue(strategy=GenerationType.xxx) 指定主键的生成策略
    • IDENTITY :根据数据库的主键自增长策略
    • GenerationType.TABLE :使用一个特定的数据库表格来保存主键
    • GenerationType.SEQUENCE :在某些数据库中,不支持主键自增长,比如Oracle,其提供了一种叫做”序列(sequence)”的机制生成主键。此时,GenerationType.SEQUENCE就可以作为主键生成策略。该策略的不足之处正好与TABLE相反,由于只有部分数据库(Oracle,PostgreSQL,DB2)支持序列对象,所以该策略一般不应用于其他数据库。类似的,该策略一般与另外一个注解一起使用@SequenceGenerator,@SequenceGenerator注解指定了生成主键的序列.然后JPA会根据注解内容创建一个序列(或使用一个现有的序列)。如果不指定序列,则会自动生成一个序列SEQ_GEN_SEQUENCE
    • GenerationType.AUTO :把主键生成策略交给持久化引擎(persistence engine),持久化引擎会根据数据库在以上三种主键生成策略中选择其中一种。此种主键生成策略比较常用,由于JPA默认的生成策略就是GenerationType.AUTO,所以使用此种策略时.可以显式的指定@GeneratedValue(strategy = GenerationType.AUTO)也可以直接@GeneratedValue
  • 实例如下:
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)  //数据库自增
private Integer id;

配置

spring:
datasource:                ## 配置数据源
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://118.31.15.108:3306/jpa?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false
driver-class-name: com.mysql.jdbc.Driver
username: root
password: ****
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 6000
timeBetweenEvictionRunsMillis: 6000
minEvictableIdleTimeMillis: 25200000
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
validationQuery: SELECT 1 FROM DUAL
RemoveAbandanded: true
removeAbandonedTimeout: 1800
logAbandoned: true
jpa:
show-sql: true    #控制台打印sql语句
database: MYSQL   # 指定数据库的类型,不填会默认检测
generate-ddl: false  ## 是否自动生成表,默认是false
# hibernate:
# ddl-auto: update

创建一个实体类

/**
 * 用户的实体类,其中的变量和数据库默认是以驼峰形式对应的,比如industryId,那么在表中的字段一定要是industry_id,否则将会报错
 */
@Table(name="t_user")  //指定对应数据库对应的表名
@Entity    //标记这是一个实体类
@Data    	//lombook的自动生成set,get
public class User{
	@Id    //标记主键
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	private Integer id;
	
	private String name;
	
	private Integer age;
	
	private String address;
	
	private Integer industryId;   //在数据库中的对应字段一定要是industry_id
}

基本的查询

  • 定义一个 UserRepository ,相当于Mybatis中的Mapper,如下:
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import cn.tedu.jpa.domain.User;
import java.lang.String;

/**
 * JpaRepository的接口,相当于mapper
 * 泛型:JpaRepository<User, Integer> :第一个是实体类的类型,第二个是主键的类型
 */
public interface UserRepositoryextends JpaRepository<User,Integer>{
	
	/**
	 * 根据指定条件查询 Byxxx(where xxx=xxx),除了根据主键查询,否则返回的都是List
	 * 	其中查询的条件对应的类型必须相同
	 */
	List<User>findByName(String name);
	
	/**
	 * 并列条件查询 ,相当于where name=xxx and age=xxx
	 */
	List<User>findByNameAndAge(String name,Integer age);
	
	/*
	 * 三个条件的并列查询 where xxx and xxx and xxx
	 */
	List<User>findByNameAndAgeAndIndustryId(String name,Integer age,Integer industryId);
	
	/*
	 * Top或者First指定返回结果数量,默认返回第一个,相当于limit 1
	 */
	UserfindTopByNameAndAge(String name,Integer age);
	
	/*
	 * Topn或者Firstn指定返回结果数量,这里的n表示返回的数量,相当于limit n
	 */
	List<User>findTop2ByNameAndAge(String name,Integer age);
	
	/*
	 * In 相当于where age in(....) 其中的变量类型可以数组、List、Set只要是Collection即可,泛型必须和查询条件的类型一致
	 */
	List<User>findByAgeIn(Integer[] ages);
	
	/*
	 * 统计数据  相当于select count(*) where age=xxx
	 */
	LongcountByAge(Integer age);
	
}
  • 测试类如下:
@RunWith(SpringRunner.class)
@SpringBootTest
public class JpaServerApplicationTests{

	@Resource
	private UserRepository userRepository;
	
	/**
	 * 新增数据(单个)
	 */
	@Test
	public void addUser(){
		User user=new User();
		user.setAge(22);
		user.setName("陈加兵");
		User user2 = userRepository.save(user);  //自增主键的返回
		System.out.println(user);  
	}
	
	
	/**
	 * 批量插入
	 */
	@Test
	public void saveAll(){
		User user1=new User();
		user1.setAge(22);
		user1.setName("陈加兵");
		User user2=new User();
		user2.setAge(22);
		user2.setName("陈加兵");
		
		List<User> users=new ArrayList<>();
		users.add(user1);
		users.add(user2);
		List<User> usersResturn=userRepository.saveAll(users);   //返回列表,自增主键的返回
		for (User user : usersResturn) {
			System.out.println(user);
		}
	}
	
	/**
	 * 更新数据,使用的仍然是save方法,如果其中包含id,那么就是更新数据,否则就是添加
	 * 	1、如果有数据不更新,那么就出入null即可
	 */
	@Test
	public void update(){
		User user1=new User();
		user1.setId(1);
		user1.setAge(22);
		user1.setName("郑元梅");
		User user = userRepository.save(user1);
		System.out.println(user);
	}
	
	/**
	 * 统计数据
	 */
	@Test
	public void count(){
		System.out.println(userRepository.count());
	}
	
	/**
	 * 统计数据
	 */
	@Test
	public void countByAge(){
		System.out.println(userRepository.countByAge(23));
	}
	
	@Test
	public void findByName(){
		List<User> users=userRepository.findTop2ByNameAndAge("陈加兵", 22);
		for (User user : users) {
			System.out.println(user);
		}
		
	}
	
	@Test
	public void findByAgeIn(){
		Integer[] ages= {22,23};
		List<User> users=userRepository.findByAgeIn(ages);
		for (User user : users) {
			System.out.println(user);
		}
		
		}
	}
}

自定义查询@Query

使用HQL语句查询

  • 默认使用的就是HQL语句查询的,如下:
/**
 * 使用hql表达式查询,其中?1表示对应第一个参数,不能直接使用?作为占位符
 */
@Query(value="select u from User u where u.age=?1 and u.name=?2")
List<User>findUserList(Integer age,String name);

使用sql语句查询

  • 需要指定 nativeQuery=true
/**
 * 使用sql语句查询,其中nativeQuery表示使用本地查询,即是sql语句查询
 */
@Query(value="select * from t_user where age=?1 order by industry_id desc",nativeQuery=true)
List<User>findUserListByAge(Integer age);

删除和修改

  • 使用自定义sql的时候,如果涉及到删除和修改的sql需要满足两个条件才能执行,如下:
    @Modifying
    
/**
	 * 删除和修改信息,必须同时使用@Modifying注解标注
	 */
	@Modifying
	@Query(value="delete from t_user where industry_id=?1",nativeQuery=true)
	void deleteByIndustryId(Integer industryId);

复杂条件查询

  • Repository接口需要继承 JpaSpecificationExecutor ,如下:
public interface UserRepositoryextends JpaRepository<User,Integer>,JpaSpecificationExecutor<User>{
  • 查询如下:
/**
	 *   结果筛选
	 * @param user  封装了查询的条件
	 * @return
	 */
	public List<User> findAll_2(User user){
		List<User> users = userRepository.findAll(new Specification<User>() {
			/**
			 * @param root 根对象,用于封装查询的条件,比如name,jack、age 10等
			 * @param query  封装查询关键字  比如group by order by
			 * @param criteriaBuilder  封装对象条件
			 * @return 返回null表示没有查询条件
			 */
			@Override
			public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder){
				//new 一个集合,存放所有的查询条件
				List<Predicate> predicates=new ArrayList<>();
				
				if (!StringUtils.isEmpty(user.getName())) {  //如果name不是null,就填入到筛选条件中
					//第一个参数是表达式,第二个参数是值,相当于where name=%name%
					Predicate predicate = criteriaBuilder.like(root.get("name").as(String.class),"%"+user.getName()+"%");
					predicates.add(predicate);   //加入到条件集合中
				}
				
				if (!StringUtils.isEmpty(user.getAddress())) { //如果地址不为空,填入筛选条件
					//where address=xxx
					Predicate predicate = criteriaBuilder.equal(root.get("address").as(String.class), user.getAddress());
					predicates.add(predicate);
				}
				
				if (user.getAge()!=null) { //如果年龄不为空
					//where age<=xxx
					Predicate predicate = criteriaBuilder.le(root.get("age").as(Integer.class), user.getAge());
					predicates.add(predicate);
				}
				
				Predicate[] parray=new Predicate[predicates.size()];
				//返回,这里的使用的and条件,将上面所有的条件用and连接
				return criteriaBuilder.and(predicates.toArray(parray));
		}
		});
	return users;
}


	/**
	 * 测试
	 */
	@Test
	public void test1(){
		User user=new User();
		user.setName("a");  //封装name
		List<User> users = findAll_2(user);
		for (User user2 : users) {
			System.out.println(user2);
		}
	}

分页查询

PageRequest

  • 构造方法如下:
    • public PageRequest(int page, int size)
      size
      page
      
    • public PageRequest(int page, int size, Direction direction, String... properties)
      direction
      properties
      

Page

int getTotalPages()
long getTotalElements()
boolean hasContent();
List<T> getContent();
boolean isFirst();
boolean isLast();
boolean hasNext();
boolean hasPrevious();
Pageable nextPageable();
Pageable previousPageable();

简单查询

  • 以相同的排序方式查询
@Test
public void findAll(){
	//构造分页数据,查找第二页,每页2条记录,order by age,industryId desc
	Pageable pageable=new PageRequest(1, 2,Direction.DESC,"age","industryId");
	Page<User> pages = userRepository.findAll(pageable);  //执行分页查询的方法
	if (pages.hasContent()) {  //如果查询到了内容
		List<User> users = pages.getContent();  //获取查询到的结果
		long total = pages.getTotalElements();   //获取总数
	}
}
  • 不同的排序方式查询
@Test
public void findAll(){
	Order order1=new Order(Direction.DESC, "age");  //创建排序方式
	Order order2=new Order(Direction.ASC, "industryId");
	List<Order> orders=new ArrayList<>();  //放入集合
	orders.add(order1);
	orders.add(order2);
	
	Sort sort=new Sort(orders);  //创建Sort
	
	//构造分页数据,查找第二页,每页2条记录,order by age desc,industryId asc
	Pageable pageable=new PageRequest(0, 2,sort);
	Page<User> pages = userRepository.findAll(pageable);  //执行分页查询的方法
	if (pages.hasContent()) {  //如果查询到了内容
		List<User> users = pages.getContent();  //获取查询到的结果
		long total = pages.getTotalElements();   //获取总数
		for (User user : users) {
			System.out.println(user);
		}
	}
}

复杂条件分页查询

  • Repository接口需要继承 JpaSpecificationExecutor ,如下:
public interface UserRepositoryextends JpaRepository<User,Integer>,JpaSpecificationExecutor<User>{
  • 和复杂条件查询一样,只是多了一个分页
/**
	 *   结果筛选
	 * @param user  封装了查询的条件
	 * @return
	 */
	public List<User> findAll_3(User user,Integer pageNum,Integer pageSize){
		 
		Pageable pageable=new PageRequest(pageNum-1, pageSize);   //分页的查询
		 
		Page<User> pages = userRepository.findAll(new Specification<User>() {
			/**
			 * @param root 根对象,用于封装查询的条件,比如name,jack、age 10等
			 * @param query  封装查询关键字  比如group by order by
			 * @param criteriaBuilder  封装对象条件
			 * @return 返回null表示没有查询条件
			 */
			@Override
			public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder){
				//new 一个集合,存放所有的查询条件
				List<Predicate> predicates=new ArrayList<>();
				
				if (!StringUtils.isEmpty(user.getName())) {  //如果name不是null,就填入到筛选条件中
					//第一个参数是表达式,第二个参数是值,相当于where name=%name%
					Predicate predicate = criteriaBuilder.like(root.get("name").as(String.class),"%"+user.getName()+"%");
					predicates.add(predicate);   //加入到条件集合中
				}
				
				if (!StringUtils.isEmpty(user.getAddress())) { //如果地址不为空,填入筛选条件
					//where address=xxx
					Predicate predicate = criteriaBuilder.equal(root.get("address").as(String.class), user.getAddress());
					predicates.add(predicate);
				}
				
				if (user.getAge()!=null) { //如果年龄不为空
					//where age<=xxx
					Predicate predicate = criteriaBuilder.le(root.get("age").as(Integer.class), user.getAge());
					predicates.add(predicate);
				}
				
				Predicate[] parray=new Predicate[predicates.size()];
				//返回,这里的使用的and条件,将上面所有的条件用and连接
				return criteriaBuilder.and(predicates.toArray(parray));
		}
		},pageable);
		
		return pages.getContent();  //返回结果
}
	
	/**
	 * 测试
	 */
	@Test
	public void test2(){
		User user=new User();
		user.setName("a");  //封装name
		List<User> users = findAll_3(user,1,10);
		for (User user2 : users) {
			System.out.println(user2);
		}
	}
原文  https://chenjiabing666.github.io/2018/12/20/SpringBoot整合Spring-data-jpa/
正文到此结束
Loading...