无法使用Oracle检索Hibernate中最后插入的行的标识 [英] Cannot retrieve the id of the last inserted row in Hibernate using Oracle

查看:119
本文介绍了无法使用Oracle检索Hibernate中最后插入的行的标识的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用Spring版本3.0.2的Hibernate Tools 3.2.1.GA。我试图按照如下方式将最后插入的行的id检索到Oracle(10g)数据库。

 会话会话= 。NewHibernateUtil.getSessionFactory()的getCurrentSession(); 
session.beginTransaction();

国家c =新国家();

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
必须在调用save()之前手动赋值:model.Country


这个语句 c.setCountryId(new BigDecimal(0));插入过程中确实需要这是Oracle数据库中生成的主键的序列,由于该行,此语句 System.out.println(c.getCountryId()); 总是返回 0 这实际上预计会返回当前会话中当前插入的id。



那么,怎样才能得到最后生成的id在这种情况下?我是否错误地使用了一种方法?是否有其他方法?




编辑:

  CREATE TABLECOUNTRY

COUNTRY_IDNUMBER(35,0)NOT NULL ENABLE,
COUNTRY_CODEVARCHAR2(10),
COUNTRY_NAMEVARCHAR2(50),
ZONE_IDNUMBER(35,0),

CONSTRAINTCOUNTRY_PKPRIMARY KEY(COUNTRY_ID)ENABLE,
CONSTRAINTCOUNTRY_FKFOREIGN KEY(ZONE_ID)
REFERENCEZONE(ZONE_ID)ON DELETE CASCADE ENABLE

/

在插入COUNTRY之前创建或替换TRIGGERBI_COUNTRY

为每行

begin
选择COUNTRY_SEQ。 nextval:来自dual的NEW.COUNTRY_ID;
end;

/
ALTER TRIGGERBI_COUNTRYENABLE
/


解决方案

在调用save()之前,必须手动分配此类的ids,意味着您正在使用标识符生成策略'Assigned'。
$ b


赋予
让应用程序在调用save()之前为对象分配一个标识符。如果没有指定任何元素,这是默认策略。


如果您没有定义任何策略,hibernate默认为'assigned'。 'assigned'策略意味着hibernate期望应用程序提供自己的id。



如果您想在Oracle中使用序列标识生成器,可以使用以下命令配置 -



如果您使用xml -

 < id name =countryIdtype =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)
私有整数序列;

你的代码看起来像这样 -

  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对象中。

 从dual中选择Country_Id_Seq.nextVal; 

触发问题



由于在插入行时使用触发器来增加id,这会导致休眠序列出现问题。 Hibernate使用序列来生成一个id,数据库使用触发器来增加id。这导致id被递增两次。

您有三个选项来解决这个问题。


  1. 删除触发器,因为它不是必需的。如果您仍然需要触发器,因为表可以在应用程序之外更新,您可以更新触发器,以便仅在id为未在插入语句中设置
    使用Oracle Trigger从序列中生成id的HIbernate问题

  2. 使用触发器在数据中设置id之前,创建一个自定义id生成器它被保存到数据库。看看下面的链接 - https://forum.hibernate.org/viewtopic.php? t = 973262


I'm using Hibernate Tools 3.2.1.GA with the Spring version 3.0.2. I'm trying to retrieve the id of the last inserted row into the Oracle(10g) database as follows.

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();       

This statement System.out.println(c.getCountryId()); is expected to return the currently inserted id after the data is serialized to the database and before the transaction is committed but it doesn't because of the following line in the preceding code snippet (as it presumably appears to me).

c.setCountryId(new BigDecimal(0));

I'm not sure why this statement is required in my case (while inserting). I saw this statement nowhere. Omission of this line causes the following exception to be thrown.

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

Is this statement c.setCountryId(new BigDecimal(0)); really required during insertion? It's a sequence generated primary key in the Oracle database and because of that line, this statement System.out.println(c.getCountryId()); always returns 0 which is actually expected to return the currently inserted id in the current session.

So, how can I get the last generated id in this case? Am I following a wrong way, is there a different way?


EDIT:

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
/ 

解决方案

The exception 'ids for this class must be manually assigned before calling save()' means that you are using the identifier generation strategy of 'Assigned'.

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

If you do not define any strategy, hibernate defaults to 'assigned'. 'assigned' strategy implies that hibernate expects that the application supplies it's own ids.

If you want to use a sequence id generator in Oracle, you can do so with the following configuration -

If you are using xml -

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

If you are using annotations -

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

And your code should look like so -

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()); 

When 'session.save(c)' executes, hibernate makes the following sql call to Oracle, retrieves the id and sets it in Country object.

select Country_Id_Seq.nextVal from dual;

Problem with trigger

Since you are using a trigger to increment the id when a row is inserted, this will cause a problem with hibernate sequence. Hibernate is using the sequence to generate an id and the database is using the trigger to increment the id. This is resulting in the id being incremented twice.

You have a three options to resolve this.

  1. Delete the trigger because it's not necessary.

  2. If you still need the trigger because the table could be updated outside the application, you could update the trigger such that the id is generated only if the id is not set in the insert statement HIbernate issue with Oracle Trigger for generating id from a sequence

  3. Create a custom id generator that uses the trigger to set the id in the data before it is saved to db. Check out the following link - https://forum.hibernate.org/viewtopic.php?t=973262

这篇关于无法使用Oracle检索Hibernate中最后插入的行的标识的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆