Hibernate学习(二)
持久化對象的聲明周期
1、Hibernate管理的持久化對象(PO persistence object )的生命周期有四種狀態,分別是transient、persistent、detached和removed,如圖所示:
?
- 瞬時狀態:new出來的對象僅僅存在虛擬機的內存中,虛擬機關閉數據丟失
- 持久化狀態:通過save方法保存到數據庫中,即使虛擬機關閉也可以中數據庫中讀取到想要的數據。通過get load find從數據庫加載到數據并沒有拋出異常,就立即進入持久化狀態,并不是非要提交事務才進入持久化狀態,執行完save操作就已經是持久化狀態了
- 游離態:把session關閉或者將對象驅除或者清除了就是游離的狀態
- 移除狀態:通過delete方法之后,數據庫中沒有數據了,但數據加載到了jvm所管理內存中,對象對應的內存中是有數據的,類似于瞬時狀態
2、測試案例
創建表sql
--Mysql DROP TABLE IF EXISTS t_customer ;CREATE TABLE t_customer (id INT(5) PRIMARY KEY ,email VARCHAR(60) UNIQUE NOT NULL,password VARCHAR(32) NOT NULL ,nickname VARCHAR(150) ,gender VARCHAR(3) ,birthdate DATE ,married CHAR(1) );--Oracle CREATE TABLE t_customer (id NUMBER(5) PRIMARY KEY ,email VARCHAR2(60) UNIQUE NOT NULL,password VARCHAR2(32) NOT NULL ,nickname VARCHAR2(150) ,gender VARCHAR2(3) ,birthdate DATE ,married CHAR(1) );持久化對象類
package ecut.session.entity;import java.util.Date;/*** 實體類 Customer <================> 數據庫表: t_customer* 屬性 <================> 列* id <================> id* emial <================> email* password <================> password* nickname <================> nickname* gender <================> gender* birthdate <================> birthdate* married <================> married* * new Customer(); <==========> 一條記錄 (關系)* */ public class Customer {// 對象標識符 ( Object Identifier ) 屬性 ( 對應數據庫主鍵 ) 使用包裝類型,才會有null值,才可以執行saveOrUpdateprivate Integer id; // 屬性的值 被稱作 對象標識符private String email;private String password;private String nickname;private char gender;private Date birthdate;private boolean married;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getNickname() {return nickname;}public void setNickname(String nickname) {this.nickname = nickname;}public char getGender() {return gender;}public void setGender(char gender) {this.gender = gender;}public Date getBirthdate() {return birthdate;}public void setBirthdate(Date birthdate) {this.birthdate = birthdate;}public boolean isMarried() {return married;}public void setMarried(boolean married) {this.married = married;}}映射文件
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="ecut.session.entity.Customer" table="t_customer"><!-- 對于 與 數據庫主鍵 對應的 對象標識符屬性 來說,要單獨使用 id 標簽來映射 --><id name="id" type="integer" column="id" ><generator class="increment" /> <!-- 由 hibernate 提供的 對象標識符 生成策略 --></id><!-- 指定 那個屬性 ( name 指定屬性名 ) 對應 那個列 ( column 屬性指定 列名 ) --><property name="email" type="string" column="email" /><!-- 使用 type 屬性指定 映射類型 ( 既不是 Java 類型,也不是 數據庫類型,而是 中間類型 ( 媒婆 ) ) --><property name="password" type="string" column="password" /><property name="nickname" type="string" column="nickname" /><!-- Java 中的 char 類型在 hibernate 中對應的映射類型是 character --><property name="gender" type="character" column="gender" /><property name="birthdate" type="date" column="birthdate" /><!-- Java 中的 boolean 類型在 hibernate 中對應的映射類型可以是 true_false 、yes_no --><property name="married" type="yes_no" column="married" /></class></hibernate-mapping>hibernate配置文件
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE hibernate-configuration PUBLIC"-//Hibernate/Hibernate Configuration DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"><hibernate-configuration><session-factory><!-- 指定連接數據庫的基本信息 --><property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property><property name="hibernate.connection.url">jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF8</property><property name="hibernate.connection.username">root</property><property name="hibernate.connection.password">123456</property><!-- 設置事務隔離級別 , 取值可以是 1、2、4、8 1—Read uncommitted isolation2—Read committed isolation4—Repeatable read isolation8—Serializable isolation--><property name="hibernate.connection.isolation">1</property><!-- 設置事務是否自動提交 , 取值可以是 true 、false --><property name="hibernate.connection.autocommit">false</property><!-- 指定數據方言類 --><property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property><!-- 指示是否顯示 執行過的 SQL 語句 --><property name="hibernate.show_sql">true</property><!-- 指示是否對 SQL 語句進行格式化輸出 --><property name="hibernate.format_sql">true</property><mapping resource="ecut/session/entity/Customer.hbm.xml"/></session-factory></hibernate-configuration>配置文件中的核心配置說明
?java.sql.Connection 中定義的事務隔離級別:
- public static final int?? ?TRANSACTION_NONE?? ?:?? ?0
- public static final int?? ?TRANSACTION_READ_UNCOMMITTED?? ?:?? ?1
- public static final int?? ?TRANSACTION_READ_COMMITTED?? ?:?? ?2
- public static final int?? ?TRANSACTION_REPEATABLE_READ?? ?:?? ?4
- public static final int?? ?TRANSACTION_SERIALIZABLE?? ?:?? ?8
?測試類:
package ecut.session.test;import java.util.Calendar; import java.util.Date;import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.After; import org.junit.Before; import org.junit.Test;import ecut.session.entity.Customer;public class TestLifecycle {private SessionFactory factory ;private Session session ; public @Before void init() {// 創建一個 Configuration 對象,用來讀取配置文件 ( 默認位置、默認名稱 )Configuration config = new Configuration();// 讀取配置文件config.configure("ecut/session/hibernate.cfg.xml");//config.configure(); // 讀取 默認位置 ( 當前 classpath ) 的 默認名稱 ( hibernate.cfg.xml ) 的配置文件// 使用 Configuration 創建 SessionFactoryfactory = config.buildSessionFactory();// 創建 Session 對象 ( 這里的 Session 是 Java 程序 跟 數據庫 之間的 會話 )session = factory.openSession();}public @Test void state() throws InterruptedException {Calendar calendar = Calendar.getInstance();Customer c = new Customer(); // Transient ( 瞬時狀態 ) c.setEmail( "zhangsanfeng@wudang.com" );c.setPassword( "hello2017" );calendar.set( 1345 , 5 , 10 );Date birthdate = calendar.getTime() ;c.setBirthdate( birthdate );c.setGender( '男' );c.setNickname( "張三豐" );c.setMarried( false );System.out.println( session.contains( c ) ); // false Transaction tran = session.beginTransaction(); // session.getTransaction().begin();session.save( c ); // Persistent ( 持久化狀態 )System.out.println( "~~~1~~~~~~~~~~~~~~~~~~" );session.flush(); // 將當前尚未執行的 SQL 語句立即執行System.out.println( "~~~2~~~~~~~~~~~~~~~~~~" );Thread.sleep( 1 );System.out.println( "~~~3~~~~~~~~~~~~~~~~~~" );tran.commit(); // 提交事務 ( 如果還有沒有執行的 SQL 語句就執行它們 )System.out.println( session.contains( c ) ); // true session.evict( c ); // Detached ( 游離狀態 ) System.out.println( session.contains( c ) ); // false,是否被session所管理,session中已經沒有這個數據了 System.out.println( c.getEmail() );//虛擬機中依然有數據 }public @Test void removed() {Customer c = session.get( Customer.class , 4 ); // 持久化狀態if( c != null ) {System.out.println( session.contains( c ) );System.out.println( c.getEmail() );Transaction tran = session.getTransaction();tran.begin();session.delete(c); // 刪除對象System.out.println( "~~~1~~~~~~~~~~~~~~~~~~" );session.flush(); // 將當前尚未執行的 SQL 語句立即執行System.out.println( "~~~2~~~~~~~~~~~~~~~~~~" );tran.commit();System.out.println( session.contains( c ) );System.out.println( c.getEmail() );}}public @After void destory(){session.close();factory.close();}}若沒有flush操作則insert語句在提交事務之后輸出執行,若有flush操作則將當前尚未執行的 SQL 語句立即執行即在提交事務之前輸出insert語句。在save方法執行之后就已經是出于持久化狀態無論sql語句是否執行。若處于游離態則對象已經不再被session所管理即contains方法返回false。
測試類中的方法說明:
- 判斷指定的對象是否 被 Session 對象所管理:? boolean? contains( Object po )
- 將尚未執行的SQL語句執行:?? ??? ?void ?? ?flush()
- 將 一個 被 Session 管理的對象驅逐: void? evict( Object po )
- 將 整個 Session 所管理的所有的對象全部清理: void? clear()
- 如果 一個 Session 對象執行了 close() 方法,則該 Session 對象將無效,一次 曾經被它管理的對象也將進入游離狀態
3、四種狀態的比較
Persistent 和 Detached區別在于是否被session所管理
核心: 處于 持久化狀態的 對象 的 OID 與 數據庫中的 某條記錄的 主鍵 一定是 相等的。
Hibernate中的核心類和接口
1、org.hibernate.cfg.Configuration:Configuration類表示配置對象,用來讀取并解析 hibernate 配置文件
- ?? ?注意:Configuration類的configure實例方法負責讀取配置文件(hibernate.cfg.xml)
2、org.hibernate.SessionFactory:SessionFactory接口實例專門用來創建連接到指定數據庫的會話對象
3、org.hibernate.Session:Session接口的實例是hibernate應用的核心對象,提供了大量的對持久化對象進行操作的方法
- ?? ?注意:這里的會話指的是當前的Java應用程序和數據庫服務器之間的會話(絕對不是HttpSession)
4、org.hibernate.Transaction:Transaction接口的實例表示事務對應的對象,用來對事務進行控制
5、org.hibernate.query.Query:Query接口的實例是hibernate應用中查詢時的核心對象
- 注意:Hibernate早期(5.x之前)版本中使用query接口是org.hibernate.Query
Session接口只要方法
1、session接口中定義的用來操作持久化對象的方法
- Serializable ?? ?save(Object object)?? ? 保存一個對象到數據庫中并返回與之對應的對象標識符(主鍵的值)
- void persist(Object object) 標準的JPA(Java Persistence API 應用程序編程接口(application program interface))提供的方法,用來持久化一個對象,javax.persistence.EntityManager中的方法
- void saveOrUpdate(Object object) 用來更新一個持久化對象(需要根據對象標識符來實現),默認是根據對象標識符是否為null 來判斷應該執行保存操作還是更新操作
- void update(Object object) 用來持久化或更新一個對象
- void delete(Object object) 用來刪除一個持久化的對象
- <T> T get(Class<T> entityType,Serializable id) 從數據庫匯總查詢一條記錄并封裝成一個相應類型的Java對象,默認不支持延遲加載,當id對應的數據不存在時返回null
- <T> T load(Class<T> theClass,Serializable id)? 從數據庫匯總查詢一條記錄并封裝成一個相應類型的Java對象,默認支持延遲加載,當id對應的數據不存在時拋出ObjectNotFoundException
- <T> T find(Class<T> entityClass, Object primaryKey)? 從數據庫匯總查詢一條記錄并封裝成一個相應類型的Java對象??? javax.persistence.EntityManager中的方法,默認不支持延遲加載,當id對應的數據不存在時返回null
- Query ?? ?createQuery(String queryString) 根據給定的 queryString 來創建一個查詢器(基于HQL實現的)
- void? evict(Object arg0) 將指定的對象從關聯的session對象中驅逐
2、保存操作的測試案例
package ecut.session.test;import java.io.Serializable; import java.util.List;import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.hibernate.query.Query; import org.junit.After; import org.junit.Before; import org.junit.Test; import ecut.session.entity.Customer;public class TestSessionMethod {private SessionFactory factory ;private Session session ; public @Before void init() {// 創建一個 Configuration 對象,用來讀取配置文件 ( 默認位置、默認名稱 )Configuration config = new Configuration();// 讀取配置文件config.configure("ecut/session/hibernate.cfg.xml");//config.configure(); // 讀取 默認位置 ( 當前 classpath ) 的 默認名稱 ( hibernate.cfg.xml ) 的配置文件// 使用 Configuration 創建 SessionFactoryfactory = config.buildSessionFactory();// 創建 Session 對象 ( 這里的 Session 是 Java 程序 跟 數據庫 之間的 會話 )session = factory.openSession();}public @Test void testSave() {Customer c = new Customer();c.setEmail( "zhangcuishan@wudang.com" );c.setPassword( "hello2017" );Transaction tran = session.getTransaction();try{tran.begin();// dynamic-insert="false" : // insert into t_customer (email, password, nickname, gender, birthdate, married, id) values (?, ?, ?, ?, ?, ?, ?)// dynamic-insert="true"// insert into t_customer (email, password, gender , married ,id) values (?, ?, ?,?, ?)System.out.println( "customer.id : " + c.getId() );Serializable id = session.save( c );System.out.println( "id : " + id );System.out.println( "customer.id : " + c.getId() );tran.commit();} catch ( HibernateException e) {tran.rollback();}}public @Test void testPersist() {Customer c = new Customer();c.setEmail( "moshenggu@wudang.com" );c.setPassword( "hello2017" );Transaction tran = session.getTransaction();try{tran.begin();System.out.println( "customer.id : " + c.getId() );session.persist( c );System.out.println( "customer.id : " + c.getId() );tran.commit();} catch ( HibernateException e) {tran.rollback();}}public @After void destory(){session.close();factory.close();}}save方法是持久化對象之后并返回這個對象的主鍵,persist沒有返回值,是標準JPA(Java Persistence API )提供的方法,來自? javax.persistence.EntityManager接口。另外執行插入操作時,不想對所有的字段執行insert操作可以在映射配置文件中的class標簽中指定動態插入
<class name="ecut.session.entity.Customer" table="t_customer" dynamic-insert="true" >3、刪除測試案例
package ecut.session.test;import java.io.Serializable; import java.util.List;import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.hibernate.query.Query; import org.junit.After; import org.junit.Before; import org.junit.Test; import ecut.session.entity.Customer;public class TestSessionMethod {private SessionFactory factory ;private Session session ; public @Before void init() {// 創建一個 Configuration 對象,用來讀取配置文件 ( 默認位置、默認名稱 )Configuration config = new Configuration();// 讀取配置文件config.configure("ecut/session/hibernate.cfg.xml");//config.configure(); // 讀取 默認位置 ( 當前 classpath ) 的 默認名稱 ( hibernate.cfg.xml ) 的配置文件// 使用 Configuration 創建 SessionFactoryfactory = config.buildSessionFactory();// 創建 Session 對象 ( 這里的 Session 是 Java 程序 跟 數據庫 之間的 會話 )session = factory.openSession();}public @Test void testDelete1() {// 先嘗試從數據庫中獲取某條記錄對應的一個 Java 對象Customer c = session.get( Customer.class , 3 );// 如果指定 id 對應的 對象存在 ( 數據庫中有相應的記錄 )if( c != null ) {Transaction tran = session.getTransaction();try{tran.begin();session.delete( c ); // 刪除對象 tran.commit();System.out.println(c.getId());} catch ( HibernateException e) {tran.rollback();}}}public @Test void testDelete2() {// 自己創建一個對象并指定 id Customer c = new Customer();c.setId(2); // 如果 id 是 2 的記錄在數據庫中存在 Transaction tran = session.getTransaction();try {tran.begin();session.delete( c ); // 刪除對象 tran.commit();} catch (HibernateException e) {tran.rollback();}}public @After void destory(){session.close();factory.close();}}兩種刪除,第一種先查詢,如果存在這個對象就執行刪除操作,第二種直接根據id刪除。
4、查詢測試案例
package ecut.session.test;import org.hibernate.ObjectNotFoundException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.junit.After; import org.junit.Before; import org.junit.Test; import ecut.session.entity.Customer;public class TestLoadData {private SessionFactory factory ;private Session session ; public @Before void init() {// 創建一個 Configuration 對象,用來讀取配置文件 ( 默認位置、默認名稱 )Configuration config = new Configuration();// 讀取配置文件config.configure("ecut/session/hibernate.cfg.xml");//config.configure(); // 讀取 默認位置 ( 當前 classpath ) 的 默認名稱 ( hibernate.cfg.xml ) 的配置文件// 使用 Configuration 創建 SessionFactoryfactory = config.buildSessionFactory();// 創建 Session 對象 ( 這里的 Session 是 Java 程序 跟 數據庫 之間的 會話 )session = factory.openSession();}public @Test void testGet1() {Customer c = session.get( Customer.class , 2 );if( c != null ){System.out.println( c.getEmail() );} else {System.out.println( "數據庫中沒有對應的數據" );}}public @Test void testGet2() {System.out.println( "準備查詢數據庫" );Customer c = session.get( Customer.class , 1 ); // 立即查詢并返回數據if( c != null ){System.out.println( "獲取到的數據是" );System.out.println( c.getEmail() );}}public @Test void testLoad1() {Customer c = null ;try{c = session.load( Customer.class , 2 );System.out.println( c.getEmail() );} catch ( ObjectNotFoundException e) {System.out.println( "數據庫中沒有對應的數據 , " + e.getMessage() );}}/** 延遲加載 ( 懶加載 ) * 關閉對 Customer 的延遲加載: <class name="ecut.session.entity.Customer" table="t_customer" lazy="false" >* 啟用對 Customer 的延遲加載: <class name="ecut.session.entity.Customer" table="t_customer" lazy="true" >* */public @Test void testLoad2() {System.out.println( "準備查詢數據庫" );Customer c = session.load( Customer.class , 1 ); // 默認并不立即查詢,如果不存在會在最后面才拋出異常System.out.println( "獲取到的數據是 Id" );System.out.println( c.getId() ); // 因為 id 是 load 方法中指定的,因此不需要查詢數據庫System.out.println( "獲取到的數據是 Email" );System.out.println( c.getEmail() ); // 獲取 id 之外的 其它 數據時,不得不查詢數據庫 }public @Test void testFind1() {Customer c = session.find( Customer.class , 2 );if( c != null ){System.out.println( c.getEmail() );} else {System.out.println( "數據庫中沒有對應的數據" );}}public @Test void testFind2() {System.out.println( "準備查詢數據庫" );Customer c = session.find( Customer.class , 1); // 立即查詢并返回數據if( c != null ){System.out.println( "獲取到的數據是 " );System.out.println( c.getEmail() );}}public @After void destory(){session.close();factory.close();}}get 、load 、find三種查詢方法的比較:
- get 、load 、find 都是用來從數據庫中加載一條記錄并包裝成指定類型的對象
- get( Class<?> c , Serializable id )
a、當 id 對應的數據在 數據庫中不存在時,get 返回 null
b、get 方法會立即查詢數據庫 并返回數據
- load( Class<?> c , Serializable id )
a、當 id 對應的數據在 數據庫中不存在時,load 方法會拋出 ObjectNotFoundException
b、load 方法 "默認" 不會立即查詢數據庫,而是等到要使用除了id之外的其它數據時才執行查詢操作并返回數據
關閉對 Customer 的延遲加載:
? 啟用對 Customer 的延遲加載:
<class name="ecut.session.entity.Customer" table="t_customer" lazy="true" >- find( Class<?> c , Serializable id ) 屬于 JPA 規范中定義的方法 ( javax.persistence.EntityManager )
?? ???? a、當 id 對應的數據在 數據庫中不存在時,find 返回 null
?? ??? ?b、find 方法會立即查詢數據庫 并返回數據
5、查詢多條數據測試案例
package ecut.session.test;import java.io.Serializable; import java.util.List;import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.hibernate.query.Query; import org.junit.After; import org.junit.Before; import org.junit.Test; import ecut.session.entity.Customer;public class TestSessionMethod {private SessionFactory factory ;private Session session ; public @Before void init() {// 創建一個 Configuration 對象,用來讀取配置文件 ( 默認位置、默認名稱 )Configuration config = new Configuration();// 讀取配置文件config.configure("ecut/session/hibernate.cfg.xml");//config.configure(); // 讀取 默認位置 ( 當前 classpath ) 的 默認名稱 ( hibernate.cfg.xml ) 的配置文件// 使用 Configuration 創建 SessionFactoryfactory = config.buildSessionFactory();// 創建 Session 對象 ( 這里的 Session 是 Java 程序 跟 數據庫 之間的 會話 )session = factory.openSession();} public @Test void query() {// Hibernate 3.x : org.hibernate.Query// HQL : Hibernate Query Language FROM之后跟的是實體類的類名 SELECT c FROM Customer AS cString HQL = "FROM Customer AS c ORDER BY c.id DESC" ; // SQL : SELECT * FROM t_customer // 創建 查詢器 //Query<?> query = session.createQuery( HQL);Query<Customer> query = session.createQuery( HQL , Customer.class );System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~");// 使用 查詢器 進行查詢List<Customer> list = query.list(); System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~");for( Customer c : list ){System.out.println( c.getId() + " , " + c.getEmail() );}}public @After void destory(){session.close();factory.close();}}HQL : Hibernate Query Language FROM之后跟的是實體類的類名 SELECT c FROM Customer AS c,調用list方法可以指明具體的返回類型也可以用?代替。
6、更新測試案例
package ecut.session.test;import java.util.Date;import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.After; import org.junit.Before; import org.junit.Test; import ecut.session.entity.Customer;public class TestUpdate {private SessionFactory factory ;public @Before void init() {// 創建一個 Configuration 對象,用來讀取配置文件 ( 默認位置、默認名稱 )Configuration config = new Configuration();// 讀取配置文件config.configure("ecut/session/hibernate.cfg.xml");//config.configure(); // 讀取 默認位置 ( 當前 classpath ) 的 默認名稱 ( hibernate.cfg.xml ) 的配置文件// 使用 Configuration 創建 SessionFactoryfactory = config.buildSessionFactory();}/** 更新一個持久化狀態的對象中的數據 后 同步到數據庫中 ,但是不用 update 方法 */public @Test void testUpdate1() throws InterruptedException {Session session = factory.openSession();// 執行查詢操作獲取數據Customer c = session.find( Customer.class , 1 ); // 持久化狀態if(c != null){System.out.println( c.getNickname() + " : " + c.getEmail() );Transaction tran = session.beginTransaction(); // 開啟一個事務并返回該事務的引用//c.setEmail( "sanfeng@wudang.com" );//可以在映射配置文件中設置動態插入和動態更新,只更新所更改的數值c.setNickname( "三豐".equals( c.getNickname() ) ? "君寶" : "三豐" );//如果數據值更改了(只有數據更改了才會執行update語句),提交事務的時候更改的值會同步到數據庫 Thread.sleep( 1 );tran.commit(); // 提交事務 }session.close();}/** 使用 update 方法將 游離狀態 的對象 還原到 持久化狀態*/public @Test void testUpdate2() {Session firstSession = factory.openSession();Customer c = firstSession.find( Customer.class , 1 ); // 持久化狀態 firstSession.close(); // 游離狀態 String nickname = c.getNickname() ;//可以在映射配置文件中設置動態插入和動態更新,只更新所更改的數值c.setNickname( "三豐".equals( nickname ) ? "君寶" : "三豐" );Session secondSession = factory.openSession() ;secondSession.getTransaction().begin();secondSession.update( c ); // 將一個 游離狀態 的對象重新轉換到 持久化狀態,無法動態更新,動態更新是針對持久化對象的,只有是持久化對象才知道數據是什么樣的。secondSession.getTransaction().commit(); // 提交事務后,事務即結束 System.out.println( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" );secondSession.getTransaction().begin();String email = c.getEmail() ;//已經是持久化對象因此可以動態對象c.setEmail( "sanfeng@wudang.com".equals( email ) ? "junbao@qq.com" :"zsf@qq.com" );secondSession.getTransaction().commit();}/** 使用 merge 方法 將一個 游離狀態的 對象的 數據 合并到 與其id相等的持久化狀態的對象中去*/public @Test void testUpdate3() {Session session = factory.openSession();Customer c1 = session.find( Customer.class , 1 ); // c1 處于持久化狀態 session.evict( c1 ); // c1 開始進入到 游離狀態 String nickname = c1.getNickname() ;c1.setNickname( "三豐".equals( nickname ) ? "君寶" : "三豐" );Customer c2 = session.find( Customer.class , 1 ) ; // 持久化狀態// 根據 c1.id 來在 session 管理的對象中尋找 與它id 相同的對象// 如果找到 id 相同的對象,就將 c1 中的數據 合并到 相應的持久化狀態的對象中去// 最后 merge 方法返回 那個持久化狀態的對象Object o = session.merge( c1 ); // c1.id == c2.id id是一樣的將兩個對象的數據進行合并 session.getTransaction().begin();session.getTransaction().commit();//只要事務開啟之后提交就好了,代碼位置沒有要求 System.out.println( o == c1 ); // falseSystem.out.println( o == c2 ); // true c1合并到c2中了,輸出日志中動態更新起了作用,因此是持久化對象C2 System.out.println( session.contains( c1 ) ); // falseSystem.out.println( session.contains( c2 ) ); // true }/** 使用 saveOrUpdate 方法執行 更新操作,saveOrUpdate的操作條件 取決于映射文件中的unsaved-value屬性的屬性值*/public @Test void testUpdate4() {Session session = factory.openSession();Customer c = session.find( Customer.class , 1 ); // 持久化狀態session.close(); // 游離狀態 System.out.println( "id : " + c.getId() );String nickname = c.getNickname() ;c.setNickname( "三豐".equals( nickname ) ? "君寶" : "三豐" );session = factory.openSession();//重新開啟一個session session.getTransaction().begin();// <id name="id" type="integer" column="id" unsaved-value="null" >// 取決于 c.id 是否是 null ,如果 id 是 null 就執行 insert ,否則執行 updatesession.saveOrUpdate( c ); // 執行 update 操作,將 游離狀態的對象 轉換到 持久化狀態 session.getTransaction().commit();}/** 使用 saveOrUpdate 方法執行 保存操作 */public @Test void testSave() {/*Session session = factory.openSession();Customer c = session.find( Customer.class , 1 ); // 持久化狀態session.close(); // 游離狀態c.setId( null ); //等價于new一個新的對象c.setEmail( "zhangwuji@wudang.com" );c.setNickname( "曾阿牛" );*/Customer c = new Customer();c.setEmail( "yinsusu@tianying.com" );c.setPassword( "hello2017" );Date birthdate = null ;c.setBirthdate( birthdate );c.setGender( '女' );c.setNickname( "素素" );c.setMarried( false );Session session = factory.openSession();session.getTransaction().begin();// <id name="id" type="integer" column="id" unsaved-value="null" >// 取決于 c.id 是否是 null ,如果 id 是 null 就執行 insert ,否則執行 updatesession.saveOrUpdate( c ); // 執行 insert 操作,對象 進入 持久化狀態 session.getTransaction().commit();}public @After void destory(){factory.close();}}更新操作有四種方法
- 更新一個持久化狀態的對象中的數據 后 同步到數據庫中 ,但是不用 update 方法
- 使用 update 方法將 游離狀態 的對象 還原到 持久化狀態
- 使用 merge 方法 將一個 游離狀態的 對象的 數據 合并到 與其id相等的持久化狀態的對象中去
- 使用 saveOrUpdate 方法執行 更新操作,saveOrUpdate的操作條件 取決于映射文件中的unsaved-value屬性的屬性值
可以在映射文件中配置dynamic-update屬性來實現動態更新
<class name="ecut.session.entity.Customer" table="t_customer" dynamic-insert="true" dynamic-update="true" >saveOrUpdate也可以完成插入操作
在映射文件中需要在id標簽中指定unsaved-value屬性的屬性值,來決定什么時候執行插入操作什么時候執行更新操作
<!-- 對于 與 數據庫主鍵 對應的 對象標識符屬性 來說,要單獨使用 id 標簽來映射 unsaved-value 默認是null 當id是null的時候執行插入操作,當id不是null時候執行update操作--><id name="id" type="integer" column="id" unsaved-value="null" ><generator class="increment" /> <!-- 由 hibernate 提供的 對象標識符 生成策略 --></id>轉載請于明顯處標明出處:
https://www.cnblogs.com/AmyZheng/p/9313649.html
轉載于:https://www.cnblogs.com/AmyZheng/p/9313649.html
總結
以上是生活随笔為你收集整理的Hibernate学习(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 浅谈WebGIS开放数据(矢量数据)
- 下一篇: 经典算法问题 - 最大连续子数列和