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

但我不断收到一个属性值异常。

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$$69ccb4e4.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)
4

5 回答 5

4

对于非 id 字段的自定义序列生成器,您可以将 @GeneratorType 与 ValueGenerator 类实现一起使用。例如:

  1. 实体:
    import org.hibernate.annotations.GeneratorType

    @GeneratorType(type = CustomGenerator.class, when = GenerationTime.INSERT)
    @Column(name = "CUSTOM_COLUMN", unique = true, nullable = false, updatable = false, lenght = 64)
    private String custom;
  1. 值生成器实现:
public class CustomGenerator extends ValueGenerator<String> {
        private static final String TODAY_EXAMPLE_QUERY = "from Example where createDate>:start and createDate<:end order by createDate desc";
        private static final String START_PARAMETER = "start";
        private static final String END_PARAMETER = "end";
        private static final String NEXTVAL_QUERY = "select EXAMPLE_SEQ.nextval from dual";
        private final SimpleDateFormat dataFormat = new SimpleDateFormat("yyyyMMdd");

        @Override
        public String generateValue(Session session, Object owner) {
            Date now = new Date();
            Query<Example> todayQuery = session.createQuery(TODAY_EXAMPLE_QUERY, Example.class);
            todayQuery.setParameter(START_PARAMETER, start(now));
            todayQuery.setParameter(END_PARAMETER, end(now));
            Example todayLastExample = todayQuery.setMaxResult(1).setHibernateFlushMode(COMMIT).uniqueResult();

            NativeQuery nextvalQuery = session.createSQLQuery(NEXTVAL_QUERY);
            Number nextvalValue = nextvalQuery.setFlushMode(COMMIT).uniqueResult();
            return dataFormat.format(now) + someParameter(todayLastExample) + nextvalValue.longValue();
        }
    }
于 2020-06-10T17:50:53.637 回答
2

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

你有几个选项来完成你想要的,但没有一个真的像使用你写的注释那样优雅。这些建议各有利弊(数据库可移植性、复杂性、实体管理器与会话等),但一些想法是:

  • 实现一个 PreInsertListener 并将其添加到您的AnnotationConfiguration. 此侦听器将查找需要此功能的实体类型,并获取/分配下一个序列值
  • 制作一个数据库触发器来处理使用序列值填充列。将 Java 代码中的列标记为insertable = false, updatable = false
  • 将生成逻辑放入实体中的回调方法中,并使用 @PrePersist 注释对其进行标记
  • 将该字段作为构造函数的一部分填充(从那时起,您在构造函数中有一个 DB 调用和一些潜在的事务边界歧义而不是首选)
于 2012-09-19T14:53:14.703 回答
2

这至少在 Postgres 中对我有用

@Generated(GenerationTime.INSERT)
@Column(name = "internal_id", columnDefinition = "serial", updatable = false)
private int internalId;
于 2020-09-01T13:30:03.220 回答
1

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

顺便说一句,在这个 SO 问题中检查这个响应:Hibernate JPA Sequence (non-Id)

于 2012-09-19T13:55:23.527 回答
1

我刚刚遇到了一个类似的问题,我需要创建一个序列并将其附加到一个不是主键的字段。

我一直在努力尝试使用@GeneratedValue@SequenceGenerator注释,因为正如 Web 上所述:@GeneratedValue只能与 Hibernate 实体字段上的 @Id 注释一起使用。这告诉 Hibernate 不要关心该字段是否为空,它将在插入数据库时​​进行管理。但是这里 Hibernate 总是抛出异常,因为 GeneratedValue 在字段上被忽略了。

所以解决方案很简单:只需将此注释替换为@Generated(GenerationTime.INSERT)并添加columnDefinition = "serial"到您的@Column(name = "huhu", columnDefinition = "serial", updatable = false, ...)

通常,如果您首先创建了附加到数据库中字段的正确序列,它现在应该可以工作了。

于 2019-04-11T16:22:35.160 回答