目錄
前言
今天在做一個小功能的時候,出現了一個令人抓狂的異常,一直以爲是自己代碼或者sql 的問題,講道理,這麼簡單的一個SQL我都會寫錯嗎,不可能?講道理這麼簡單的一個功能,我邏輯會寫錯嗎,也不可能?總之檢查了一遍又一遍,最終才找到解決方法。
一、問題出現
咱們來回顧一下這個異常
首先我寫了一個簡單的SQL語句,如下
public int updateVoiceLinePhoneNo(String lineId,String totalPhoneNo) {
String sql="UPDATE yjltable SET name='"+totalPhoneNo+"' WHERE id='111'";
System.out.println(sql.toString());
int i = em.createNativeQuery(sql).executeUpdate();
return i;
}
然後service和controller層我就省略了,很簡單的三層架構例子
當時抓狂的異常就在下面了,部分敏感部分我就用*號替換了,也不重要
17:21:42.209 [grp0#CsfServerRequestHandleThread-3630ad242aa24fea9f2c2f6a5ea35435] DEBUG com.****************.executor.request.filter.RecordFilter - 請求 [requestId=3630ad242aa24fea9f2c2f6a5ea35435, serviceCode=MinTools_**************_updateVoiceLinePhoneNo, version=1.0, systemParams={Accept=*/*, User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0, Connection=keep-alive, Host=localhost:36102, Accept-Encoding=gzip, deflate, serialize-type=json, uuid=3630ad242aa24fea9f2c2f6a5ea35435, csf.app.ip=0:0:0:0:0:0:0:1, csf.app.name=null, csf_version=1.0, Accept-Language=zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2, Content-Length=38, Content-Type=application/json}, businessParams={lineId=111, totalPhoneNo=aaaaaaaa}, calleeProtocol=RESTFUL, isDevelopPattern=false, timeoutByApi=-1]
UPDATE yjltable SET name='aaaaaaaa' WHERE id='111'
17:21:45.552 [grp0#CsfServerRequestHandleThread-3630ad242aa24fea9f2c2f6a5ea35435] DEBUG org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler - Creating new EntityManager for shared EntityManager invocation
17:21:45.640 [grp0#CsfServerRequestHandleThread-3630ad242aa24fea9f2c2f6a5ea35435] DEBUG org.hibernate.stat.internal.StatisticsInitiator - Statistics initialized [enabled=false]
17:21:45.745 [grp0#CsfServerRequestHandleThread-3630ad242aa24fea9f2c2f6a5ea35435] DEBUG org.hibernate.engine.transaction.internal.TransactionImpl - On TransactionImpl creation, JpaCompliance#isJpaTransactionComplianceEnabled == false
17:21:45.746 [grp0#CsfServerRequestHandleThread-3630ad242aa24fea9f2c2f6a5ea35435] DEBUG org.springframework.orm.jpa.EntityManagerFactoryUtils - Closing JPA EntityManager
17:21:45.752 [grp0#CsfServerRequestHandleThread-3630ad242aa24fea9f2c2f6a5ea35435] DEBUG com.****************.common.exception.adapter.ServerExceptionAdapter - 服務端異常處理的實現類爲:com.****************.common.exception.handler.DefaultServerExceptionHandler
17:21:45.957 [grp0#CsfServerRequestHandleThread-3630ad242aa24fea9f2c2f6a5ea35435] ERROR com.****************.executor.request.worker.AsyncRequestTask - 業務執行線程拋出異常:{date=2019-06-17 17:21:45, exceptionStack=javax.persistence.TransactionRequiredException: Executing an update/delete query
at org.hibernate.query.internal.AbstractProducedQuery.executeUpdate(AbstractProducedQuery.java:1586)
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:402)
at com.sun.proxy.$Proxy88.executeUpdate(Unknown Source)
at com.*************.dao.VoiceLineDaoImpl.updateVoiceLinePhoneNo(VoiceLineDaoImpl.java:65)
at com.*************.msservice.service.impl.VoiceLineServiceImplCSVImpl.updateVoiceLinePhoneNo(VoiceLineServiceImplCSVImpl.java:206)
at com.****************.msservice.controller.impl.VoiceLineControllerCSVImpl.updateVoiceLinePhoneNo(VoiceLineControllerCSVImpl.java:48)
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 com.****************.executor.request.worker.ServiceExecutor.invoke(ServiceExecutor.java:33)
at com.****************.executor.request.worker.ServiceExecutorAdapter.invoke(ServiceExecutorAdapter.java:59)
at com.****************.executor.request.filterchain.FilterChainImpl.doFilter(FilterChainImpl.java:179)
at com.****************.executor.request.filter.params.mapping.TransportParamsMappingFilter.doFilter(TransportParamsMappingFilter.java:82)
at com.****************.executor.request.filter.ParamsMappingWrapperFilter.doFilter(ParamsMappingWrapperFilter.java:114)
at com.****************.executor.request.filterchain.FilterChainImpl.doFilter(FilterChainImpl.java:173)
at com.****************.executor.request.filter.ProcessServiceFilter.doFilter(ProcessServiceFilter.java:38)
at com.****************.executor.request.filterchain.FilterChainImpl.doFilter(FilterChainImpl.java:173)
at com.****************.executor.request.filter.ServiceValidateFilter.doFilter(ServiceValidateFilter.java:61)
at com.****************.executor.request.filter.DevelopNoHandleWrapperFilter.doFilter(DevelopNoHandleWrapperFilter.java:28)
at com.****************.executor.request.filterchain.FilterChainImpl.doFilter(FilterChainImpl.java:173)
at com.****************.executor.request.filter.ThrouputControlFilter.doFilter(ThrouputControlFilter.java:23)
at com.****************.executor.request.filter.DevelopNoHandleWrapperFilter.doFilter(DevelopNoHandleWrapperFilter.java:28)
at com.****************.executor.request.filterchain.FilterChainImpl.doFilter(FilterChainImpl.java:173)
at com.****************.executor.request.filter.RecordFilter.doFilter(RecordFilter.java:27)
at com.****************.executor.request.filterchain.FilterChainImpl.doFilter(FilterChainImpl.java:173)
at com.****************.executor.request.filter.SystemParamsHandleFilter.doFilter(SystemParamsHandleFilter.java:41)
at com.****************.executor.request.filterchain.FilterChainImpl.doFilter(FilterChainImpl.java:173)
at com.****************.executor.request.worker.FilterAndExecute.filterAndExecute(FilterAndExecute.java:37)
at com.****************.executor.request.worker.AsyncRequestTask.executeCall(AsyncRequestTask.java:167)
at com.****************.thread.pool.MuiltPoolTask$AbstractMuiltPoolTask.call(MuiltPoolTask.java:159)
at com.****************.thread.pool.MuiltPoolTask$AbstractMuiltPoolTask.call(MuiltPoolTask.java:100)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
, serviceCode=MinTools_IVoiceLineControllerCSV_updateVoiceLinePhoneNo, processName=DEFAULT_APPFRAME_SERVER_NAME1560763302186, requestId=3630ad242aa24fea9f2c2f6a5ea35435, resultCode=csf1045, exceptionMessage=調用服務MinTools_***********************_updateVoiceLinePhoneNo的業務代碼發生異常}
17:21:46.017 [grp0#CsfServerRequestHandleThread-3630ad242aa24fea9f2c2f6a5ea35435] DEBUG com.****************.thread.pool.MuiltPoolTask$AbstractMuiltPoolTask - 任務MinTools_***************************_updateVoiceLinePhoneNo銷燬完成,狀態變更爲FINISH_RUN,耗時3976ms
異常截圖如下,截圖可以看的更清楚一些
主要是,在執行select (em.createNativeQuery(sql).getResultList())語句是可以的,但是執行DML等sql語句的時候,比如update(em.createNativeQuery(sql).executeUpdate)就會報這種錯。反正是檢查了一遍自己所有的代碼,確認不是自己的問題後,纔開始尋找大神們的解決方法,最後的最後,翻閱了各種“沒有用、或者不相關”的內容後,在小小的一個評論裏發現了某大神的身影。
二、問題解決
解決方法:
大家在Dao層上,有DML語句(update、delete、insert)上,加上這三個註解@Transactional@Modifying@Query 就可以了,如圖所示
@Transactional
@Modifying
@Query
import org.springframework.transaction.annotation.Transactional;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.jpa.repository.Modifying;
這樣的話,再次運行測試,就不會再報錯了,
至於爲什麼要加上 這幾個註解呢?
這就涉及到官方的問題了:jpa官方文檔:https://docs.spring.io/spring-data/jpa/docs/current/reference/html/
這裏我就不過多解釋了,我找了一篇相對而言介紹的比較詳細和通俗易懂的,大家可以看一下下面這篇文章:
JPA中自定義的插入、更新、刪除方法爲什麼要添加@Modifying註解和@Transactional註解?
參考文章
https://ask.csdn.net/questions/178819
https://www.cnblogs.com/wuhenzhidu/p/jpa.html
感謝原作者的分享,讓技術人能夠更快的解決問題