无法使用Oracle检索Hibernate中最后插入的行的ID

我正在使用Hibernate Tools 3.2.1.GA和Spring 3.0.2版.我正在尝试将最后插入的行的id检索到Oracle(10g)数据库中,如下所示.

Session session=NewHibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();

Country c=new Country();

c.setCountryId(new BigDecimal(0));
c.setCountryName(request.getParameter("txtCountryName"));
c.setCountryCode(request.getParameter("txtCountryCode"));
Zone z=(Zone) session.get(Zone.class, new BigDecimal(request.getParameter("zoneId")));
c.setZone(z);
session.save(c);

session.flush();    
System.out.println(c.getCountryId());    
session.getTransaction().commit();       

此语句System.out.println(c.getCountryId());在将数据序列化到数据库之后并且在提交事务之前,期望返回当前插入的id,但是由于前面的代码片段中的以下行(因为它可能在我看来),它不会返回.

c.setCountryId(new BigDecimal(0));

我不确定为什么在我的情况下(插入时)需要这个语句.我没看到这句话.省略此行会导致抛出以下异常.

org.hibernate.id.IdentifierGenerationException: ids for this class
must be manually assigned before calling save(): model.Country

这个语句是c.setCountryId(new BigDecimal(0));插入时真的需要吗?它是Oracle数据库中序列生成的主键,由于该行,此语句为System.out.println(c.getCountryId());始终返回0,实际上预期返回当前会话中当前插入的id.

那么,在这种情况下,如何获取最后生成的id?我是否采取了错误的方式,是否有不同的方式?

编辑:

CREATE TABLE  "COUNTRY" 
(   
    "COUNTRY_ID" NUMBER(35,0) NOT NULL ENABLE, 
    "COUNTRY_CODE" VARCHAR2(10), 
    "COUNTRY_NAME" VARCHAR2(50), 
    "ZONE_ID" NUMBER(35,0), 

    CONSTRAINT "COUNTRY_PK" PRIMARY KEY ("COUNTRY_ID") ENABLE, 
    CONSTRAINT "COUNTRY_FK" FOREIGN KEY ("ZONE_ID")
                            REFERENCES  "ZONE" ("ZONE_ID") ON DELETE CASCADE ENABLE
)
/

CREATE OR REPLACE TRIGGER  "BI_COUNTRY" 
before insert on "COUNTRY"               
for each row  

begin   
    select "COUNTRY_SEQ".nextval into :NEW.COUNTRY_ID from dual; 
end; 

/
ALTER TRIGGER  "BI_COUNTRY" ENABLE
/ 

解决方法:

在调用save()之前必须手动分配此类的异常ID,这意味着您正在使用“已分配”的标识符生成策略.

assigned
lets the application assign an identifier to the object before save() is called. This is the default strategy if no element is specified.

如果您没有定义任何策略,则hibernate默认为“已分配”. ‘assigned’策略意味着hibernate期望应用程序提供它自己的id.

如果要在Oracle中使用序列ID生成器,可以使用以下配置执行此操作 –

如果您使用的是xml –

   <id name="countryId" type="java.lang.Integer">  
        <column name="Country_Id" />  
        <generator class="sequence">  
            <param name="sequence">Country_Id_Seq</param>               
        </generator>  
    </id>

如果您使用注释 –

   @Id
   @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="Country_Id_Seq")
   @SequenceGenerator(name="Country_Id_Seq", sequenceName="Country_Id_Seq"  )
   private Integer sequence;

你的代码看起来应该是这样的 –

Country c=new Country();

c.setCountryName(request.getParameter("txtCountryName"));
c.setCountryCode(request.getParameter("txtCountryCode"));
Zone z=(Zone) session.get(Zone.class, new BigDecimal(request.getParameter("zoneId")));
c.setZone(z);
session.save(c);

session.flush();    
System.out.println(c.getCountryId()); 

当’session.save(c)’执行时,hibernate对Oracle进行以下sql调用,检索id并在Country对象中设置它.

select Country_Id_Seq.nextVal from dual;

触发问题

由于在插入行时使用触发器来增加id,因此会导致hibernate序列出现问题. Hibernate使用序列生成id,数据库正在使用触发器来增加id.这导致id递增两次.

您有三个选项可以解决此问题.

>删除触发器,因为没有必要.
>如果仍然需要触发器,因为表可以在应用程序外部更新,则可以更新触发器,以便仅在insert语句中未设置id时生成id
HIbernate issue with Oracle Trigger for generating id from a sequence
>创建一个自定义ID生成器,该生成器使用触发器在数据保存到db之前设置数据中的id.请查看以下链接 – https://forum.hibernate.org/viewtopic.php?t=973262

上一篇:mysql-如何获取表的列名称为Null?


下一篇:数据库备份问题总结