前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringBoot整合Spring-data-jpa

SpringBoot整合Spring-data-jpa

作者头像
爱撒谎的男孩
发布2019-12-31 15:45:40
1.5K0
发布2019-12-31 15:45:40
举报
文章被收录于专栏:码猿技术专栏

文章目录

1. SpringBoot整合Spring data jpa

1.1. 依赖

1.2. 主键生成策略

1.3. 配置

1.4. 创建一个实体类

1.5. 基本的查询

1.6. 自定义查询@Query

1.6.1. 使用HQL语句查询

1.6.2. 使用sql语句查询

1.6.3. 删除和修改

1.7. 复杂条件查询

1.8. 分页查询

1.8.1. PageRequest

1.8.2. Page

1.8.3. 简单查询

1.8.4. 简单条件分页查询

1.8.5. 复杂条件分页查询

1.9. 查找关键字

1.10. 参考文章

SpringBoot整合Spring data jpa

依赖

代码语言:javascript
复制
<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
  • 实例如下:
代码语言:javascript
复制
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)  //数据库自增
private Integer id;

配置

代码语言:javascript
复制
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

创建一个实体类

代码语言:javascript
复制
/**
 * 用户的实体类,其中的变量和数据库默认是以驼峰形式对应的,比如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,如下:
代码语言:javascript
复制
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 UserRepository extends 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
	 */
	User findTopByNameAndAge(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
	 */
	Long countByAge(Integer age);
	
}
  • 测试类如下:
代码语言:javascript
复制
@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语句查询的,如下:
代码语言:javascript
复制
/**
 * 使用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
代码语言:javascript
复制
/**
 * 使用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标注
    • 在事务中执行
代码语言:javascript
复制
/**
	 * 删除和修改信息,必须同时使用@Modifying注解标注
	 */
	@Modifying
	@Query(value="delete from t_user where industry_id=?1",nativeQuery=true)
	void deleteByIndustryId(Integer industryId);

复杂条件查询

  • Repository接口需要继承JpaSpecificationExecutor,如下:
代码语言:javascript
复制
public interface UserRepository extends JpaRepository<User, Integer>,JpaSpecificationExecutor<User>{
  • 查询如下:
代码语言:javascript
复制
/**
	 *   结果筛选
	 * @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:从第几页开始,从0开始,0 表示第一页
    • public PageRequest(int page, int size, Direction direction, String... properties)
      • direction: 排序的方式,枚举类,其中有ASC,DESC
      • properties: 进行排序的字段,可以指定多个

Page

  • int getTotalPages():返回共有多少页数
  • long getTotalElements():获取总数
  • boolean hasContent();: 当前分页是否有数据
  • List<T> getContent();: 返回当前页所有的数据
  • boolean isFirst();:判断当前的页数是否是第一页
  • boolean isLast();: 是否是最后页
  • boolean hasNext();: 是否还有下一页
  • boolean hasPrevious();: 是否还有前一页
  • Pageable nextPageable();: 获取下一页
  • Pageable previousPageable();:获取前一页

简单查询

  • 以相同的排序方式查询
代码语言:javascript
复制
@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();   //获取总数
	}
}
  • 不同的排序方式查询
代码语言:javascript
复制
@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);
		}
	}
}

简单条件分页查询

  • 方法如下:
代码语言:javascript
复制
/*
 * 根据条件查询的结果分页,相当于select * from user where name=xxx limit #,#
 */
List<User> findByName(String name,Pageable pageable);

复杂条件分页查询

  • Repository接口需要继承JpaSpecificationExecutor,如下:
代码语言:javascript
复制
public interface UserRepository extends JpaRepository<User, Integer>,JpaSpecificationExecutor<User>{
  • 和复杂条件查询一样,只是多了一个分页
代码语言:javascript
复制
/**
	 *   结果筛选
	 * @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);
		}
	}

查找关键字

关键词

样品

JPQL代码段

And

findByLastnameAndFirstname

… where x.lastname = ?1 and x.firstname = ?2

Or

findByLastnameOrFirstname

… where x.lastname = ?1 or x.firstname = ?2

Is,Equals

findByFirstname,findByFirstnameIs,findByFirstnameEquals

… where x.firstname = ?1

Between

findByStartDateBetween

… where x.startDate between ?1 and ?2

LessThan

findByAgeLessThan

… where x.age < ?1

LessThanEqual

findByAgeLessThanEqual

… where x.age <= ?1

GreaterThan

findByAgeGreaterThan

… where x.age > ?1

GreaterThanEqual

findByAgeGreaterThanEqual

… where x.age >= ?1

After

findByStartDateAfter

… where x.startDate > ?1

Before

findByStartDateBefore

… where x.startDate < ?1

IsNull

findByAgeIsNull

… where x.age is null

IsNotNull,NotNull

findByAge(Is)NotNull

… where x.age not null

Like

findByFirstnameLike

… where x.firstname like ?1

NotLike

findByFirstnameNotLike

… where x.firstname not like ?1

StartingWith

findByFirstnameStartingWith

… where x.firstname like ?1(附加参数绑定%)

EndingWith

findByFirstnameEndingWith

… where x.firstname like ?1(与前置绑定的参数%)

Containing

findByFirstnameContaining

… where x.firstname like ?1(参数绑定包装%)

OrderBy

findByAgeOrderByLastnameDesc

… where x.age = ?1 order by x.lastname desc

Not

findByLastnameNot

… where x.lastname <> ?1

In

findByAgeIn(Collection<Age> ages)

… where x.age in ?1

NotIn

findByAgeNotIn(Collection<Age> ages)

… where x.age not in ?1

True

findByActiveTrue()

… where x.active = true

False

findByActiveFalse()

… where x.active = false

IgnoreCase

findByFirstnameIgnoreCase

… where UPPER(x.firstame) = UPPER(?1)

Top或者First

findTopByNameAndAge,findFirstByNameAndAge

where … limit 1

Topn或者Firstn

findTop2ByNameAndAge,findFirst2ByNameAndAge

where … limit 2

Distinct

findDistinctPeopleByLastnameOrFirstname

select distinct ….

count

countByAge,count

select count(*)

参考文章

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-12-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • SpringBoot整合Spring data jpa
    • 依赖
      • 主键生成策略
        • 配置
          • 创建一个实体类
            • 基本的查询
              • 自定义查询@Query
                • 使用HQL语句查询
                • 使用sql语句查询
                • 删除和修改
              • 复杂条件查询
                • 分页查询
                  • PageRequest
                  • Page
                  • 简单查询
                  • 简单条件分页查询
                  • 复杂条件分页查询
                • 查找关键字
                  • 参考文章
                  相关产品与服务
                  数据库
                  云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档