14

Q1。: 在数据库中使用序列 ID 有什么区别

一个。

CREATE TABLE Person
(
   id long NOT NULL AUTO_INCREMENT
   ...
   PRIMARY KEY (id)
)

相对

B.

@Entity
public class Person {
    @Id
    @TableGenerator(name="TABLE_GEN", table="SEQUENCE_TABLE", pkColumnName="SEQ_NAME",
        valueColumnName="SEQ_COUNT", pkColumnValue="PERSON_SEQ")
    @GeneratedValue(strategy=GenerationType.TABLE, generator="TABLE_GEN")
    private long id;
    ...
}

我的系统是高度并发的。由于我的数据库是 Microsoft SQL 服务器,我认为它不支持@SequenceGenerator,所以我必须坚持使用@TableGenerator容易出现并发问题的数据库。

Q2。此处的此链接(http://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#Advanced_Sequencing)表明B可能会遇到并发问题,但我不理解建议的解决方案。如果有人能向我解释如何避免B的并发问题,我将不胜感激。这是他们解决方案的一个片段:

If a large sequence pre-allocation size is used this becomes less of an issue, because the sequence table is rarely accessed.

Q2.1:我们在这里谈论多少分配大小?我应该做allocationSize=10还是allocationSize=100

Some JPA providers use a separate (non-JTA) connection to allocate the sequence ids in, avoiding or limiting this issue. In this case, if you use a JTA data-source connection, it is important to also include a non-JTA data-source connection in your persistence.xml.

Q2.2:我使用 EclipseLink 作为我的提供者;我必须按照上面的建议去做吗?

Q3。如果B遇到并发问题,A是否也会遇到同样的问题?

4

2 回答 2

15

A:使用 IDENTITY id 生成,@GeneratedValue(IDENTITY)

B:使用 TABLE id 生成

JPA 支持三种类型,IDENTITY, SEQUENCE and TABLE.

两者都有取舍。

IDENTITY 不允许预分配,因此在每次 INSERT 后需要额外的 SELECT,防止批量写入,并且需要刷新才能访问 id,这可能导致并发性差。

TABLE 允许预分配,但在序列表上的锁可能存在并发问题。

从技术上讲,SEQUENCE id 生成是最好的,但并非所有数据库都支持它。

使用 TABLE 排序,如果您使用 100 的 preallocaiton 大小,那么只有每 100 次插入才会锁定序列表中的行,因此只要您通常不会同时有 100 次插入,您就不会遭受任何损失并发。如果您的应用程序做了很多插入,可能使用 1000 或更大的值。

EclipseLink 将使用单独的事务进行 TABLE 排序,因此将减少任何与序列表锁定有关的并发问题。如果您使用的是 JTA,那么您需要指定一个非 jta 数据源来执行此操作并在您的 persistence.xml 属性中配置一个序列连接池。

于 2012-04-10T14:59:14.940 回答
15

使用 TableGenerator 将在表中查找和维护下一个 id 值,并且基本上由 JPA 而不是您的数据库维护。当您有多个线程访问您的数据库并试图找出 id 字段的下一个值可能是什么时,这可能会导致并发问题。

auto_increment 类型将使您的数据库关心您的表的下一个 id,即。它将在运行插入时由数据库服务器自动确定——这肯定是并发安全的。

更新:

有什么东西让你远离使用 GenerationType.AUTO 吗?

GenerationType.AUTO 确实选择了一种适当的方式来检索您的实体的 id。所以在最好的情况下使用内置功能。但是,您需要检查生成的 SQL 并查看那里究竟发生了什么——因为 MSSQL 不提供序列,我假设它会使用 GenerationType.IDENTITY。

如前所述, auto_increment 列负责分配下一个 id 值,即。那里没有并发问题 - 即使有多个线程并行处理数据库。挑战在于将此功能转移给 JPA 使用。

于 2012-04-09T15:11:05.363 回答