java 如何对非 ID 字段使用序列生成器?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12495399/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use a sequence generator for a non ID field?
提问by B. TIger
public class SequenceControlNumber extends SequenceGenerator {
private static final Logger log =
LoggerFactory.getLogger(SequenceGenerator.class);
@Override
public Serializable generate(SessionImplementor session, Object obj) {
Connection connection = session.connection();
try {
PreparedStatement st = connection.prepareStatement
("SELECT nextval ('sequencecontrolnumber') as nextval");
try {
ResultSet rs = st.executeQuery();
try {
rs.next();
int currentVall = rs.getInt("sequencecontrolnumber");
int result = 0;
if(currentVall <255){
result = currentVall +1;
}
if ( log.isDebugEnabled() ) {
log.debug("Sequence identifier generated: " + result);
}
return result;
}
finally {
rs.close();
}
}
finally {
session.getBatcher().closeStatement(st);
}
}
catch (SQLException sqle) {
throw JDBCExceptionHelper.convert(
session.getFactory().getSQLExceptionConverter(),
sqle,"could not get next sequence value");
}
}
}
In my model class this is my annotation:
在我的模型类中,这是我的注释:
@GenericGenerator(name="seq_id",
strategy="br.com.otgmobile.service.dao.SequenceControlNumber")
@GeneratedValue(generator="seq_id")
@Column(name="sequencecontrolnumber",unique=false, nullable=false)
private Integer sequenceControlNumber;
but I keep getting a a property value exception.
但我不断收到属性值异常。
javax.persistence.PersistenceException: org.hibernate.PropertyValueException: not-null property references a null or transient value: br.com.otgmobile.model.niagarahw06.ComandoNiagaraHw06.sequenceControlNumber
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1179)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1112)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1118)
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:618)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
at $Proxy33.persist(Unknown Source)
at br.com.otgmobile.service.dao.ComandoNiagaraHw06DAO.add(ComandoNiagaraHw06DAO.java:57)
at br.com.otgmobile.service.dao.ComandoNiagaraHw06DAO$$FastClassByCGLIB$$e19cf51d.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:149)
at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:689)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:90)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622)
at br.com.otgmobile.service.dao.ComandoNiagaraHw06DAO$$EnhancerByCGLIB$ccb4e4.add(<generated>)
at br.com.otgmobile.server.NiagaraSocketManager.testPersistComandos(NiagaraSocketManager.java:100)
at br.com.otgmobile.server.NiagaraSocketManager.start(NiagaraSocketManager.java:45)
at br.com.otgmobile.server.NiagaraDaemon.run(NiagaraDaemon.java:25)
at java.lang.Thread.run(Thread.java:722)
Caused by: org.hibernate.PropertyValueException: not-null property references a null or transient value: br.com.otgmobile.model.niagarahw06.ComandoNiagaraHw06.sequenceControlNumber
at org.hibernate.engine.Nullability.checkNullability(Nullability.java:101)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:313)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:144)
at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:69)
at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:179)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:135)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:61)
at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:800)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:774)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:778)
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:612)
采纳答案by Stephan
Check the value of result
returned from the generate method in SequenceControlNumber
class.
检查类中result
生成方法返回的值SequenceControlNumber
。
BTW check this response in this SO question : Hibernate JPA Sequence (non-Id)
顺便说一下,在这个 SO 问题中检查这个响应:Hibernate JPA Sequence (non-Id)
回答by Jeff
The @GeneratedValue
annotation is not something that Hibernate will process as part of a column's information. It has to be used in conjunction with the @Id
annotation. It just says how the id is generated when there is an id.
该@GeneratedValue
注释是不是东西,Hibernate会处理作为列的信息的一部分。它必须与@Id
注释结合使用。它只是说当有id时如何生成id。
You have a few options to accomplish what you want, but none of them are really as elegant as just using an annotation like you've written. These suggestions have their pros and cons (database portability, complexity, entity manager vs. session, etc.) but some ideas are:
您有几个选项可以完成您想要的操作,但没有一个选项能像您编写的那样使用注释那样优雅。这些建议各有利弊(数据库可移植性、复杂性、实体管理器与会话等),但一些想法是:
- Implement a PreInsertListener and add it to your
AnnotationConfiguration
. This listener would look for the type of entity that needed this functionality and would get/assign the next sequence value - Make a database trigger to handle populating the column with a sequence value. Mark the column in your Java code as
insertable = false, updatable = false
- Put your generate logic into a callback method in your entity and mark it with a @PrePersist annotation
- Populate the field as part of the constructor (not preferred since then you have a DB call in a constructor and some potential transaction boundary ambiguity)
- 实现 PreInsertListener 并将其添加到您的
AnnotationConfiguration
. 此侦听器将查找需要此功能的实体类型,并获取/分配下一个序列值 - 制作一个数据库触发器来处理用序列值填充列。将 Java 代码中的列标记为
insertable = false, updatable = false
- 将您的生成逻辑放入实体中的回调方法中,并使用 @PrePersist 批注对其进行标记
- 将字段填充为构造函数的一部分(不首选,因为您在构造函数中有一个 DB 调用和一些潜在的事务边界歧义)
回答by Alex
I just faced a similar issue where I needed to create and attach a sequence to a field which is not a primary key.
我刚刚遇到了一个类似的问题,我需要创建一个序列并将其附加到一个不是主键的字段。
I was struggling trying to use @GeneratedValue
and @SequenceGenerator
annotations, because as stated on the Web : @GeneratedValue
can only be used along an @Id annotation on an Hibernate entity field.
This, tells Hibernate not to care about the field being null, it will be managed at insertion time into the database. But here Hibernate was always throwing Exception because the GeneratedValue was ignored on the field.
我正在努力尝试使用@GeneratedValue
和@SequenceGenerator
注释,因为如 Web 上所述:@GeneratedValue
只能与 Hibernate 实体字段上的 @Id 注释一起使用。这告诉 Hibernate 不要关心该字段是否为空,它将在插入数据库时进行管理。但是这里 Hibernate 总是抛出异常,因为该字段中的 GeneratedValue 被忽略了。
So the solution is simple : Just replace this annotation by @Generated(GenerationTime.INSERT)
and add columnDefinition = "serial"
into your @Column(name = "huhu", columnDefinition = "serial", updatable = false, ...)
所以解决方案很简单:只需替换此注释@Generated(GenerationTime.INSERT)
并将其添加columnDefinition = "serial"
到您的@Column(name = "huhu", columnDefinition = "serial", updatable = false, ...)
Normally it should now work, if you have created the correct sequence attached to the field in the database in the first place.
通常,如果您首先创建了附加到数据库字段的正确序列,它现在应该可以工作了。