问题
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.
回答1:
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 exist
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.
回答2:
@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
}
来源:https://stackoverflow.com/questions/53595226/how-to-autoincrement-an-id-in-a-composite-primary-key-in-hibernate