Reputation: 1906
I'm trying to test a composed primary key, unfortunatly something is running incorrectly.
The Course class that contains the composed primary key
@Entity(name = "Course")
public class Course {
@EmbeddedId
private PkCourse pkCourse;
public Course() {}
public Course( PkCourse pkCourse) {
this.pkCourse = pkCourse;
}
public PkCourse getPkCourse() {
return pkCourse;
}
public void setPkCourse( PkCourse pkCourse ) {
this.pkCourse = pkCourse;
}
}
the class that represent a composed primary key
@Embeddable
public class PkCourse implements Serializable {
@Column(name = "courseName")
private String courseName;
@Column(name = "courseGrade")
private Integer grade;
PkCourse(){
}
public PkCourse( String courseName, Integer grade ) {
this.courseName = courseName;
this.grade = grade;
}
public String getCourseName() {
return courseName;
}
public void setCourseName( String courseName ) {
this.courseName = courseName;
}
public Integer getGrade() {
return grade;
}
public void setGrade( Integer grade ) {
this.grade = grade;
}
@Override
public boolean equals( Object o ) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PkCourse pkCourse = (PkCourse) o;
return courseName.equals(pkCourse.courseName) &&
Objects.equals(grade, pkCourse.grade);
}
@Override
public int hashCode() {
return Objects.hash(courseName, grade);
}
}
My testing program
private void composedPrimaryKey() {
PkCourse composedPK = new PkCourse("database", 3);
Course course = new Course(composedPK);
courseRepository.save(course);
}
my jpa repository
public interface CourseRepository extends JpaRepository<Course, PkCourse> {
}
The exception I'm getting
Caused by: org.springframework.dao.InvalidDataAccessResourceUsageException: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet
Caused by: java.sql.SQLSyntaxErrorException: Table 'company.course' doesn't exist
The full trace
> java.lang.IllegalStateException: Failed to execute CommandLineRunner
> at
> org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:783)
> [spring-boot-2.1.7.RELEASE.jar:2.1.7.RELEASE] at
> org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:764)
> [spring-boot-2.1.7.RELEASE.jar:2.1.7.RELEASE] at
> org.springframework.boot.SpringApplication.run(SpringApplication.java:319)
> [spring-boot-2.1.7.RELEASE.jar:2.1.7.RELEASE] at
> org.springframework.boot.SpringApplication.run(SpringApplication.java:1214)
> [spring-boot-2.1.7.RELEASE.jar:2.1.7.RELEASE] at
> org.springframework.boot.SpringApplication.run(SpringApplication.java:1203)
> [spring-boot-2.1.7.RELEASE.jar:2.1.7.RELEASE] at
> jpa.hibearnate.example.hibernateDemo4.HibernateDemoApplication.main(HibernateDemoApplication.java:26)
> [classes/:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native
> Method) ~[na:1.8.0_131] at
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
> ~[na:1.8.0_131] at
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
> ~[na:1.8.0_131] at java.lang.reflect.Method.invoke(Method.java:498)
> ~[na:1.8.0_131] at
> org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
> [spring-boot-devtools-2.1.7.RELEASE.jar:2.1.7.RELEASE] Caused by:
> org.springframework.dao.InvalidDataAccessResourceUsageException: could
> not extract ResultSet; SQL [n/a]; nested exception is
> org.hibernate.exception.SQLGrammarException: could not extract
> ResultSet at
> org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:279)
> ~[spring-orm-5.1.9.RELEASE.jar:5.1.9.RELEASE] at
> org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:253)
> ~[spring-orm-5.1.9.RELEASE.jar:5.1.9.RELEASE] at
> org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:527)
> ~[spring-orm-5.1.9.RELEASE.jar:5.1.9.RELEASE] at
> org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
> ~[spring-tx-5.1.9.RELEASE.jar:5.1.9.RELEASE] at
> org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
> ~[spring-tx-5.1.9.RELEASE.jar:5.1.9.RELEASE] at
> org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153)
> ~[spring-tx-5.1.9.RELEASE.jar:5.1.9.RELEASE] at
> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
> ~[spring-aop-5.1.9.RELEASE.jar:5.1.9.RELEASE] at
> org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:144)
> ~[spring-data-jpa-2.1.10.RELEASE.jar:2.1.10.RELEASE] at
> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
> ~[spring-aop-5.1.9.RELEASE.jar:5.1.9.RELEASE] at
> org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$ExposeRepositoryInvocationInterceptor.invoke(CrudMethodMetadataPostProcessor.java:364)
> ~[spring-data-jpa-2.1.10.RELEASE.jar:2.1.10.RELEASE] at
> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
> ~[spring-aop-5.1.9.RELEASE.jar:5.1.9.RELEASE] at
> org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
> ~[spring-aop-5.1.9.RELEASE.jar:5.1.9.RELEASE] at
> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
> ~[spring-aop-5.1.9.RELEASE.jar:5.1.9.RELEASE] at
> org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
> ~[spring-data-commons-2.1.10.RELEASE.jar:2.1.10.RELEASE] at
> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
> ~[spring-aop-5.1.9.RELEASE.jar:5.1.9.RELEASE] at
> org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
> ~[spring-aop-5.1.9.RELEASE.jar:5.1.9.RELEASE] at
> com.sun.proxy.$Proxy71.save(Unknown Source) ~[na:na] at
> jpa.hibearnate.example.hibernateDemo4.HibernateDemoApplication.composedPrimaryKey(HibernateDemoApplication.java:37)
> [classes/:na] at
> jpa.hibearnate.example.hibernateDemo4.HibernateDemoApplication.run(HibernateDemoApplication.java:31)
> [classes/:na] at
> org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:780)
> [spring-boot-2.1.7.RELEASE.jar:2.1.7.RELEASE] ... 10 common frames
> omitted Caused by: org.hibernate.exception.SQLGrammarException: could
> not extract ResultSet at
> org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:63)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:69)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.loader.Loader.getResultSet(Loader.java:2167)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1930)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1892)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.loader.Loader.doQuery(Loader.java:937)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:340)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:310)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.loader.Loader.loadEntity(Loader.java:2281)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:64)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:54)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4273)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:511)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:481)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:222)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:281)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:124)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:92)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1257)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.internal.SessionImpl.access$2000(SessionImpl.java:208)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.doLoad(SessionImpl.java:2881)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.load(SessionImpl.java:2855)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.internal.SessionImpl.get(SessionImpl.java:1098)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:290)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:170)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:69)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:901)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> org.hibernate.internal.SessionImpl.merge(SessionImpl.java:887)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final] at
> sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> ~[na:1.8.0_131] at
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
> ~[na:1.8.0_131] at
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
> ~[na:1.8.0_131] at java.lang.reflect.Method.invoke(Method.java:498)
> ~[na:1.8.0_131] at
> org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:309)
> ~[spring-orm-5.1.9.RELEASE.jar:5.1.9.RELEASE] at
> com.sun.proxy.$Proxy69.merge(Unknown Source) ~[na:na] at
> org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:538)
> ~[spring-data-jpa-2.1.10.RELEASE.jar:2.1.10.RELEASE] at
> sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> ~[na:1.8.0_131] at
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
> ~[na:1.8.0_131] at
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
> ~[na:1.8.0_131] at java.lang.reflect.Method.invoke(Method.java:498)
> ~[na:1.8.0_131] at
> org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:359)
> ~[spring-data-commons-2.1.10.RELEASE.jar:2.1.10.RELEASE] at
> org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200)
> ~[spring-data-commons-2.1.10.RELEASE.jar:2.1.10.RELEASE] at
> org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:644)
> ~[spring-data-commons-2.1.10.RELEASE.jar:2.1.10.RELEASE] at
> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
> ~[spring-aop-5.1.9.RELEASE.jar:5.1.9.RELEASE] at
> org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:608)
> ~[spring-data-commons-2.1.10.RELEASE.jar:2.1.10.RELEASE] at
> org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595)
> ~[spring-data-commons-2.1.10.RELEASE.jar:2.1.10.RELEASE] at
> org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595)
> ~[spring-data-commons-2.1.10.RELEASE.jar:2.1.10.RELEASE] at
> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
> ~[spring-aop-5.1.9.RELEASE.jar:5.1.9.RELEASE] at
> org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
> ~[spring-data-commons-2.1.10.RELEASE.jar:2.1.10.RELEASE] at
> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
> ~[spring-aop-5.1.9.RELEASE.jar:5.1.9.RELEASE] at
> org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:295)
> ~[spring-tx-5.1.9.RELEASE.jar:5.1.9.RELEASE] at
> org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
> ~[spring-tx-5.1.9.RELEASE.jar:5.1.9.RELEASE] at
> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
> ~[spring-aop-5.1.9.RELEASE.jar:5.1.9.RELEASE] at
> org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
> ~[spring-tx-5.1.9.RELEASE.jar:5.1.9.RELEASE] ... 24 common frames
> omitted Caused by: java.sql.SQLSyntaxErrorException: Table
> 'company.course' doesn't exist at
> com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120)
> ~[mysql-connector-java-8.0.17.jar:8.0.17] at
> com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
> ~[mysql-connector-java-8.0.17.jar:8.0.17] at
> com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
> ~[mysql-connector-java-8.0.17.jar:8.0.17] at
> com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953)
> ~[mysql-connector-java-8.0.17.jar:8.0.17] at
> com.mysql.cj.jdbc.ClientPreparedStatement.executeQuery(ClientPreparedStatement.java:1003)
> ~[mysql-connector-java-8.0.17.jar:8.0.17] at
> com.zaxxer.hikari.pool.ProxyPreparedStatement.executeQuery(ProxyPreparedStatement.java:52)
> ~[HikariCP-3.2.0.jar:na] at
> com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeQuery(HikariProxyPreparedStatement.java)
> ~[HikariCP-3.2.0.jar:na] at
> org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:60)
> ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
Edit1
I solved the problem of the Course table creation by replacing the Integer attribute grade
by a String atttribute.
Edit2
My hibernate log:
> Hibernate:
>
> drop table if exists course Hibernate:
>
> create table course (
> course_name varchar(255) not null,
> course_grade integer not null,
> primary key (course_name, course_grade)
> ) engine=MyISAM 2019-08-15 09:36:34.238 WARN 11508 --- [ restartedMain] o.h.t.s.i.ExceptionHandlerLoggedImpl :
> GenerationTarget encountered exception accepting command : Error
> executing DDL "
> create table course (
> course_name varchar(255) not null,
> course_grade integer not null,
> primary key (course_name, course_grade)
> ) engine=MyISAM" via JDBC Statement
>
> org.hibernate.tool.schema.spi.CommandAcceptanceException: Error
> executing DDL "
> create table course (
> course_name varchar(255) not null,
> course_grade integer not null,
> primary key (course_name, course_grade)
> ) engine=MyISAM" via JDBC Statement
Caused by: java.sql.SQLSyntaxErrorException: Specified key was too long; max key length is 1000 bytes
Hibernate:
select
course0_.course_name as course_n1_0_0_,
course0_.course_grade as course_g2_0_0_
from
course course0_
where
course0_.course_name=?
and course0_.course_grade=?
2019-08-15 09:36:34.718 ERROR 11508 --- [ restartedMain] o.h.engine.jdbc.spi.SqlExceptionHelper : Table 'company.course' doesn't exist
Could someone explains why it didn't work with two attribute with differents types?(String and Integer in my first case).
Edit 3
Also, I solved my problem by modifiying the annotation
@Column(name = "courseName")
private String courseName;
to
@Column(name = "courseName", length = 20)
private String courseName;
I tried this modification based on the exception line
Caused by: java.sql.SQLSyntaxErrorException: Specified key was too long; max key length is 1000 bytes
Could someone explains what is the magic behind that?
Upvotes: 1
Views: 1121
Reputation: 146520
If you look at the DDL
create table course (
course_name varchar(255) not null,
course_grade integer not null,
primary key (course_name, course_grade)
) engine=MyISAM" via JDBC Statement
There is limit on size of value that is indexed in MyISAM
tables, this default size is also dependent version of your MySQL
Now ideal way to create such table is not to use course_name
and course_grade
as a primary key but rather you should use a uuid
or auto gen id
and then put a unique index on a combination of course_name
and course_grade
.
In case you still face an issue with that, You can also try different fixes mentioned in threads referred in this answer
SET @@global.innodb_large_prefix = 1;
Upgrade to higher MySQL version 5.7+
set GLOBAL storage_engine='InnoDb';
Referrences
#1071 - Specified key was too long; max key length is 1000 bytes
#1071 - Specified key was too long; max key length is 767 bytes
Upvotes: 3