Java 使用MySQL和Oracle生成Hibernate自动密钥

Java 使用MySQL和Oracle生成Hibernate自动密钥,java,mysql,oracle,hibernate,jpa,Java,Mysql,Oracle,Hibernate,Jpa,我正在开发一个Java应用程序,它应该在具有相同数据库模式的两个不同数据库上执行CRUD操作(使用Hibernate4.3.8)。 有一个MySQL(版本5.1.73)和一个Oracle(11g Express Edition 11.2.0.2.0-64位)数据库 带有JPA注释的Java类是通过Hibernate代码生成从数据库表生成的 问题是我们现在需要使用自动主键生成,MySQL使用GenerationType.IDENTITY,Oracle使用GenerationType.SEQUENC

我正在开发一个Java应用程序,它应该在具有相同数据库模式的两个不同数据库上执行CRUD操作(使用Hibernate4.3.8)。 有一个MySQL(版本5.1.73)和一个Oracle(11g Express Edition 11.2.0.2.0-64位)数据库

带有JPA注释的Java类是通过Hibernate代码生成从数据库表生成的

问题是我们现在需要使用自动主键生成,MySQL使用GenerationType.IDENTITY,Oracle使用GenerationType.SEQUENCE。此外,在一些罕见的情况下,我们需要自己手动设置主键的能力

注释类中的以下代码可用于两个数据库的自动密钥生成,但如果主键是自设置的,则会失败

@GeneratedValue(strategy=GenerationType.AUTO, generator="sequence_generator")
@SequenceGenerator(name="sequence_generator", sequenceName="SEQUENCE1")
@Column(name = "id", unique = true, nullable = false)
public Integer getId() {
    return this.id;
}

如果没有@GeneratedValue和@SequenceGenerator注释,可以手动设置主键,但自动生成不起作用。

请尝试以下操作:

@Id
@Column( name = "ID" )
@TableGenerator( 
        name = "AppSeqStore", 
        table = "APP_SEQ_STORE", 
        pkColumnName = "APP_SEQ_NAME", 
        pkColumnValue = "LISTENER_PK", 
        valueColumnName = "APP_SEQ_VALUE", 
        initialValue = 1, 
        allocationSize = 1 )
@GeneratedValue( strategy = GenerationType.TABLE, generator = "AppSeqStore" )
数据库中的这个表:

CREATE TABLE APP_SEQ_STORE (
    APP_SEQ_NAME VARCHAR(255) NOT NULL,
    APP_SEQ_VALUE NUMBER(10) NOT NULL,
    PRIMARY KEY(APP_SEQ_NAME)
)

INSERT INTO APP_SEQ_STORE VALUES ('LISTENER_PK', 0)
这些都可以在Oracle、MS Sql Server和使用JBoss作为应用服务器的MySql中使用

更多信息请点击此处:

即使使用了
GenerationType.AUTO
而没有任何特定于序列的参数,也无法保存指定的标识符

如果您愿意做出一些妥协,有一些变通办法:

  • 一种方法是切换到指定的标识符。您可以使用UUID标识符,它适用于MySQL和Oracle,并且您还可以手动分配值

  • 另一种方法是使用自定义表生成器

  • 首先定义一个可识别的接口:

        public interface Identifiable<T extends Serializable> {
            T getId();
        }
    
    此生成器能够将分配的标识符与合成生成的标识符混合使用:

        doInTransaction(session -> {
            for (int i = 0; i < 5; i++) {
                session.persist(new AssignTableSequenceIdentifier());
            }
            AssignTableSequenceIdentifier tableSequenceIdentifier = new AssignTableSequenceIdentifier();
            tableSequenceIdentifier.id = -1L;
            session.merge(tableSequenceIdentifier);
            session.flush();
        });
    
    对于Oracle,您可以组合序列和指定的生成器。简而言之,考虑以下发电机:

        public class AssignedTableGenerator extends TableGenerator {
    
            @Override
            public Serializable generate(SessionImplementor session, Object obj) {
                if(obj instanceof Identifiable) {
                    Identifiable identifiable = (Identifiable) obj;
                    Serializable id = identifiable.getId();
                    if(id != null) {
                        return id;
                    }
                }
                return super.generate(session, obj);
            }
        }
    
    public class AssignedSequenceStyleGenerator 
        extends SequenceStyleGenerator {
     
        @Override
        public Serializable generate(SessionImplementor session, 
            Object obj) {
            if(obj instanceof Identifiable) {
                Identifiable identifiable = (Identifiable) obj;
                Serializable id = identifiable.getId();
                if(id != null) {
                    return id;
                }
            }
            return super.generate(session, obj);
        }
    }
    
    您可以将其映射到实体,如下所示:

    @Id
    @GenericGenerator(
        name = "assigned-sequence",
        strategy = "com.vladmihalcea.book.hpjp.hibernate.identifier.AssignedSequenceStyleGenerator",
        parameters = @org.hibernate.annotations.Parameter(
            name = "sequence_name", 
            value = "post_sequence"
        )
    )
    @GeneratedValue(
        generator = "assigned-sequence", 
        strategy = GenerationType.SEQUENCE
    )
    private Long id;
    

    所有的代码都可以在上使用,并且工作起来很有魅力。

    试试这个[manually-specify-the-value-of-a-primary-key-in-jpa-generatedvalue-column][1]。有很多解决方案。[1] :此线程中以数据库为中心的解决方案不适用于我,因为不应更改数据库架构。除了我之外,还有其他人相信数据库模式不会改变。我不知道是否有可能,也不知道如何编写自己的自定义Id生成器,它支持MySQL和Oracle数据库(标识和序列)。在所有的例子中,他们要么使用IdentifierGenerator,要么使用Sequencegenerator。这个问题并不清楚。你是说你有一些类,你想Hibernate自动生成标识符,并手动分配标识符给其他类;或者你是说你想让Hibernate在大多数情况下自动为一个类的实例分配标识符,但在某些情况下你想手动为同一个类的某些实例分配标识符?你应该使用触发器来获得一个同质的跨数据库解决方案。我以前的Spring 4项目在MySQL和Oracle 11g上都运行良好仅使用
    @SequenceGenerator(name=“id\u generator”,sequenceName=“sq\u id\u user”)
    注释,但现在我使用的是Spring Boot 2和Hibernate 5,它抱怨10.1.24-MariaDB中不存在序列。这种方法对mysql db有效吗?似乎我得到了以下例外原因:org.hibernate.MappingException:org.hibernate.dialogue.mysql5dialogue不支持sequencesHi Vlad,您是说使用TableGenerator而不是SequenceGenerator吗?我已经有了一个实体类,并将其用于OracleDB和SequenceGenerator。但我的目的是对mysql数据库也使用相同的类。据我所知,mysql数据库中没有等价的序列,所以我应该改变我的Id生成策略(即使用另一个表而不是序列)?Hi-Vlad。谢谢你的建议。我遵循这个链接:可以使用相同的实体,OracleDB使用序列,MFSQLDB使用自动增量。thnx如果我将代码(包括名称和导入的所有更改)插入到应用程序中,服务器将拒绝使用它。你忘记了一些重要的细节。专业提示1:从堆栈溢出复制代码并随机粘贴到应用程序中不是一件明智的事情。专业提示2:当您可以找到并运行代码以看到它像一个符咒一样工作时,为什么要从堆栈溢出复制代码。
    @Id
    @GenericGenerator(
        name = "assigned-sequence",
        strategy = "com.vladmihalcea.book.hpjp.hibernate.identifier.AssignedSequenceStyleGenerator",
        parameters = @org.hibernate.annotations.Parameter(
            name = "sequence_name", 
            value = "post_sequence"
        )
    )
    @GeneratedValue(
        generator = "assigned-sequence", 
        strategy = GenerationType.SEQUENCE
    )
    private Long id;