简体   繁体   中英

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

I have a table with a composite primary key - groupId and batchId . Entity class looks like:

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

    @EmbeddedId
    private EmployeePK employeePK;

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

Composite 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.

//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). As of now, this code will save a new entry with batchId as 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 .

Please note I am using hibernate 5

You may give a try with oracle, I couldn't recollect but it should work. But please check for if any drawbacks with the approach if any.

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

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

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

<?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

@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:

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]

The below is the error I get while I try with MySql

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

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.

@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

Use of the GeneratedValue annotation is not supported for derived primary keys.

And I found nothing about how to do it with build in tools. So you need to do yours own implementation of that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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