Java JPA GenerationType.AUTO 不考虑具有自动增量的列
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25047226/
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
JPA GenerationType.AUTO not considering column with auto increment
提问by felipe_gdr
I have a table with a simple int id column with Identity auto increment in SQL Server.
我有一个表,其中包含一个简单的 int id 列,在 SQL Server 中具有标识自动增量。
The entity's Id is annotated with @Id
and @GeneratedValue
实体的 Id 用@Id
和@GeneratedValue
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", length = 4, precision = 10, nullable = false)
private Integer id;
In SQL Server the column is properly set as Identity with Seed
and Increment
equals to 1.
在 SQL Server 中,列被正确设置为标识,Seed
并且Increment
等于 1。
When I try to persist an instance of this entity, Hibernate tries to query the hibernate_sequence table to obtain the ID value. Since I haven't created that table in my schema I'm getting an error:
当我尝试保留此实体的实例时,Hibernate 会尝试查询 hibernate_sequence 表以获取 ID 值。由于我尚未在我的架构中创建该表,因此出现错误:
could not read a hi value: com.microsoft.sqlserver.jdbc.SQLServerException: Invalid object name 'MySchema.hibernate_sequence'
could not read a hi value: com.microsoft.sqlserver.jdbc.SQLServerException: Invalid object name 'MySchema.hibernate_sequence'
If I change the generation type to IDENTITY everything works as expected
如果我将生成类型更改为 IDENTITY,则一切正常
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", length = 4, precision = 10, nullable = false)
private Integer id;
I cannot change it this way, since my App will run both on MS SQL and ORACLE, and the latter does not support auto incremented columns.
我不能这样改变它,因为我的应用程序将在 MS SQL 和 ORACLE 上运行,而后者不支持自动递增的列。
As far as I know the AUTO type should use the auto increment behaviour if the underlying database has support to it, so I don't know why is not working.
据我所知,如果底层数据库支持自动增量行为,AUTO 类型应该使用自动增量行为,所以我不知道为什么不起作用。
UPDATE:
更新:
It took me some time but I was able to understand exactly what is going on.
我花了一些时间,但我能够确切地理解发生了什么。
I am working with legacy databases with the following behaviours:
我正在使用具有以下行为的旧数据库:
- MSSQL: id generation uses table IDENTITY
- ORACLE: id generation uses a trigger. The trigger queries and updates a custom table where all the "next ids" are stored. This table is called SEQ.
- MSSQL:id 生成使用表 IDENTITY
- ORACLE:id 生成使用触发器。触发器查询并更新存储所有“下一个 ID”的自定义表。该表称为 SEQ。
Here is the outcome of using some id generation strategies:
这是使用一些 id 生成策略的结果:
- AUTO: does not work in MSSQL, as explained above
- IDENTITY: works in MSSQL but is not supported by Oracle
- "native": works in MSSQL but fails in ORACLE. It fails because Hibernate activates its default sequence strategy, which uses hibernate_sequences.nextval. Since this is a legacy application the values from the SEQ table (mentioned above) and the hibernate_sequencesare not synchronized (SEQ's value for that particular table is at 6120, and hibernate_sequences' is at 1, which is expected since it was not used until now).
- AUTO:在 MSSQL 中不起作用,如上所述
- IDENTITY:适用于 MSSQL,但不受 Oracle 支持
- "native": 在 MSSQL 中工作但在 ORACLE 中失败。它失败是因为 Hibernate 激活了它的默认序列策略,它使用 hibernate_sequences.nextval。由于这是一个遗留应用程序,来自 SEQ 表(如上所述)和hibernate_sequences的值不同步(该特定表的 SEQ 值为 6120,hibernate_sequences 为 1,这是预期的,因为它直到现在才被使用)。
So what I need to figure out is a way to configure that entity to:
所以我需要弄清楚的是一种将该实体配置为:
- Use MSSQL Identity feature OR
- When using Oracle, do not automatically set any value to the ID variable and leave everything up to the pre-existing trigger
- 使用 MSSQL 身份功能或
- 使用 Oracle 时,不要自动为 ID 变量设置任何值并将所有内容留给预先存在的触发器
This can cause me serious issues on Oracle when I need to insert entities that depend on the main entity (via foreign key), because Hibernate won't know which ID value was generated by the "external" trigger.
当我需要插入依赖于主实体(通过外键)的实体时,这可能会导致我在 Oracle 上出现严重问题,因为 Hibernate 不知道哪个 ID 值是由“外部”触发器生成的。
回答by Vlad Mihalcea
Orcale 12c supports IDENTITY and SQL SERVER 2012 supports SEQUENCES. I believe a SEQUENCE is always a better choice than an IDENTITY. IDENTITY disables batching and SEQUENCES allow you to provide optimizers, such as the pooled-lo optimization strategy.
Orcale 12c 支持 IDENTITY,SQL SERVER 2012 支持 SEQUENCES。我相信SEQUENCE 总是比 IDENTITY 更好的选择。IDENTITY 禁用批处理,而 SEQUENCES 允许您提供优化器,例如pooled-lo 优化策略。
This is how the actual identifier generator is chosen for the configured GenerationType value:
这是为配置的 GenerationType 值选择实际标识符生成器的方式:
switch ( generatorEnum ) {
case IDENTITY:
return "identity";
case AUTO:
return useNewGeneratorMappings
? org.hibernate.id.enhanced.SequenceStyleGenerator.class.getName()
: "native";
case TABLE:
return useNewGeneratorMappings
? org.hibernate.id.enhanced.TableGenerator.class.getName()
: MultipleHiLoPerTableGenerator.class.getName();
case SEQUENCE:
return useNewGeneratorMappings
? org.hibernate.id.enhanced.SequenceStyleGenerator.class.getName()
: "seqhilo";
}
If you use the new identifier generators:
properties.put("hibernate.id.new_generator_mappings", "true");
The AUTO will actually use a SequenceStyleGenerator and where the database doesn't support sequences, you end up using a TABLE generator instead (which is a portable solution but it's less efficient than IDENTITY or SEQUENCE).
If you use the legacy identifier generators, you then end up with the "native" generation strategy, meaning:
public Class getNativeIdentifierGeneratorClass() { if ( supportsIdentityColumns() ) { return IdentityGenerator.class; } else if ( supportsSequences() ) { return SequenceGenerator.class; } else { return TableHiLoGenerator.class; } }
如果您使用新的标识符生成器:
properties.put("hibernate.id.new_generator_mappings", "true");
AUTO 实际上将使用 SequenceStyleGenerator,并且在数据库不支持序列的情况下,您最终会使用 TABLE 生成器(这是一种可移植的解决方案,但效率不如 IDENTITY 或 SEQUENCE)。
如果您使用旧式标识符生成器,则最终会使用“本机”生成策略,这意味着:
public Class getNativeIdentifierGeneratorClass() { if ( supportsIdentityColumns() ) { return IdentityGenerator.class; } else if ( supportsSequences() ) { return SequenceGenerator.class; } else { return TableHiLoGenerator.class; } }
If a new Oracle12gDialect is going to be added and it will support IDENTITY, then AUTO might switch to IDENTITY rather than SEQUENCE, possibly breaking your current expectations. Currently there is no such dialect available so on Oracle you have SEQUENCE and in MSSQL you have IDENTITY.
如果要添加新的 Oracle12gDialect 并且它将支持 IDENTITY,那么 AUTO 可能会切换到 IDENTITY 而不是 SEQUENCE,这可能会打破您当前的预期。目前没有这样的方言可用,因此在 Oracle 上您有 SEQUENCE,而在 MSSQL 中您有 IDENTITY。
Conclusion:
结论:
Try it like this:
像这样尝试:
@Id
@GenericGenerator(name = "native_generator", strategy = "native")
@GeneratedValue(generator = "native_generator")
private Long id;
- make the id a Long instead of Integer, and you can let the HBMDDL handle the primary key column type.
- force Hibernate to use the "native" generator
- 将 id 设为 Long 而不是 Integer,您可以让 HBMDDL 处理主键列类型。
- 强制 Hibernate 使用“本机”生成器
If your legacy system uses a table for generating sequence values and there was no hilo optimization ever used you can use a table identifier generator:
如果您的旧系统使用表来生成序列值并且没有使用过 hilo 优化,您可以使用表标识符生成器:
@Id
@GeneratedValue(generator = "table", strategy=GenerationType.TABLE)
@TableGenerator(name = "table", allocationSize = 1
)
private Long id;
You can also use the JPA table generator, just make sure you configure the right optimizer. For more info check my Hibernate tutorial
您还可以使用 JPA 表生成器,只需确保配置正确的优化器即可。有关更多信息,请查看我的Hibernate 教程
回答by Daniel Rodríguez
I had a similar problem and found this information(deeper explained in here).
我遇到了类似的问题并找到了此信息(在此处进行了更深入的解释)。
Adding this property into my persistence.xml file fixed the issue:
将此属性添加到我的 persistence.xml 文件中修复了该问题:
<property name="hibernate.id.new_generator_mappings" value="false" />
回答by Muhammad Rfeaat
because
因为
@GeneratedValue(strategy = GenerationType.AUTO)
@GeneratedValue(strategy = GenerationType.AUTO)
use SequenceStyleGenerator
by default in earlier versions
SequenceStyleGenerator
在早期版本中默认使用
you have to look at this https://hibernate.atlassian.net/browse/HHH-11014