JPA或Hibernate生成(非主键)列值,而不是从1开始

问题描述 投票:3回答:3

我想要一个JPA / Hibernate(最好是JPA)注释,它可以生成列的值,该列不是主键,并且它不是从1开始的。

根据我所见,JPA无法使用@GeneratedValue和@SequenceGenerator和@TableGenerator做到这一点。或其他任何内容。

我看过一个solution,带有一个额外的桌子,我发现它并不优雅。

我可以使用Hibernate批注,因为我已经有了hibernate批注。

我想使用@Generated,但是我无法使它起作用,claim人们可能。

@Generated(GenerationTime.INSERT)
private long invoiceNumber;//invoice number

更新:一项额外的要求,如果交易被回滚,我们在编号上不能有空白。有人吗?

java mysql hibernate jpa auto-increment
3个回答
7
投票

@GeneratedValue仅适用于标识符,因此您不能使用它。如果您使用MySQL,则会受到很大限制,因为不支持数据库序列。

InnoDB doesn't support multiple AUTO_INCREMENT columns,并且如果您的表PK是AUTO_INCREMENTED,那么您有两个选择:

  1. 选择一个行为类似序列生成器的单独表,您已经说过不满意的解决方案。

  2. 使用INSERT TRIGGER来增加该列。


1
投票

这是对我有用的-我们在服务中对所有代码进行了编码。这是实体:

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Registrant extends AbstractEntity {
    //....
    private long invoiceNumber;//invoice number

    @Entity
    public static class InvoiceNumberGenerator {
        @Id
        @GeneratedValue
        private int id;
        private long counter;

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public long getCounter() {
            return counter;
        }

        public void setCounter(long counter) {
            this.counter = counter;
        }
    }
}

然后我们有一个执行魔术的服务(实际上没有魔术,所有操作都是手动完成的:]

public synchronized Registrant save(Registrant registrant) {
    long counter = getInvoiceNumber();
    registrant.setInvoiceNumber(counter);

    return registrantRepository.save(registrant);
}

private long getInvoiceNumber() {
    //mist: get the invoice number from the other table
    long count = registrantInvoiceNumberGeneratorRepository.count();
    if(count > 1) {
        throw new RuntimeException(": InvoiceNumberGenerator table has more than one row. Fix that");
    }

    Registrant.InvoiceNumberGenerator generator;
    if(count == 0) {
        generator = new Registrant.InvoiceNumberGenerator();
        generator.setCounter(1000001);
        generator = registrantInvoiceNumberGeneratorRepository.save(generator);
    } else {
        generator = registrantInvoiceNumberGeneratorRepository.findFirstByOrderByIdAsc();
    }


    long counter = generator.getCounter();
    generator.setCounter(counter+1);
    registrantInvoiceNumberGeneratorRepository.save(generator);
    return counter;
}

注意synchronized方法-这样没人能得到相同的数字。

我不敢相信没有自动装置可以做到这一点。


0
投票

与@Vlad Mihalcea有关,现在您可以使用@GeneratorType为非id列生成您自己的自定义值。例如:

  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. ValueGenerator实现:
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);
            query.setParameter(START_PARAMETER, start(now));
            query.setParameter(END_PARAMETER, end(now));
            Example lastExample = todayQuery.setMaxResult(1).setHibernateFlushMode(COMMIT).uniqueResult();

            NativeQuery nextvalQuery = session.createSQLQuery(NEXTVAL_QUERY);
            Number nextvalValue = nextvalQuery.setFlushMode(COMMIT).uniqueResult();
            return dataFormat.format(now) + someParameter(lastExample) + nextvalValue.longValue();
        }
    }
© www.soinside.com 2019 - 2024. All rights reserved.