JPA-JPQL

/**
 * JPQL,Java Persistence Query Language 的簡稱。是一種和 SQL 相似的中間性和對象化查詢語言,它最終會被編譯成針對不一樣底層數據庫的 SQL 查詢,從而屏蔽不一樣數據庫的差別。
 * JPQL 語言的語句能夠是 select 語句、update 語句或delete語句,它們都經過 Query 接口封裝執行
 * Query接口封裝了執行數據庫查詢的相關方法。調用 EntityManager 的 createQuery、create NamedQuery 及 createNativeQuery 方法能夠得到查詢對象,進而調用 Query 接口的相關方法來執行查詢操做
 *
 * int executeUpdate()
 * 用於執行update或delete語句
 *
 * List getResultList()
 * 用於執行select語句並返回結果集實體列表
 *
 * Object getSingleResult()
 * 用於執行只返回單個結果實體的select語句
 *
 * Query setFirstResult(int startPosition)
 * 用於設置從哪一個實體記錄開始返回查詢結果
 *
 * Query setMaxResults(int maxResult)
 * 用於設置返回結果實體的最大數。與setFirstResult結合使用可實現分頁查詢
 *
 * Query setFlushMode(FlushModeType flushMode)
 * 設置查詢對象的Flush模式。參數能夠取2個枚舉值:FlushModeType.AUTO 爲自動更新數據庫記錄,FlushMode Type.COMMIT 爲直到提交事務時才更新數據庫記錄
 *
 * setHint(String hintName, Object value)
 * 設置與查詢對象相關的特定供應商參數或提示信息。參數名及其取值須要參考特定 JPA 實現庫提供商的文檔。若是第二個參數無效將拋出IllegalArgumentException異常
 *
 * setParameter(int position, Object value)
 * 爲查詢語句的指定位置參數賦值。Position 指定參數序號,value 爲賦給參數的值
 *
 * setParameter(int position, Date d, TemporalType type)
 * 爲查詢語句的指定位置參數賦 Date 值。Position 指定參數序號,value 爲賦給參數的值,temporalType 取 TemporalType 的枚舉常量,包括 DATE、TIME 及 TIMESTAMP 三個,用於將 Java 的 Date 型值臨時轉換爲數據庫支持的日期時間類型(java.sql.Date、java.sql.Time及java.sql.Timestamp)
 *
 * setParameter(int position, Calendar c, TemporalType type)
 * 爲查詢語句的指定位置參數賦 Calenda r值。position 指定參數序號,value 爲賦給參數的值,temporalType 的含義及取捨同前
 *
 * setParameter(String name, Object value)
 * 爲查詢語句的指定名稱參數賦值
 *
 * setParameter(String name, Date d, TemporalType type)
 * 爲查詢語句的指定名稱參數賦 Date 值。用法同前
 *
 * setParameter(String name, Calendar c, TemporalType type)
 * 爲查詢語句的指定名稱參數設置Calendar值。name爲參數名,其它同前。該方法調用時若是參數位置或參數名不正確,或者所賦的參數值類型不匹配,將拋出 IllegalArgumentException 異常
 */

 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com</groupId>
    <artifactId>jpa</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.14</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>5.4.1.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-jpamodelgen</artifactId>
            <version>5.4.1.Final</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-ehcache</artifactId>
            <version>5.4.1.Final</version>
        </dependency>
        <dependency>
            <groupId>org.ehcache</groupId>
            <artifactId>ehcache</artifactId>
            <version>3.6.3</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-nop</artifactId>
            <version>1.7.25</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!-- 指定jdk -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

persistence.xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd"
             version="2.2">
    <persistence-unit name="jpaname" transaction-type="RESOURCE_LOCAL">

        <!-- 配置使用什麼 ORM 產品來做爲 JPA 的實現 -->
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>

        <!-- 實體類 -->
        <class>com.jpa.yingshe.Customer</class>

        <!--
        配置二級緩存的策略
        ALL:全部的實體類都被緩存
        NONE:全部的實體類都不被緩存.
        ENABLE_SELECTIVE:標識 @Cacheable(true) 註解的實體類將被緩存
        DISABLE_SELECTIVE:緩存除標識 @Cacheable(false) 之外的全部實體類
        UNSPECIFIED:默認值,JPA 產品默認值將被使用
        -->
        <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>

        <properties>
            <!-- 數據庫信息 -->
            <property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://xxx.xxx.xxx.xxx/jpa?useSSL=false"/>
            <property name="javax.persistence.jdbc.user" value="xxx"/>
            <property name="javax.persistence.jdbc.password" value="xxx"/>

            <!-- 配置 hibernate 屬性 -->
            <property name="hibernate.format_sql" value="true"/>
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.hbm2ddl.auto" value="update"/>

            <!-- 二級緩存相關 -->
            <property name="hibernate.cache.use_second_level_cache" value="true"/>
            <property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.internal.EhcacheRegionFactory"/>
            <property name="hibernate.cache.use_query_cache" value="true"/>
        </properties>
    </persistence-unit>
</persistence>

ehcache.xml

<ehcache>
    <diskStore path="./target/tmp"/>

    <defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="true"
        />

    <cache name="sampleCache1"
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="300"
        timeToLiveSeconds="600"
        overflowToDisk="true"
        />

    <cache name="sampleCache2"
        maxElementsInMemory="1000"
        eternal="true"
        timeToIdleSeconds="0"
        timeToLiveSeconds="0"
        overflowToDisk="false"
        /> -->
</ehcache>

實體類

Customer

package com.jpa.yingshe;

import javax.persistence.*;

@Cacheable
@Table(name = "JPA_CUTOMERS")
@Entity
public class Customer {

    private Integer id;
    private String lastName;

    private String email;

    public Customer() {
    }

    public Customer(String lastName) {
        this.lastName = lastName;
    }

    @GeneratedValue(strategy = GenerationType.AUTO)
    @Id
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    @Column(name = "LAST_NAME", length = 50, nullable = false)
    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "Customer{" +
                "id=" + id +
                ", lastName='" + lastName + '\'' +
                ", email='" + email + '\'' +
                '}';
    }
}

測試

添加幾條數據html

package jpa.test;

import com.jpa.yingshe.Customer;
import org.hibernate.jpa.QueryHints;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import javax.persistence.*;
import java.util.List;

public class JPAJPQLTest {
    private EntityManagerFactory entityManagerFactory;
    private EntityManager entityManager;
    private EntityTransaction transaction;

    @Before
    public void init() {
        entityManagerFactory = Persistence.createEntityManagerFactory("jpaname");
        entityManager = entityManagerFactory.createEntityManager();
        transaction = entityManager.getTransaction();
        transaction.begin();
    }

    @After
    public void destroy() {
        transaction.commit();
        entityManager.close();
        entityManagerFactory.close();
    }

    @Test
    public void testPersist() {
        Customer c1 = new Customer();
        c1.setEmail("vfdgsdfs");
        c1.setLastName("131waw");

        entityManager.persist(c1);
    }
}

單個查詢

@Test
public void testHelloJPQL() {
    String jpql = "FROM Customer c WHERE c.id >= ?0";
    Query query = entityManager.createQuery(jpql);

    query.setParameter(0, 1);
    List<Customer> customers = query.getResultList();
    System.out.println(customers.size());
}

部分屬性查詢

// 若只查詢部分屬性, 則將返回 Object[] 類型的結果. 或者 Object[] 類型的 List
// 也能夠在實體類中建立對應的構造器, 而後再 JPQL 語句中利用對應的構造器返回實體類的對象
@Test
public void testPartlyProperties() {
    String jpql = "SELECT new Customer(c.lastName) FROM Customer c WHERE c.id > ?0";
    List result = entityManager.createQuery(jpql).setParameter(0, 40).getResultList();

    System.out.println(result.size());
    System.out.println(result.get(0));
}

 

標記查詢 @NamedQuery

@NamedQuery(name="testNamedQuery", query="FROM Customer c WHERE c.id = ?0")
@Cacheable
@Table(name = "JPA_CUTOMERS")
@Entity
public class Customer {

    private Integer id;
// createNamedQuery 適用於在實體類前使用 @NamedQuery 標記的查詢語句
@Test
public void testNamedQuery() {
    Query query = entityManager.createNamedQuery("testNamedQuery").setParameter(0, 1);
    Customer customer = (Customer) query.getSingleResult();

    System.out.println(customer);
}

本地 SQL 查詢

// createNativeQuery 適用於本地 SQL
@Test
public void testNativeQuery() {
    String sql = "SELECT email FROM JPA_CUTOMERS WHERE id = ?1";
    Query query = entityManager.createNativeQuery(sql).setParameter(1, 1);

    Object result = query.getSingleResult();
    System.out.println(result);
}

緩存查詢

// 不使用 hibernate 的查詢緩存
@Test
public void testQueryCache() {
    String jpql = "FROM Customer c WHERE c.id > ?1";
    Query query = entityManager.createQuery(jpql);

    query.setParameter(1, 1);
    List<Customer> customers = query.getResultList();
    System.out.println(customers.size());

    query = entityManager.createQuery(jpql);

    query.setParameter(1, 1);
    customers = query.getResultList();
    System.out.println(customers.size());
}

開啓緩存後查詢,十、JPA-二級緩存java

// 使用 hibernate 的查詢緩存,setHint(QueryHints.HINT_CACHEABLE, true)
@Test
public void testQueryCache() {
    String jpql = "FROM Customer c WHERE c.id > ?1";
    Query query = entityManager.createQuery(jpql).setHint(QueryHints.HINT_CACHEABLE, true);

    query.setParameter(1, 1);
    List<Customer> customers = query.getResultList();
    System.out.println(customers.size());

    query = entityManager.createQuery(jpql).setHint(QueryHints.HINT_CACHEABLE, true);

    query.setParameter(1, 1);
    customers = query.getResultList();
    System.out.println(customers.size());
}

OrderBy

@Test
public void testOrderBy() {
    String jpql = "FROM Customer c WHERE c.id > ?1 ORDER BY c.lastName DESC";
    Query query = entityManager.createQuery(jpql).setHint(QueryHints.HINT_CACHEABLE, true);
    
    query.setParameter(1, 1);
    List<Customer> customers = query.getResultList();
    System.out.println(customers.size());
}

GroupBy

//查詢 order 數量大於 2 的那些 Customer
@Test
public void testGroupBy() {
    String jpql = "SELECT c.email FROM Customer c GROUP BY c.email HAVING count(c.id) >= 2";
    List<Customer> customers = entityManager.createQuery(jpql).getResultList();

    System.out.println(customers);
}

關聯查詢

修改實體類 Customermysql

private Set<Order> orders;

//使用 @OneToMany 來映射 1-n 的關聯關係//注意: 若在 1 的一端的 @OneToMany 中使用 mappedBy 屬性, 則 @OneToMany 端就不能再使用 @JoinColumn 屬性了
@OneToMany(mappedBy = "customer")
public Set<Order> getOrders() {
    return orders;
}

public void setOrders(Set<Order> orders) {
    this.orders = orders;
}

添加實體類 Ordersql

package com.jpa.yingshe;

import javax.persistence.*;

@Table(name = "JPA_ORDERS")
@Entity
public class Order {

    private Integer id;
    private String orderName;

    private Customer customer;

    @GeneratedValue
    @Id
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    @Column(name = "ORDER_NAME")
    public String getOrderName() {
        return orderName;
    }

    public void setOrderName(String orderName) {
        this.orderName = orderName;
    }

    // 映射單向 n-1 的關聯關係
    // 使用 @ManyToOne 來映射多對一的關聯關係
    // 使用 @JoinColumn 來映射外鍵
    @JoinColumn(name = "CUSTOMER_ID")
    @ManyToOne()
    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }
}

JPQL插入中文數據亂碼,修改下鏈接SQL的語句,xml中一些特殊字符需轉義數據庫

persistence.xmlapache

<!-- &amp; & 和 -->
<!-- &lt; < 小於號 -->
<!-- &gt; > 大於號 -->
<!-- &apos; ' 單引號 -->
<!-- &quot; " 雙引號 -->
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://xxx.xxx.xxx.xxx/jpa?useSSL=false&amp;characterEncoding=utf-8"/>

添加一些數據緩存

@Test
public void testPersist() {
    Customer c1 = new Customer();
    c1.setEmail("cbcv");
    c1.setLastName("ert");

    Order order = new Order();
    order.setCustomer(c1);
    order.setOrderName("cbcv");

    Order order1 = new Order();
    order1.setCustomer(c1);
    order1.setOrderName("34543");

    Order order2 = new Order();
    order2.setCustomer(c1);
    order2.setOrderName("mbndr");

    entityManager.persist(c1);

    entityManager.persist(order);
    entityManager.persist(order1);
    entityManager.persist(order2);
}

先看不使用關聯時的查詢服務器

@Test
public void testLeftOuterJoinFetch(){
    String jpql = "FROM Customer c WHERE c.id = ?1";

    Customer customer = (Customer) entityManager.createQuery(jpql).setParameter(1, 14).getSingleResult();
    System.out.println(customer.getLastName());
    System.out.println(customer.getOrders().size());
}

使用關聯查詢app

// JPQL 的關聯查詢同 HQL 的關聯查詢
@Test
public void testLeftOuterJoinFetch(){
    String jpql = "FROM Customer c LEFT OUTER JOIN FETCH c.orders WHERE c.id = ?1";

    Customer customer = (Customer) entityManager.createQuery(jpql).setParameter(1, 14).getSingleResult();
    System.out.println(customer.getLastName());
    System.out.println(customer.getOrders().size());
}

不使用 FETCH 的關聯查詢會返回一個 Object 集合maven

@Test
public void testLeftOuterJoinFetch(){
    String jpql = "FROM Customer c LEFT OUTER JOIN c.orders WHERE c.id = ?1";

    List<Object[]> result = entityManager.createQuery(jpql).setParameter(1, 14).getResultList();
    System.out.println(result);
}

 子查詢

// JPQL 子查詢
@Test
public void testSubQuery(){
    //查詢全部 Customer 的 lastName 爲 ert 的 Order
    String jpql = "SELECT o FROM Order o WHERE o.customer = (SELECT c FROM Customer c WHERE c.lastName = ?1)";

    Query query = entityManager.createQuery(jpql).setParameter(1, "ert");
    List<Order> orders = query.getResultList();
    System.out.println(orders.size());
}

內建函數

//JPQL 內建函數
@Test
public void testJpqlFunction(){
    String jpql = "SELECT upper(c.email) FROM Customer c";

    List<String> emails = entityManager.createQuery(jpql).getResultList();
    System.out.println(emails);
}

/**
 * JPQL 提供了一些內建函數,包括字符串處理函數、算術函數和日期函數。
 *
 * 經常使用字符串處理函數:
 * concat(String s1, String s2):字符串合併/鏈接函數。
 * substring(String s, int start, int length):取字串函數。
 * trim([leading|trailing|both,] [char c,] String s):從字符串中去掉首/尾指定的字符或空格。
 * lower(String s):將字符串轉換成小寫形式。
 * upper(String s):將字符串轉換成大寫形式。
 * length(String s):求字符串的長度。
 * locate(String s1, String s2[, int start]):從第一個字符串中查找第二個字符串(子串)出現的位置。若未找到則返回0。
 *
 * 經常使用算術函數有:
 * abs、mod、sqrt、size 等。Size 用於求集合的元素個數。
 *
 * 日期函數主要有三個:
 * current_date、current_time、current_timestamp,它們不須要參數,返回服務器上的當前日期、時間和時戳。
 */

UPDATE 和 DELETE

@Test
public void testExecuteUpdate(){
    String jpql = "UPDATE Customer c SET c.lastName = ?1 WHERE c.id = ?2";
    Query query = entityManager.createQuery(jpql).setParameter(1, "YYY").setParameter(2, 18);

    query.executeUpdate();
}

// 有主外鍵要先刪除外鍵
@Test
public void testExecuteDelete(){
    String jpql = "DELETE Order o WHERE o.id = ?2";
    Query query = entityManager.createQuery(jpql).setParameter(2, 21);

    query.executeUpdate();
}

 


官方文檔

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息