我使用休眠工具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这个类必须调用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
/
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.
Delete the trigger because it's not necessary.
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
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
如果一个序列生成的值到一个ID列,那么你应该该序列与在实体定义你的ID列,这样的属性与插入过程中由Hibernate的ID值填入相关联。
使用说明:
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CountryIdSequence")
@SequenceGenerator(name = "CountryIdSequence", sequenceName = "COUNTRY_ID_SEQUENCE")
@Column(name = "COUNTRY_ID")
private BigDecimal countryId;
使用HBM:
<id name="countryId" type="big_decimal">
<column name="COUNTRY_ID" />
<generator class=""sequence">
<param name="sequence">COUNTRY_ID_SEQUENCE</param>
</generator>
</id>
然后,将可以保存了。
在数据库层对实体所做的任何修改,直到您刷新对象不会反映在休眠实体层。
session.save(c);
session.flush();
// Refresh the object for columns modified in the DB by IDENTITY / SEQUENCE / Triggers.
session.refresh(c);
System.out.println(c.getCountryId());