1. 程式人生 > >三、hibernate中持久化類的使用

三、hibernate中持久化類的使用

持久化對象 console image 持久 就是 ssi seq sybase 內存

hibernate的持久化類

  • 持久化:將內存中的一個對象持久化到數據庫中的過程,hibernate就是一個用來進行持久化的框架
  • 持久化類:一個Java對象與數據庫中表建立了關系映射,那麽這個類在hibernate中就可以稱之為持久化類
    • Java實體類
    • 該Java類的映射文件 

持久化類的使用 

提供無參構造

從之前測試類中查詢的使用來看:

User user = session.get(User.class, 1);

說明hibernate內部是使用反射技術實現生成對象實例,所以持久化類中的Java實體類必須提供一個無參構造

定義私有屬性,公有的getter/setter方法

hibernate生成對象實例時,需要獲取、設置屬性值

定義唯一標識屬性OID(對應數據庫表中的主鍵)

  • hibernate緩存是一個map,他會根據OID作為緩存對象的key,我們的映射文件中<id>標簽指定的屬性值會作為OID
  • Java對象通過地址來定位一個對象,數據庫的表中通過主鍵來定位到一條數據記錄
  • hibernate中通過持久化類的唯一標識屬性來定位一個對象

例如User中的id

public class User {

	private Integer id;
	private String name;
	private String password;
	......
} 

映射文件配置id屬性

<hibernate-mapping>
	<!-- 配置表與實體的映射關系 -->
	<class name="com.qf.entity.User" table="user">
		<id name="id" column="id">
			<generator class="native"></generator>
		</id>
		......
	</class>
</hibernate-mapping>

屬性定義最好使用包裝類

因為基本數據類型默認值是0,容易出現很多問題

例如:

  • 保存數據時,id屬性如果沒有設置具體值,默認使用0,保存兩次就會出現異常
  • 表中某些字段值是0,無法區分是沒存值還是存的值就是0

最好不要使用final修飾持久化類

  • 主要原因是影響延遲加載的使用,延遲加載是用於優化hibernate的
  • 延遲加載返回的是一個代理對象,hibernate延遲加載是使用javassist技術來實現的
  • javassist可以對沒有實現接口的類產生代理,使用字節碼增強技術繼承這個類並進行代理
  • final修飾的類無法被繼承,那麽就無法產生代理對象,也就不能做延遲加載了(get方法和load方法的查詢完全一致)

主鍵

主鍵分類

  • 自然主鍵:就是充當主鍵的字段本身具有一定的含義,是構成記錄的組成部分,比如學生的學號,除了充當主鍵之外,同時也是學生記錄的重要組成部分
  • 代理主鍵:就是充當主鍵的字段本身不具有業務意義,只具有主鍵作用,比如自動增長的ID
  • 實際開發中推薦使用代理主鍵,因為不涉及業務邏輯,後期不會發生修改源代碼的情況(OCP原則)

主鍵生成策略

<hibernate-mapping>
	<!-- 配置表與實體的映射關系 -->
	<class name="com.qf.entity.User" table="user">
		<id name="id" column="id">
			<!-- 主鍵生成策略 -->
			<generator class="native"></generator>
		</id>
		<property name="name" column="name"/>
		<property name="password" column="password"/>
	</class>
</hibernate-mapping>

increment

  • 由Hibernate從數據庫中取出主鍵的最大值(每個session只取1次),以該值為基礎,每次增量為1
  • 適用於int、short、long類型的主鍵
  • 線程不安全,適用於單線程程序

identity

  • identity由底層數據庫生成標識符
    • identity是由數據庫自己生成的,但這個主鍵必須設置為自增長,使用identity的前提條件是底層數據庫支持自動增長字段類型
    • 適用DB2、SQL Server、MySQL、Sybase和HypersonicSQL,不適用Oracle
  • 適用於int、short、long類型的主鍵
  • 線程安全

sequence

  • 采用數據庫提供的sequence機制生成主鍵,需要數據庫支持sequence
  • oralce、DB、SAP DB、PostgerSQL、McKoi中的sequence適用,Mysql不適用 
  • 適用於int、short、long類型的主鍵

uuid

  • Hibernate在保存對象時,生成一個UUID字符串作為主鍵,保證了唯一性,但其並無任何業務邏輯意義,只能作為主鍵
  • 唯一缺點長度較大,32位(Hibernate將UUID中間的“-”刪除了)的字符串,占用存儲空間大
  • Hibernate在維護主鍵時,不用去數據庫查詢,從而提高效率,而且它是跨數據庫的,以後切換數據庫極其方便

native(常用)

  • native由hibernate根據使用的數據庫自行判斷采用identity、hilo、sequence其中一種作為主鍵生成方式,靈活性很強

assigned

  • Hibernate不負責維護主鍵生成
  • 人為控制主鍵生成,存儲對象前,必須要使用主鍵的setter方法給主鍵賦值

foreign

  • 使用另外一個相關聯的對象的主鍵作為該對象主鍵
  • 主要用於一對一關系中

持久化類的狀態

狀態

  • 瞬時態:沒有唯一標識OID(映射到數據庫表的主鍵上具體的值),也不被session管理
  • 持久態:有唯一標識OID,被session管理
  • 脫管態:有唯一標識OID,不被session管理
        @Test
	public void save(){
		Session session = SessionFactoryUtil.getSession();
		
		Transaction ts = session.beginTransaction();
		//瞬時態對象:新建對象,還沒有唯一標識OID,也沒有被session對象管理
		User user = new User("hz", "0");
		
		//持久態對象:有唯一標識OID,並且被session對象管理
		Serializable save = session.save(user);
		System.out.println("user:"+user);
		
		ts.commit();
		session.close();
		
		//脫管態對象:session銷毀了,不被session對象管理,但是還有唯一標識OID
		System.out.println("user:"+user);
	}

幾種狀態的轉換

技術分享圖片

瞬時態對象

獲取:User user = new User();

轉換

  • 轉換成持久態對象:save()、saveOrUpdate()
  • 轉換成脫管態對象:user.setId(2);

持久態對象

獲取:get()、load()、find()、iterate()

轉換

  • 轉換成瞬時態對象:delete()
  • 轉換成脫管態對象:
    • session.close():銷毀session對象
    • session.clear():清空所有對象
    • session.evict(obj):清空某一個對象

脫管態對象

獲取:User user = new User(3,"","");或者User user = new User(); user.setId(3);

轉換

  • 轉換成瞬時態對象:user.setId(null);
  • 轉換成持久態對象:update()、saveOrUpdate()、lock()

持久態對象可以自動更新數據庫

        @Test
	public void test(){
		Session session = SessionFactoryUtil.getSession();
		Transaction ts = session.beginTransaction();
		
		//獲得持久化對象
		User user = session.get(User.class, 1);
		System.out.println("name:"+user.getName());
		user.setName("test");
		
		ts.commit();
		session.close();
	}        

  控制臺輸出

Hibernate: 
    select
        user0_.id as id1_0_0_,
        user0_.name as name2_0_0_,
        user0_.password as password3_0_0_ 
    from
        user user0_ 
    where
        user0_.id=?
name:wxf
Hibernate: 
    update
        user 
    set
        name=?,
        password=? 
    where
        id=?

再次執行test()方法,console輸出

Hibernate: 
    select
        user0_.id as id1_0_0_,
        user0_.name as name2_0_0_,
        user0_.password as password3_0_0_ 
    from
        user user0_ 
    where
        user0_.id=?
name:test
  • 測試方法中並沒有做update操作,但是執行了update操作,是因為get方法獲取的user是持久化對象,可以自動更新數據庫
  • 如果setName方法設置的值和數據庫裏的name一樣,也不會執行update操作

三、hibernate中持久化類的使用