/** * 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 異常 */
<?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>
<?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> <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>
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(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); }
// 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()); }
@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()); }
//查詢 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
<!-- & & 和 --> <!-- < < 小於號 --> <!-- > > 大於號 --> <!-- ' ' 單引號 --> <!-- " " 雙引號 --> <property name="javax.persistence.jdbc.url" value="jdbc:mysql://xxx.xxx.xxx.xxx/jpa?useSSL=false&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,它們不須要參數,返回服務器上的當前日期、時間和時戳。 */
@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(); }