小编典典

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

jsp

我在spring版本3.0.2中使用了Hibernate Tools3.2.1.GA。我正在尝试按以下方式将最后插入的行的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:此类的ID必须在调用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
/

阅读 221

收藏
2020-06-08

共1个答案

小编典典

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

Assign 允许应用程序在调用save()之前为该对象分配一个标识符。如果未指定任何元素,则这是默认策略。

如果您未定义任何策略,则hibernate默认为“已分配”。“分配”策略意味着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递增两次。

您可以通过以下三种方法解决此问题。

  1. 删除触发器,因为它不是必需的。

  2. 如果由于可以在应用程序外部更新表而仍需要触发器,则可以更新触发器,以便仅当在Oracle触发器的插入语句HIbernate问题中未设置 ID来从序列生成ID时,才生成ID。

  3. 创建一个自定义id生成器,该生成器使用触发器在将数据保存到db之前设置其ID。查看以下链接-https://forum.hibernate.org/viewtopic.php?t=973262

2020-06-08