1. 程式人生 > >Hibernate兩種方式進行對映配置

Hibernate兩種方式進行對映配置

hibernate.cfg.xml檔案如下:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="connection.driver_class">org.postgresql.Driver</property>
        <property name="connection.url">jdbc:postgresql://127.0.0.1:5433/hibernatepractice</property>
        <property name="connection.username">postgres</property>
        <property name="connection.password">postgresql</property>
        <property name="connection.pool_size">2</property>
        <property name="dialect">org.hibernate.dialect.PostgreSQLDialect</property>
        <property name="show_sql">true</property>
    </session-factory>
</hibernate-configuration>

hibernate的兩種對映配置分別為xml和註解。兩種方式的主要差異點在hibernate.cfg.xml中新增的對映方式不同,對實體類的要求不同


1、xml方式進行對映配置

①在hibernate.cfg.xml中session-factory下新增屬性:

<mapping resource="User.cfg.xml" />

②在hibernate.cfg.xml同級目錄下新增User.cfg.xml檔案如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        '-//Hibernate/Hibernate Mapping DTD 3.0//EN'
        'http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd'>
<hibernate-mapping>
    <class name="com.hsb.hibernate.entity.User" table="tab_user">
        <id name="uuid">
            <generator class="assigned" />
        </id>
        <property name="userId"></property>
        <property name="name"></property>
        <property name="age"></property>
    </class>
</hibernate-mapping>


至此,xml配置完成。
UserDao.java程式碼如下:

public class UserDao {
    public void saveUser(User user) {
        SessionFactory sf = new Configuration().configure()
                .buildSessionFactory();
        Session session = null;
        Transaction transaction = null;
 
        try {
            session = sf.openSession();
            transaction = session.beginTransaction();
            session.save(user);
            transaction.commit();
        } catch (HibernateException e) {
            transaction.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }
    }
}
經測試,可以用。


2、註解方式進行對映配置

①在hibernate.cfg.xml的session-factory中新增如下屬性:

<mapping class="com.hsb.hibernate.entity.User" />
注意和第一種方式的不同,class和resource
②在實體類中新增各種註解

@Entity
@Table(name = "tab_user")
public class User {
    @Id
    @GenericGenerator(name = "generator", strategy = "increment")
    @GeneratedValue(generator = "generator")
    @Column(name = "uuid")
    private int uuid;
    @Column(name = "userid")
    private String userId;
    @Column(name = "name")
    private String name;
    @Column(name = "age")
    private int age;
 
    public int getUuid() {
        return uuid;
    }
 
    public void setUuid(int uuid) {
        this.uuid = uuid;
    }
 
    public String getUserId() {
        return userId;
    }
 
    public void setUserId(String userId) {
        this.userId = userId;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
}
注意:實體類中的型別應和資料庫中欄位的型別匹配。資料庫中的欄位名稱應儘量避免大寫字母,如果欄位名稱中有大寫字母,會插入或更新失敗,提示欄位不存在。

註解方式不需要再xml檔案中將實體類和資料表進行關聯對映,而是採用在實體類中進行註解。
使用註解時應注意以下幾點:

a、如果實體類屬性名與表字段名不一致的時候,要麼都註解在屬性前,要麼都註解在get方法前。不能部分註解在屬性前,部分註解在方法前。

b、如果實體類屬性名與表字段名一致的時候,可以部分註解在屬性前,部分註解在方法前。

c、如果在實體類中某些屬性不註解:(屬性和get都不寫註解),預設為表字段名與實體類屬性名一致。

d、如果實體類的某個成員屬性不需要存入資料庫中,使用@Transient 進行註解就可以了。(xml方式配置中的某些欄位不寫就是不需要對這個成員屬性進行對映)

e、表名稱可以在實體類前進行註解。

f、所有這些註解在:javax.persistence包下。而不是在hibernate包中。

至此,註解方式對映配置完成。

UserDao.java程式碼如下:


public class UserDao {
    public void saveUser(User user) {
        SessionFactory sessionFactory = new AnnotationConfiguration()
                .configure().buildSessionFactory();
        Session session = null;
        Transaction transaction = null;
 
        try {
            session = sessionFactory.openSession();
            transaction = session.beginTransaction();
            session.save(user);
            transaction.commit();
        } catch (HibernateException e) {
            transaction.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }
    }
}

經測試,可用。
注:In Hibernate 3.6, “org.hibernate.cfg.AnnotationConfiguration” is deprecated, and all its functionality has been moved to “org.hibernate.cfg.Configuration“.So , you can safely replace your “AnnotationConfiguration” with “Configuration” class.


BuildSessionFactory API has been deprecated, and it's easy to do well. you can use StandardServiceRegistryBuilder, because ServiceRegistryBuilder also has been deprecated.

Configuration configuration = new Configuration();
        configuration.configure();
        StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder()
                .applySettings(configuration.getProperties());
        SessionFactory sessionFactory = configuration
                .buildSessionFactory(builder.build());

兩種方式的區別是明顯的,但是如果不注意還是容易忽視,尤其是入門的時候。相比xml的配置方式,註解顯然更適用於大型工程,也更容易使用和管理。另外,註解方式是在hibernate4中引入的,如果在hibernate3中想使用這種方式,需要引入hibernate-annotation包。

參考文章:

http://www.cnblogs.com/xiaoluo501395377/p/3374955.html

附:

Hibernate各種主鍵生成策略與配置詳解    
轉自:http://www.cnblogs.com/kakafra/archive/2012/09/16/2687569.html
1、assigned
主鍵由外部程式負責生成,在 save() 之前必須指定一個。Hibernate不負責維護主鍵生成。與Hibernate和底層資料庫都無關,可以跨資料庫。在儲存物件前,必須要使用主鍵的setter方法給主鍵賦值,至於這個值怎麼生成,完全由自己決定,這種方法應該儘量避免。

<id name="id" column="id">

<generator class="assigned" />

</id>

“ud”是自定義的策略名,人為起的名字,後面均用“ud”表示。

特點:可以跨資料庫,人為控制主鍵生成,應儘量避免。

2、increment
由Hibernate從資料庫中取出主鍵的最大值(每個session只取1次),以該值為基礎,每次增量為1,在記憶體中生成主鍵,不依賴於底層的資料庫,因此可以跨資料庫。

<id name="id" column="id">

<generator class="increment" />

</id>

Hibernate呼叫org.hibernate.id.IncrementGenerator類裡面的generate()方法,使用select max(idColumnName) from tableName語句獲取主鍵最大值。該方法被宣告成了synchronized,所以在一個獨立的Java虛擬機器內部是沒有問題的,然而,在多個JVM同時併發訪問資料庫select max時就可能取出相同的值,再insert就會發生Dumplicate entry的錯誤。所以只能有一個Hibernate應用程序訪問資料庫,否則就可能產生主鍵衝突,所以不適合多程序併發更新資料庫,適合單一程序訪問資料庫,不能用於群集環境。

官方文件:只有在沒有其他程序往同一張表中插入資料時才能使用,在叢集下不要使用。

特點:跨資料庫,不適合多程序併發更新資料庫,適合單一程序訪問資料庫,不能用於群集環境。

3、hilo
hilo(高低位方式high low)是hibernate中最常用的一種生成方式,需要一張額外的表儲存hi的值。儲存hi值的表至少有一條記錄(只與第一條記錄有關),否則會出現錯誤。可以跨資料庫。

<id name="id" column="id">

<generator class="hilo">

<param name="table">hibernate_hilo</param>

<param name="column">next_hi</param>

<param name="max_lo">100</param>

</generator>

</id>

<param name="table">hibernate_hilo</param> 指定儲存hi值的表名

<param name="column">next_hi</param> 指定儲存hi值的列名

<param name="max_lo">100</param> 指定低位的最大值

也可以省略table和column配置,其預設的表為hibernate_unique_key,列為next_hi

<id name="id" column="id">

<generator class="hilo">

<param name="max_lo">100</param>

</generator>

</id>

hilo生成器生成主鍵的過程(以hibernate_unique_key表,next_hi列為例):

1. 獲得hi值:讀取並記錄資料庫的hibernate_unique_key表中next_hi欄位的值,資料庫中此欄位值加1儲存。

2. 獲得lo值:從0到max_lo迴圈取值,差值為1,當值為max_lo值時,重新獲取hi值,然後lo值繼續從0到max_lo迴圈。

3. 根據公式 hi * (max_lo + 1) + lo計算生成主鍵值。

注意:當hi值是0的時候,那麼第一個值不是0*(max_lo+1)+0=0,而是lo跳過0從1開始,直接是1、2、3……

那max_lo配置多大合適呢?

這要根據具體情況而定,如果系統一般不重啟,而且需要用此表建立大量的主鍵,可以吧max_lo配置大一點,這樣可以減少讀取資料表的次數,提高效率;反之,如果伺服器經常重啟,可以吧max_lo配置小一點,可以避免每次重啟主鍵之間的間隔太大,造成主鍵值主鍵不連貫。

特點:跨資料庫,hilo演算法生成的標誌只能在一個數據庫中保證唯一。

4、seqhilo
與hilo類似,通過hi/lo演算法實現的主鍵生成機制,只是將hilo中的資料表換成了序列sequence,需要資料庫中先建立sequence,適用於支援sequence的資料庫,如Oracle。

<id name="id" column="id">

<generator class="seqhilo">

<param name="sequence">hibernate_seq</param>

<param name="max_lo">100</param>

</generator>

</id>

特點:與hilo類似,只能在支援序列的資料庫中使用。
5、sequence
採用資料庫提供的sequence機制生成主鍵,需要資料庫支援sequence。如oralce、DB、SAP DB、PostgerSQL、McKoi中的sequence。MySQL這種不支援sequence的資料庫則不行(可以使用identity)。

<generator class="sequence">

<param name="sequence">hibernate_id</param>

</generator>

<param name="sequence">hibernate_id</param> 指定sequence的名稱

Hibernate生成主鍵時,查詢sequence並賦給主鍵值,主鍵值由資料庫生成,Hibernate不負責維護,使用時必須先建立一個sequence,如果不指定sequence名稱,則使用Hibernate預設的sequence,名稱為hibernate_sequence,前提要在資料庫中建立該sequence。

特點:只能在支援序列的資料庫中使用,如Oracle。

6、identity
identity由底層資料庫生成識別符號。identity是由資料庫自己生成的,但這個主鍵必須設定為自增長,使用identity的前提條件是底層資料庫支援自動增長欄位型別,如DB2、SQL Server、MySQL、Sybase和HypersonicSQL等,Oracle這類沒有自增欄位的則不支援。

<id name="id" column="id">

<generator class="identity" />

</id>

例:如果使用MySQL資料庫,則主鍵欄位必須設定成auto_increment。

id int(11) primary key auto_increment

特點:只能用在支援自動增長的欄位資料庫中使用,如MySQL。

7、native
native由hibernate根據使用的資料庫自行判斷採用identity、hilo、sequence其中一種作為主鍵生成方式,靈活性很強。如果能支援identity則使用identity,如果支援sequence則使用sequence。

<id name="id" column="id">

<generator class="native" />

</id>

例如MySQL使用identity,Oracle使用sequence

注意:如果Hibernate自動選擇sequence或者hilo,則所有的表的主鍵都會從Hibernate預設的sequence或hilo表中取。並且,有的資料庫對於預設情況主鍵生成測試的支援,效率並不是很高。

使用sequence或hilo時,可以加入引數,指定sequence名稱或hi值表名稱等,如

<param name="sequence">hibernate_id</param>

特點:根據資料庫自動選擇,專案中如果用到多個數據庫時,可以使用這種方式,使用時需要設定表的自增欄位或建立序列,建立表等。

8、uuid
UUID:Universally Unique Identifier,是指在一臺機器上生成的數字,它保證對在同一時空中的所有機器都是唯一的。按照開放軟體基金會(OSF)制定的標準計算,用到了乙太網卡地址、納秒級時間、晶片ID碼和許多可能的數字,標準的UUID格式為:

xxxxxxxx-xxxx-xxxx-xxxxxx-xxxxxxxxxx (8-4-4-4-12)

其中每個 x 是 0-9 或 a-f 範圍內的一個十六進位制的數字。

<id name="id" column="id">

<generator class="uuid" />

</id>

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

特點:uuid長度大,佔用空間大,跨資料庫,不用訪問資料庫就生成主鍵值,所以效率高且能保證唯一性,移植非常方便,推薦使用。

9、guid
GUID:Globally Unique Identifier全球唯一識別符號,也稱作 UUID,是一個128位長的數字,用16進製表示。演算法的核心思想是結合機器的網絡卡、當地時間、一個隨即數來生成GUID。從理論上講,如果一臺機器每秒產生10000000個GUID,則可以保證(概率意義上)3240年不重複。

<id name="id" column="id">

<generator class="guid" />

</id>

Hibernate在維護主鍵時,先查詢資料庫,獲得一個uuid字串,該字串就是主鍵值,該值唯一,缺點長度較大,支援資料庫有限,優點同uuid,跨資料庫,但是仍然需要訪問資料庫。

注意:長度因資料庫不同而不同

MySQL中使用select uuid()語句獲得的為36位(包含標準格式的“-”)

Oracle中,使用select rawtohex(sys_guid()) from dual語句獲得的為32位(不包含“-”) 

特點:需要資料庫支援查詢uuid,生成時需要查詢資料庫,效率沒有uuid高,推薦使用uuid。

10、foreign
使用另外一個相關聯的物件的主鍵作為該物件主鍵。主要用於一對一關係中。

<id name="id" column="id">

<generator class="foreign">

<param name="property">user</param>

</generator>

</id>

<one-to-one name="user" class="domain.User" constrained="true" />

該例使用domain.User的主鍵作為本類對映的主鍵。

特點:很少使用,大多用在一對一關係中。

11、select
使用觸發器生成主鍵,主要用於早期的資料庫主鍵生成機制,能用到的地方非常少。

12、其他註釋方式配置
註釋方式與配置檔案底層實現方式相同,只是配置的方式換成了註釋方式

自動增長,適用於支援自增欄位的資料庫

@Id

@GeneratedValue(strategy = GenerationType.IDENTITY)

根據底層資料庫自動選擇方式,需要底層資料庫的設定

如MySQL,會使用自增欄位,需要將主鍵設定成auto_increment。

@Id

@GeneratedValue(strategy = GenerationType.AUTO)

使用表儲存生成的主鍵,可以跨資料庫。

每次需要主鍵值時,查詢名為"hibernate_table"的表,查詢主鍵列"gen_pk"值為"2"記錄,得到這條記錄的"gen_val"值,根據這個值,和allocationSize的值生成主鍵值。

@Id

@GeneratedValue(strategy = GenerationType.TABLE, generator = "ud")

@TableGenerator(name = "ud",

table = "hibernate_table",

pkColumnName = "gen_pk",

pkColumnValue = "2",

valueColumnName = "gen_val",

initialValue = 2,

allocationSize = 5)

使用序列儲存主鍵值

@Id

@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ud")

@SequenceGenerator(name = "ud",

sequenceName = "hibernate_seq",

allocationSize = 1,

initialValue = 2)

13、小結
1、為了保證物件識別符號的唯一性與不可變性,應該讓Hibernate來為主鍵賦值,而不是程式。

2、正常使用Hibernate維護主鍵,最好將主鍵的setter方法設定成private,從而避免人為或程式修改主鍵,而使用assigned方式,就不能用private,否則無法給主鍵賦值。

2、Hibernate中唯一一種最簡單通用的主鍵生成器就是uuid。雖然是個32位難讀的長字串,但是它沒有跨資料庫的問題,將來切換資料庫極其簡單方便,推薦使用!

3、自動增長欄位型別與序列

資料庫

自動增長欄位

序列

MySQL

 
Oracle

     

DB2

MS SQL Server

 
Sybase

 
HypersonicSQL

 
PostgreSQL

     

SAP DB

     

HSQLDB

 
Infomix

 
4、關於hilo機制注意:

hilo演算法生成的標誌只能在一個數據庫中保證唯一。

當用戶為Hibernate自行提供連線,或者Hibernate通過JTA,從應用伺服器的資料來源獲取資料庫連線時,無法使用hilo,因為這不能保證hilo單獨在新的資料庫連線的事務中訪問hi值表,這種情況,如果資料庫支援序列,可以使用seqhilo。

5、使用identity、native、GenerationType.AUTO等方式生成主鍵時,只要用到自增欄位,資料庫表的欄位必須設定成自動增加的,否則出錯。

6、還有一些方法未列出來,例如uuid.hex,sequence-identity等,這些方法不是很常用,且已被其他方法代替,如uuid.hex,官方文件裡建議不使用,而直接使用uuid方法。

7、Hibernate的各版本主鍵生成策略配置有略微差別,但實現基本相同。如,有的版本預設sequence不指定序列名,則使用名為hibernate_sequence的序列,有的版本則必須指定序列名。

8、還可以自定義主鍵生成策略,這裡暫時不討論,只討論官方自帶生成策略。
--------------------- 
作者:銅和尚 
來源:CSDN 
原文:https://blog.csdn.net/yunshixin/article/details/52856564?utm_source=copy 
版權宣告:本文為博主原創文章,轉載請附上博文連結!