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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29716620/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 15:46:46  来源:igfitidea点击:

JPA or Hibernate to generate a (non primary key) column value, not starting from 1

javamysqlhibernatejpaauto-increment

提问by mist

I want a JPA/Hibernate (preferably JPA) annotation that can generate the value of a column, that is not a primary key and it doesn't start from 1.

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

From what I have seen JPA cannot do that with @GeneratedValue and @SequenceGenerator and @TableGenerator. Or with anything else.

从我所看到的 JPA 不能用 @GeneratedValue 和 @SequenceGenerator 和 @TableGenerator 做到这一点。或与其他任何东西。

I have seen a solutionwith an extra table, which I find is not elegant.

我见过一个带有额外桌子的解决方案,我发现它并不优雅。

I can live with a Hibernate annotation, because I already have hibernate annotations.

我可以忍受 Hibernate 注释,因为我已经有了 Hibernate 注释。

I want to use @Generated but I cannot make it work and people claimthat it is possible.

我想使用 @Generated 但我无法让它工作,人们声称这是可能的。

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

Update: an extra requirement, if the transaction is rolled back, we can't have a gap in the numbering. Anyone?

更新:一个额外的要求,如果事务回滚,我们不能在编号上有间隙。任何人?

采纳答案by mist

Here's what worked for me - we coded all of it in the service. Here's the entity:

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

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

And then we have a service that does the magic (actually there's no magic, all is done manually):

然后我们有一个服务可以施展魔法(实际上没有魔法,一切都是手动完成的):

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

Note the synchronizedmethod - so that nobody can get the same number.

注意synchronized方法 - 这样没有人可以获得相同的数字。

I can't believe there's nothing automatic that can do that.

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

回答by Vlad Mihalcea

The @GeneratedValueonly works for identifiers and so you can't use it. If you use MySQL, you are quite limited, since database sequences are not supported.

@GeneratedValue只适用于标识符,所以你不能使用它。如果您使用 MySQL,您将受到很大限制,因为不支持数据库序列。

InnoDB doesn't support multiple AUTO_INCREMENT columnsand if your table PK is AUTO_INCREMENTED, then you have two options:

InnoDB不支持多个 AUTO_INCREMENT 列,如果您的表 PK 是 AUTO_INCREMENTED,那么您有两个选择:

  1. Go for a separate table that behaves like a sequence generator, the solution you already said you are not happy about.

  2. Use an INSERT TRIGGERto increment that column.

  1. 寻找一个单独的表,它的行为类似于序列生成器,这是您已经说过不满意的解决方案。

  2. 使用INSERT TRIGGER增加该列。