在Hibernate中實(shí)現(xiàn)Oracle的自動(dòng)增長(zhǎng)
根據(jù)hibernate的文檔,有兩種方式實(shí)現(xiàn)實(shí)體對(duì)象的主鍵自動(dòng)增長(zhǎng)。
***種:設(shè)置ID的增長(zhǎng)策略是sequence,同時(shí)指定sequence的名字,***每個(gè)表建一個(gè)sequence,此種做法就如同MS-SQL,MY-SQL中的自動(dòng)增長(zhǎng)一樣,不需要?jiǎng)?chuàng)建觸發(fā)器,具體的oracle數(shù)據(jù)庫(kù)腳本及hibernate配置文件如下:
[1]oracle數(shù)據(jù)表的創(chuàng)建腳本:
- CREATE TABLE DEPARTMENT (
- ID NUMBER(19,0) DEFAULT '0' NOT NULL,
- NAME VARCHAR2(255) NOT NULL,
- DESCRIPTION CLOB
- );
- ALTER TABLE DEPARTMENT ADD CONSTRAINT PRIMARY_0 PRIMARY KEY(ID) ENABLE;
- ALTER TABLE DEPARTMENT ADD CONSTRAINT UK_DEPARTMENT_1 UNIQUE (NAME);
- CREATE SEQUENCE DEPARTMENT_ID_SEQ MINVALUE 10000 MAXVALUE 999999999999999999999999 INCREMENT BY 1 NOCYCLE;
創(chuàng)建DEPARTMENT表,并為DEPARTMENT表創(chuàng)建一個(gè)單獨(dú)的SEQUENCE,名字為SEQUENCE_ID_SEQ,并不需要?jiǎng)?chuàng)建觸發(fā)器。
[2]hibernate映射文件的配置:
- < ?xml version="1.0"?>
- < !DOCTYPE hibernate-mapping PUBLIC
- "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- < hibernate-mapping package="com.liyanframework.demo.domain">
- < class name="Department" table="DEPARTMENT">
- < id name="id" column="ID">
- < generator class="sequence">
- < param name="sequence">DEPARTMENT_ID_SEQ< /param>
- < /generator>
- < /id>
- < property name="name" column="NAME" type="string" />
- < property name="description" column="DESCRIPTION" type="text" />
- < /class>
- < /hibernate-mapping>
在hibernate映射文件中,對(duì)ID的生成策略選擇sequence,指定sequence的名字DEPARTMENT_ID_SEQ就可以了,當(dāng)你保存新對(duì)象的時(shí)候,hibernate會(huì)自動(dòng)取得DEPARTMENT_ID_SEQ.NEXTVAL作為新對(duì)象的ID保存到數(shù)據(jù)庫(kù),所以不需要再使用觸發(fā)器再來(lái)生成新記錄的ID。
第二種:設(shè)置ID的增長(zhǎng)策略是native,但是需要?jiǎng)?chuàng)建一個(gè)名字為hibernate_sequence(這個(gè)名字好像是hibernate默認(rèn)的 sequence名字,不創(chuàng)建會(huì)出錯(cuò)的)的全局使用的sequence,然后再對(duì)每一個(gè)表的ID生成的時(shí)候,使用觸發(fā)器,取得 hibernate_sequence.CURRVAL作為新記錄的ID,具體的oracle數(shù)據(jù)庫(kù)腳本及hibernate配置文件如下:
[1]oracle數(shù)據(jù)表的創(chuàng)建腳本:
- CREATE TABLE STAFF (
- ID NUMBER(19,0) DEFAULT '0' NOT NULL,
- NAME VARCHAR2(255) NOT NULL,
- AGE NUMBER(3,0) NOT NULL,
- BIRTHDAY DATE NOT NULL,
- SALARY NUMBER(10,2) NOT NULL,
- LEVELNESS FLOAT NOT NULL,
- CREATETIME TIMESTAMP NOT NULL,
- ENABLE CHAR(2) DEFAULT 'Y' NOT NULL,
- STATUS VARCHAR2(64) NOT NULL,
- DEPARTMENT_ID NUMBER(19,0)
- );
- ALTER TABLE STAFF ADD CONSTRAINT PRIMARY_1 PRIMARY KEY(ID) ENABLE;
- ALTER TABLE STAFF ADD CONSTRAINT STAFF_IBFK_0 FOREIGN KEY(DEPARTMENT_ID) REFERENCES DEPARTMENT(ID) ENABLE;
- ALTER TABLE STAFF ADD CONSTRAINT UK_STAFF_1 UNIQUE (NAME);
- CREATE INDEX IDX_STAFF_STATUS ON STAFF(STATUS);
- CREATE SEQUENCE HIBERNATE_SEQUENCE MINVALUE 90000 MAXVALUE 999999999999999999999999 INCREMENT BY 1 NOCYCLE;
- CREATE OR REPLACE TRIGGER STAFF_ID_TRG BEFORE INSERT ON STAFF
- FOR EACH ROW
- BEGIN
- IF INSERTING AND :NEW.ID IS NULL THEN
- SELECT HIBERNATE_SEQUENCE.CURRVAL INTO :NEW.ID FROM DUAL;
- END IF;
- END;
創(chuàng)建STAFF表,但是并沒(méi)有為STAFF創(chuàng)建相應(yīng)的主鍵sequence,而是創(chuàng)建了一個(gè)名字為HIBERNATE_SEQUENCE的 sequence,然后創(chuàng)建一個(gè)觸發(fā)器STAFF_ID_TRG,當(dāng)執(zhí)行INSERT操作時(shí),hibernate會(huì)先執(zhí)行一次 HIBERNATE_SEQUENCE.NEXTVAL,所以在觸發(fā)器中只需要取得HIBERNATE_SEQUENCE.CURRVAL作為新記錄的 ID。
[2]hibernate映射文件的配置:
- < ?xml version="1.0"?>
- < !DOCTYPE hibernate-mapping PUBLIC
- "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- < hibernate-mapping package="com.liyanframework.demo.domain">
- < class name="Staff" table="STAFF">
- < id name="id" column="ID">
- < generator class="native" />
- < /id>
- < property name="name" column="NAME" type="string" />
- < property name="age" column="AGE" type="integer" />
- < property name="birthday" column="BIRTHDAY" type="date" />
- < property name="salary" column="SALARY" type="big_decimal" />
- < property name="level" column="LEVELNESS" type="float" />
- < property name="createTime" column="CREATETIME" type="timestamp" />
- < property name="enable" column="ENABLE" type="character" />
- < property name="status" column="STATUS" type="string" />
- < many-to-one name="department" column="DEPARTMENT_ID" class="Department" />
- < /class>
- < /hibernate-mapping>
在hibernate映射文件中,對(duì)ID的生成策略選擇native,hibernate會(huì)根據(jù)你數(shù)據(jù)庫(kù)的觸發(fā)器來(lái)生成新記錄的ID。
比較兩種做法,第二種做法也就是hibernate在代碼中,實(shí)現(xiàn)了oracle中的觸發(fā)器功能。對(duì)于不同的情況,選擇不懂的做法。如果新的系統(tǒng),新建的 oracle數(shù)據(jù)庫(kù),推薦使用***種做法,簡(jiǎn)單,容易移植到其他支持自動(dòng)增長(zhǎng)的數(shù)據(jù)庫(kù);如果是老的系統(tǒng),需要把其他數(shù)據(jù)庫(kù)轉(zhuǎn)換為oracle的,那就要用第二種了,使用native的方式,可以不改動(dòng)配置文件,兼容oracle和mysql之類(lèi)帶有自動(dòng)增長(zhǎng)的數(shù)據(jù)庫(kù)。
安裝有oracle數(shù)據(jù)庫(kù),創(chuàng)建數(shù)據(jù)庫(kù),總是要?jiǎng)?chuàng)建一個(gè)主鍵ID,唯一標(biāo)示各條記錄,但oracle不支持自動(dòng)編號(hào),所以還得創(chuàng)建一個(gè)SEQUENCE(序列)語(yǔ)句如
create sequence bign nocycle maxvalue 9999999999 start with1;//增加數(shù)據(jù)
insertintotable (ID,..) values(bign.nextval,..)
在hibernate中的映射文件可這么寫(xiě)
- < id name="id" type="java.lang.Long" column="ID">
- < generator class="sequence">
- < param name="sequence">bign< /param>
- < /generator>
- < /id>
或
- < id name="id" type="java.lang.Long" column="ID">
- < generator class="increment">
- < /id>
(increment 用與為long,short或者int類(lèi)型生成唯一標(biāo)示。只有在沒(méi)有其他進(jìn)程忘同一張表中插入數(shù)據(jù)時(shí)才能使用。在集群下不要使用)