有两个应用程序:一个是使用Spring boot-1.5.18.Release版本,其hibernate版本为5.0.12。最终
:https://search.maven.org/artifact/org.springframework.boot/spring-boot-dependencies/1.5.18.RELEASE/pom
另一个应用程序使用Spring boot-2.4.1版本,该版本的hibernate版本为5.4.25.Final:https://search.maven.org/artifact/org.springframework.boot/spring-boot-dependencies/2.4.1/pom其中我们使用了@SequenceGenerator(name="SequenceGenerator",sequenceName="ABCD_SEQ",allocationSize=1(,
由于应用程序未启动,因此需要分配大小
而在第一个应用程序中不需要分配大小。
数据库序列是用";增加1〃;两个应用程序都使用相同的oracle数据库。
这两个应用程序使用了许多类似的实体,这些实体被复制到另一个应用程序/项目中。
但是,当插入来自第二个应用程序的记录(其中spring boot为2.4.1(时,我们会遇到唯一的序列生成器问题。
经过分析,我们发现第一个应用程序(1.5.18.Release(正在突然增加序列,尽管它应该增加1,在两者之间留下很多间隙,有时会增加50100等。和当第二个应用程序(2.4.1(试图插入记录时,存在唯一约束的错误。
请提供帮助,确切地在哪里搜索根本原因,或者在这种情况下如何使用hibernate缓存机制?
第一次申请的实体之一(1.5.18.发布(
@Entity
@Table(name = "MERCURY_INSTANCE")
public class MercuryInstance implements Serializable {
@Id
@Column(name = "MERCURY_INSTANCE_KEY", nullable = false)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seqGen")
@SequenceGenerator(name = "seqGen", sequenceName = "MERCURY_INSTANCE_SEQ")
private Long mercuryInstanceKey;
@ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY)
@JoinColumn(name = "MERCURY_KEY", referencedColumnName = "MERCURY_KEY", nullable = false)
private MERCURY mercury;
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "MERCURY_INSTANCE_KEY", referencedColumnName = "MERCURY_INSTANCE_KEY", nullable = false)
private MercuryInstanceTechParams MercuryInstanceTechParams;
@ManyToMany(mappedBy = "mercuryGroupInstances")
private List<MercuryGroupInstance> MercuryGroupInstances;
@Column(name = "CREATED_DATE")
private Timestamp createdDte;
@Column(name = "CREATED_BY")
private String createdBy;
@Column(name = "UPDATED_DATE")
private Timestamp updatedDte;
@Column(name = "UPDATED_BY")
private String updatedBy;
/* getter and setters of above fields */
}
虽然另一个应用程序(2.4.1(类似,但唯一的区别是序列生成器,例如:
@Id
@Column(name = "MERCURY_INSTANCE_KEY", nullable = false)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seqGen")
@SequenceGenerator(name = "seqGen", sequenceName = "MERCURY_INSTANCE_SEQ", allocationSize = 1)
private Long mercuryInstanceKey;
数据库序列为:
"创建序列";INSTANCE_ SEQ";MINVALUE 1 MAXVALUE 99999999999999999999从55 NOCACHE NOORDER NOCYCLE开始递增1;
@SequenceGenerator
的分配大小为50。首先,最佳做法是将您的分配大小与数据库序列中的INCREMENT BY
值对齐。
这个值往往取决于您的应用程序是读密集型还是写密集型。此外,您还必须考虑性能(如果它经常写入数据库,则较低的值可能会导致性能问题(。如果您的应用程序是只读应用程序,那么使用分配大小1000或1的影响可以忽略不计。
下一代序列Id基于allocationSize
例如,第一个应用程序请求1-50的id,第二个应用程序每次插入时都会询问。在这种情况下,1-50的id将被第一个应用程序使用,但随后第二个应用程序请求一个id,并将被赋予1-50范围内的id(由于INCREMENT BY=1
(。这导致了一个例外,任何应用程序都将使用相同的id保存第二个id。
因此,最简单的解决方案是改变:
@SequenceGenerator(name = "seqGen", sequenceName = "MERCURY_INSTANCE_SEQ")
的第一个应用程序:
@SequenceGenerator(name = "seqGen", sequenceName = "MERCURY_INSTANCE_SEQ", allocationsize=1)
'allocationSize'并不意味着实体ID将增加此值,但这是一个数字,之后将再次进行数据库查询以获取下一个数据库序列值。在应用程序端,实体实例的id总是会增加1,除非我们达到allocationSize限制。达到"allocationSize"后,将再次从数据库序列中检索下一个id。如果应用程序在达到allocationSize限制之前重新启动或重新部署,我们将看到下一个值的一次性跳跃。"allocationSize是为了提高性能。
在您的第一个场景中:序列生成器是一致的。它的唯一任务是生成唯一的整数值,而不是其他的。如前所述,这种行为是由oracle缓存、预分配序列号(默认为20(引起的。ID列是一个代理/人工主键,仅用于唯一标识行,不应从中派生任何信息。即使您不缓存序列号,由于回滚事务、删除、应用程序和数据库服务器重新启动,您也永远不会得到一系列不间断的ID。在大容量事务系统中,不缓存序列会带来严重的性能损失。
在第二个场景中:尝试将SequenceGenerator放在类的顶部,以使hibernate获取正确的序列。
@Entity
@Table(name = "{your_table_name}")
@SequenceGenerator(name = "seqGen", sequenceName = "MERCURY_INSTANCE_SEQ", allocationSize = 1)
public class {$your class name$} {
@Id
@Column(name = "MERCURY_INSTANCE_KEY", nullable = false)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seqGen")
private Long mercuryInstanceKey;