Spring Boot JPA 連接數據庫

何爲JPA

JPA全稱Java Persistence API,是Sun官方提出的一種ORM規範!

對於Sun官網而言, 一是想簡化現有Java EE和Java SE應用開發工作。 二是想整合ORM技術,實現天下歸一。

對於JPA規範,都在包路徑:javax.persistence.*下,像一些常用的如:@Entity、@Id及@Transient都在此路徑下。這些也是一些現在市面上常用的ORM一些約定俗成的註解了。

簡單來說,JPA是一套規範。所以使用Jpa的一個好處是,可以更換實現而不必改動太多代碼。

JPA與hibernate的關係 

JPA規範本質上就是一種ORM規範,注意不是ORM框架——因爲JPA並未提供ORM實現,它只是制訂了一些規範,提供了一些編程的API接口,但具體實現則由服務廠商來提供實現。  

JPA和Hibernate的關係就像JDBC和JDBC驅動的關係,JPA是規範,Hibernate除了作爲ORM框架之外,它也是一種JPA實現。JPA怎麼取代Hibernate呢?JDBC規範可以驅動底層數據庫嗎?答案是否定的,也就是說,如果使用JPA規範進行數據庫操作,底層需要hibernate作爲其實現類完成數據持久化工作。  

何爲Sping-data-jpa

Spring Data JPA是 Spring Data 的一個子項目, 它通過提供基於 JPA的 Repository 極大地減少了 JPA作爲數據訪問方案的代碼量。Spring Data JPA是Spring基於Hibernate開發的一個JPA框架。可以極大的簡化JPA的寫法,可以在幾乎不用寫具體代碼的情況下,實現對數據的訪問和操作。除了CRUD外,還包括如分頁、排序等一些常用的功能。

下面將通過一個完整的例子來說明JPA的使用方式

Spring Data JPA提供的接口,也是Spring Data JPA的核心概念:

  1. Repository:最頂層的接口,是一個空的接口,目的是爲了統一所有Repository的類型,且能讓組件掃描的時候自動識別。
  2. CrudRepository :是Repository的子接口,提供CRUD的功能
  3. PagingAndSortingRepository:是CrudRepository的子接口,添加分頁和排序的功能
  4. JpaRepository:是PagingAndSortingRepository的子接口,增加了一些實用的功能,比如:批量操3作等。
  5. JpaSpecificationExecutor:用來做負責查詢的接口
  6. Specification:是Spring Data JPA提供的一個查詢規範,要做複雜的查詢,只需圍繞這個規範來設置查詢條件即可。

SpringBoot集成Spring-data-jpa

添加相關依賴
添加spring-boot-starter-data-jpa依賴:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>6.0.6</version>
</dependency>

修改屬性配置文件

在屬性配置文件中添加 JPA 相關屬性,注意這些並非必須,我們如果只添加dataSource 的 url\username\password\driver-class-name 也可以正常使用,有關JPA的其他配置都是可選的。

可以在application.yml文件中配置配置數據源:

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1/test?characterEncoding=utf-8&useUnicode=true&serverTimezone=UTC&useSSL=false&autoReconnect=true
    username: root
    password: 9958

  jpa:
    database-platform: org.hibernate.dialect.MySQL5Dialect
    hibernate:
#      ddl-auto: create #每次啓動都會重新創建
      ddl-auto: update #如果表中有數據就不會重新創建
    show-sql: true

也可以在application.properties文件配置mysql的驅動類,數據庫地址,數據庫賬號、密碼信息

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

spring.datasource.url=jdbc:mysql://127.0.0.1/test?characterEncoding=utf8&serverTimezone=UTC

spring.datasource.username=root

spring.datasource.password=9958

spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect

spring.jpa.hibernate.ddl-auto=update

spring.jpa.show-sql=true

注意,如果通過jpa在數據庫中建表,需要將jpa.hibernate.ddl-auto改爲create,建完表之後要改爲update,否則每次重啓工程都會刪除表並新建。spring.jap.hibernate.ddl-auto有四個值:

  1. create: 每次加載 hibernate 時都會刪除上一次的生成的表,然後根據你的 model 類再重新來生成新表,哪怕兩次沒有任何改變也要這樣執行,這就是導致數據庫表數據丟失的一個重要原因。
  2. create-drop :每次加載 hibernate 時根據 model 類生成表,但是 sessionFactory 一關閉,表就自動刪除。
  3. update:最常用的屬性,第一次加載 hibernate 時根據 model 類會自動建立起表的結構(前提是先建立好數據庫),以後加載 hibernate 時根據 model 類自動更新表結構,即使表結構改變了但表中的行仍然存在不會刪除以前的行。要注意的是當部署到服務器後,表結構是不會被馬上建立起來的,是要等 應用第一次運行起來後纔會。
  4. validate :每次加載 hibernate 時,驗證創建數據庫表結構,只會和數據庫中的表進行比較,不會創建新表,但是會插入新值。

創建實體類

傳統上,JPA實體類在persistence.xml文件中指定的。使用Spring Boot,這個文件是沒有必要的,因爲它使用“實體掃描”,默認情況下主配置 @EnableAutoConfiguration 或 @SpringBootApplication 下面的所有包都將會被掃描。任何使用註解 @Entity, @Embeddable 或 @MappedSuperclass 的類都將被管理。

/**
 * 通過@Entity 表明是一個映射的實體類, @Id表明id, @GeneratedValue 字段自動生成
 */
@Entity
public class Girl {
    @Id
    @GeneratedValue
    private int id;
    private String name;
    private int age;

...  省略getter setter
}

Entity 中不映射成列的字段得加 @Transient 註解,不加註解也會映射成列

定義數據訪問層

使用 Spring Data JPA建立數據訪問層十分簡單, 只需定義一個繼承 JpaRepository 的接口即可,定義如下:

public interface GirlRepository extends JpaRepository<Girl, Integer> {

}

繼承 JpaRepository 接口意味着我們默認已經有了下面的數據訪問操作方法:

@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
    List<T> findAll();
    List<T> findAll(Sort var1);
    List<T> findAllById(Iterable<ID> var1);
    <S extends T> List<S> saveAll(Iterable<S> var1);
    void flush();
    <S extends T> S saveAndFlush(S var1);
    void deleteInBatch(Iterable<T> var1);
    void deleteAllInBatch();
    T getOne(ID var1);
    <S extends T> List<S> findAll(Example<S> var1);
    <S extends T> List<S> findAll(Example<S> var1, Sort var2);
}

定義查詢方法

( 1 ) 根據屬性名査詢

Spring Data JPA支持通過定義在 Repository 接口中的方法名來定義査詢,而方法名是根據實體類的屬性名來確定的 。

1)常規查詢。根據屬性名來定義査詢方法,示例如下:

/*通過年齡相等查詢,參數爲age
* 相當於JPQL:select g from Girl g whrer g.age=?1
*/
List<Girl> findByAge(Integer age);
/*通過名字like查詢,參數爲name
*相當於JPQL:select g from Girl g whrer g.name like ?1
*/
List<Girl> findByNameLike(String name);

從代碼可以看出,這裏使用了 findBy、 Like、 And這樣的關鍵字。其中 findBy可以用 find、read、 readBy、 query、 queryBy、 get、 getBy來代替。

而 Like和 and這類査詢關鍵字, 如表

 

2)限制結果數量。結果數量是用 top和 first關鍵字來實現的,例如:

List<Girl> findFirst10Byname(String name);

List<Girl> findTop20Byname(String name);

(2)使用 JPA的NamedQuery查詢

spring Data JpA支持用 JPA的 NameQuery 來定義査詢方法,即一個名稱映射一個查詢語句,在實體類中:

@Entity
@NamedQuery(name = "Girl.findByName", query = "select g from Girl g  where g.name=?1")
public class Girl {
..}

調用這條查詢語句的方法:

public interface GirlRepository extends JpaRepository<Girl, Integer> {
    /*使用NamedQuery裏定義的查詢語句,而不是根據方法名稱查詢*/
    List<Girl> findByName(String name);

(3)使用@Query 査詢

1)使用參數索引 。 Spring Data JPA還支持用@Query註解在接口的方法上實現査詢,例如:

@Query("select g from Girl g where g.id=?1")

Optional<Girl> findById(Integer name);

2)使用命名參數。上面的例子是使用參數的索引號來査詢的,在 Spring Data JPA裏還支持在語句裏用名稱來匹配査詢參數

@Query("select g from Girl g where g.id=:name and g.age=:age")

Optional<Girl> findByName(@Param("name") String name,@Param("age") int age);

3 ) 更新査詢。 Sprmg Data JPA支持@Modifying和@Query 註解組合來事件更新查詢, 例如

@Modifying
@Transactional
@Query("update Girl g set g.name=?1")
int setName(String name);

其中返回值int表示更新語句影響的行數。

(4)排序與分頁

Spring Data JPA充分考慮了在實際開發中所必須的排序和分頁的場景,爲我們提供了Sort類以及Page接口和Pageable接口

1)定義:

//使用排序

List<Girl> findByName(String name, Sort sort);

//使用分頁

List<Girl> findByName(String name, Pageable pageable);

2)使用

//使用排序
List<Girl> findByName(String name, Sort sort);
//使用分頁
List<Girl> findByName(String name, Pageable pageable);
2)使用
List<Girl> list1=girlRepository.findByName(name,Sort.by(Sort.Direction.ASC,"age"));
List<Girl> list2=girlRepository.findByName(name, PageRequest.of(0,10));

具體的測試和代碼,我就不完全粘貼了,想看的可以直接看我的代碼

 

源碼

參考:

http://blog.csdn.net/catoop/article/details/50508397

http://blog.csdn.net/forezp/article/details/70545038

http://www.ityouknow.com/springboot/2016/08/20/spring-boot-jpa.html

https://gitchat.csdn.net/columnTopic/5ab9c2e0c864031e9f8302dc

https://my.oschina.net/xiedeshou/blog/2350428

https://blog.csdn.net/u010412719/article/details/70147824

https://blog.csdn.net/u013030980/article/details/78135335

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章