1. JPA認識
JPA是Java Persistence API的簡稱,它是Sun公司在充分吸收現有ORM框架(Hibernate)的基礎上,開發而來的一個Java EE 5.0平台標准的開源的對象關系映射(ORM)規范。
Hibernate與JPA的關系:
Hibernate是一個開放源代碼的對象關系映射(ORM)框架,它對JDBC進行了非常輕量級的對象封裝,將POJO與數據庫表建立映射關系,是一個全自動的ORM框架,Hibernate可以自動生成SQL語句,自動執行,使Java程序員可以隨心所欲地使用面向對象思維來操縱數據庫。
而JPA是Sun官方提出的Java持久化規范,而JPA是在充分吸收Hibernate、TopLink等ORM框架的基礎上發展而來的。
總結一句話就是:JPA是持久化的關系映射規范、接口API,而Hibernate是其實現。
1.1. JPA的優缺點
優點:
① 操作代碼很簡單,插入—persist、修改—merge、查詢—find、刪除—remove;
② 直接面向持久化對象操作;
③ 提供了世界級的數據緩存:包括一級緩存、二級緩存、查詢緩存;
④ 切換數據庫移植性強,對應各種數據庫抽取了一個方言配置接口,換數據庫只需修改方言配置、驅動jar包、數據庫連接4個信息即可。
缺點:
① 不能干預SQL語句的生成;
② 對於SQL優化效率要求較高的項目,不適合使用JPA;
③ 對於數據量上億級別的大型項目,也不適合使用JPA。
2. 手動創建一個Hello World的JPA項目
2.1. 導入JPA項目所需jar包
Hibernate版本可以到官網進行下載:http://hibernate.org/orm/releases/
這里作為學習使用Hibernate 4.3.8的版本jar包,即JPA2.1版本為例進行項目jar包的構建:
導入項目所需要的Hibernate的jar包分為三類:
① Hibernate所必需的jar包:
目錄路徑位置:\hibernate-release-4.3.8.Final\lib\required
導入如下圖所示jar包集合:
② 還需要導入JPA支持的jar包,目錄路徑:\hibernate-release-4.3.8.Final\lib\jpa與數據庫Mysql連接驅動jar包;
2.2. 配置核心配置文件persistence.xml
配置文件必需放在項目的classpath目錄的資源文件resources\META-INF目錄下(JPA規范要求);
persistence.xml文件具體配置如下:
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0"> <!--持久化單元 name:和項目名稱對應--> <persistence-unit name="cn.yif.jpa01" transaction-type="RESOURCE_LOCAL"> <properties> <!-- 必須配置4個連接數據庫屬性:配置信息可以在project/etc/hibernate.properties中找到 --> <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" /> <property name="hibernate.connection.url" value="jdbc:mysql:///jpa01_0307" /> <property name="hibernate.connection.username" value="root" /> <property name="hibernate.connection.password" value="admin" /> <!-- 必須配置1個數據庫方言屬性 --> <!-- 實現跨數據庫關鍵類 :查詢MySQLDialect的getLimitString方法 --> <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" /> <!-- 可選配置 --> <!-- 是否自動生成表 --> <property name="hibernate.hbm2ddl.auto" value="create" /> <!-- 是否顯示sql --> <property name="hibernate.show_sql" value="true" /> <!-- 格式化sql --> <property name="hibernate.format_sql" value="true" /> </properties> </persistence-unit> </persistence>
2.3.創建持久化Domain類Employee
package cn.yif.domain; import javax.persistence.*; //@Entity表示該類是由jpa管理的持久化對象,對應數據庫中的一張表 @Entity //@Table表示對應數據庫的表名 @Table(name = "t_employee") public class Employee { //@Id是必須的注解,表示對應數據庫的主鍵 @Id //@GeneratedValue表示主鍵的生成策略,多數都是使用AUTO //@GeneratedValue默認不配置也是AUTO @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; //@Column表示如果數據庫列名與屬性名不一致,需要配置 @Column(name = "e_name") private String name; @Column(name = "e_age") private Integer age; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "Employee{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; } }
2.4.創建Junit4測試類代碼
import cn.yif.domain.Employee; import org.junit.Test; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.Persistence; public class JPAHelloTest { @Test public void testInsertEmpByJPA(){ Employee employee = new Employee(); employee.setName("高偉翔"); employee.setAge(34); // 對應配置文件里面的persistence-unit name="cn.yif.jpa01" // 通過持久化類創建一個實體類管理工廠 EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("cn.yif.jpa01"); //創建一個實體管理類,可以實現CRUD EntityManager entityManager = entityManagerFactory.createEntityManager(); //由entityManager來開啟事務 EntityTransaction transaction = entityManager.getTransaction(); transaction.begin(); //持久操作CRUD 寫入persist entityManager.persist(employee); // 提交事務 transaction.commit(); //關閉資源 entityManager.close(); entityManagerFactory.close(); } }
通過以上的步驟,就可以在創建的jpa01_0307數據庫里面由JPA自動創建一張t_employee表並插入一條數據:
3. 實現完整的JPA CRUD流程
3.1.抽取JPAUtil類
package cn.yif.utils; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; /** * 工具類:單例模式/靜態單例模式 靜態方法 */ public class JPAUtil { // 私有化這個構造器,不讓其它人創建這個類 private JPAUtil(){} // 實體管理工廠 // 注意:EntityManagerFactory這個類是線程安全 private static EntityManagerFactory entityManagerFactory; /** * 靜態代碼塊,類加載的時候就會執行里面的代碼,只會執行一次 */ static{ try { entityManagerFactory = Persistence.createEntityManagerFactory("cn.yif.jpa01"); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("拿到EntityManagerFactory運行時出錯:"+e.getMessage()); } } // 拿到一個EntityManager對象 // 每次拿EntityManager都需要重新創建(EntityManager不是線程安全的對象,每次使用都重新創建一次) public static EntityManager getEntityManager(){ return entityManagerFactory.createEntityManager(); } public static void close(EntityManager entityManager){ //關閉資源 entityManager.close(); entityManagerFactory.close(); } }
4. persitence.xml中hibernate.hbm2ddl.auto屬性值配置
如上,hibernate.hbm2ddl.auto屬性的value值一共有4種配置:create-drop、create、update、validate。下面來解釋這四種不同配置場景的區別與作用:
① create-drop
create-drop作用:先刪除表,在創建表,最后再刪除表;
注意:必須執行entityManagerFactory.close()代碼才會最后刪除表,執行drop表功能
② create
create作用:先刪除表,在創建表。
③ update
update作用:
如果數據庫中沒有當前JPA持久化的表就根據最新映射來創建表;
如果數據庫已經有表了,則不會刪除原來表的任何結構,只會新增列;
注意如果是表里面沒有這個屬性,映射信息domain類中有,則會增加這個屬性
④ validate
validate作用:
如果數據庫中表不存在或者domain類中的屬性大於數據庫表中的字段,會拋出異常;
會驗證映射信息domain類與數據庫表中的對應字段,如果一一對應或者映射小於數據庫表中的字段,不會拋出異常
5. 單表映射配置細節
5.1.持久類domain映射配置細節
5.1.1. 日期與時間類型格式
① 日期與時間格式配置
使用@Temporal注解配置:
@Temporal(TemporalType.TIMESTAMP)
默認配置,會設置數據庫表的時間格式為:“yyyy-MM-dd hh:mm:ss"
@Temporal(TemporalType.DATE)
會設置數據庫表的時間格式為:”yyyy-MM-dd"
@Temporal(TemporalType.TIME)
會設置數據庫表的時間格式為:“hh:mm:ss”
持久類domain配置
@Temporal(TemporalType.TIMESTAMP) private Date createTime; // 創建時間:格式--"yyyy-MM-dd hh:mm:ss"(年--月--日--時--分--秒) @Temporal(TemporalType.DATE) private Date brithday; // 生日:格式--"yyyy-MM-dd"(年--月--日) @Temporal(TemporalType.TIME) private Date classTime; // 上課時間:格式--"hh:mm:ss""(時--分--秒)
具體設置格式如下:
5.1.2. 文本長度與長文本類型
domain類對應普通表中的長度如果不配置長度,默認vachar字段類型在數據庫表中的長度會給到255,比較占用空間,我們可以通過JPA注解配置來指定固定的length長度值。
普通String類屬性字段長度配置:
@Column(name = "t_name", length = 20)
@Column(name = "pwd", length = 100)
在@Column注解上加上length長度配置,即可指定數據庫表中varchar字段的長度;
長文本類型屬性字段配置:
在對應domain類的屬性上加上注解@Lob,對應這個字段在數據庫中就會被設置成longtext類型,能儲存大文本。
持久類domain配置
@Lob // 設置為長文本類型 private String Intro; // 個人簡介:長文本類型
5.1.3. 屬性約束設置
非空約束:
配置@Column(nullable = false)
唯一約束:
配置@Column(unique = true)
5.1.4. 其他映射配置
① 臨時屬性配置:Transient(臨時屬性—該屬性在持久化對象上有,但是不會寫入數據庫);
@Transient private String temp;
② 設置是否能更新able:@Column(updatable=false),表示添加的時候會進行添加,但是修改的時候不能修改(了解就行,一般不用);
③ 設置是否能添加able:@Column(insertable=false),表示添加的時候不能操作,但是修改的時候可以操作修改(了解就行,一般不用);
④ 自定義持久類domain屬性規則:@Column(columnDefinition=”int check(age > 18)”),Mysql不支持這個規則,Oracle才支持(了解就行,Mysql數據庫用不了)