JPA 學習筆記
jpa是什麼
Java Persistence API:用於對象持久化的 API
Java EE 5.0 平臺標準的 ORM 規範,使得應用程序以統一的方式訪問持久層
JPA和Hibernate的關係
JPA 是 hibernate 的一個抽象(就像JDBC和JDBC驅動的關係):
JPA 是規範:JPA 本質上就是一種 ORM 規範,不是ORM 框架 ——
因爲 JPA 並未提供 ORM 實現,它只是制訂了一些規範,提供了一些編程的 API 接口,但具體實現則由 ORM 廠商提供實現
Hibernate 是實現:Hibernate 除了作爲 ORM 框架之外,它也是一種 JPA 實現
從功能上來說, JPA 是 Hibernate 功能的一個子集
jpa的hello world程序
首先弄個jpa的helloworld程序
persistence.xml 文件。這個要放到resources目錄下面的META-INF目錄下面.
JPA規範要求在類路徑的META-INF目錄下面放persistence.xml,文件名稱是固定的。
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="jpa-1" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<!-- 添加持久化類 -->
<class>com.mamh.jpa.Customer</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql:///mage"/>
<property name="javax.persistence.jdbc.user" value="mage"/>
<property name="javax.persistence.jdbc.password" value="123456"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="create"/>
<property name="hibernate.show_sql" value="true"/>
</properties>
</persistence-unit>
</persistence>
pom.xml 文件,採用maven來管理jar包的依賴,這裏加的jar包比較多.
幾個比較關鍵的jar包, hibernate-entitymanager ,hibernate-jpa-2.1-api ,hibernate-commons-annotations
<?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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>mage</groupId>
<artifactId>jpa</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>jpa Maven Webapp</name>
<url>http://maven.apache.org</url>
<properties>
<spring.version>5.0.4.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--spring jar包-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/taglibs/standard -->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<!--spring相關包, 在web中需要使用spring-web和spring-webmvc這2個jar包的-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-orm -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.8.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.6</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-commons-annotations</artifactId>
<version>3.2.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.3.11.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<version>1.0.0.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.3.11.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>4.3.11.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-validator -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.3.2.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>5.2.15.Final</version>
</dependency>
<!--日誌jar-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>1.9.13</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-lgpl</artifactId>
<version>1.9.13</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-lgpl</artifactId>
<version>1.9.13</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.2.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>jcifs</groupId>
<artifactId>jcifs</artifactId>
<version>1.3.17</version>
</dependency>
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.0</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
<version>8.0.23</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/jaxen/jaxen -->
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.6</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.13</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.9.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-dbutils/commons-dbutils -->
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.struts/struts2-core -->
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>2.5.16</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.struts/struts2-spring-plugin -->
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-spring-plugin</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.5</version>
</dependency>
</dependencies>
<build>
<finalName>jpa</finalName>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
</plugin>
</plugins>
</build>
</project>
持久化類:
package com.mamh.jpa;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Table(name = "jpa_customer")
@Entity
public class Customer {
private Integer id;
private String lastName;
private String email;
private int age;
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.AUTO)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name = "last_name")
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;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
測試類
package com.mamh.jpa;
import org.junit.Test;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
public class CustomerTest {
@Test
public void test() {
String name = "jpa-1";
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory(name);
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
Customer customer = new Customer();
customer.setAge(12);
customer.setLastName("jerry......");
customer.setEmail("email.....");
entityManager.persist(customer);
transaction.commit();
entityManager.close();
entityManagerFactory.close();
}
}
jpa中常用的註解
@Entity 放到實體類上面
@Entity 標註用於實體類聲明語句之前,指出該Java 類爲實體類,將映射到指定的數據庫表。
如聲明一個實體類 Customer,它將映射到數據庫中的 customer 表上。
@Table(name = “jpa_customer”)設置表名
當實體類與其映射的數據庫表名不同名時需要使用 @Table 標註說明,該標註與 @Entity 標註並列使用,
置於實體類聲明語句之前,可寫於單獨語句行,也可與聲明語句同行。
@Table 標註的常用選項是 name,用於指明數據庫的表名
@Table標註還有一個兩個選項 catalog 和 schema 用於設置表所屬的數據庫目錄或模式,通常爲數據庫名。
uniqueConstraints 選項用於設置約束條件,通常不須設置。
@Id映射主鍵的,放到getter方法上
@Id 標註用於聲明一個實體類的屬性映射爲數據庫的主鍵列。該屬性通常置於屬性聲明語句之前,可與聲明語句同行,也可寫在單獨行上。
@Id標註也可置於屬性的getter方法之前。
@GeneratedValue(strategy = GenerationType.AUTO)設置生成主鍵的策略
@GeneratedValue 用於標註主鍵的生成策略,通過 strategy 屬性指定。默認情況下,
JPA 自動選擇一個最適合底層數據庫的主鍵生成策略:
SqlServer 對應 identity,
MySQL 對應 auto increment。
在 javax.persistence.GenerationType 中定義了以下幾種可供選擇的策略:
IDENTITY:採用數據庫 ID自增長的方式來自增主鍵字段,Oracle 不支持這種方式;
AUTO: JPA自動選擇合適的策略,是默認選項;
SEQUENCE:通過序列產生主鍵,通過 @SequenceGenerator 註解指定序列名,MySql 不支持這種方式
TABLE:通過表產生主鍵,框架藉由表模擬序列產生主鍵,使用該策略可以使應用更易於數據庫移植。
@Basic 默認的註解
@Basic 表示一個簡單的屬性到數據庫表的字段的映射,對於沒有任何標註的 getXxxx() 方法,默認即爲@Basic
fetch: 表示該屬性的讀取策略,有 EAGER 和 LAZY 兩種,分別表示主支抓取和延遲加載,默認爲 EAGER.
optional:表示該屬性是否允許爲null, 默認爲true
@Column(name = “last_name”) 設置列,name映射到數據庫表中的列名
當實體的屬性與其映射的數據庫表的列不同名時需要使用@Column 標註說明,
該屬性通常置於實體的屬性聲明語句之前,還可與 @Id 標註一起使用。
@Column 標註的常用屬性是 name,用於設置映射數據庫表的列名。此外,
該標註還包含其它多個屬性,如:unique 、nullable、length 等。
@Column 標註的 columnDefinition 屬性: 表示該字段在數據庫中的實際類型.
通常 ORM 框架可以根據屬性類型自動判斷數據庫中字段的類型,但是對於Date類型
仍無法確定數據庫中字段類型究竟是DATE,TIME還是TIMESTAMP.此外,String的
默認映射類型爲VARCHAR, 如果要將 String 類型映射到特定數據庫的 BLOB 或TEXT 字段類型.
@Column標註也可置於屬性的getter方法之前
@Transient 不需要影響爲數據庫表的列的方法上加上這個註解
表示該屬性並非一個到數據庫表的字段的映射,ORM框架將忽略該屬性.
如果一個屬性並非數據庫表的字段映射,就務必將其標示爲@Transient,否則,ORM框架默認其註解爲@Basic
@Temporal(TemporalType.TIMESTAMP) 設置時間日期對應到數據庫表列的類型的
在覈心的 Java API 中並沒有定義 Date 類型的精度(temporal precision).
而在數據庫中,表示 Date 類型的數據有 DATE, TIME, 和 TIMESTAMP 三種精度(即單純的日期,時間,或者兩者 兼備).
在進行屬性映射時可使用@Temporal註解來調整精度.
jpa中常用的類
Persistence類
Persistence 類是用於獲取 EntityManagerFactory 實例。該類包含一個名爲 createEntityManagerFactory 的 靜態方法 。
createEntityManagerFactory 方法有如下兩個重載版本。
帶有一個參數的方法以 JPA 配置文件 persistence.xml 中的持久化單元名爲參數
帶有兩個參數的方法:前一個參數含義相同,後一個參數 Map類型,用於設置 JPA 的相關屬性,
這時將忽略其它地方設置的屬性。Map 對象的屬性名必須是 JPA 實現庫提供商的名字空間約定的屬性名。
EntityManagerFactory
EntityManagerFactory 接口主要用來創建 EntityManager 實例。該接口約定了如下4個方法:
createEntityManager():用於創建實體管理器對象實例。
createEntityManager(Map map):用於創建實體管理器對象實例的重載方法,Map 參數用於提供 EntityManager 的屬性。
isOpen():檢查 EntityManagerFactory 是否處於打開狀態。實體管理器工廠創建後一直處於打開狀態,除非調用close()方法將其關閉。
close():關閉 EntityManagerFactory 。 EntityManagerFactory 關閉後將釋放所有資源,
isOpen()方法測試將返回 false,其它方法將不能調用,否則將導致IllegalStateException異常。
EntityManager
在 JPA 規範中, EntityManager 是完成持久化操作的核心對象。實體作爲普通 Java 對象,
只有在調用 EntityManager 將其持久化後纔會變成持久化對象。EntityManager 對象在一
組實體類與底層數據源之間進行 O/R 映射的管理。它可以用來管理和更新 Entity Bean,
根椐主鍵查找 Entity Bean, 還可以通過JPQL語句查詢實體。
實體的狀態:
新建狀態: 新創建的對象,尚未擁有持久性主鍵。
持久化狀態:已經擁有持久性主鍵並和持久化建立了上下文環境
遊離狀態:擁有持久化主鍵,但是沒有與持久化建立上下文環境
刪除狀態: 擁有持久化主鍵,已經和持久化建立上下文環境,但是從數據庫中刪除。
EntityManager.find()方法
find (Class<T> entityClass,Object primaryKey):返回指定的 OID 對應的實體類對象,
如果這個實體存在於當前的持久化環境,則返回一個被緩存的對象;否則會創建一個新的 Entity,
並加載數據庫中相關信息;若 OID 不存在於數據庫中,則返回一個 null。第一個參數爲被查詢的
實體類類型,第二個參數爲待查找實體的主鍵值。
@Test
public void testFind(){
Customer customer = entityManager.find(Customer.class, 1);
System.out.println(customer);
}
EntityManager.getReference()方法,只有在使用對象的時候纔去數據庫中查詢。會出現懶加載異常。
getReference (Class<T> entityClass,Object primaryKey):與find()方法類似,不同的是:如果緩存中不存在指定的 Entity, EntityManager 會創建一個 Entity 類的代理,但是不會立即加載數據庫中的信息,只有第一次真正使用此 Entity 的屬性才加載,所以如果此 OID 在數據庫不存在,getReference() 不會返回 null 值, 而是拋出EntityNotFoundException
@Test
public void testRef() {
Customer customer = entityManager.getReference(Customer.class, 1);
System.out.println("----------------------");
System.out.println(customer);
}
EntityManager.persist()方法,使對象由臨時狀態變爲持久化狀態。
persist (Object entity):用於將新創建的 Entity 納入到 EntityManager 的管理。該方法執行後,傳入 persist() 方法的 Entity 對象轉換成持久化狀態。
如果傳入 persist() 方法的 Entity 對象已經處於持久化狀態,則 persist() 方法什麼都不做。
如果對刪除狀態的 Entity 進行 persist() 操作,會轉換爲持久化狀態。
如果對遊離狀態的實體執行 persist() 操作,可能會在 persist() 方法拋出 EntityExistException(也有可能是在flush或事務提交後拋出)。
@Test
public void testPersist() {
Customer customer = new Customer();
customer.setAge(12);
customer.setLastName("jerry1......");
customer.setEmail("email.....");
customer.setBirth(new Date());
customer.setCreateTime(new Date());
entityManager.persist(customer);
}
如果這時設置了customer的ID,則會報錯的。
EntityManager.remove()方法,刪除數據庫記錄,只能刪除持久化對象,遊離對象不行。
remove (Object entity):刪除實例。如果實例是被管理的,即與數據庫實體記錄關聯,則同時會刪除關聯的數據庫記錄。
@Test
public void testRemove() {
Customer customer = new Customer();
customer.setId(123);
entityManager.remove(customer);
}
這樣才能刪除
@Test
public void testRemove() {
//Customer customer = new Customer();
//customer.setId(123);
Customer customer = entityManager.find(Customer.class, 1);
entityManager.remove(customer);
}
EntityManager.merge()方法 merge (T entity):merge() 用於處理 Entity 的同步。即數據庫的插入和更新操作
會創建一個新的對象,把臨時對象的屬性複製到新的對象中,然後對新的對象執行持久化操作,新的對象中會有id,之前的對象沒有id了。
@Test
public void testMerge() {
Customer customer = new Customer();
customer.setAge(12);
customer.setLastName("Tom......");
customer.setEmail("email.....");
customer.setBirth(new Date());
customer.setCreateTime(new Date());
Customer merge = entityManager.merge(customer);
System.out.println(customer);
System.out.println(merge);
}
若傳入的是一個遊離對象,也就是說傳入的對象有ID值。
@Test
public void testMerge1() {
Customer customer = new Customer();
customer.setAge(12);
customer.setLastName("Tom......");
customer.setEmail("email.....");
customer.setBirth(new Date());
customer.setCreateTime(new Date());
customer.setId(100);
Customer merge = entityManager.merge(customer);
System.out.println(customer);
System.out.println(merge);
}
flush ():同步持久上下文環境,即將持久上下文環境的所有未保存實體的狀態信息保存到數據庫中。
setFlushMode (FlushModeType flushMode):設置持久上下文環境的Flush模式。參數可以取2個枚舉
FlushModeType.AUTO 爲自動更新數據庫實體,
FlushModeType.COMMIT 爲直到提交事務時才更新數據庫記錄。
getFlushMode ():獲取持久上下文環境的Flush模式。返回FlushModeType類的枚舉值。
refresh (Object entity):用數據庫實體記錄的值更新實體對象的狀態,即更新實例的屬性值。
clear ():清除持久上下文環境,斷開所有關聯的實體。如果這時還有未提交的更新則會被撤消。
contains (Object entity):判斷一個實例是否屬於當前持久上下文環境管理的實體。
isOpen ():判斷當前的實體管理器是否是打開狀態。
getTransaction ():返回資源層的事務對象。EntityTransaction實例可以用於開始和提交多個事務。
close ():關閉實體管理器。之後若調用實體管理器實例的方法或其派生的查詢對象的方法都將拋出 IllegalstateException 異常,除了getTransaction 和 isOpen方法(返回 false)。不過,當與實體管理器關聯的事務處於活動狀態時,調用 close 方法後持久上下文將仍處於被管理狀態,直到事務完成。
EntityTransaction
EntityTransaction 接口用來管理資源層實體管理器的事務操作。通過調用實體管理器的getTransaction方法 獲得其實例。
begin ()
用於啓動一個事務,此後的多個數據庫操作將作爲整體被提交或撤消。若這時事務已啓動則會拋出 IllegalStateException 異常。
commit ()
用於提交當前事務。即將事務啓動以後的所有數據庫更新操作持久化至數據庫中。
rollback ()
撤消(回滾)當前事務。即撤消事務啓動後的所有數據庫更新操作,從而不對數據庫產生影響。
setRollbackOnly ()
使當前事務只能被撤消。
getRollbackOnly ()
查看當前事務是否設置了只能撤消標誌。
isActive ()
查看當前事務是否是活動的。如果返回true則不能調用begin方法,否則將拋出 IllegalStateException 異常;如果返回 false 則不能調用 commit、rollback、setRollbackOnly 及 getRollbackOnly 方法,否則將拋出 IllegalStateException 異常。
多對一關聯關係
多對一在插入數據的情況:
@Test
public void testManyToOne() {
//多對一映射關聯關係
//一個customer可以有多個order。
Customer customer = new Customer();
customer.setAge(112);
customer.setLastName("b");
customer.setEmail("b");
customer.setBirth(new Date());
customer.setCreateTime(new Date());
Order order = new Order();
order.setOderName("o-ff-1");
Order order1 = new Order();
order1.setOderName("o-ff-2");
order.setCustomer(customer);
order1.setCustomer(customer);
entityManager.persist(customer);
entityManager.persist(order);
entityManager.persist(order1);
}
Hibernate:
insert
into
jpa_customer
(age, birth, createTime, email, last_name)
values
(?, ?, ?, ?, ?)
Hibernate:
insert
into
jpa_order
(customer_id, order_name)
values
(?, ?)
Hibernate:
insert
into
jpa_order
(customer_id, order_name)
values
(?, ?)
Process finished with exit code 0
保存的時候建議先保存一的那一端對象,也就是先保存customer。
然後再保存多的那一端,也就是order。這樣不會多出sql語句。
@Test
public void testManyToOne() {
//多對一映射關聯關係
//一個customer可以有多個order。
Customer customer = new Customer();
customer.setAge(112);
customer.setLastName("b");
customer.setEmail("b");
customer.setBirth(new Date());
customer.setCreateTime(new Date());
Order order = new Order();
order.setOderName("o-ff-1");
Order order1 = new Order();
order1.setOderName("o-ff-2");
order.setCustomer(customer);
order1.setCustomer(customer);
entityManager.persist(order);
entityManager.persist(order1);
entityManager.persist(customer);
}
Hibernate:
insert
into
jpa_order
(customer_id, order_name)
values
(?, ?)
Hibernate:
insert
into
jpa_order
(customer_id, order_name)
values
(?, ?)
Hibernate:
insert
into
jpa_customer
(age, birth, createTime, email, last_name)
values
(?, ?, ?, ?, ?)
Hibernate:
update
jpa_order
set
customer_id=?,
order_name=?
where
id=?
Hibernate:
update
jpa_order
set
customer_id=?,
order_name=?
where
id=?
Process finished with exit code 0
多對一在獲取的時候:
@Test
public void testManyToOne() {
Order order = entityManager.find(Order.class, 1);
System.out.println(order);
}
Hibernate:
select
order0_.id as id1_1_0_,
order0_.customer_id as customer3_1_0_,
order0_.order_name as order_na2_1_0_,
customer1_.id as id1_0_1_,
customer1_.age as age2_0_1_,
customer1_.birth as birth3_0_1_,
customer1_.createTime as createTi4_0_1_,
customer1_.email as email5_0_1_,
customer1_.last_name as last_nam6_0_1_
from
jpa_order order0_
left outer join
jpa_customer customer1_
on order0_.customer_id=customer1_.id
where
order0_.id=?
Order{id=1, oderName='o-ff-1', customer=Customer{id=5, lastName='b', email='b', age=112, createTime=2018-05-31 13:34:20.0, birth=2018-05-31}}
Process finished with exit code 0
這裏會使用一個左外鏈接。
在Order類裏面可以設置customer @ManyToOne (fetch = FetchType.LAZY) 爲懶加載。
多對一在刪除數據的情況
@Test
public void testManyToOne2() {
Customer customer = entityManager.find(Customer.class, 6);
entityManager.remove(customer);
}
這種情況下是不讓刪除的,因爲有個外鍵。
一對多關聯關係
一對多關聯關係插入數據的情況
@Test
public void testOneToMany() {
Customer customer = new Customer();
customer.setAge(112);
customer.setLastName("zz");
customer.setEmail("zzzzz");
customer.setBirth(new Date());
customer.setCreateTime(new Date());
Order order = new Order();
order.setOderName("o-ff-1");
Order order1 = new Order();
order1.setOderName("o-ff-2");
customer.getOrders().add(order);
customer.getOrders().add(order1);
entityManager.persist(customer);
entityManager.persist(order);
entityManager.persist(order1);
}
單向一對多,執行保存時,會多出update語句。因爲多的一端在插入的時候不會同時插入外鍵列。
一對多關聯關係查詢數據的情況
@Test
public void testOneToMany1() {
Customer customer = entityManager.find(Customer.class, 7);
System.out.println(customer);
}
默認是懶加載的情況。
通用可以使用 @OneToMany(fetch = FetchType.EAGER) 來修改。然後那個查詢會變爲左外鏈接。
雙向一對多關聯關係
/**
* 雙向一對多關聯關係
*/
@Test
public void testOneToMany2() {
Customer customer = new Customer();
customer.setAge(112);
customer.setLastName("zz");
customer.setEmail("zzzzz");
customer.setBirth(new Date());
customer.setCreateTime(new Date());
Order order = new Order();
order.setOderName("o-ff-1");
Order order1 = new Order();
order1.setOderName("o-ff-2");
customer.getOrders().add(order);
customer.getOrders().add(order1);
order1.setCustomer(customer);
order.setCustomer(customer);
entityManager.persist(customer);
entityManager.persist(order);
entityManager.persist(order1);
}
先插入customer,然後在插入order,只有2個update語句,如果反過來插入,會有4條update語句的。
Hibernate:
insert
into
jpa_customer
(age, birth, createTime, email, last_name)
values
(?, ?, ?, ?, ?)
Hibernate:
insert
into
jpa_order
(customer_id, order_name)
values
(?, ?)
Hibernate:
insert
into
jpa_order
(customer_id, order_name)
values
(?, ?)
Hibernate:
update
jpa_order
set
customer_id=?
where
id=?
Hibernate:
update
jpa_order
set
customer_id=?
where
id=?
Process finished with exit code 0
在進行雙向一對多的關聯關係時。建議使用多的一方來維護管理關係。
可以在customer上設置 @OneToMany(fetch = FetchType.EAGER,cascade = {CascadeType.REMOVE},mappedBy = “customer”)
這樣customer就不會維護關聯關係了。
此時這個不能同時使用 @JoinColumn(name = “customer_id”) 了。
雙向一對一的關聯關係
package com.mamh.jpa;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@Entity
@Table(name = "jpa_department")
public class Department {
private int id;
private String deptName;
private Manager manager;
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Column(name = "name")
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
/**
* 使用 @OneToOne 來映射1-1關聯關係。
* @return
*/
@JoinColumn(name = "manager_id", unique = true)
@OneToOne
public Manager getManager() {
return manager;
}
public void setManager(Manager manager) {
this.manager = manager;
}
}
package com.mamh.jpa;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@Entity
@Table(name = "jpa_manager")
public class Manager {
private int id;
private String mgrName;
private Department deptartment;
@Id
@GeneratedValue
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Column(name = "name")
public String getMgrName() {
return mgrName;
}
public void setMgrName(String mgrName) {
this.mgrName = mgrName;
}
@OneToOne(mappedBy = "manager")
public Department getDeptartment() {
return deptartment;
}
public void setDeptartment(Department deptartment) {
this.deptartment = deptartment;
}
}
@Test
public void testDepartment(){
Manager manager = new Manager();
manager.setMgrName("bright.ma");
Department department = new Department();
department.setDeptName("scm");
department.setManager(manager);
manager.setDeptartment(department);
//先保存不維護關聯關係的那一方
entityManager.persist(manager);
entityManager.persist(department);
}
在添加數據的時候, 先保存不維護關聯關係的那一方,這裏就是先保存manager。
Hibernate:
insert
into
jpa_manager
(name)
values
(?)
Hibernate:
insert
into
jpa_department
(name, manager_id)
values
(?, ?)
Process finished with exit code 0
獲取的情況
@Test
public void testOnetoOneFind() {
Department department = entityManager.find(Department.class, 1);
System.out.println(department);
}
Hibernate:
select
department0_.id as id1_1_0_,
department0_.name as name2_1_0_,
department0_.manager_id as manager_3_1_0_,
manager1_.id as id1_2_1_,
manager1_.name as name2_2_1_
from
jpa_department department0_
left outer join
jpa_manager manager1_
on department0_.manager_id=manager1_.id
where
department0_.id=?
Hibernate:
select
department0_.id as id1_1_1_,
department0_.name as name2_1_1_,
department0_.manager_id as manager_3_1_1_,
manager1_.id as id1_2_0_,
manager1_.name as name2_2_0_
from
jpa_department department0_
left outer join
jpa_manager manager1_
on department0_.manager_id=manager1_.id
where
department0_.manager_id=?
com.mamh.jpa.Department@649f2009
@Test
public void testOnetoOneFind1() {
Manager manager = entityManager.find(Manager.class, 1);
System.out.println(manager);
}
Hibernate:
select
manager0_.id as id1_2_0_,
manager0_.name as name2_2_0_,
department1_.id as id1_1_1_,
department1_.name as name2_1_1_,
department1_.manager_id as manager_3_1_1_
from
jpa_manager manager0_
left outer join
jpa_department department1_
on manager0_.id=department1_.manager_id
where
manager0_.id=?
com.mamh.jpa.Manager@14bb2297
雙向一對一的關聯關係
基於主鍵來做這個一對一關聯關係,可以使用“@PrimaryKeyJoinColumn(name = “id”)”
雙向多對多關聯關係
package com.mamh.jpa;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import java.util.HashSet;
import java.util.Set;
@Entity
@Table(name = "jpa_item")
public class Item {
private Integer id;
private String itemName;
private Set<Category> categories = new HashSet<Category>();
@GeneratedValue
@Id
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name = "item_name")
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
@ManyToMany
@JoinTable( name = "jpa_item_category",
joinColumns = {
@JoinColumn(name = "item_id", referencedColumnName = "id")
},
inverseJoinColumns = { //對方那個表
@JoinColumn(name = "categroy_id", referencedColumnName = "id")
}
)
public Set<Category> getCategories() {
return categories;
}
public void setCategories(Set<Category> categories) {
this.categories = categories;
}
}
package com.mamh.jpa;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import java.util.HashSet;
import java.util.Set;
@Entity
@Table(name = "jpa_category")
public class Category {
private Integer id;
private String categoryName;
private Set<Item> items = new HashSet<Item>();
@GeneratedValue
@Id
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name = "category_name")
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
@ManyToMany(mappedBy = "categories")
public Set<Item> getItems() {
return items;
}
public void setItems(Set<Item> items) {
this.items = items;
}
}
使用@ManyToMany註解來映射多對多關聯關係。使用@JoinTable來映射中間表
@ManyToMany
@JoinTable( name = "jpa_item_category", //name指定中間表的表名
joinColumns = { // joinColumns映射當前類所在表在中間表中的外鍵。
@JoinColumn(name = "item_id", referencedColumnName = "id")
},
inverseJoinColumns = { //對方那個表
@JoinColumn(name = "categroy_id", referencedColumnName = "id")
}
)
@ManyToMany(mappedBy = "categories")
public Set<Item> getItems() {
return items;
}
多對多的保存
@Test
public void testManyToMany() {
Item i1 = new Item();
i1.setItemName("i - 1");
Item i2 = new Item();
i2.setItemName("i - 2");
Category c1 = new Category();
c1.setCategoryName("c - 1");
Category c2 = new Category();
c2.setCategoryName("c - 2");
i1.getCategories().add(c1);
i1.getCategories().add(c2);
i2.getCategories().add(c1);
i2.getCategories().add(c2);
c1.getItems().add(i1);
c1.getItems().add(i2);
c2.getItems().add(i1);
c2.getItems().add(i2);
entityManager.persist(i1);
entityManager.persist(i2);
entityManager.persist(c1);
entityManager.persist(c2);
}
輸出結果
Hibernate:
insert
into
jpa_item
(item_name)
values
(?)
Hibernate:
insert
into
jpa_item
(item_name)
values
(?)
Hibernate:
insert
into
jpa_category
(category_name)
values
(?)
Hibernate:
insert
into
jpa_category
(category_name)
values
(?)
Hibernate:
insert
into
jpa_item_category
(item_id, categroy_id)
values
(?, ?)
Hibernate:
insert
into
jpa_item_category
(item_id, categroy_id)
values
(?, ?)
Hibernate:
insert
into
jpa_item_category
(item_id, categroy_id)
values
(?, ?)
Hibernate:
insert
into
jpa_item_category
(item_id, categroy_id)
values
(?, ?)
Process finished with exit code 0
多對多的查詢
1.先獲取維護關聯關係的,也就是先獲取Item。
@Test
public void testManyToManyFind() {
Item item = entityManager.find(Item.class, 2);
System.out.println(item.getItemName());
System.out.println(item.getCategories().size());
}
Hibernate:
select
item0_.id as id1_3_0_,
item0_.item_name as item_nam2_3_0_
from
jpa_item item0_
where
item0_.id=?
i - 2
Hibernate:
select
categories0_.item_id as item_id1_3_0_,
categories0_.categroy_id as categroy2_4_0_,
category1_.id as id1_0_1_,
category1_.category_name as category2_0_1_
from
jpa_item_category categories0_
inner join
jpa_category category1_
on categories0_.categroy_id=category1_.id
where
categories0_.item_id=?
2
Process finished with exit code 0
- 獲取 不維護關聯關係的,也就是先獲取Category。
@Test
public void testManyToManyFind() {
Category category = entityManager.find(Category.class, 1);
System.out.println(category.getCategoryName());
System.out.println(category.getItems().size());
}
Hibernate:
select
category0_.id as id1_0_0_,
category0_.category_name as category2_0_0_
from
jpa_category category0_
where
category0_.id=?
c - 1
Hibernate:
select
items0_.categroy_id as categroy2_0_0_,
items0_.item_id as item_id1_4_0_,
item1_.id as id1_3_1_,
item1_.item_name as item_nam2_3_1_
from
jpa_item_category items0_
inner join
jpa_item item1_
on items0_.item_id=item1_.id
where
items0_.categroy_id=?
2
Process finished with exit code 0
通過以上兩種方式獲取的,效果是一樣的,因爲是有一張中間表,獲取那邊都是一樣的。
jpql
@Test
public void testJpql() {
String jpsql = "select new Customer(c.lastName,c.age) FROM Customer c where c.age > ?";
Query query = entityManager.createQuery(jpsql);
query.setParameter(1, 1);
List resultList = query.getResultList();
System.out.println(resultList);
}
命名查詢
需要在實體類上面加上註解@NamedQuery(name = “testNamedQuery”, query = “select c from Customer c where c.id = ?”)
@Test
public void testNamedQuery() {
Query query = entityManager.createNamedQuery("testNamedQuery");
query.setParameter(1, 3);
List resultList = query.getResultList();
System.out.println(resultList);
}
@Test
public void testNativeQuery() {
String sql = "SELECT age FROM jpa_customer WHERE id = ?";
Query query = entityManager.createNativeQuery(sql);
query.setParameter(1, 3);
List resultList = query.getResultList();
System.out.println(resultList);
}
一級緩存
jpa默認是有一級緩存的。
@Test
public void testCache() {
Customer customer = entityManager.find(Customer.class, 3); //這裏一級緩存爲什麼沒有生效呢????
System.out.println(customer.getLastName());
System.out.println("");
Customer customer1 = entityManager.find(Customer.class, 3);
System.out.println(customer1.getLastName());
}
上面的代碼查詢2次,只會發送一條sql語句的。特別注意 查詢出來的數據要存在,如果不存在也是發送2條sql語句了。
二級緩存
@Test
public void testCache1() {
Customer customer = entityManager.find(Customer.class, 3); //這裏一級緩存爲什麼沒有生效呢????
System.out.println(customer.getLastName());
transaction.commit();
entityManager.close();
System.out.println("");
entityManager = entityManagerFactory.createEntityManager();
transaction = entityManager.getTransaction();
transaction.begin();
Customer customer1 = entityManager.find(Customer.class, 3);
System.out.println(customer1.getLastName());
}
配置文件
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="jpa-1" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<!-- 添加持久化類 -->
<class>com.mamh.jpa.Customer</class>
<class>com.mamh.jpa.Order</class>
<class>com.mamh.jpa.Department</class>
<class>com.mamh.jpa.Manager</class>
<class>com.mamh.jpa.Item</class>
<class>com.mamh.jpa.Category</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:///atguigu"/>
<property name="javax.persistence.jdbc.user" value="atguigu"/>
<property name="javax.persistence.jdbc.password" value="123456"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.show_sql" value="true"/>
<!--二級緩存相關的 -->
<property name="hibernate.cache.use_second_level_cache" value="true"/>
<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory"/>
<property name="hibernate.cache.use_query_cache" value="true"/>
</properties>
</persistence-unit>
</persistence>
最後實體類上面要加上@Cacheable(true)註解
這樣最後的輸出就只會發送一個sql語句了
Hibernate:
select
customer0_.id as id1_1_0_,
customer0_.age as age2_1_0_,
customer0_.birth as birth3_1_0_,
customer0_.createTime as createTi4_1_0_,
customer0_.email as email5_1_0_,
customer0_.last_name as last_nam6_1_0_
from
jpa_customer customer0_
where
customer0_.id=?
Tom
Tom
查詢緩存
需要在配置文件中配置啓用查詢緩存
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="jpa-1" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<!-- 添加持久化類 -->
<class>com.mamh.jpa.Customer</class>
<class>com.mamh.jpa.Order</class>
<class>com.mamh.jpa.Department</class>
<class>com.mamh.jpa.Manager</class>
<class>com.mamh.jpa.Item</class>
<class>com.mamh.jpa.Category</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql:///atguigu"/>
<property name="javax.persistence.jdbc.user" value="atguigu"/>
<property name="javax.persistence.jdbc.password" value="123456"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.show_sql" value="true"/>
<!--二級緩存相關的 -->
<property name="hibernate.cache.use_second_level_cache" value="true"/>
<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory"/>
<property name="hibernate.cache.use_query_cache" value="true"/>
</properties>
</persistence-unit>
</persistence>
還有就是jar的版本要對。 hibernate-ehcache的版本要對。
<?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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>mage</groupId>
<artifactId>jpa</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>jpa Maven Webapp</name>
<url>http://maven.apache.org</url>
<properties>
<spring.version>5.0.4.RELEASE</spring.version>
<hibernate.version>4.3.11.Final</hibernate.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--spring jar包-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/taglibs/standard -->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<!--spring相關包, 在web中需要使用spring-web和spring-webmvc這2個jar包的-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-orm -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.8.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.6</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-commons-annotations</artifactId>
<version>3.2.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<version>1.0.0.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-validator -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.3.2.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!--日誌jar-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>1.9.13</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-lgpl</artifactId>
<version>1.9.13</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-lgpl</artifactId>
<version>1.9.13</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.2.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>jcifs</groupId>
<artifactId>jcifs</artifactId>
<version>1.3.17</version>
</dependency>
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.0</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
<version>8.0.23</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/jaxen/jaxen -->
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.6</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.13</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.9.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-dbutils/commons-dbutils -->
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.struts/struts2-core -->
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>2.5.16</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.struts/struts2-spring-plugin -->
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-spring-plugin</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.5</version>
</dependency>
</dependencies>
<build>
<finalName>jpa</finalName>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
</plugin>
</plugins>
</build>
</project>
@Test
public void testQueryCache() {
String jpsql = "select new Customer(c.lastName,c.age) FROM Customer c where c.age > ?";
//Query query = entityManager.createQuery(jpsql);
Query query = entityManager.createQuery(jpsql).setHint(QueryHints.HINT_CACHEABLE, true);
query.setParameter(1, 1);
List resultList = query.getResultList();
System.out.println(resultList);
//query = entityManager.createQuery(jpsql); //默認是發送2條sql查詢語句的
query = entityManager.createQuery(jpsql).setHint(QueryHints.HINT_CACHEABLE,true); //默認是發送2條sql查詢語句的
query.setParameter(1, 1);
resultList = query.getResultList();
System.out.println(resultList);
}
本來是發送2個sql語句的,現在使用了查詢緩存只發送1個sql語句。
Hibernate:
select
customer0_.last_name as col_0_0_,
customer0_.age as col_1_0_
from
jpa_customer customer0_
where
customer0_.age>?
[
Customer{id=null, lastName='Tom', email='null', age=12, createTime=null, birth=null},
Customer{id=null, lastName='Jerry', email='null', age=12, createTime=null, birth=null},
Customer{id=null, lastName='b', email='null', age=112, createTime=null, birth=null},
Customer{id=null, lastName='dsf', email='null', age=112, createTime=null, birth=null},
Customer{id=null, lastName='zz', email='null', age=112, createTime=null, birth=null},
Customer{id=null, lastName='zz', email='null', age=112, createTime=null, birth=null},
Customer{id=null, lastName='zz', email='null', age=112, createTime=null, birth=null},
Customer{id=null, lastName='aa', email='null', age=112, createTime=null, birth=null},
Customer{id=null, lastName='Tim', email='null', age=12, createTime=null, birth=null}]
[
Customer{id=null, lastName='Tom', email='null', age=12, createTime=null, birth=null},
Customer{id=null, lastName='Jerry', email='null', age=12, createTime=null, birth=null},
Customer{id=null, lastName='b', email='null', age=112, createTime=null, birth=null},
Customer{id=null, lastName='dsf', email='null', age=112, createTime=null, birth=null},
Customer{id=null, lastName='zz', email='null', age=112, createTime=null, birth=null},
Customer{id=null, lastName='zz', email='null', age=112, createTime=null, birth=null},
Customer{id=null, lastName='zz', email='null', age=112, createTime=null, birth=null},
Customer{id=null, lastName='aa', email='null', age=112, createTime=null, birth=null},
Customer{id=null, lastName='Tim', email='null', age=12, createTime=null, birth=null}]
Process finished with exit code 0
order by 和 group by 子句
@Test
public void testOrderBy() {
String jsql = "from Customer c where c.age > ? order by c.id asc";
Query query = entityManager.createQuery(jsql);
query.setParameter(1, 1);
List resultList = query.getResultList();
System.out.println(resultList);
}
Hibernate:
select
customer0_.id as id1_1_,
customer0_.age as age2_1_,
customer0_.birth as birth3_1_,
customer0_.createTime as createTi4_1_,
customer0_.email as email5_1_,
customer0_.last_name as last_nam6_1_
from
jpa_customer customer0_
where
customer0_.age>?
order by
customer0_.id asc
[
Customer{id=3, lastName='Tom', email='[email protected]', age=12, createTime=2018-05-31 09:32:04.0, birth=2018-05-30},
Customer{id=4, lastName='Jerry', email='[email protected]', age=12, createTime=2018-05-31 09:32:12.0, birth=2018-05-30},
Customer{id=5, lastName='b', email='b', age=112, createTime=2018-05-31 13:34:20.0, birth=2018-05-31},
Customer{id=6, lastName='dsf', email='adfa', age=112, createTime=2018-05-31 13:36:33.0, birth=2018-05-31},
Customer{id=7, lastName='zz', email='zzzzz', age=112, createTime=2018-05-31 16:02:17.0, birth=2018-05-31},
Customer{id=8, lastName='zz', email='zzzzz', age=112, createTime=2018-06-04 11:33:16.0, birth=2018-06-03},
Customer{id=9, lastName='zz', email='zzzzz', age=112, createTime=2018-06-04 11:34:05.0, birth=2018-06-03},
Customer{id=10, lastName='aa', email='aa', age=112, createTime=2018-06-04 11:41:09.0, birth=2018-06-03},
Customer{id=100, lastName='Tim', email='fdadfa', age=12, createTime=2018-05-31 09:33:39.0, birth=2018-05-30}]
@Test
public void testGroupBy() {
String jsql = "select o.customer FROM Order o group by o.customer HAVING count(o.id)>2";
Query query = entityManager.createQuery(jsql);
List resultList = query.getResultList();
System.out.println(resultList);
}
Hibernate:
select
customer1_.id as id1_1_,
customer1_.age as age2_1_,
customer1_.birth as birth3_1_,
customer1_.createTime as createTi4_1_,
customer1_.email as email5_1_,
customer1_.last_name as last_nam6_1_
from
jpa_order order0_
inner join
jpa_customer customer1_
on order0_.customer_id=customer1_.id
group by
order0_.customer_id
having
count(order0_.id)>2
[
Customer{id=10, lastName='aa', email='aa', age=112, createTime=2018-06-04 11:41:09.0, birth=2018-06-03}]
關聯查詢
@Test
public void testLeftOuterJoinFetch() {
//String jsql = "from Customer c left outer join fetch c.orders where c.id=?";
String jsql = "from Customer c where c.id=?";
Query query = entityManager.createQuery(jsql);
query.setParameter(1, 10);
Customer customer = (Customer) query.getSingleResult();
System.out.println(customer.getLastName());
System.out.println(customer.getOrders().size());
}
如上代碼沒有使用left outer join fetch,這樣先獲取customer會發送一條sql語句。然後在獲取oder又會發送一條sql語句的。
Hibernate:
select
customer0_.id as id1_1_,
customer0_.age as age2_1_,
customer0_.birth as birth3_1_,
customer0_.createTime as createTi4_1_,
customer0_.email as email5_1_,
customer0_.last_name as last_nam6_1_
from
jpa_customer customer0_
where
customer0_.id=?
aa
Hibernate:
select
orders0_.customer_id as customer3_1_0_,
orders0_.id as id1_6_0_,
orders0_.id as id1_6_1_,
orders0_.customer_id as customer3_6_1_,
orders0_.order_name as order_na2_6_1_
from
jpa_order orders0_
where
orders0_.customer_id=?
3
以下代碼加上left outer join fetch,效果就不一樣了。
@Test
public void testLeftOuterJoinFetch() {
String jsql = "from Customer c left outer join fetch c.orders where c.id=?";
Query query = entityManager.createQuery(jsql);
query.setParameter(1, 10);
Customer customer = (Customer) query.getSingleResult();
System.out.println(customer.getLastName());
System.out.println(customer.getOrders().size());
}
Hibernate:
select
customer0_.id as id1_1_0_,
orders1_.id as id1_6_1_,
customer0_.age as age2_1_0_,
customer0_.birth as birth3_1_0_,
customer0_.createTime as createTi4_1_0_,
customer0_.email as email5_1_0_,
customer0_.last_name as last_nam6_1_0_,
orders1_.customer_id as customer3_6_1_,
orders1_.order_name as order_na2_6_1_,
orders1_.customer_id as customer3_1_0__,
orders1_.id as id1_6_0__
from
jpa_customer customer0_
left outer join
jpa_order orders1_
on customer0_.id=orders1_.customer_id
where
customer0_.id=?
aa
3
如果不加fetch,返回的結果會是多個
@Test
public void testLeftOuterJoinFetch1() {
String jsql = "from Customer c left outer join c.orders where c.id=?";
//String jsql = "from Customer c where c.id=?";
Query query = entityManager.createQuery(jsql);
query.setParameter(1, 10);
List list = query.getResultList();
System.out.println(list);
}
Hibernate:
select
customer0_.id as id1_1_0_,
orders1_.id as id1_6_1_,
customer0_.age as age2_1_0_,
customer0_.birth as birth3_1_0_,
customer0_.createTime as createTi4_1_0_,
customer0_.email as email5_1_0_,
customer0_.last_name as last_nam6_1_0_,
orders1_.customer_id as customer3_6_1_,
orders1_.order_name as order_na2_6_1_
from
jpa_customer customer0_
left outer join
jpa_order orders1_
on customer0_.id=orders1_.customer_id
where
customer0_.id=?
[[Ljava.lang.Object;@6622a690, [Ljava.lang.Object;@30b9eadd, [Ljava.lang.Object;@497570fb]
子查詢
@Test
public void testSubQuery() {
String jsql = "select o from Order o where o.customer = (select c from Customer c where c.lastName = ?)";
Query query = entityManager.createQuery(jsql);
query.setParameter(1, "aa");
List list = query.getResultList();
System.out.println(list);
}
Hibernate:
select
order0_.id as id1_6_,
order0_.customer_id as customer3_6_,
order0_.order_name as order_na2_6_
from
jpa_order order0_
where
order0_.customer_id=(
select
customer1_.id
from
jpa_customer customer1_
where
customer1_.last_name=?
)
[Order{id=11, oderName='o-ff-1'}, Order{id=12, oderName='o-ff-2'}, Order{id=13, oderName='o-ff-3'}]
Process finished with exit code 0
jpql的udpate操作
@Test
public void testUpdate(){
String jsql = "update Customer c set c.lastName = ? where c.id = ?";
Query query = entityManager.createQuery(jsql);
query.setParameter(1, "aaa");
query.setParameter(2, 10);
query.executeUpdate();
}
jpql的delete操作
spring整合JPA
有這麼三種整合方式
LocalEntityManagerFactoryBean:適用於那些僅使用 JPA 進行數據訪問的項目,
該 FactoryBean 將根據JPA PersistenceProvider 自動檢測配置文件進行工作,
一般從“META-INF/persistence.xml”讀取配置信息,這種方式最簡單,但不能設置
Spring 中定義的DataSource,且不支持 Spring 管理的全局事務
從JNDI中獲取:用於從 Java EE 服務器獲取指定的EntityManagerFactory,
這種方式在進行 Spring 事務管理時一般要使用 JTA 事務管理
LocalContainerEntityManagerFactoryBean:適用於所有環境的 FactoryBean,
能全面控制 EntityManagerFactory 配置,如指定 Spring 定義的 DataSource 等等。
package com.mamh.jpa;
public class JPATest {
private ApplicationContext context = null;
private PersonService personService;
@Before
public void init() {
context = new ClassPathXmlApplicationContext("spring.xml");
personService = context.getBean(PersonService.class);
}
@Test
public void testPersonService(){
Person p1 = new Person();
p1.setAge(12);
p1.setEmail("[email protected]");
p1.setLastName("aa");
Person p2 = new Person();
p2.setAge(13);
p2.setEmail("[email protected]");
p2.setLastName("bb");
System.out.println(personService.getClass().getName());
personService.savePerson(p1);
personService.savePerson(p2);
}
@Test
public void testDataSource() {
DataSource dataSource = context.getBean(DataSource.class);
EntityManagerFactory entityManagerFactory = (EntityManagerFactory) context.getBean("entityManagerFactory");
try {
System.out.println(dataSource.getConnection());
} catch (SQLException e) {
e.printStackTrace();
}
}
}
package com.mamh.jpa.service;
@Service
public class PersonService {
@Autowired
private PersonDao personDao;
@Transactional
public void savePerson(Person p){
personDao.save(p);
}
}
package com.mamh.jpa.dao;
@Repository
public class PersonDao {
/**
* 如何獲取到和當前事務關聯的entitymanger
* 對象呢?
*/
@PersistenceContext
private EntityManager entityManager;
public void save(Person person) {
entityManager.persist(person);
}
}
package com.mamh.jpa.entities;
@Table(name = "jpa_person")
@Entity
public class Person {
private Integer id;
private String lastName;
private String email;
private int age;
@Id
@GeneratedValue
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name = "last_name")
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@Column(name = "email")
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Column(name = "age")
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:property-placeholder location="classpath:db.prop"/>
<context:component-scan base-package="com.mamh.jpa.dao"/>
<context:component-scan base-package="com.mamh.jpa.service"/>
<!-- 配置數據源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="initialPoolSize" value="${jdbc.initPoolSize}"/>
<property name="maxPoolSize" value="${jdbc.maxPoolSize}"/>
</bean>
<!-- 配置 EntityMangerFactory -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- 配置jpa提供商適配器 -->
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
<property name="packagesToScan" value="com.mamh.jpa.entities"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<!-- 配置jpa使用的事務管理器 -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<!-- 配置支持基於註解事務配置 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>