关于java:如何通过JPA GenerationType.AUTO提供初始值或增量ID

How to provide Initial value OR Increment ID with JPA GenerationType.AUTO

我正在使用以下代码定义MyEntity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Entity
@Table(name ="MY_TABLE")
public class MyEntity {

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name ="MY_TABLE_ID")
private Integer myTableId;

@Column(name ="MY_TABLE_NM")
private String myTableName;

//Getters Setters
}

对于我的应用程序启动后的第一个POST,我创建MyEntity一切正常,MY_TABLE_ID以1开头并按预期工作。

我的问题是,如果有人在执行POST之前手动插入数据,那么我会得到重复的密钥异常,因为myTableId输入为1(已经存在)。

我的主要问题是我现在无法创建database sequence来使用GenerationType.SEQUENCE来解决此问题,因为现在无法更改数据库。
我尝试了GenerationTypeTableGenerator的各种组合,但无法成功解决。

initialValue设置为更大的数字以避免重复的值可以暂时解决我的问题,但我也无法做到。

如果有人可以在initialValueAUTO的帮助下为我提供帮助,或者在不更改数据库的情况下为我提供其他更好的解决方案,那将是不错的方法:)


由于MY_TABLE_ID是一个标识列,因此以下注释将起作用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Entity
@Table(name ="MY_TABLE")
public class MyEntity {

@Id
@GeneratedValue(strategy=GenerationType.IDENTITY) // <-- IDENTITY instead of AUTO
@Column(name ="MY_TABLE_ID")
private Integer myTableId;

@Column(name ="MY_TABLE_NM")
private String myTableName;

//Getters Setters
}

标识列将在提交事务后立即自动分配一个值。您不要为标识列设置任何值,因为它是数据库分配值的工作。因此,您也无需考虑任何初始值(对于标识列完全忽略它们)


在此处提供的答案中以及在stackoverflow和其他论坛上的类似问题中,我尝试了各种选择,

我没有什么限制,

  • 由于数据库更改被冻结,我无法创建数据库序列。
  • 我不想引入新的Custom IdGenerator类,因为它会使与我一起工作的其他人感到困惑。
  • 使用以下更改已解决:

    通过increment策略添加GenericGenerator可以帮助我,对代码进行了以下更改。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    @Entity
    @Table(name ="MY_TABLE")
    public class MyEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator="seq")
    @GenericGenerator(name ="seq", strategy="increment")
    @Column(name ="MY_TABLE_ID")
    private Integer myTableId;

    @Column(name ="MY_TABLE_NM")
    private String myTableName;

    //Getters Setters
    }

    它帮助了我,因为,
    来自Hiberbate DOC

    increment

    An IdentifierGenerator that returns a long, constructed by counting
    from the maximum primary key value at startup. Not safe for use in a
    cluster!

    因为,即使手动插入它,它也会增加已经存在的myTableId,这解决了我的问题。


    如果需要更多控制,也可以实现自己的生成器。
    请参见此接口IdentifierGenerator。
    因此,您可以获取记录计数,例如通过@NamedQuery。
    然后,您可以自己生成一个标识符。

    1
    2
    3
    4
    5
    6
    7
    8
    public class MyEntityKeyGenerator implements IdentifierGenerator {
    @Override
    public Serializable generate(SessionImplementor session, Object object) {
        // SELECT count(ent) from MyEntity ent;
        Long count = (Long) session.getNamedQuery("count-query").uniqueResult();
        // calc and return id value
       }
    }

    实体:

    1
    2
    3
    4
    5
    6
    class MyEntity {
    @Id
    @GenericGenerator(name ="my_generator",
            strategy ="org.common.MyEntityKeyGenerator")
    @GeneratedValue(generator ="my_generator")
    private Long id;...

    别忘了锁。


    我使用生成类型Identity,这基本上意味着db负责ID生成。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    @AllArgsConstructor
    @NoArgsConstructor
    @Getter
    @Setter
    @MappedSuperclass
    @EntityListeners(EntityListener.class)
    @EqualsAndHashCode(of = {"id","createdAt"})
    public abstract  class AbstractEntity<ID extends Serializable> implements Serializable {

        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private ID id;

        @Temporal(TemporalType.TIMESTAMP)
        @Column(name ="CREATED_AT", updatable = false)
        private Date createdAt;

        @Temporal(TemporalType.TIMESTAMP)
        @Column(name ="UPDATED_AT")
        private Date updatedAt;

    }

    您还可以使用序列生成:

    1
    2
    3
    4
    5
    6
    @Entity
    @SequenceGenerator(name="seq", initialValue=1, allocationSize=100)
    public class EntityWithSequenceId {
        @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq")
        @Id long id;
    }