简体   繁体   English

JPA GenerationType.AUTO没有考虑具有自动增量的列

[英]JPA GenerationType.AUTO not considering column with auto increment

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中,该列已正确设置为Identity with SeedIncrement等于1。

When I try to persist an instance of this entity, Hibernate tries to query the hibernate_sequence table to obtain the ID value. 当我尝试持久化该实体的实例时,Hibernate尝试查询hibernate_sequence表以获取ID值。 Since I haven't created that table in my schema I'm getting an error: 由于我没有在我的架构中创建该表,我收到一个错误:

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 MSSQL:id生成使用表IDENTITY
  • ORACLE: id generation uses a trigger. ORACLE:id生成使用触发器。 The trigger queries and updates a custom table where all the "next ids" are stored. 触发器查询并更新存储所有“下一个ID”的自定义表。 This table is called SEQ. 该表称为SEQ。

Here is the outcome of using some id generation strategies: 以下是使用一些id生成策略的结果:

  • AUTO: does not work in MSSQL, as explained above AUTO:在MSSQL中不起作用,如上所述
  • IDENTITY: works in MSSQL but is not supported by Oracle IDENTITY:在MSSQL中有效,但Oracle不支持
  • "native": works in MSSQL but fails in ORACLE. “native”:在MSSQL中工作但在ORACLE中失败。 It fails because Hibernate activates its default sequence strategy, which uses hibernate_sequences.nextval. 它失败了,因为Hibernate激活了它的默认序列策略,它使用了hibernate_sequences.nextval。 Since this is a legacy application the values from the SEQ table (mentioned above) and the hibernate_sequences are 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). 由于这是一个遗留应用程序,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 使用MSSQL身份功能或
  • When using Oracle, do not automatically set any value to the ID variable and leave everything up to the pre-existing trigger 使用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值。

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" />

Orcale 12c supports IDENTITY and SQL SERVER 2012 supports SEQUENCES. Orcale 12c支持IDENTITY,SQL SERVER 2012支持SEQUENCES。 I believe a SEQUENCE is always a better choice than an IDENTITY . 我相信SEQUENCE总是比IDENTITY更好的选择 IDENTITY disables batching and SEQUENCES allow you to provide optimizers, such as the pooled-lo optimization strategy . IDENTITY禁用批处理,SEQUENCES允许您提供优化程序,例如池化优化策略

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"); 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). AUTO实际上将使用SequenceStyleGenerator,并且数据库不支持序列,您最终会使用TABLE生成器(这是一个可移植的解决方案,但它的效率低于IDENTITY或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; } } 

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. 如果要添加新的Oracle12gDialect并且它将支持IDENTITY,那么AUTO可能会切换到IDENTITY而不是SEQUENCE,可能会破坏您当前的期望。 Currently there is no such dialect available so on Oracle you have SEQUENCE and in MSSQL you have IDENTITY. 目前没有这样的方言,所以在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. 使id为Long而不是Integer,并且可以让HBMDDL处理主键列类型。
  • force Hibernate to use the "native" generator 强制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. 您也可以使用JPA表生成器,只需确保配置正确的优化器。 For more info check my Hibernate tutorial 有关更多信息,请查看我的Hibernate教程

because 因为

@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 你必须看看这个https://hibernate.atlassian.net/browse/HHH-11014

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM