休眠 UUID 为 UUID 类型
Posted
技术标签:
【中文标题】休眠 UUID 为 UUID 类型【英文标题】:Hibernate UUID as UUID type 【发布时间】:2014-10-26 00:06:01 【问题描述】:尝试使用UUID
作为 PostgreSQL 和 H2 的我的 id,当前的例外是 H2
java.lang.IllegalArgumentException: Can not set java.util.UUID field com.lm.model.Task.id to java.lang.String
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:758)
at org.hibernate.property.DirectPropertyAccessor$DirectSetter.set(DirectPropertyAccessor.java:122)
at org.hibernate.tuple.entity.AbstractEntityTuplizer.setIdentifier(AbstractEntityTuplizer.java:381)
at org.hibernate.persister.entity.AbstractEntityPersister.setIdentifier(AbstractEntityPersister.java:4751)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:184)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:137)
at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:84)
at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:206)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:149)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:75)
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:811)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:784)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:789)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1181)
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:483)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:342)
at com.sun.proxy.$Proxy68.persist(Unknown Source)
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:483)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:289)
at com.sun.proxy.$Proxy68.persist(Unknown Source)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:389)
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:483)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:405)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:390)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:344)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodIntercceptor.invoke(CrudMethodMetadataPostProcessor.java:111)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy70.save(Unknown Source)
at org.springframework.data.rest.core.invoke.CrudRepositoryInvoker.invokeSave(CrudRepositoryInvoker.java:106)
at org.springframework.data.rest.webmvc.RepositoryEntityController.createAndReturn(RepositoryEntityController.java:383)
at org.springframework.data.rest.webmvc.RepositoryEntityController.postCollectionResource(RepositoryEntityController.java:211)
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:483)
at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:749)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:689)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:863)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:646)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:683)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1720)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1679)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
这是我的实体
@Entity
@Table(name = "tasks")
public class Task
private static final Logger log = LoggerFactory.getLogger(Task.class);
@Id
@NotNull
@GeneratedValue(generator="system-uuid")
@GenericGenerator(name="system-uuid", strategy = "uuid")
@Column(name = "task_id", columnDefinition = "uuid")
private UUID id;
@NotNull
@NotEmpty
@Size(min = 1, max = 120)
private String description;
public String getDescription ()
return description;
public void setDescription (final String description)
this.description = description;
public UUID getId ()
return id;
public void setId ( final UUID uuid )
id = uuid;
我不确定它是否相关,但我正在使用 Spring Data Rest Repository 来保存它。
我希望最终能够作为 PostgreSQL 中的本机类型持续存在,并且无论 H2 是什么都需要 UUID(我对 H2 相当陌生)。
【问题讨论】:
一个简单的@Id @GeneratedValue private java.util.UUID id;
在 H 上的 Hibernate 5+ 中工作。请参阅 documentation。可能也适用于其他数据库。
@NatanCox 很有趣,在让他们制作功能后,我从未更新过这个答案
@NatanCox 更新了我的答案,包括我为pgjdbc bug 写的文字
【参考方案1】:
更新: 使用 Hibernate 5 I was able to get more cross database compatible UUID's included(注意:我不是实施者,尽管我确实尝试过)。
@Entity
public class MyEntity
@Id
@GeneratedValue
@Column( columnDefinition = "uuid", updatable = false )
public UUID getId()
return id;
原创
Dzone posted an article about a second version of the UUID generator last year
首先创建自己的用户类型(至少在 hibernate 实现类似之前)
public class UUIDType extends AbstractSingleColumnStandardBasicType<UUID>
public static final String NAME = "uuid-name";
public static final UUIDType INSTANCE = new UUIDType();
public UUIDType()
super( UUIDSqlTypeDescriptor.INSTANCE, UUIDTypeDescriptor.INSTANCE );
public String getName()
return NAME;
public static class UUIDSqlTypeDescriptor implements SqlTypeDescriptor
public static final UUIDSqlTypeDescriptor INSTANCE = new UUIDSqlTypeDescriptor();
public int getSqlType()
// ugh
return Types.VARCHAR;
@Override
public boolean canBeRemapped()
return true;
public <X> ValueBinder<X> getBinder( final JavaTypeDescriptor<X> javaTypeDescriptor )
return new BasicBinder<X>( javaTypeDescriptor, this )
@Override
protected void doBind( PreparedStatement st, X value, int index, WrapperOptions options )
throws SQLException
st.setObject( index, javaTypeDescriptor.unwrap( value, UUID.class, options ) );
;
public <X> ValueExtractor<X> getExtractor( final JavaTypeDescriptor<X> javaTypeDescriptor )
return new BasicExtractor<X>( javaTypeDescriptor, this )
@Override
protected X doExtract( ResultSet rs, String name, WrapperOptions options ) throws SQLException
return javaTypeDescriptor.wrap( rs.getObject( name ), options );
@Override
protected X doExtract( CallableStatement statement, int index, WrapperOptions options )
throws SQLException
return javaTypeDescriptor.wrap( statement.getObject( index ), options );
@Override
protected X doExtract( CallableStatement statement, String name, WrapperOptions options )
throws SQLException
return javaTypeDescriptor.wrap( statement.getObject( name ), options );
;
然后注释你的模型package-info.java
@TypeDef(
name = UUIDType.NAME,
defaultForType = UUID.class,
typeClass = UUIDType.class
)
package com.xenoterracide.rpf.model;
import org.hibernate.annotations.TypeDef;
import org.hibernate.type.UUIDType;
import java.util.UUID;
终于在你的实体中
@Id
@Override
@GeneratedValue(generator = "uuid2")
@GenericGenerator(name = "uuid2", strategy = "uuid2")
@Column(name = "id", columnDefinition = "uuid")
public UUID getId()
return id;
【讨论】:
以上是关于休眠 UUID 为 UUID 类型的主要内容,如果未能解决你的问题,请参考以下文章
tomcat restart => 找不到 SessionFactory [uuid=...,name=null]
Pyspark 可为空的 uuid 类型 uuid 但表达式的类型为字符变化
如何修复“UUID 类型的方法参数缺少 URI 模板变量 'uuid'”?