美文网首页
Spring Boot 使用数据库

Spring Boot 使用数据库

作者: 清十郎sama | 来源:发表于2019-12-23 14:48 被阅读0次

前端调用后端 REST API,后端操作 MYSQL 数据库执行查询变更数据的操作。这几乎是现在最常见的开发场景。这篇要讲的就是 Spring Boot 开发中对数据库操作相关的内容。

Spring Boot 数据库操作的常用技术选择主要是两种:

这篇文章将会采用 Spring Data JPA。

为什么选择 Spring Data JPA 而不是 MyBatis?
我选择 Spring Data JPA 的理由很简单,我们选择了 Spring 作为开发框架,那么我所有技术选型在没有明显差距的情况下,我会选择 Spring 推荐的。而在 Spring 官方文档中,所有数据库相关的部分都是使用 Spring Data JPA。
这里多解释一句,实际和 MyBatis 对标的应该是 Hibernate,同属于数据持久层。Spring Data JPA 是更上一层的数据访问层,而作为数据访问层,Spring Data JPA 使用的数据持久层技术是 Hibernate。

使用 Spring Data JPA

Spring Data JPA 的基本使用非常简单,并且教程很多,这里我不赘述。给大家一些现成的教程链接:

Tips

使用 lombok 让 JPA “Entity” 类更简洁
编写 Entity 类时,我们经常需要反复的写 get/set 方法。不止麻烦,而且代码反复。这时我们可以引入 “org.projectlombok:lombok” 工具,在 Entity 类上加上 @Data,这样我们就可以省去 get/set 方法的书写了。

怎么定义自增主键
为主键变量添加 @GeneratedValue(strategy = GenerationType.IDENTITY) 注解即可。

@Data
@Entity
public class Student implements Serializable{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
 
@Column(nullable = false)
private String name;
}

更灵活的数据库操作 - 在 Spring Data JPA 中使用 Sql 查询语句
参考:Spring Data JPA Docs - 2.1.5.RELEASE: Using @Query

灵活的条件查询 - JPA query with optional parameters
在做 MySQL 查询时,我们经常会用到多条件查询。比如一个表 学生(id,姓名,性别,年纪)。我们要查询学生,可能会用到 id,或者姓名,或者姓名+性别,或者年纪+性别等等。如果我们针对每一种情况都写一个查询方法会非常麻烦。这时我们可能会想到在 Repository 中添加如下方法:

List<Student> findAllByIdAndNameAndGenderAndAge(Student student)

具体我们要查询时,比如我们想要查询所有姓名为“张三”的男学生,我们可能会通过以下方式:

Student student = new Student();
student.setName("张三");
student.setGender("男");
return studentRepository.findAllByIdAndNameAndGenderAndAge(student);

这样我们会得到类似 "select * from student where name="张三" and gender="男" "的结果吗?
答案是不会。对于未赋值的参数,JPA 默认认其值为 null,而不是忽略这个查询条件。所以你会得到类似 "select * from student where name="张三" and gender="男" and id=null and age=null " 的结果。
那么我们该如何做呢?这里可以使用 JPA 里面的 ExampleMatcher
定义 Repository:

List<Student> findAllByIdAndNameAndGenderAndAge(Example<Student> example)
// or List<Student> findAll(Example<Student> example)

调用查询:

Student student = new Student();
student.setName("张三");
student.setGender("男");
ExampleMatcher matcher = ExampleMatcher.matching().withIgnoreNullValues();
Example<Student> exampleQuery = Example.of(student, matcher);
return studentRepository.findAllByIdAndNameAndGenderAndAge(exampleQuery);

注意!:使用 Example 这种方式一定要注意下面一点:定义表映射的类时不要使用基本数据类型!!!!
原因很简单,因为我们忽略空值的方法是判断 null。基本数据类型比如 int 是没有 null 值的,当一个 int 字段未定义时,其值会取 0。从而破坏你的查询!因此,当我们想要使用 int 时,我们应该使用 Integer 类型。

基于 @Query 实现灵活的条件查询
上一节提到的 ExampleMatcher 是不定项参数查询最简单便捷的实现。但同时,该方法存在一些限制:

  • No support for nested or grouped property constraints, such as firstname = ?0 or (firstname = ?1 and lastname = ?2)
  • Only supports starts/contains/ends/regex matching for strings and exact matching for other property types.

还是以上一节学生表(id,姓名,性别,年纪)为例。
假设我们为这张表新增一个出生年月字段。同时我们想要写一个查询方法,这个方法在支持不定项参数条件查询的前提下,还能针对日期的时间范围进行查询。比如我想要查询所有出生年月于1991年1月到1996年5月之间的男生。
这时我们会发现,一个方法,不定项参数和时间范围查询,这三个条件我们通过 ExampleMatcher 无法同时满足。针对这类复杂且难以涵盖的场景,我们可以通过 @Query 注解写 SQL 来实现。方法如下:

@Query("SELECT p FROM person p WHERE (:name is null or p.name = :name)"+
        "and (:gender is null or p.gender = :gender)"+
        "and (:birthStart is null or b.birth >= :birthStart)"+
        "and (:birthEnd is null or b.birth <= :birthEnd)")
List<BeBusiness> myQueryMethod(String name, String gender, Date transTimeStart, Date transTimeEnd, Pageable pageable);

通过 (:? is null or p.name = :?) 这样的语法,我们可以实现不定项参数的功能。详见:baeldung: spring-data-jpa-null-parameters

@Query 可以与 PagingAndSortingRepository 中的 sort / pageable 功能组合使用。

相关文章

网友评论

      本文标题:Spring Boot 使用数据库

      本文链接:https://www.haomeiwen.com/subject/yorznctx.html