JPA是Java Persistence API的簡稱,是sun公司早期推出的Java持久層規范,目前實現JPA規范的主流框架有Hibernate、OpenJPA等。Hibernate框架是當前較為流行的JPA實現之一,在Spring Data JPA中,默認底層實現也是使用的Hibernate。
目錄:
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<? |
... |