如何将序列生成器用于非ID字段?

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"); } } } 

在我的模型类中,这是我的注释:

 @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; 

但我一直得到一个属性值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() 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$$69ccb4e4.add() 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) 

检查SequenceControlNumber类中generate方法返回的result值。

BTW在这个SO问题中检查这个响应: Hibernate JPA Sequence(non-Id)

@GeneratedValue注释不是Hibernate将作为列信息的一部分处理的东西。 它必须与@Id注释一起使用。 它只是说当id有id时如何生成id。

你有几个选项可以完成你想要的东西,但是它们都没有像你所写的那样使用注释那么优雅。 这些建议有其优点和缺点(数据库可移植性,复杂性,实体管理器与会话等),但有些想法是:

  • 实现PreInsertListener并将其添加到AnnotationConfiguration 。 此侦听器将查找需要此function的实体类型,并将获取/分配下一个序列值
  • 创建数据库触发器以处理使用序列值填充列。 将Java代码中的列标记为insertable = false, updatable = false
  • 将生成逻辑放入实体中的回调方法中,并使用@PrePersist注释对其进行标记
  • 填充字段作为构造函数的一部分(不是首选,因为那时你在构造函数中有一个DB调用和一些潜在的事务边界歧义)