问题遇到的现象和发生背景
使用JPA进行数据库的查询和更新操作,其中实体类中的updateTime字段使用了自动更新策略,并手写实现接口AttributeConverter进行转换。java字段为Date,数据库中使用Number(14)。单线程执行任何查询和更新都没有问题,但是通过多线程,查询或更新不同的记录时,会有概率出现转换异常。目前尚未发现问题原因。
问题相关代码,请勿粘贴截图
//实体类
@Data
@Entity
@Table(name = "my_order")
@EntityListeners(AuditingEntityListener.class)
public class Order
{
@Column(name = "fundCode")
private String fundCode;
@Column(name = "APPLICATIONAMOUNT")
private double updateBal;
@Id
@Column(name = "orderId")
private String orderId;
@Column(name = "CREATEDTIME")
@CreatedDate
@Convert(converter = AppDateConvertDBLong.class)
private Date createTime;
@Column(name = "UPDATETIME")
@LastModifiedDate
@Convert(converter = AppDateConvertDBLong.class)
private Date updateTime; //该字段使用自动生成策略并实现转换接口
}
//转换接口
public class AppDateConvertDBLong implements AttributeConverter<Date,Long>
{
private static final SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMddHHmmss");
@Override
public Long convertToDatabaseColumn(Date attribute)
{
try
{
return attribute == null ? null : Long.parseLong(sdf.format(attribute));
}
catch (NumberFormatException e)
{
logger.error("convertToDatabaseColumn error : {}",attribute);
logger.error("convertToDatabaseColumn error :",e);
//如果失败默认返回当前时间
return DateUtils.getLong14ForDate();
}
}
@Override
public Date convertToEntityAttribute(Long dbData)
{
try
{
return dbData == null ? null : sdf.parse(String.valueOf(dbData));
} catch (ParseException e)
{
logger.error("convertToEntityAttribute error : {}",dbData);
logger.error("convertToEntityAttribute error :",e);
return null;
}
}
}
运行结果及报错内容
分别来自两个方向的异常:
1 update Date转Long
Caused by: javax.persistence.PersistenceException: Error attempting to apply AttributeConverter
at org.hibernate.type.descriptor.converter.AttributeConverterSqlTypeDescriptorAdapter$2.doConversion(AttributeConverterSqlTypeDescriptorAdapter.java:148)
at org.hibernate.type.descriptor.converter.AttributeConverterSqlTypeDescriptorAdapter$2.extract(AttributeConverterSqlTypeDescriptorAdapter.java:121)
at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:257)
at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:253)
at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:243)
at org.hibernate.type.AbstractStandardBasicType.hydrate(AbstractStandardBasicType.java:329)
at org.hibernate.persister.entity.AbstractEntityPersister.hydrate(AbstractEntityPersister.java:3131)
at org.hibernate.loader.Loader.loadFromResultSet(Loader.java:1863)
at org.hibernate.loader.Loader.hydrateEntityState(Loader.java:1791)
at org.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:1764)
at org.hibernate.loader.Loader.getRow(Loader.java:1616)
at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:740)
at org.hibernate.loader.Loader.getRowsFromResultSet(Loader.java:1039)
at org.hibernate.loader.Loader.processResultSet(Loader.java:990)
at org.hibernate.loader.Loader.doQuery(Loader.java:959)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:349)
at org.hibernate.loader.Loader.doList(Loader.java:2843)
at org.hibernate.loader.Loader.doList(Loader.java:2825)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2657)
at org.hibernate.loader.Loader.list(Loader.java:2652)
at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:506)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:400)
at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:219)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1414)
at org.hibernate.query.internal.AbstractProducedQuery.doList(AbstractProducedQuery.java:1636)
at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1604)
at org.hibernate.query.Query.getResultList(Query.java:165)
at org.hibernate.query.criteria.internal.compile.CriteriaQueryTypeQueryAdapter.getResultList(CriteriaQueryTypeQueryAdapter.java:76)
at sun.reflect.GeneratedMethodAccessor437.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$DeferredQueryInvocationHandler.invoke(SharedEntityManagerCreator.java:409)
at com.sun.proxy.$Proxy335.getResultList(Unknown Source)
at org.springframework.data.jpa.repository.query.JpaQueryExecution$CollectionExecution.doExecute(JpaQueryExecution.java:126)
at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:88)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:154)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:142)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor$QueryMethodInvoker.invoke(QueryExecutorMethodInterceptor.java:195)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:152)
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)
... 28 common frames omitted
Caused by: java.lang.NumberFormatException: For input string: ""
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Long.parseLong(Long.java:601)
at java.lang.Long.parseLong(Long.java:631)
at java.text.DigitList.getLong(DigitList.java:195)
at java.text.DecimalFormat.parse(DecimalFormat.java:2051)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:2162)
at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
at java.text.DateFormat.parse(DateFormat.java:364)
at com.cicc.aiis.util.convertor.AppDateConvertDBLong.convertToEntityAttribute(AppDateConvertDBLong.java:43)
at com.cicc.aiis.util.convertor.AppDateConvertDBLong.convertToEntityAttribute(AppDateConvertDBLong.java:15)
at org.hibernate.metamodel.model.convert.internal.JpaAttributeConverterImpl.toDomainValue(JpaAttributeConverterImpl.java:45)
at org.hibernate.type.descriptor.converter.AttributeConverterSqlTypeDescriptorAdapter$2.doConversion(AttributeConverterSqlTypeDescriptorAdapter.java:140)
//2 查询时 Long转Date
java.text.ParseException: Unparseable date: "411207231111"
at java.text.DateFormat.parse(DateFormat.java:366)
at com.cicc.aiis.util.convertor.AppDateConvertDBLong.convertToEntityAttribute(AppDateConvertDBLong.java:43)
at com.cicc.aiis.util.convertor.AppDateConvertDBLong.convertToEntityAttribute(AppDateConvertDBLong.java:15)
at org.hibernate.metamodel.model.convert.internal.JpaAttributeConverterImpl.toDomainValue(JpaAttributeConverterImpl.java:45)
at org.hibernate.type.descriptor.converter.AttributeConverterMutabilityPlanImpl.deepCopyNotNull(AttributeConverterMutabilityPlanImpl.java:33)
at org.hibernate.type.descriptor.java.MutableMutabilityPlan.deepCopy(MutableMutabilityPlan.java:35)
at org.hibernate.type.AbstractStandardBasicType.deepCopy(AbstractStandardBasicType.java:308)
at org.hibernate.type.AbstractStandardBasicType.deepCopy(AbstractStandardBasicType.java:304)
at org.hibernate.type.TypeHelper.deepCopy(TypeHelper.java:55)
at org.hibernate.engine.internal.TwoPhaseLoad.initializeEntityFromEntityEntryLoadedState(TwoPhaseLoad.java:340)
at org.hibernate.engine.internal.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:156)
at org.hibernate.engine.internal.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:126)
at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:1193)
at org.hibernate.loader.Loader.processResultSet(Loader.java:1001)
at org.hibernate.loader.Loader.doQuery(Loader.java:959)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:349)
at org.hibernate.loader.Loader.doList(Loader.java:2843)
at org.hibernate.loader.Loader.doList(Loader.java:2825)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2657)
at org.hibernate.loader.Loader.list(Loader.java:2652)
at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:506)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:400)
at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:219)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1414)
at org.hibernate.query.internal.AbstractProducedQuery.doList(AbstractProducedQuery.java:1636)
at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1604)
at org.hibernate.query.Query.getResultList(Query.java:165)
at org.hibernate.query.criteria.internal.compile.CriteriaQueryTypeQueryAdapter.getResultList(CriteriaQueryTypeQueryAdapter.java:76)
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.orm.jpa.SharedEntityManagerCreator$DeferredQueryInvocationHandler.invoke(SharedEntityManagerCreator.java:409)
at com.sun.proxy.$Proxy335.getResultList(Unknown Source)
at org.springframework.data.jpa.repository.query.JpaQueryExecution$CollectionExecution.doExecute(JpaQueryExecution.java:126)
at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:88)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:154)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:142)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor$QueryMethodInvoker.invoke(QueryExecutorMethodInterceptor.java:195)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:152)
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)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:149)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy257.findSubEntrustOrdersByEntrustPortfolioIdAndOrderStatus(Unknown Source)
at com.cicc.aiis.service.trade.EntrustPortfolioServiceImpl.querySubEntrustsByStatus(EntrustPortfolioServiceImpl.java:329)
at com.cicc.aiis.service.trade.EntrustPortfolioServiceImpl$$FastClassBySpringCGLIB$$592c3f78.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
at com.cicc.aiis.service.trade.EntrustPortfolioServiceImpl$$EnhancerBySpringCGLIB$$dde6175e.querySubEntrustsByStatus(<generated>)
at com.cicc.aiis.service.trade.EntranceServiceImpl.reservationToOrder(EntranceServiceImpl.java:148)
at com.cicc.aiis.service.trade.EntranceServiceImpl$$FastClassBySpringCGLIB$$dfb5bb5b.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
at com.cicc.aiis.service.trade.EntranceServiceImpl$$EnhancerBySpringCGLIB$$6cb190e7.reservationToOrder(<generated>)
at com.cicc.aiis.service.impl.ReservationOrderServiceImpl.processOrder(ReservationOrderServiceImpl.java:114)
at com.cicc.aiis.service.impl.ReservationOrderServiceImpl.processEachOrder(ReservationOrderServiceImpl.java:99)
at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1374)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:291)
at java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:731)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
我的解答思路和尝试过的方法
其中第一个异常问题 我甚至在代码中显示的setUpdateTime(new Date),也会报错
而第二个异常,数据库中绝对是可读的14位时间戳 20211213112328 抛异常时却显示读到了411207231111 ,这个很诡异啊,411207231111 这个数据在数据库也搜不到。多试几次还会出现别的数字,比如11123 这种随机的错误的时间数字
最关键的时候只要使用多线程,就会出现,单线程就一点问题没有。我用的是List.parallelStream().forEach的方式
我想要达到的结果
希望高人指点,谢谢