Spring Boot JPA

栏目: Java · 发布时间: 7年前

内容简介:Spring Boot JPA

JPA(Java Persistence API)是一套 Java 持久化规范 用于将应用程序中的对象映射到关系型数据库

应用程序的数据访问层通常为域对象提供创建 读取 更新和删除(CRUD)操作 Spring Data JPA 提供了这方面的通用接口以及持久化存储特定的实现 它旨在简化数据访问层 作为应用程序的开发人员 你只需要编写数据库的存取接口 由 Spring 运行时自动生成这些接口的适当实现 开发人员不需要编写任何具体的实现代码

Spring Data JPA 选择目前最流行之一的 Hibernate 用作 JPA 实现的提供者

环境

  • JDK 8
  • Maven 3
  • IntelliJ IDEA 2016
  • Spring Boot 1.5.2.RELEASE
  • MySQL 5.5

依赖配置

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-data-jpa</artifactId>
 <exclusions>
 <exclusion>
 <groupId>org.apache.tomcat</groupId>
 <artifactId>tomcat-jdbc</artifactId>
 </exclusion>
 </exclusions>
</dependency>
<dependency>
 <groupId>com.zaxxer</groupId>
 <artifactId>HikariCP</artifactId>
 <version>2.6.1</version>
</dependency>
<dependency>
 <groupId>mysql</groupId>
 <artifactId>mysql-connector-java</artifactId>
 <version>5.1.40</version>
</dependency>

应用配置

数据源配置

spring:
 datasource:
 url: jdbc:mysql://127.0.0.1/jpa_testing_repository
 username: root
 password: root
 driver-class-name: com.mysql.jdbc.Driver
 hikari:
 auto-commit: true
 connection-test-query: 'SELECT 1'
 maximum-pool-size: 10

自动更新表结构

spring:
 jpa:
 hibernate:
 ddl-auto: update

SQL 输出

logging:
 level:
 root: warn
 org.hibernate.SQL: debug

完整配置

src/main/resources/application.yml

spring:
 datasource:
 url: jdbc:mysql://127.0.0.1/jpa_testing_repository
 username: root
 password: root
 driver-class-name: com.mysql.jdbc.Driver
 hikari:
 auto-commit: true
 connection-test-query: 'SELECT 1'
 maximum-pool-size: 10
 jpa:
 hibernate:
 ddl-auto: update

logging:
 level:
 root: warn
 org.hibernate.SQL: debug

创建数据库脚本

CREATE DATABASE jpa_testing_repository DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

实体类定义

@Entity
@Table
public class Product{

 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 private Long id;

 private String name;

 private String category;

 private Double price;

 private Integer stock;

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

 // getters and setters

 @Override
 public String toString(){
 return "{id=" + id + ", name=" + name + ", category=" + category + ", price=" + price + ", stock=" + stock + ", createTime=" + createTime + "}";
 }

}

核心接口

Spring Data JPA 核心接口列表:

接口 父接口 描述
Repository - 标记接口 Spring 组件扫描到能自动识别
CrudRepository Repository 提供一组 CRUD 操作方法
PagingAndSortingRepository CrudRepository 提供一组分页和 排序 的方法
JpaRepository PagingAndSortingRepository 额外提供一组实用的操作方法

CrudRepository

方法 描述 SQL
S save(S) 保存或更新实体对象 INSERT ... VALUES(?...)

UPDATE ... SET ...
Iterable<S> save(Iterable<S>) 保存集合里面所有的实体对象 产生多条:
INSERT ... VALUES(?...)
T findOne(ID) 根据主键查找 若查找不到则返回 null SELECT ... WHERE ID = ?
boolean exists(ID) 判断给定的主键的记录是否存在 SELECT COUNT(*) ... WHERE ID = ?
Iterable<T> findAll() 查找所有的记录 SELECT ... FROM ...
Iterable<T> findAll(Iterable<ID>) 查找给定的主键集合的所有记录 SELECT ... WHERE ID IN(...)
long count() 统计数据库中记录的总条数 SELECT COUNT(*) ...
void delete(ID) 根据主键删除记录 如果主键不存在则抛出异常 1. SELECT ... WHERE ID = ?
2. DELETE ... WHERE ID = ?
void delete(T) 删除参数给定的实体对象记录 注意 它只跟实体对象参数的 ID 属性值有关:
1.如果实体对象参数的 ID 属性没有设值或该值在数据库表中找不到对应的记录 则会先产生 INSERT SQL 然后再删除刚刚插入的记录 实际上做的是无用功;
2.如果实体对象参数的 ID 属性有值且在数据库表中有对应的记录 则将其删除
1. SELECT ... WHERE ID = ?
2. DELETE ... WHERE ID = ?
或:
1. INSERT ... VALUES(?...)
2. DELETE ... WHERE ID = ?
void delete(Iterable<? extends T>) 删除集合里面所有的实体对象记录 产生多条:
1. SELECT ... WHERE ID = ?
2. DELETE ... WHERE ID = ?
或:
1. INSERT ... VALUES(?...)
2. DELETE ... WHERE ID = ?
void deleteAll() 删除数据库中所有的记录 产生一条:
SELECT ... FROM ...
产生多条:
DELETE ... WHERE ID = ?

PagingAndSortingRepository

方法 描述 SQL
Iterable<T> findAll(Sort sort) 排序查询 SELECT ... ORDER BY ...
Page<T> findAll(Pageable pageable) 分页查询 1. SELECT ... LIMIT ...
2. SELECT COUNT(ID) ...

Page

方法 描述
totalElements 数据库中总的记录条数
totalPages 分页的总页数
size 当前分页的数据含有的记录条数
content 数据内容集合
sort 分页查询的排序对象
isFirst() 是否是第一页
isLast() 是否是最后一页
hasContent() 当前的分页数据是否内容
hasNext() 是否有下一页
hasPrevious() 是否有上一页
nextPageable() 下一页的分页对象参数
previousPageable() 上一页的分页对象参数

排序查询示例

@Override
public void run(String... args) throws Exception{
 List<Order> orders = new ArrayList<>();
 orders.add(new Order("sex"));
 orders.add(new Order(Direction.DESC, "createTime"));
 orders.add(new Order("email").with(Direction.DESC));
 userRepository.findAll(new Sort(orders)).forEach(System.out::println);
}

分页查询示例

@Override
public void run(String... args) throws Exception{
 // 分页索引从0开始, 表示第一页
 Page<User> page = userRepository.findAll(new PageRequest(0, 2));
 page.forEach(System.out::println);
}

JpaRepository

方法 描述 SQL
List<T> findAll() 参考 CrudRepository.findAll()
List<T> findAll(Sort) 参考 PagingAndSortingRepository.findAll(Sort)
List<T> findAll(Iterable<ID<) 参考 CrudRepository.findAll(Iterable<ID<)
List<S> save(Iterable<S>) 参考 CrudRepository.save(Iterable<S>)
deleteInBatch(Iterable<T>) 批量删除实体对象的记录 它只跟实体对象参数的 ID 属性值有关 DELETE ... WHERE ID = ? OR ID = ? ...
deleteAllInBatch() 批量删除全部记录 DELETE FROM ...

数据访问接口编写

为使用基础的 CRUD 操作 可继承 JpaRepository 不需要编写任何具体的实现

public interface ProductRepository extends JpaRepository<Product, Long>{

}

Application

@SpringBootApplication
public class Application implements CommandLineRunner{

 @Autowired
 private ProductRepository productRepository;

 public static void main(String[] args){
 SpringApplication.run(Application.class);
 }

 @Override
 public void run(String... args) throws Exception{
 /* ------------------------ 保存数据 ------------------------ */
 productRepository.save(createProduct("深入理解Java虚拟机", "图书", 60.8, 100));
 productRepository.save(createProduct("HotSpot实战", "图书", 50.3, 20));
 productRepository.save(createProduct("Java并发编程实战", "图书", 44.6, 80));
 productRepository.save(createProduct("Java多线程编程核心技术", "图书", 55.5, 0));
 productRepository.save(createProduct("Effective Java中文版", "图书", 66.6, 30));
 productRepository.save(createProduct("深入分析Java Web技术内幕", "图书", 77.7, 50));
 productRepository.save(createProduct("大型网站技术架构核心原理与案例分析", "图书", 88.8, 0));
 productRepository.save(createProduct("美的电饭煲", "家电", 279.0, 60));
 productRepository.save(createProduct("小熊迷你养生壶全", "家电", 99.98, 0));
 productRepository.save(createProduct("海尔三门冰箱", "家电", 358.10, 80));
 /* ------------------------ 查询数据 ------------------------ */
 productRepository.findAll().forEach(System.out::println);
 }

 private Product createProduct(String name, String category, Double price, Integer stock){
 Product product = new Product();
 product.setName(name);
 product.setPrice(price);
 product.setStock(stock);
 product.setCategory(category);
 product.setCreateTime(new Date());
 return product;
 }

}

创建查询方法

Spring Data JPA 提供的查询策略:

名称 描述
CREATE 查询创建策略 尝试从查询方法名称中构造一个特定的存储查询 其做法是从该查询方法名称中移除一组已知的特定前缀 并解析其余部分
USE_DECLARED_QUERY 使用声明查询策略 尝试查找 @Query 注解标注的方法 并使用指定的查询语句
CREATE_IF_NOT_FOUND 默认使用的策略 它结合了 CREATEUSE_DECLARED_QUERY 策略 并且优先尝试使用 USE_DECLARED_QUERY 策略 再尝试使用 CREATE 策略

查询创建策略

自定义的查询方法名称必须满足以下规则:

  • 以下面罗列的前缀之一开始命名:
    • findBy
    • find…By
    • readBy
    • read…By
    • queryBy
    • query…By
    • countBy
    • count…By
    • getBy
    • get…By
  • 第一个 By 之后添加查询的条件 可以使用特定的实体类的属性名称和支持的查询关键字(参考查询关键字表)来组合;
  • 如果要限制查询结果返回的数据的个数 可以在第一个 By 之前添加 FirstTop 关键字 此关键字后面还可以带数字 表示返回前多少条数据 如果数字省略 则表示返回第一条数据(如:findFirstByName(返回第1条) findTopByName(返回第1条) findTop10ByName(返回前10条)) 当查询方法匹配到多个结果时 返回指定大小的结果或只返回第一条数据的结果;
  • 当需要查询唯一结果时 在第一个 By 之前添加 Distinct 关键字(如:findDistinctNameBy)
  • 如果查询方法指定了 N 个搜索条件 则此方法的签名也必须含有 N 个参数 即方法参数的数量必须等于搜索条件的数量 方法参数必须按搜索条件相同的顺序给出;
  • 查询方法参数中 可以含有特殊的 Pageable 和 Sort 参数 用于分页和排序(注:此条款不受上一条款约束)

查询关键字表

关键字 示例 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
findByAgeNotNull
findByAgeIsNotNull
… 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 (parameter bound with appended %)
EndingWith findByFirstnameEndingWith … where x.firstname like ?1 (parameter bound with prepended %)
Containing findByFirstnameContaining … where x.firstname like ?1 (parameter bound wrapped in %)
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> age) … 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)

查询返回值类型表

类型 描述
void 不需要返回值
Primitives Java 基本数据类型
Wrapper Java 基本数据类型对应的包装类型
T 期望返回的实体数据类型 查询方法至多返回一条数据结果 多于一条数据的结果将抛出异常 没有查询到数据结果 则返回 null
Iterator<T> 迭代器类型
Collection<T> 集合类型
List<T> List 集合类型
Optional<T> Java8 Optional 类型
Stream<T> Java8 Stream 类型
Future<T> Java8 Future 类型 使用 @Async 注解标注查询方法 并且需要启用 Spring 异步方法执行的功能
CompletableFuture<T> Java8 CompletableFuture 类型 使用 @Async 注解标注查询方法 并且需要启用 Spring 异步方法执行的功能
ListenableFuture Spring ListenableFuture 类型 使用 @Async 注解标注查询方法 并且需要启用 Spring 异步方法执行的功能
Slice 分页相关
Page<T> 分页相关

@Query 创建查询

JPQL(Java Persistence Query Language Java 持久化查询语言)和 SQL 之间有很多相似之处 它们之间主要的区别在于前者处理 JPA 实体(类名 –> 表名 属性 –> 列名) 而后者则直接涉及关系数据

SQL:

@Query(value = "SELECT * FROM PRODUCT WHERE CATEGORY = ?", nativeQuery = true)
List<Product> selectByCategory(String category);

JPQL:

@Query("select p from Product p where p.category = ?")
List<Product> selectByCategory(String category);

更多 JPQL 的语法移步到: JPQL 语言语法

事务控制

第 17 行抛出异常 此时 p1 p2 已保存到数据库:

@Service
public class ProductService{

 @Autowired
 private ProductRepository productRepository;

 public void batchSave(){
 Product p1 = new Product();
 p1.setName("商品A");
 Product p2 = new Product();
 p2.setName("商品B");
 Product p3 = new Product();
 p3.setName("商品C");
 productRepository.save(p1);
 productRepository.save(p2);
 // 模拟异常
 p3.setStock(100 / 0);
 productRepository.save(p3);
 }

}

通过使用 @Transactional 注解控制事务 以下示例 p1 p2 p3 均未入库 第 17 抛出异常导致数据回滚:

@Service
public class ProductService{

 @Autowired
 private ProductRepository productRepository;

 @Transactional
 public void batchSave(){
 Product p1 = new Product();
 p1.setName("商品A");
 Product p2 = new Product();
 p2.setName("商品B");
 Product p3 = new Product();
 p3.setName("商品C");
 productRepository.save(p1);
 productRepository.save(p2);
 // 模拟异常
 p3.setStock(100 / 0);
 productRepository.save(p3);
 }

}

参考文档:

http://docs.spring.io/spring-data/jpa/docs/1.11.1.RELEASE/reference/html


以上所述就是小编给大家介绍的《Spring Boot JPA》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

网站分析实战

网站分析实战

王彦平 吴盛峰 / 电子工业出版社 / 2013-1 / 59.00元

《网站分析实战:如何以数据驱动决策,提升网站价值》由王彦平、吴盛峰著。目前,越来越多的网站开始重视数据,并期望从中发现新的机会,不管你是做网络营销、互联网产品设计、电子商务运营、个人站点运营维护,我们都希望从数据中寻找有价值的结论,并且指导公司管理层的决策,最终创造更大的网站价值。《网站分析实战:如何以数据驱动决策,提升网站价值》以通俗易懂的方式来讲解网站分析所需掌握的知识,剖析日常工作中遇到的问......一起来看看 《网站分析实战》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具