简体   繁体   English

如何在 Hibernate 的复合主键中自动增加一个 Id?

[英]How to autoincrement an Id in a composite primary key in Hibernate?

I have a table with a composite primary key - groupId and batchId .我有一个包含复合主键的表 - groupIdbatchId Entity class looks like:实体 class 看起来像:

@Entity(name="EMPLOYEE")
public class Employee {

    @EmbeddedId
    private EmployeePK employeePK;

    //Other columns and their getters and setters
    //Getters and setters
}

Composite PK:复合PK:

@Embeddable
public class EmployeePK implements Serializable {

    private long groupId;
    private long batchId;

    @GeneratedValue(strategy=GenerationType.AUTO)
    public long getBatchId() {
        return batchId;
    }

    public void setBatchId(long batchId) {
        this.batchId = batchId;
    }
}

I'm trying to auto increment the batch Id, for a new record to be inserted.我正在尝试自动增加批次 ID,以便插入新记录。

//For saving
Employee employee = new Employee();
EmployeePK pk = new IRAmendmentBatchesPK();
pk.setBatchId(0);
pk.setGroupId(4388);

Employee employee = employeeRepository.save(employee);


//Repository Interface
public interface EmployeeRepository extends JpaRepository<Employee, EmployeePK>{

}

I'm explicity setting batchId as 0, in hopes that the auto-incremented value is set in the batchId during save(insert).我明确将batchId设置为 0,希望在保存(插入)期间在 batchId 中设置自动增量值。 As of now, this code will save a new entry with batchId as 0.到目前为止,此代码将保存一个 batchId 为 0 的新条目。

As I have mentioned in comment, I have used @IdClass it worked while I have tried in hsqldb in-memory database, but failed to work in mysql .正如我在评论中提到的,我在hsqldb内存数据库中尝试时使用了@IdClass它工作,但在mysql失败。

Please note I am using hibernate 5请注意我使用的是休眠 5

You may give a try with oracle, I couldn't recollect but it should work.您可以尝试使用 oracle,我不记得了,但它应该可以工作。 But please check for if any drawbacks with the approach if any.但是请检查该方法是否有任何缺点(如果有)。

pom.xml pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.techdisqus</groupId>
    <artifactId>spring5-mvc-hibernate-example</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <properties>
        <failOnMissingWebXml>false</failOnMissingWebXml>
        <spring.version>5.0.0.RELEASE</spring.version>
        <hibernate.version>5.2.11.Final</hibernate.version>
        <hibernate.validator>5.4.1.Final</hibernate.validator>
        <c3p0.version>0.9.5.2</c3p0.version>
        <jstl.version>1.2.1</jstl.version>
        <tld.version>1.1.2</tld.version>
        <servlets.version>3.1.0</servlets.version>
        <jsp.version>2.3.1</jsp.version>
        <hsqldb.version>1.8.0.10</hsqldb.version>
    </properties>
    <dependencies>
        <!-- Spring MVC Dependency -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- Spring ORM -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- Hibernate ORM -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>${hibernate.version}</version>
        </dependency>

        <!-- Hibernate-C3P0 Integration -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-c3p0</artifactId>
            <version>${hibernate.version}</version>
        </dependency>

        <!-- c3p0 -->
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>${c3p0.version}</version>
        </dependency>

        <!-- Hibernate Validator -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>${hibernate.validator}</version>
        </dependency>

        <!-- JSTL Dependency -->
        <dependency>
            <groupId>javax.servlet.jsp.jstl</groupId>
            <artifactId>javax.servlet.jsp.jstl-api</artifactId>
            <version>${jstl.version}</version>
        </dependency>

        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>${tld.version}</version>
        </dependency>

        <!-- Servlet Dependency -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>${servlets.version}</version>
            <scope>provided</scope>
        </dependency>

        <!-- JSP Dependency -->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>${jsp.version}</version>
            <scope>provided</scope>
        </dependency>

        <!-- HSQL Dependency -->
          <dependency>
            <groupId>hsqldb</groupId>
            <artifactId>hsqldb</artifactId>
            <version>${hsqldb.version}</version>
        </dependency>  

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.12</version>
        </dependency>
    </dependencies>

    <build>
        <sourceDirectory>src/main/java</sourceDirectory>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>

            <!-- Embedded Apache Tomcat required for testing war -->
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <path>/</path>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Book.java书.java

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.Table;

@Entity(name = "Book")
@Table(name = "book")
@IdClass( PK.class )
public class Book {

    @Id
    @Column(name = "registration_number")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long registrationNumber;

    @Id
    @Column(name = "publisher_id")
    private Integer publisherId;

    private String title;

    public Long getRegistrationNumber() {
        return registrationNumber;
    }

    public void setRegistrationNumber(Long registrationNumber) {
        this.registrationNumber = registrationNumber;
    }

    public Integer getPublisherId() {
        return publisherId;
    }

    public void setPublisherId(Integer publisherId) {
        this.publisherId = publisherId;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    @Override
    public String toString() {
        return "Book [registrationNumber=" + registrationNumber + ", publisherId=" + publisherId + ", title=" + title
                + "]";
    }
 }

PK.java PK.java

import java.io.Serializable;
import java.util.Objects;

public class PK implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 2371758145387850080L;

    private Long registrationNumber;
    private Integer publisherId;

    public PK(Long registrationNumber, Integer publisherId) {
        this.registrationNumber = registrationNumber;
        this.publisherId = publisherId;
    }


    public PK() {
    }

    @Override
    public boolean equals(Object o) {
        if ( this == o ) {
            return true;
        }
        if ( o == null || getClass() != o.getClass() ) {
            return false;
        }
        PK pk = (PK) o;
        return Objects.equals( registrationNumber, pk.registrationNumber ) &&
                Objects.equals( publisherId, pk.publisherId );
    }

    @Override
    public int hashCode() {
        return Objects.hash( registrationNumber, publisherId );
    }
}

hibernate.cfg.xml休眠文件.cfg.xml

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.archive.autodetection">class,hbm</property>
        <property name="hibernate.dialect">org.hibernate.dialect.HSQLDialect</property>
        <property name="hibernate.show_sql">true</property>
        <property name="hibernate.connection.driver_class">org.hsqldb.jdbcDriver</property>
        <property name="hibernate.connection.username">sa</property>
        <property name="hibernate.connection.password"></property>
        <property name="hibernate.connection.url">jdbc:hsqldb:mem:test</property>
        <property name="hibernate.hbm2ddl.auto">create</property>

        <property name="hibernate.c3p0.min_size">5</property>
        <property name="hibernate.c3p0.max_size">20</property>
        <property name="hibernate.c3p0.acquire_increment">2</property>
        <property name="hibernate.c3p0.acquire_increment">1800</property>
        <property name="hibernate.c3p0.max_statements">150</property>
    </session-factory>
</hibernate-configuration>

HibernateConfig.java休眠配置文件

@Configuration
@EnableTransactionManagement
@ComponentScans(value = { @ComponentScan("com.techdisqus")})
public class HibernateConfig {

    @Autowired
    private ApplicationContext context;

    @Bean
    public LocalSessionFactoryBean getSessionFactory() {
        LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
        factoryBean.setConfigLocation(context.getResource("classpath:hibernate.cfg.xml"));
        factoryBean.setAnnotatedClasses(Book.class);
        return factoryBean;
    }

    @Bean
    public HibernateTransactionManager getTransactionManager() {
        HibernateTransactionManager transactionManager = new HibernateTransactionManager();
        transactionManager.setSessionFactory(getSessionFactory().getObject());
        return transactionManager;
    }

}

BookDAOImpl.java BookDAOImpl.java

@Repository
public class BookDAOImpl implements BookDAO {

    @Autowired
    private SessionFactory sessionFactory;

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }




    public void save(Book book) {
        Session session = this.sessionFactory.openSession();
        Transaction tx = session.beginTransaction();
        session.persist(book);
        tx.commit();
        session.close();

    }

}

client code:客户端代码:

public class SpringHibernateMain2 {

    public static void main(String[] args) {

        ApplicationContext appContext = new AnnotationConfigApplicationContext(HibernateConfig.class);

        BookDAO personDAO = appContext.getBean(BookDAO.class);

        Book book = new Book();
        book.setPublisherId(12);
        book.setTitle("t 1");
        //book.setRegistrationNumber(2l);
        personDAO.save(book);

        System.out.println("book::"+book);




        //context.close();

    }

}

from logs while using with H:与 H 一起使用时来自日志:

Hibernate: call next value for hibernate_sequence Hibernate: insert into book (title, publisher_id, registration_number) values (?, ?, ?) book::Book [registrationNumber=1, publisherId=12, title=t 1] Hibernate: 调用 hibernate_sequence 的下一个值 Hibernate: insert into book (title,publisher_id, registration_number) values (?, ?, ?) book::Book [registrationNumber=1,publisherId=12, title=t 1]

The below is the error I get while I try with MySql以下是我尝试使用MySql遇到的error

Hibernate: select next_val as id_val from hibernate_sequence for update Dec 04, 2018 6:24:53 PM org.hibernate.id.enhanced.TableStructure$1$1 execute ERROR: could not read a hi value java.sql.SQLSyntaxErrorException: Table 'security.hibernate_sequence' doesn't exis t休眠:从 hibernate_sequence 中选择 next_val 作为 id_val 进行更新 2018 年 12 月 4 日下午 6:24:53 org.hibernate.id.enhanced.TableStructure$1$1 执行错误:无法读取高值 java.sql.SQLSyntaxErrorException:表 'security. hibernate_sequence' 不存在

I have tried with accepted answer in the post Hibernate insert failing when embedded key contains identity column on SQL Server but no luck with it. 当嵌入式密钥包含 SQL Server 上的标识列时,我在Hibernate insert failed帖子中尝试了接受的答案,但没有成功。

@Embeddable
public class EmployeePK implements Serializable {

    private long groupId;
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long batchId;

   
    public long getBatchId() {
        return batchId;
    }

    public void setBatchId(long batchId) {
        this.batchId = batchId;
    }

//implements equals and hashcode

}

It's precised in the Javadoc of oracle that is not possible and not in the spec: https://docs.oracle.com/javaee/6/api/javax/persistence/GeneratedValue.html它在 oracle 的 Javadoc 中是精确的,这是不可能的,也不在规范中: https://docs.oracle.com/javaee/6/api/javax/persistence/GeneratedValue.html

Use of the GeneratedValue annotation is not supported for derived primary keys.派生主键不支持使用 GeneratedValue 注释。

And I found nothing about how to do it with build in tools.而且我对如何使用内置工具进行操作一无所知。 So you need to do yours own implementation of that.所以你需要自己实现它。

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

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