如下是mapper文件里的sql代碼
<update id="updateByTransBatchIdAndBankId" parameterType="java.util.List"> <foreach collection="list" item="item" index="index" open="begin" close=";end;" separator=";"> update T_PLAT_ORDER set STATE = 1 where ORDER_ID = #{item.orderId,jdbcType=VARCHAR} and state in (0,11) </foreach> </update>
如下是Dao接口方法
package com.cn.yft.ora.dao; public interface TPlatOrderDAO { /** * 根據訂單流水號更新交易狀態為0或4的訂單狀態為1 * @param list * @return */ int updateByTransBatchIdAndBankId(List<TBankOrder> list); }
程序運行時,發現有坑。不管實際更新幾條,包括0條,mybatis並不打印執行行數。通過程序打印出來,發現結果始終是一個固定的值。而且,生產與本地還不一樣。生產打印出來都是-1, 本地環境打印出來都是1,在Navicat里連接本地Oracle數據庫里執行結果也是1。
程序中的jdbc配置
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> <!-- <property name="minIdle" value="${jdbc.minIdle}"/>--> <!-- <property name="maxIdle" value="${jdbc.maxIdle}"/>--> </bean> <bean id="sqlSessionFactoryDb" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <!-- 自動掃描entity目錄, 省掉Configuration.xml里的手工配置 --> <property name="mapperLocations" value="classpath*:com/cn/yft/ora/mapper/*.xml"/> </bean> <!-- 定義事務管理配置 --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean>
怎么發現的這個坑呢? 由於程序要根據這個批量操作數據的影響行數,來判斷是否進行后續邏輯處理。卻發現后續邏輯竟然一直不處理。通過添加log,這才發現,原來這個影響行數並不是我們的預期結果。
mybatis執行begin..end語句 為什么不返回影響行數呢?
原因未暫查出來。
那么,問題還得修復呀。
我的臨時解決辦法,是不用begin..end。
像下面這樣,直接干掉begin..end行不行呢?
<update id="updateByTransBatchIdAndBankId" parameterType="java.util.List"> <foreach collection="list" item="item" index="index" close=";" separator=";"> update T_PLAT_ORDER set STATE = 1 where ORDER_ID = 'ddd' and state in (0,11) </foreach> </update>
經過測試,直接干到begin..end是有些草率的。當入參List里只有一條數據時執行沒問題,畢竟,這只是執行了一個單條update語句,顯然不會有問題。而一旦存在多條update語句時,就會遇到包含Oracle錯誤碼的java.sql.SQLSyntaxErrorException: ORA-00911: 無效字符

2022-02-21 10:35:21,397 DEBUG [main] jdbc.BaseJdbcLogger (com.cn.yft.ora.dao.TPlatOrderDAO.updateByTransBatchIdAndBankId:145) - ==> Preparing: update T_PLAT_ORDER set STATE = 1 where ORDER_ID = 'ddd' and state in (0,11) ; update T_PLAT_ORDER set STATE = 1 where ORDER_ID = 'ddd' and state in (0,11) ; 2022-02-21 10:35:21,397 DEBUG [main] jdbc.BaseJdbcLogger (com.cn.yft.ora.dao.TPlatOrderDAO.updateByTransBatchIdAndBankId:145) - ==> Parameters: 2022-02-21 10:35:21,437 INFO [main] xml.XmlBeanDefinitionReader (org.springframework.beans.factory.xml.XmlBeanDefinitionReader:317) - Loading XML bean definitions from class path resource [org/springframework/jdbc/support/sql-error-codes.xml] 2022-02-21 10:35:21,484 INFO [main] support.SQLErrorCodesFactory (org.springframework.jdbc.support.SQLErrorCodesFactory:126) - SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase, Hana] org.springframework.jdbc.BadSqlGrammarException: ### Error updating database. Cause: java.sql.SQLSyntaxErrorException: ORA-00911: 無效字符 ### The error may involve com.cn.yft.ora.dao.TPlatOrderDAO.updateByTransBatchIdAndBankId-Inline ### The error occurred while setting parameters ### SQL: update T_PLAT_ORDER set STATE = 1 where ORDER_ID = 'ddd' and state in (0,11) ; update T_PLAT_ORDER set STATE = 1 where ORDER_ID = 'ddd' and state in (0,11) ; ### Cause: java.sql.SQLSyntaxErrorException: ORA-00911: 無效字符 ; bad SQL grammar []; nested exception is java.sql.SQLSyntaxErrorException: ORA-00911: 無效字符 at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:91) at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73) at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81) at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:75) at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:447) at com.sun.proxy.$Proxy32.update(Unknown Source) at org.mybatis.spring.SqlSessionTemplate.update(SqlSessionTemplate.java:295) at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:62) at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:53) at com.sun.proxy.$Proxy33.updateByTransBatchIdAndBankId(Unknown Source) at com.cn.yft.ora.dao.TPlatOrderDAOTest.updateByTransBatchIdAndBankId(TPlatOrderDAOTest.java:39) ... Caused by: java.sql.SQLSyntaxErrorException: ORA-00911: 無效字符 at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:450) at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:399) at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:1059) at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:522) at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:257) at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:587) at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:225) at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:53) at oracle.jdbc.driver.T4CPreparedStatement.executeForRows(T4CPreparedStatement.java:943) at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1150) at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:4798) at oracle.jdbc.driver.OraclePreparedStatement.execute(OraclePreparedStatement.java:4901) at oracle.jdbc.driver.OraclePreparedStatementWrapper.execute(OraclePreparedStatementWrapper.java:1385) at org.apache.commons.dbcp.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:172) at org.apache.commons.dbcp.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:172) 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:497) at org.apache.ibatis.logging.jdbc.PreparedStatementLogger.invoke(PreparedStatementLogger.java:59) at com.sun.proxy.$Proxy36.execute(Unknown Source) at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:46) at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:74) at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:50) at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117) at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76) at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:198) 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:497) at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:434) ... 34 more
接下來,依然沿着干掉begin..end的方針,這次呢,我們轉變sql,改成in操作。因為我們這個批處理操作的場景用in完全可以,這樣也不用糾結多條update部分成功怎么辦的情況。ok,問題暫時解決。
<update id="updateByTransBatchIdAndBankId" parameterType="java.util.List"> update T_PLAT_ORDER set STATE = 1 where ORDER_ID in <foreach collection="list" item="item" index="index" close=")" open="(" separator=","> #{item.orderId,jdbcType=VARCHAR} </foreach> and state in (0,11) </update>
2022-02-21 10:55:02,732 DEBUG [main] jdbc.BaseJdbcLogger (com.cn.yft.ora.dao.TPlatOrderDAO.updateByTransBatchIdAndBankId:145) - ==> Preparing: update T_PLAT_ORDER set STATE = 1 where ORDER_ID in ( ? , ? , ? ) and state in (0,11) 2022-02-21 10:55:02,734 DEBUG [main] jdbc.BaseJdbcLogger (com.cn.yft.ora.dao.TPlatOrderDAO.updateByTransBatchIdAndBankId:145) - ==> Parameters: 3f12bcd8-3afe-4743-ae14-c5d53fbc1a76(String), 2022020911335800504754(String), 2022021817531700189078(String) 2022-02-21 10:55:02,744 DEBUG [main] jdbc.BaseJdbcLogger (com.cn.yft.ora.dao.TPlatOrderDAO.updateByTransBatchIdAndBankId:145) - <== Updates: 2
后續:mybatis連接Oracle執行begin..end批量update操作,未返回實際影響行數。本次曲線救國,具體原因日后還需再分析和定位。