【问题标题】:How to provide Initial value OR Increment ID with JPA GenerationType.AUTO如何使用 JPA GenerationType.AUTO 提供初始值或增量 ID
【发布时间】:2019-08-26 03:22:00
【问题描述】:

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

@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 是身份列吗?
  • 是的,MY_TABLE_ID 是一个标识列。

标签: java hibernate jpa post spring-data-jpa


【解决方案1】:

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

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

一旦提交事务,标识列将自动分配一个值。您不能为标识列设置任何值,因为它是数据库分配值的工作。因此,您也不需要考虑任何初始值(对于身份列完全忘记它们)

【讨论】:

  • 如果表已经有MY_TABLE_ID= 1,代码仍在尝试为第一个请求插入1并抛出异常。对于第二个请求代码插入 2 但我不希望发生任何异常。
  • 那你的代码有问题。这些注释是正确使用的
  • 我认为问题在于 JPA/ORM 根据这些答案dba.stackexchange.com/questions/46125/…。不过我不确定。但是,我使用 JpaRepository.save() 来插入记录。
  • JPA 不是问题,休眠也是如此。没有更多代码,我不能告诉你更多。我几乎在每个项目中都使用带有GenerationType.IDENTITY 的休眠,我从来没有遇到过这样的问题
  • 使用IDENTITY 主键列MY_TABLE_ID它试图插入NULL,它需要根据stackoverflow.com/questions/32544963/… 更改数据库
【解决方案2】:

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

我的限制很少,

  1. 由于我的数据库更改被冻结,我无法创建数据库序列。
  2. 我不想引入新的Custom IdGenerator 类,因为它会给与我一起工作的其他人带来混乱。

已通过以下更改解决:

添加GenericGeneratorincrement 策略对我有帮助,我对我的代码进行了以下更改。

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

增量

返回 long 的 IdentifierGenerator,通过计数构造 从启动时的最大主键值。不安全地用于 集群!

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

【讨论】:

  • 谢谢,这正是我想要的。
【解决方案3】:

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

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

实体:

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

别忘了锁。

【讨论】:

  • 我不想创建自定义生成器,但是带有increment 策略的 GenericGenerator 似乎正在工作,但我需要彻底测试它。
【解决方案4】:

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

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

}

你也可以使用,序列生成:

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

【讨论】:

  • 我尝试了上述两种方法,但无法让它运行仍然面临同样的问题@Mehdi
  • 你使用的是哪个数据库
  • 我正在使用 PostgreSQL
  • 我认为您应该查看 postgres 本身的解决方案,但是,如果您使用大的 allocationSize,或者使用 UUID 包生成 ID,我认为 GenerationType 序列将起作用。
猜你喜欢
  • 1970-01-01
  • 2017-09-02
  • 2014-09-22
  • 2017-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-30
  • 2020-12-24
相关资源
最近更新 更多