JPA是Java Persistence API的简称,是sun公司早期推出的Java持久层规范,目前实现JPA规范的主流框架有Hibernate、OpenJPA等。Hibernate框架是当前较为流行的JPA实现之一,在Spring Data JPA中,默认底层实现也是使用的Hibernate。
目录:
- Spring Data JPA示例搭建
- 自定义数据存储逻辑
- 方法名命名查询
Spring Data JPA示例搭建
Spring Boot 提供了一个"spring-boot-starter-data-jpa"模块,在项目中使用这个模块,就可以简单的整合Spring Data JPA、Hibernate及其他依赖所需模块。
新建一个名为spring-jpa的Maven工程,修改其pom.xml文件。
<!-- Spring Boot父工程 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
</parent>
<dependencies>
<!-- Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Data JPA -->
<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>
</dependencies>
在src/main/resource目录下新建一个名为application.yml的配置文件:
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://192.168.170.129:3306/spring-jpa
username: root
password: root
在application.yml配置文件中简单配置了数据库连接必要的参数。从中可以看出,我们项目使用的数据库名:spring-jpa。
接下来我们就可以编写项目的数据访问层和业务层了。
实体类Book:
package com.hrvy.entity;
@Entity
public class Book {
/** 主键ID */
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
/** 图书名称 */
@Column
private String bookName;
/** 图书封面 */
@Column
private String bookCover;
/** 图书作者 */
@Column
private String bookAuthor;
/** 图书价格 */
@Column
private BigDecimal bookPrice;
/** 图书状态:0=false(未删除状态)1=true(已删除状态) */
@Column
private Boolean isDelete;
/** getter/setter 方法。。。 */
}
数据访问接口BookRepository:
package com.hrvy.dao;
public interface BookRepository extends JpaRepository<Book, Integer> {
}
该接口继承JpaRepository接口,且无任何接口方法和实现类。JpaRepository接口中定义有很多数据访问方法,Spring会默认使用JDK代理来生成BookRepository接口的代理类,从而就拥有了JpaRepository的功能实现,进行数据CRUD操作。
服务层BookService:
package com.hrvy.service;
public interface BookService {
/**
* 获取所有图书信息
*
* @return
*/
List<Book> getBooks();
/**
* 保存图书
*
* @param book 图书实体
*/
void saveBook(Book book);
}
package com.hrvy.service.impl;
@Service
public class BookServiceImpl implements BookService {
@Autowired
private BookRepository bookRepository;
@Override
public List<Book> getBooks() {
return bookRepository.findAll();
}
@Override
public void saveBook(Book book) {
bookRepository.save(book);
}
}
控制层BookController:
package com.hrvy.controller;
@RestController
public class BookController {
@Autowired
private BookService bookService;
/**
* 获取全部图书
*
* @return
*/
@RequestMapping("/getbooks")
public List<Book> getBooks() {
return bookService.getBooks();
}
/**
* 添加图书
*
* @return
*/
@RequestMapping("/addbook")
public String AddBook() {
Book book = new Book();
book.setBookName("Spring Data JPA");
book.setBookAuthor("Hrvy");
bookService.saveBook(book);
return "添加成功";
}
}
运行App.java,浏览器输入http://localhost:8080/addbook进行图书添加测试,输入http://localhost:8080/getbooks进行图书查询测试。
自定义数据存储逻辑
Spring帮我们生成的代理类,虽然可以完成很多工作,但在实际应用中,有时仍需要实现我们自己的数据存储逻辑。
新建一个BookRepositoryCustom接口,在BookRepositoryCustom接口中加入需要自定义的接口方法。
BookRepositoryCustom代码如下:
package com.hrvy.dao;
public interface BookRepositoryCustom {
List<Book> findBooksCustom();
}
修改原来的BookRepository接口,让其同时继承BookRepositoryCustom和JpaRepository。
BookRepository代码如下:
package com.hrvy.dao;
public interface BookRepository extends BookRepositoryCustom, JpaRepository<Book, Integer> {
}
新建一个名为BookRepositoryCustomImpl的实现类,实现BookRepositoryCustom接口,使用EntityManger接口进行数据操作(该接口具体使用可查看JPA相关文档)。在此特别注意:该实现类的名字必须为BookRepositoryImpl或BookRepositoryCustomImpl,否则Spring会报错。原因:Spring默认会在包下查找名为“BookRepository接口名+Impl”或“BookRepositoryCustom接口名+Impl”的实现类,若查找不到,则会将接口方法findBooksCustom()按命名查询规则来代理生成实现,此时就会抛出以下异常:
org.springframework.data.mapping.PropertyReferenceException: No property findBooksCustom found for type Book!
BookRepositoryCustomImpl代码如下:
package com.hrvy.dao;
public class BookRepositoryCustomImpl implements BookRepositoryCustom {
@PersistenceContext
private EntityManager em;
@Override
public List<Book> findBooksCustom() {
StringBuilder sql = new StringBuilder();
sql.append("select ");
sql.append("* ");// 拼接表字段,这里使用"*"来代替所有字段
sql.append("from book ");
Query query = em.createNativeQuery(sql.toString(), Book.class);
return (List<Book>) query.getResultList();
}
}
运行App.java,浏览器输入http://localhost:8080/getbookscustom进行图书查询测试。
方法名命名查询
如果想根据Book的某个字段进行查询,实现类似“from book where book_name = ?”这样的查询,则可以直接在BookRepository接口中定义一个bookName方法(方法名=属性名),代码如下:
package com.hrvy.dao;
public interface BookRepository extends BookRepositoryCustom, JpaRepository<Book, Integer> {
/** 方法名命名查询:根据bookName获取Book */
List<Book> bookName(String bookName);
}
Spring会自动生成相应的查询方法,不需要我们自己编写任何逻辑实现。不仅如此,还可以使用接口的方法名,通过特定的关键字来实现不同的查询功能。例如要查询bookname和bookAuthor等于某值的Book时,则可以使用以下的方法名:
List<Book> findByBookNameAndBookAuthor(String bookName, String bookAuthor);
Spring通过定制方法名来实现相关查询,目前支持20多个关键字,如下表所示:
命名查询关键字
关键字 | 例子 | 对于的SQL |
And | findByNameAndAge | where name=? and age=? |
Is,Equals | findByName, findByNameIs, findByNameEquals | where name=? |
Between | findByAgeBetween | where age between ? and ? |
LessThan | findByAgeLessThan | where age<? |
... | | |