内容简介: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 |
默认使用的策略 。
它结合了 CREATE
和 USE_DECLARED_QUERY
策略 。
并且优先尝试使用 USE_DECLARED_QUERY
策略 ,
再尝试使用 CREATE
策略 |
查询创建策略
自定义的查询方法名称必须满足以下规则:
-
以下面罗列的前缀之一开始命名:
- findBy
- find…By
- readBy
- read…By
- queryBy
- query…By
- countBy
- count…By
- getBy
- get…By
-
第一个
By
之后添加查询的条件 , 可以使用特定的实体类的属性名称和支持的查询关键字(参考查询关键字表)来组合; -
如果要限制查询结果返回的数据的个数 ,
可以在第一个
By
之前添加First
或Top
关键字 , 此关键字后面还可以带数字 , 表示返回前多少条数据 , 如果数字省略 , 则表示返回第一条数据(如: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》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Spring Boot JPA
- Spring Boot 2和JPA入门
- 【快学springboot】7.使用Spring Boot Jpa
- Spring Boot 2.x(三):整合Spring Data JPA
- Spring Boot 最佳实践(五)Spring Data JPA 操作 MySQL 8
- Spring Boot + JPA实现MySQL批量更新源码 - github
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
云计算安全与隐私
Tim Mather、Subra Kumaraswamy、Shahed Latif / 刘戈舟、杨泽明、刘宝旭 / 机械工业出版社华章公司 / 2011-6 / 65.00元
《云计算安全与隐私》可以使你明白当把数据交付给云计算时你所面临的风险,以及为了保障虚拟基础设施和网络应用程序的安全可以采取的行动。本书是由信息安全界知名专家所著,作者在书中给出许多中肯的忠告和建议。本书的读者对象包括:IT职员、信息安全和隐私方面的从业人士、业务经理、服务提供商,以及投资机构等。阅读本书你会了解直到现在还严重匮乏的云计算安全方面的详尽信息。 《云计算安全与隐私》主要内容包括:......一起来看看 《云计算安全与隐私》 这本书的介绍吧!