JPA 复合主键含自增id

为了使用分区,需要在主键里加入分区字段,主键变为复合主键,包含自增的id和一个分区的字段part。不正确的java代码+建表语句,会导致下述错误。

  1. 导致下述错误的原因:在IdClass里的自增id属性,有注解@GeneratedValue(strategy = GenerationType.IDENTITY)

Can not set java.lang.Long field PK.id to org.hibernate.id.IdentifierGeneratorHelper

Caused by: org.hibernate.PropertyAccessException: Could not set field value [POST_INSERT_INDICATOR] value by reflection : [class com.cc.ai.demo.entity.SearchVecPK.id] setter of com.cc.ai.demo.entity.SearchVecPK.id
at org.hibernate.property.access.spi.SetterFieldImpl.set(SetterFieldImpl.java:72)
at org.hibernate.mapping.Component$ValueGenerationPlan.execute(Component.java:510)
at org.hibernate.id.CompositeNestedGeneratedValueGenerator.generate(CompositeNestedGeneratedValueGenerator.java:97)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:115)
at org.hibernate.event.internal.DefaultMergeEventListener.saveTransientEntity(DefaultMergeEventListener.java:271)
at org.hibernate.event.internal.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:243)
at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:318)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:172)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:70)
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:93)
at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:793)
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:780)
at sun.reflect.GeneratedMethodAccessor156.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at > org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:314)
at com.sun.proxy.$Proxy145.merge(Unknown Source)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:557)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.data.repository.core.support.ImplementationInvocationMetadata.invoke(ImplementationInvocationMetadata.java:72)
at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:382)
at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:205)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:550)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:155)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:130)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:80)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:367)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
… 86 common frames omitted
Caused by: java.lang.IllegalArgumentException: Can not set java.lang.Long field com.cc.ai.demo.entity.SearchVecPK.id to org.hibernate.id.IdentifierGeneratorHelper$2
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81)
at java.lang.reflect.Field.set(Field.java:764)
at org.hibernate.property.access.spi.SetterFieldImpl.set(SetterFieldImpl.java:52)
… 121 common frames omitted

  1. 导致id null exception的原因,数据库表没有auto_increment.

正确的复合主键构造方式:

@Entity
@Getter
@Setter
@ToString
@IdClass(SearchVecPK.class)
@Table(name = "search_vec")
public class SearchVecEntity {

    @Id
    @GeneratedValue // GenerationType.AUTO
    private Long id;

    @Id
    private int part;

    private String appId;
public class SearchVecPK implements Serializable {
    private Long id;
    private int part;
}
CREATE TABLE `search_vec` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `app_id` varchar(255) DEFAULT NULL,
  `part` int(11) NOT NULL,
  PRIMARY KEY (`id`,`part`) USING BTREE,
  UNIQUE KEY `UKqssgibuhvjumx98hexjpw0o3c` (`part`,`user_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=76 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC
/*!50100 PARTITION BY RANGE ( part)
(PARTITION p1 VALUES LESS THAN (1) ENGINE = InnoDB,
 PARTITION p2 VALUES LESS THAN (2) ENGINE = InnoDB)

执行:

       SearchVecEntity searchVecEntity = new SearchVecEntity();
       searchVecEntity.setPart(keyPart.getPart());
       searchVecEntity.setGroupId(key); // todo. where should this groupId set? not here.
       SearchVecEntity save = repository.save(searchVecEntity);

从结果可以看到save的id字段已经赋值。
参考:
https://www.jianshu.com/p/a7779a29bca5/

你可能感兴趣的:(hibernate,spring,java)