You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

BigDecimal转BigInteger时触发ArithmeticException: Rounding necessary异常求助

BigDecimal转BigInteger时触发ArithmeticException: Rounding necessary异常求助

大家好,我现在需要把从数据库获取的BigDecimal类型的ID转换为BigInteger,但一直触发ArithmeticException: Rounding necessary异常。数据库里的ID值是整数154,我尝试了两种转换方式都没解决问题,麻烦大家帮忙看看哪里出问题了,谢谢!

初始代码

IntegrationsUtils.logMessage(Level.INFO, "WT Refund | Processing Transaction: " + id);

BigInteger bigIntegerId = id.setScale(0, RoundingMode.DOWN).toBigInteger();

WTRefund wtRefundTransaction = getDaoFactory().getWtRefundDao()
.findById(id.toBigInteger());

更新后的代码(仍报错)

BigInteger bigIntegerId = id.setScale(0, RoundingMode.DOWN).toBigInteger();

WTRefund wtRefundTransaction = getDaoFactory().getWtRefundDao().findById(bigIntegerId);

异常栈信息

java.lang.ArithmeticException: Rounding necessary

at java.base/java.math.BigDecimal.commonNeedIncrement(BigDecimal.java:4717)
at java.base/java.math.BigDecimal.needIncrement(BigDecimal.java:4767)
at java.base/java.math.BigDecimal.divideAndRound(BigDecimal.java:4681)
at java.base/java.math.BigDecimal.setScale(BigDecimal.java:2940)
at java.base/java.math.BigDecimal.toBigIntegerExact(BigDecimal.java:3557)
at org.hibernate.type.descriptor.java.BigIntegerTypeDescriptor.wrap(BigIntegerTypeDescriptor.java:88)
at org.hibernate.type.descriptor.java.BigIntegerTypeDescriptor.wrap(BigIntegerTypeDescriptor.java:19)
at org.hibernate.type.descriptor.sql.DecimalTypeDescriptor$2.doExtract(DecimalTypeDescriptor.java:63)
at org.hibernate.type.descriptor.sql.BasicExtractor.extract(BasicExtractor.java:47)
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:3214)
at org.hibernate.persister.entity.Loadable.hydrate(Loadable.java:94)
at org.hibernate.loader.plan.exec.process.internal.EntityReferenceInitializerImpl.loadFromResultSet(EntityReferenceInitializerImpl.java:342)
at org.hibernate.loader.plan.exec.process.internal.EntityReferenceInitializerImpl.hydrateEntityState(EntityReferenceInitializerImpl.java:269)
at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.readRow(AbstractRowReader.java:80)
at org.hibernate.loader.plan.exec.internal.EntityLoadQueryDetails$EntityLoaderRowReader.readRow(EntityLoadQueryDetails.java:288)
at org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl.extractRows(ResultSetProcessorImpl.java:157)
at org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl.extractResults(ResultSetProcessorImpl.java:94)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:105)
at org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader.load(AbstractLoadPlanBasedEntityLoader.java:285)
at org.hibernate.persister.entity.AbstractEntityPersister.doLoad(AbstractEntityPersister.java:4521)
at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4511)
at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:571)
at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:539)
at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:208)
at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:327)
at org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:108)
at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:74)
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:118)
at org.hibernate.internal.SessionImpl.fireLoadNoChecks(SessionImpl.java:1231)
at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1220)
at org.hibernate.internal.SessionImpl.access$2100(SessionImpl.java:202)
at org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.doLoad(SessionImpl.java:2835)
at org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.lambda$load$1(SessionImpl.java:2812)
at org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.perform(SessionImpl.java:2768)
at org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.load(SessionImpl.java:2812)
at org.hibernate.internal.SessionImpl.find(SessionImpl.java:3400)
at org.hibernate.internal.SessionImpl.find(SessionImpl.java:3362)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:311)
at jdk.proxy2/jdk.proxy2.$Proxy117.find(Unknown Source)
at com.tlx.afx.integrations.commons.persistence.dao.BaseDAOPrimary.findById(BaseDAOPrimary.java:96)
at com.tlx.afx.integrations.commons.persistence.dao.BaseDAOPrimary$$FastClassBySpringCGLIB$$486dd08b.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708)
at com.tlx.afx.integrations.commons.persistence.dao.WTRefundDao$$EnhancerBySpringCGLIB$$a3538153.findById(<generated>)
at com.tlx.afx.integrations.inbound.accountingentries.wtrefund.WTRefundService.listenForWTRefundTransactions(WTRefundService.java:65)
at com.tlx.afx.integrations.inbound.accountingentries.AccountingEntriesJobsTrigger.listenForIncomingTransaction15(AccountingEntriesJobsTrigger.java:418)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:95)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:842)

问题分析

从异常栈能看出来,异常并不是出在你自己写的转换代码里,而是Hibernate执行findById查询时,把数据库返回的Decimal类型字段转换为BigInteger时触发的——具体是BigIntegerTypeDescriptor.wrap方法调用了toBigIntegerExact(),这个方法要求BigDecimal必须是精确的整数(没有小数部分),否则就会抛出Rounding necessary异常。

你说数据库里的ID是154,但可能实际存储的是带有微小小数位的数值(比如154.0000000001这种肉眼看不到的精度误差),或者数据库字段定义是Decimal类型且带有小数位,导致Hibernate转换时认为这不是精确的整数。

解决方案

这里有几个可行的处理思路:

  • 直接用BigDecimal作为DAO查询参数
    既然数据库字段是Decimal类型,建议把WTRefundDao的findById方法参数类型改成BigDecimal,直接用从数据库拿到的id去查询,完全避免转换过程中的精度问题。

  • 强制截断小数部分后转换
    如果必须用BigInteger查询,可以用这两种方式确保转换成功:

    // 方式1:直接调用toBigInteger(),自动截断小数部分,不会抛异常
    BigInteger bigIntegerId = id.toBigInteger();
    // 方式2:先去掉末尾的零再转字符串,彻底避免精度问题
    BigInteger bigIntegerId = new BigInteger(id.stripTrailingZeros().toPlainString());
    
  • 检查实体类ID字段类型
    确认WTRefund实体类中的ID字段类型和数据库字段匹配:如果数据库是Decimal类型,实体类应该用BigDecimal而非BigInteger,这样Hibernate加载实体时就不会触发错误的类型转换。

备注:内容来源于stack exchange,提问作者Wajih Haider

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.20 07:15:30