文章目录
  1. 1. SpringBoot整合Spring data jpa
    1. 1.1. 依赖
    2. 1.2. 主键生成策略
    3. 1.3. 配置
    4. 1.4. 创建一个实体类
    5. 1.5. 基本的查询
    6. 1.6. 自定义查询@Query
      1. 1.6.1. 使用HQL语句查询
      2. 1.6.2. 使用sql语句查询
      3. 1.6.3. 删除和修改
    7. 1.7. 复杂条件查询
    8. 1.8. 分页查询
      1. 1.8.1. PageRequest
      2. 1.8.2. Page
      3. 1.8.3. 简单查询
      4. 1.8.4. 简单条件分页查询
      5. 1.8.5. 复杂条件分页查询
    9. 1.9. 查找关键字
    10. 1.10. 参考文章
    11. 1.11. 笔者有话说

SpringBoot整合Spring data jpa

依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<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
  • 实例如下:
1
2
3
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY) //数据库自增
private Integer id;

配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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

创建一个实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 用户的实体类,其中的变量和数据库默认是以驼峰形式对应的,比如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,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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);
}
  • 测试类如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
@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语句查询的,如下:
1
2
3
4
5
/**
* 使用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
1
2
3
4
5
/**
* 使用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标注
    • 在事务中执行
1
2
3
4
5
6
/**
* 删除和修改信息,必须同时使用@Modifying注解标注
*/
@Modifying
@Query(value="delete from t_user where industry_id=?1",nativeQuery=true)
void deleteByIndustryId(Integer industryId);

复杂条件查询

  • Repository接口需要继承JpaSpecificationExecutor,如下:
1
public interface UserRepository extends JpaRepository<User, Integer>,JpaSpecificationExecutor<User>{
  • 查询如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/**
* 结果筛选
* @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();:获取前一页

简单查询

  • 以相同的排序方式查询
1
2
3
4
5
6
7
8
9
10
@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(); //获取总数
}
}
  • 不同的排序方式查询
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@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);
}
}
}

简单条件分页查询

  • 方法如下:
1
2
3
4
/*
* 根据条件查询的结果分页,相当于select * from user where name=xxx limit #,#
*/
List<User> findByName(String name,Pageable pageable);

复杂条件分页查询

  • Repository接口需要继承JpaSpecificationExecutor,如下:
1
public interface UserRepository extends JpaRepository<User, Integer>,JpaSpecificationExecutor<User>{
  • 和复杂条件查询一样,只是多了一个分页
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/**
* 结果筛选
* @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 findByFirstnamefindByFirstnameIsfindByFirstnameEquals … 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 findTopByNameAndAgefindFirstByNameAndAge where … limit 1
Topn或者Firstn findTop2ByNameAndAgefindFirst2ByNameAndAge where … limit 2
Distinct findDistinctPeopleByLastnameOrFirstname select distinct ….
count countByAgecount select count(*)

参考文章

笔者有话说

  • 最近建了一个微信交流群,提供给大家一个交流的平台,扫描下方笔者的微信二维码,备注【交流】,我会把大家拉进群

文章目录
  1. 1. SpringBoot整合Spring data jpa
    1. 1.1. 依赖
    2. 1.2. 主键生成策略
    3. 1.3. 配置
    4. 1.4. 创建一个实体类
    5. 1.5. 基本的查询
    6. 1.6. 自定义查询@Query
      1. 1.6.1. 使用HQL语句查询
      2. 1.6.2. 使用sql语句查询
      3. 1.6.3. 删除和修改
    7. 1.7. 复杂条件查询
    8. 1.8. 分页查询
      1. 1.8.1. PageRequest
      2. 1.8.2. Page
      3. 1.8.3. 简单查询
      4. 1.8.4. 简单条件分页查询
      5. 1.8.5. 复杂条件分页查询
    9. 1.9. 查找关键字
    10. 1.10. 参考文章
    11. 1.11. 笔者有话说