spring boot jpa 簡單應用示例

1.JPA簡介

JPA(Java Persistence API)是Sun官方提出的Java持久化規範,它爲Java開發人員提供了一種對象/關聯映射工具來管理Java應用中的關係數據。html

Hibernate是JPA目前最流行的實現,JPA的制定很大程度上吸取了的思想,spring-boot-starter-data-jpa默認使用的Hibernate。java

JPA的優點:spring

  1. 標準化sql

    JPA 是 JCP 組織發佈的 Java EE 標準之一,所以任何聲稱符合 JPA 標準的框架都遵循一樣的架構,提供相同的訪問API,這保證了基於JPA開發的企業應用可以通過少許的修改就可以在不一樣的JPA框架下運行。數據庫

  2. 容器級特性的支持編程

    JPA框架中支持大數據集、事務、併發等容器級事務,這使得 JPA 超越了簡單持久化框架的侷限,在企業應用發揮更大的做用。設計模式

  3. 簡單方便服務器

    JPA的主要目標之一就是提供更加簡單的編程模型:在JPA框架下建立實體和建立Java 類同樣簡單,沒有任何的約束和限制,只須要使用 javax.persistence.Entity進行註釋,JPA的框架和接口也都很是簡單,沒有太多特別的規則和設計模式的要求,開發者能夠很容易的掌握。JPA基於非侵入式原則設計,所以能夠很容易的和其它框架或者容器集成。session

  4. 查詢能力架構

    JPA的查詢語言是面向對象而非面向數據庫的,它以面向對象的天然語法構造查詢語句,能夠當作是Hibernate HQL的等價物。JPA定義了獨特的JPQL(Java Persistence Query Language),JPQL是EJB QL的一種擴展,它是針對實體的一種查詢語言,操做對象是實體,而不是關係數據庫的表,並且可以支持批量更新和修改、JOIN、GROUP BY、HAVING 等一般只有 SQL 纔可以提供的高級查詢特性,甚至還可以支持子查詢。

  5. 高級特性

    JPA 中可以支持面向對象的高級特性,如類之間的繼承、多態和類之間的複雜關係,這樣的支持可以讓開發者最大限度的使用面向對象的模型設計企業應用,而不須要自行處理這些特性在關係數據庫的持久化。

2.JPA經常使用註解

註解 解釋
@Entity 聲明類爲實體或表。
@Table 聲明表名。
@Basic 指定非約束明確的各個字段。
@Embedded 指定類或它的值是一個可嵌入的類的實例的實體的屬性。
@Id 指定的類的屬性,用於識別(一個表中的主鍵)。
@GeneratedValue 指定如何標識屬性能夠被初始化,例如自動、手動、或從序列表中得到的值。
@Transient 指定的屬性,它是不持久的,即:該值永遠不會存儲在數據庫中。
@Column 指定持久屬性欄屬性。
@SequenceGenerator 指定在@GeneratedValue註解中指定的屬性的值。它建立了一個序列。
@TableGenerator 指定在@GeneratedValue批註指定屬性的值發生器。它創造了的值生成的表。
@AccessType 這種類型的註釋用於設置訪問類型。若是設置@AccessType(FIELD),則能夠直接訪問變量而且不須要getter和setter,但必須爲public。若是設置@AccessType(PROPERTY),經過getter和setter方法訪問Entity的變量。
@JoinColumn 指定一個實體組織或實體的集合。這是用在多對一和一對多關聯。
@UniqueConstraint 指定的字段和用於主要或輔助表的惟一約束。
@ColumnResult 參考使用select子句的SQL查詢中的列名。
@ManyToMany 定義了鏈接表之間的多對多一對多的關係。
@ManyToOne 定義了鏈接表之間的多對一的關係。
@OneToMany 定義了鏈接表之間存在一個一對多的關係。
@OneToOne 定義了鏈接表之間有一個一對一的關係。
@NamedQueries 指定命名查詢的列表。
@NamedQuery 指定使用靜態名稱的查詢。

3.代碼示例

3.1. 工程結構

工程結構

3.2. pom依賴

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.2.RELEASE</version>
    <relativePath/> <!-- JDK>=1.8 -->
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

3.3. yml配置

# DataSource Config
spring:
  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:mem:test
    username: root
    password: test
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: update

jpa.hibernate.show-sql是jpa通用配置,能夠打印SQL,對於調試很是重要

jpa.hibernate.ddl-auto是hibernate的配置屬性,其主要做用是:自動建立、更新、驗證數據庫表結構。該參數的幾種配置以下:

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

3.4. 實體類(模型層)

package com.example.jpa.entity;

import lombok.Data;
import lombok.ToString;

import javax.persistence.*;

//必須註解,聲明這個類是一個實體
@Entity
//可選註解,能夠初始化建表信息,甚至徹底定製建表SQL,默認的name(表名)便是類名
@Table(name = "USER")
@Data
@ToString
public class User {
    //聲明這個屬性對應表中惟一標識(主鍵)字段
    @Id
    //可選,主鍵自增,默認GenerationType.AUTO
    @GeneratedValue
    private Long id;
    //聲明這個屬性對應表中某個字段,其中全部配置屬性都是可選的,但length默認爲255,建議手動指定以配置一個合適的長度
    @Column(name = "name", nullable = true, length = 20)
    private String name;
    @Column(name = "age", length = 3)
    private Integer age;
    @Column(name = "email", length = 50)
    private String email;
}

3.5. 倉儲類(持久層)

package com.example.jpa.repository;

import com.example.jpa.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.List;

//必選註解,聲明這是一個倉儲
@Repository
//實現org.springframework.data.repository即便用了JPA
//org.springframework.data.jpa.repository.JpaRepository實現了一些經常使用數據庫操做
//因此通常都選擇繼承JpaRepository以簡化代碼
public interface UserRepository extends JpaRepository<User,Long> {

    //按照JPA規則自定義接口
    public List<User> getByName(String name);

    //自定義PQL
    //nativeQuery=true則使用原生sql,更靈活,但失去了自動適應數據庫產品的能力,通常不推薦
    @Query(countQuery = "SELECT COUNT(U.AGE) FROM USER U WHERE U.AGE = :age")
    public int countUsersByAge(@Param("age") int age);
}

JPQL規則常見關鍵字一覽表

官方文檔

Keyword Sample JPQL snippet
And findByLastnameAndFirstname … where x.lastname = ?1 and
Or findByLastnameOrFirstname … where x.lastname = ?1 or x.firstname = ?2
Is,Equals 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 findByAge(Is)NotNull … 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 ages) … where x.age in ?1
NotIn findByAgeNotIn(Collection 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)

3.6 測試類

package com.example.jpa;

import com.example.jpa.entity.User;
import com.example.jpa.repository.UserRepository;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class JpaApplicationTests {

    @Autowired
    UserRepository userRepository;

    @Before
    public void before(){
        User user = new User();
        user.setName("蟲師");
        user.setAge(123);
        user.setEmail("xiaoyu@demo.com");
        userRepository.save(user);
        user = new User();
        user.setName("泰密");
        user.setAge(16);
        user.setEmail("taimi@demo.com");
        userRepository.save(user);
    }

    @Test
    public void contextLoads() {
        User user = new User();
        user.setName("指揮官");
        user.setAge(16);
        user.setEmail("xiaohong@demo.com");
        //spring提供的插入功能
        User save = userRepository.save(user);
        System.out.println("----插入-----\n"
                .concat(save.toString())
                .concat("\n----查詢全部----"));
        //spring提供的查詢功能
        List<User> all = userRepository.findAll();
        all.forEach(System.out::println);
        //自定義的查詢功能
        List<User> list = userRepository.getByName("蟲師");
        System.out.println("-----自定義接口------\n"
                .concat(list.toString()));
        //自定義計數功能
        int i = userRepository.countUsersByAge(16);
        System.out.println("-----自定義PQL------\n"
                .concat(String.valueOf(i)));
    }

}

3.7 控制檯輸出

Hibernate: call next value for hibernate_sequence
Hibernate: insert into user (age, email, name, id) values (?, ?, ?, ?)
Hibernate: call next value for hibernate_sequence
Hibernate: insert into user (age, email, name, id) values (?, ?, ?, ?)
Hibernate: call next value for hibernate_sequence
Hibernate: insert into user (age, email, name, id) values (?, ?, ?, ?)
----插入-----
User(id=3, name=指揮官, age=16, email=xiaohong@demo.com)
----查詢全部----
2019-01-31 15:55:19.482  INFO 3144 --- [           main] o.h.h.i.QueryTranslatorFactoryInitiator  : HHH000397: Using ASTQueryTranslatorFactory
Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.email as email3_0_, user0_.name as name4_0_ from user user0_
User(id=1, name=蟲師, age=123, email=xiaoyu@demo.com)
User(id=2, name=泰密, age=16, email=taimi@demo.com)
User(id=3, name=指揮官, age=16, email=xiaohong@demo.com)
Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.email as email3_0_, user0_.name as name4_0_ from user user0_ where user0_.name=?
-----自定義接口------
[User(id=1, name=蟲師, age=123, email=xiaoyu@demo.com)]
Hibernate: select count(user0_.id) as col_0_0_ from user user0_ where user0_.age=?
-----自定義PQL------
2
相關文章
相關標籤/搜索