UokyI opened a new issue, #8041:
URL: https://github.com/apache/incubator-seata/issues/8041

   ### Check Ahead
   
   - [x] I have searched the [issues](https://github.com/seata/seata/issues) of 
this repository and believe that this is not a duplicate.
   
   - [ ] I am willing to try to fix this bug myself.
   
   
   ### Ⅰ. Issue Description
   
   
   使用 Seata 2.2.0 配合 SQL Server 时,有联合主键的表执行 UPDATE 操作会失败,报错为 An expression of 
non-boolean type specified in a context where a condition is expected, near 
','.] with root cause。
   在afterImage方法中报错
   
org.apache.seata.rm.datasource.exec.UpdateExecutor.afterImage(UpdateExecutor.java:108)
 ~[seata-all-2.2.0.jar:2.2.0]
   
   ### Ⅱ. Describe what happened
   
   2026-04-02 13:58:14.842 [SW_CTX: N/A] [http-nio-8007-exec-1] ERROR 
o.a.c.c.C.[.[.[.[dispatcherServlet] -Servlet.service() for servlet 
[dispatcherServlet] in context with path [] threw exception [Request processing 
failed; nested exception is org.springframework.jdbc.UncategorizedSQLException: 
   ### Error updating database.  Cause: 
com.microsoft.sqlserver.jdbc.SQLServerException: An expression of non-boolean 
type specified in a context where a condition is expected, near ','.
   ### The error may exist in com/auo/mapper/AccountTableMapper.java (best 
guess)
   ### The error may involve 
com.auo.mapper.AccountTableMapper.updateBalance-Inline
   ### The error occurred while setting parameters
   ### SQL: UPDATE ACCOUNT_TABLE SET BALANCE = ? WHERE ACCOUNT_ID = ?
   ### Cause: com.microsoft.sqlserver.jdbc.SQLServerException: An expression of 
non-boolean type specified in a context where a condition is expected, near ','.
   ; uncategorized SQLException; SQL state [S0001]; error code [4145]; An 
expression of non-boolean type specified in a context where a condition is 
expected, near ','.; nested exception is 
com.microsoft.sqlserver.jdbc.SQLServerException: An expression of non-boolean 
type specified in a context where a condition is expected, near ','.] with root 
cause
   com.microsoft.sqlserver.jdbc.SQLServerException: An expression of 
non-boolean type specified in a context where a condition is expected, near ','.
        at 
com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java:265)
 ~[mssql-jdbc-9.4.1.jre8.jar:na]
        at 
com.microsoft.sqlserver.jdbc.SQLServerStatement.getNextResult(SQLServerStatement.java:1662)
 ~[mssql-jdbc-9.4.1.jre8.jar:na]
        at 
com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.doExecutePreparedStatement(SQLServerPreparedStatement.java:615)
 ~[mssql-jdbc-9.4.1.jre8.jar:na]
        at 
com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement$PrepStmtExecCmd.doExecute(SQLServerPreparedStatement.java:537)
 ~[mssql-jdbc-9.4.1.jre8.jar:na]
        at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:7417) 
~[mssql-jdbc-9.4.1.jre8.jar:na]
        at 
com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:3488)
 ~[mssql-jdbc-9.4.1.jre8.jar:na]
        at 
com.microsoft.sqlserver.jdbc.SQLServerStatement.executeCommand(SQLServerStatement.java:262)
 ~[mssql-jdbc-9.4.1.jre8.jar:na]
        at 
com.microsoft.sqlserver.jdbc.SQLServerStatement.executeStatement(SQLServerStatement.java:237)
 ~[mssql-jdbc-9.4.1.jre8.jar:na]
        at 
com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.executeQuery(SQLServerPreparedStatement.java:456)
 ~[mssql-jdbc-9.4.1.jre8.jar:na]
        at 
com.alibaba.druid.pool.DruidPooledPreparedStatement.executeQuery(DruidPooledPreparedStatement.java:227)
 ~[druid-1.1.22.jar:1.1.22]
        at 
org.apache.seata.rm.datasource.exec.UpdateExecutor.afterImage(UpdateExecutor.java:108)
 ~[seata-all-2.2.0.jar:2.2.0]
        at 
org.apache.seata.rm.datasource.exec.AbstractDMLBaseExecutor.executeAutoCommitFalse(AbstractDMLBaseExecutor.java:100)
 ~[seata-all-2.2.0.jar:2.2.0]
        at 
org.apache.seata.rm.datasource.exec.AbstractDMLBaseExecutor.lambda$executeAutoCommitTrue$2(AbstractDMLBaseExecutor.java:145)
 ~[seata-all-2.2.0.jar:2.2.0]
        at 
org.apache.seata.rm.datasource.ConnectionProxy$LockRetryPolicy.doRetryOnLockConflict(ConnectionProxy.java:356)
 ~[seata-all-2.2.0.jar:2.2.0]
        at 
org.apache.seata.rm.datasource.exec.AbstractDMLBaseExecutor$LockRetryPolicy.execute(AbstractDMLBaseExecutor.java:188)
 ~[seata-all-2.2.0.jar:2.2.0]
        at 
org.apache.seata.rm.datasource.exec.AbstractDMLBaseExecutor.executeAutoCommitTrue(AbstractDMLBaseExecutor.java:144)
 ~[seata-all-2.2.0.jar:2.2.0]
        at 
org.apache.seata.rm.datasource.exec.AbstractDMLBaseExecutor.doExecute(AbstractDMLBaseExecutor.java:83)
 ~[seata-all-2.2.0.jar:2.2.0]
        at 
org.apache.seata.rm.datasource.exec.BaseTransactionalExecutor.execute(BaseTransactionalExecutor.java:127)
 ~[seata-all-2.2.0.jar:2.2.0]
        at 
org.apache.seata.rm.datasource.exec.ExecuteTemplate.execute(ExecuteTemplate.java:168)
 ~[seata-all-2.2.0.jar:2.2.0]
        at 
org.apache.seata.rm.datasource.exec.ExecuteTemplate.execute(ExecuteTemplate.java:63)
 ~[seata-all-2.2.0.jar:2.2.0]
        at 
org.apache.seata.rm.datasource.PreparedStatementProxy.execute(PreparedStatementProxy.java:55)
 ~[seata-all-2.2.0.jar:2.2.0]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
~[na:1.8.0_181]
        at 
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
~[na:1.8.0_181]
        at 
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 ~[na:1.8.0_181]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181]
        at 
org.apache.ibatis.logging.jdbc.PreparedStatementLogger.invoke(PreparedStatementLogger.java:58)
 ~[mybatis-3.5.16.jar:3.5.16]
        at com.sun.proxy.$Proxy154.execute(Unknown Source) ~[na:na]
        at 
org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:48)
 ~[mybatis-3.5.16.jar:3.5.16]
        at 
org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:75)
 ~[mybatis-3.5.16.jar:3.5.16]
        at 
org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:50) 
~[mybatis-3.5.16.jar:3.5.16]
        at 
org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117) 
~[mybatis-3.5.16.jar:3.5.16]
        at 
org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76) 
~[mybatis-3.5.16.jar:3.5.16]
        at 
org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:197)
 ~[mybatis-3.5.16.jar:3.5.16]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
~[na:1.8.0_181]
        at 
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
~[na:1.8.0_181]
        at 
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 ~[na:1.8.0_181]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181]
        at 
org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:425)
 ~[mybatis-spring-2.1.2.jar:2.1.2]
        at com.sun.proxy.$Proxy111.update(Unknown Source) ~[na:na]
        at 
org.mybatis.spring.SqlSessionTemplate.update(SqlSessionTemplate.java:288) 
~[mybatis-spring-2.1.2.jar:2.1.2]
        at 
com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:64)
 ~[mybatis-plus-core-3.5.7.jar:3.5.7]
        at 
com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:152)
 ~[mybatis-plus-core-3.5.7.jar:3.5.7]
        at 
com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89)
 ~[mybatis-plus-core-3.5.7.jar:3.5.7]
        at com.sun.proxy.$Proxy119.updateBalance(Unknown Source) ~[na:na]
        at 
com.auo.service.impl.AccountTableServiceImpl.reduceByUser(AccountTableServiceImpl.java:74)
 ~[classes/:na]
        at 
com.auo.service.impl.AccountTableServiceImpl$$FastClassBySpringCGLIB$$cc15e1df.invoke(<generated>)
 ~[classes/:na]
        at 
org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) 
~[spring-core-5.3.23.jar:5.3.23]
        at 
org.springframework.aop.framework.CglibAopProxy.invokeMethod(CglibAopProxy.java:386)
 ~[spring-aop-5.3.23.jar:5.3.23]
        at 
org.springframework.aop.framework.CglibAopProxy.access$000(CglibAopProxy.java:85)
 ~[spring-aop-5.3.23.jar:5.3.23]
        at 
org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:704)
 ~[spring-aop-5.3.23.jar:5.3.23]
        at 
com.auo.service.impl.AccountTableServiceImpl$$EnhancerBySpringCGLIB$$9749fecd.reduceByUser(<generated>)
 ~[classes/:na]
        at 
com.auo.controller.AccountTableController.reduceByUser(AccountTableController.java:49)
 ~[classes/:na]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
~[na:1.8.0_181]
        at 
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
~[na:1.8.0_181]
        at 
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 ~[na:1.8.0_181]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181]
        at 
org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
 ~[spring-web-5.3.23.jar:5.3.23]
        at 
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
 ~[spring-web-5.3.23.jar:5.3.23]
        at 
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
 ~[spring-webmvc-5.3.23.jar:5.3.23]
        at 
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
 ~[spring-webmvc-5.3.23.jar:5.3.23]
        at 
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
 ~[spring-webmvc-5.3.23.jar:5.3.23]
        at 
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
 ~[spring-webmvc-5.3.23.jar:5.3.23]
        at 
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1071)
 ~[spring-webmvc-5.3.23.jar:5.3.23]
        at 
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:964)
 ~[spring-webmvc-5.3.23.jar:5.3.23]
        at 
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
 ~[spring-webmvc-5.3.23.jar:5.3.23]
        at 
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
 ~[spring-webmvc-5.3.23.jar:5.3.23]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:696) 
~[tomcat-embed-core-9.0.68.jar:4.0.FR]
        at 
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
 ~[spring-webmvc-5.3.23.jar:5.3.23]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:779) 
~[tomcat-embed-core-9.0.68.jar:4.0.FR]
        at 
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
 ~[tomcat-embed-core-9.0.68.jar:9.0.68]
        at 
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
 ~[tomcat-embed-core-9.0.68.jar:9.0.68]
        at 
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) 
~[tomcat-embed-websocket-9.0.68.jar:9.0.68]
        at 
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
 ~[tomcat-embed-core-9.0.68.jar:9.0.68]
        at 
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
 ~[tomcat-embed-core-9.0.68.jar:9.0.68]
        at 
org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
 ~[spring-web-5.3.23.jar:5.3.23]
        at 
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
 ~[spring-web-5.3.23.jar:5.3.23]
        at 
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
 ~[tomcat-embed-core-9.0.68.jar:9.0.68]
        at 
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
 ~[tomcat-embed-core-9.0.68.jar:9.0.68]
        at 
org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
 ~[spring-web-5.3.23.jar:5.3.23]
        at 
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
 ~[spring-web-5.3.23.jar:5.3.23]
        at 
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
 ~[tomcat-embed-core-9.0.68.jar:9.0.68]
        at 
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
 ~[tomcat-embed-core-9.0.68.jar:9.0.68]
        at 
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
 ~[spring-web-5.3.23.jar:5.3.23]
        at 
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
 ~[spring-web-5.3.23.jar:5.3.23]
        at 
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
 ~[tomcat-embed-core-9.0.68.jar:9.0.68]
        at 
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
 ~[tomcat-embed-core-9.0.68.jar:9.0.68]
        at 
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
 ~[tomcat-embed-core-9.0.68.jar:9.0.68]
        at 
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
 [tomcat-embed-core-9.0.68.jar:9.0.68]
        at 
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
 [tomcat-embed-core-9.0.68.jar:9.0.68]
        at 
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) 
[tomcat-embed-core-9.0.68.jar:9.0.68]
        at 
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) 
[tomcat-embed-core-9.0.68.jar:9.0.68]
        at 
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
 [tomcat-embed-core-9.0.68.jar:9.0.68]
        at 
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360) 
[tomcat-embed-core-9.0.68.jar:9.0.68]
        at 
org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) 
[tomcat-embed-core-9.0.68.jar:9.0.68]
        at 
org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
 [tomcat-embed-core-9.0.68.jar:9.0.68]
        at 
org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893)
 [tomcat-embed-core-9.0.68.jar:9.0.68]
        at 
org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1789)
 [tomcat-embed-core-9.0.68.jar:9.0.68]
        at 
org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) 
[tomcat-embed-core-9.0.68.jar:9.0.68]
        at 
org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
 [tomcat-embed-core-9.0.68.jar:9.0.68]
        at 
org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
 [tomcat-embed-core-9.0.68.jar:9.0.68]
        at 
org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
 [tomcat-embed-core-9.0.68.jar:9.0.68]
        at java.lang.Thread.run(Thread.java:748) [na:1.8.0_181]
   
   
   ### Ⅲ. Describe what you expected to happen
   
   UPDATE 操作应该能正常处理具有联合主键(多列唯一约束)的表。
   
   ### Ⅳ. How to reproduce it (as minimally and precisely as possible)
   
   使用建表SQL,直接测试更新SQL即可
   
   **测试表结构:**
   
   **联合主键:**
   ```sql
   IF OBJECT_ID('[ACCOUNT_TABLE]', 'U') IS NOT NULL
       DROP TABLE [ACCOUNT_TABLE];
   GO
   
   CREATE TABLE [ACCOUNT_TABLE]
   (
       [ACCOUNT_ID]   decimal(38,0)         NOT NULL,
       [USER_ID]      varchar(255)          NOT NULL,
       [BALANCE]      decimal(38,18)        NOT NULL,
       [CREATE_TIME]  datetime2             NOT NULL,
       CONSTRAINT [pk_account_table] PRIMARY KEY CLUSTERED ([ACCOUNT_ID])
           WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY 
= OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
   )
   GO
   
   CREATE NONCLUSTERED INDEX [ix_account_table_create_time]
       ON [ACCOUNT_TABLE] ([CREATE_TIME])
   GO
   
   INSERT INTO [ACCOUNT_TABLE] ([ACCOUNT_ID], [USER_ID], [BALANCE], 
[CREATE_TIME])
   VALUES (1, 'user1', 10, GETDATE());
   GO
   ```
   
   **唯一主键表结构(可正常工作,可做对比):**
   ```sql
   IF OBJECT_ID('[ACCOUNT_TABLE]', 'U') IS NOT NULL
       DROP TABLE [ACCOUNT_TABLE];
   GO
   
   CREATE TABLE [ACCOUNT_TABLE]
   (
       [ACCOUNT_ID]   decimal(38,0)         NOT NULL,
       [USER_ID]      varchar(255)          NOT NULL,
       [BALANCE]      decimal(38,18)        NOT NULL,
       [CREATE_TIME]  datetime2             NOT NULL,
       CONSTRAINT [pk_account_table] PRIMARY KEY CLUSTERED ([ACCOUNT_ID])
           WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY 
= OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
   )
   GO
   
   CREATE NONCLUSTERED INDEX [ix_account_table_create_time]
       ON [ACCOUNT_TABLE] ([CREATE_TIME])
   GO
   
   INSERT INTO [ACCOUNT_TABLE] ([ACCOUNT_ID], [USER_ID], [BALANCE], 
[CREATE_TIME])
   VALUES (1, 'user1', 10, GETDATE());
   GO
   ```
   
   
   ### Ⅴ. Anything else we need to know?
   
   AT模式
   client端 undo 的 log-serialization值为kryo
   
   ### Ⅵ. Environment
   
   - Seata 版本:2.2.0
   - 数据库:SQL Server 
     -  Microsoft SQL Server 2019 (RTM) - 15.0.2000.5 (X64) 
     -  Standard Edition (64-bit) on Windows Server 2022 Standard 10.0 <X64>
   - JDBC 驱动:mssql-jdbc-9.4.1.jre8.jar
   - 连接池:Druid 1.1.22
   - ORM 框架:MyBatis-Plus 3.5.7
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to