apache / apache/incubator-seata

应用运行中数据库表添加一个字段,马上对该表insert操作会导致NPE

Open
#3,865 4 comments 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
26k
Forks
8.8k
Avg merge
1d 8h
Merged PRs (30d)
4

Description

- [ ] I have searched the [issues](https://github.com/seata/seata/issues) of this repository and believe that this is not a duplicate.

### Ⅰ. Issue Description
业务运行的时候,修改表结构,添加一列字段,seata client就会抛出NullPointerException

### Ⅱ. Describe what happened

If there is an exception, please attach the exception trace:

```
java.sql.SQLException: java.lang.NullPointerException
at io.seata.rm.datasource.exec.ExecuteTemplate.execute(ExecuteTemplate.java:112)
at io.seata.rm.datasource.exec.ExecuteTemplate.execute(ExecuteTemplate.java:49)
at io.seata.rm.datasource.PreparedStatementProxy.execute(PreparedStatementProxy.java:54)
at sun.reflect.GeneratedMethodAccessor199.invoke
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.ibatis.logging.jdbc.PreparedStatementLogger.invoke(PreparedStatementLogger.java:59)
at com.sun.proxy.$Proxy228.execute
at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:46)
at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:74)
at sun.reflect.GeneratedMethodAccessor242.invoke
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:63)
at com.sun.proxy.$Proxy226.update
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 sun.reflect.GeneratedMethodAccessor237.invoke
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:63)
at com.sun.proxy.$Proxy225.update
at sun.reflect.GeneratedMethodAccessor237.invoke
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.ibatis.plugin.Invocation.proceed(Invocation.java:49)
at com.baomidou.mybatisplus.plugins.OptimisticLockerInterceptor.intercept(OptimisticLockerInterceptor.java:71)
at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61)
at com.sun.proxy.$Proxy225.update
at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:198)
at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:185)
at sun.reflect.GeneratedMethodAccessor416.invoke
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:433)
at com.sun.proxy.$Proxy120.insert
at org.mybatis.spring.SqlSessionTemplate.insert(SqlSessionTemplate.java:278)
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:57)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59)
at com.sun.proxy.$Proxy209.insert
at com.baomidou.mybatisplus.service.impl.ServiceImpl.insert(ServiceImpl.java:98)
at com.baomidou.mybatisplus.service.impl.ServiceImpl$$FastClassBySpringCGLIB$$3e2398a4.invoke()
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:746)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at io.seata.spring.annotation.GlobalTransactionalInterceptor.invoke(GlobalTransactionalInterceptor.java:87)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
```

### Ⅲ. Describe what you expected to happen
查看源代码可以发现每次操作之前Executor都会校验connectionPoxy的lockKeys
![image](https://user-images.githubusercontent.com/16588223/125411842-e47d3880-e3f0-11eb-8edf-87729fdd47e7.png)
如果tablemeta与当前数据库对应不上会返回一个空值导致proxy获取不到锁
![image](https://user-images.githubusercontent.com/16588223/125414620-5e000cda-3bf5-45f3-9741-e7e4abe51562.png)
发现源码中可通过修改上图中的配置自动刷新tablemeta功能
client.rm.tableMetaCheckEnable=true 默认值false
TABLE_META_CHECKER_INTERVAL = 60000ms (无法修改)

希望可以新增支持动态刷新表结构功能,或者能提供配置刷新间隔时间的参数注入

### Ⅳ. How to reproduce it (as minimally and precisely as possible)

1. 应用启动并连接seata
2. 新增一个字段
3. 马上对该表进行insert操作

### Ⅴ. Anything else we need to know?
None

### Ⅵ. Environment:

- JDK version : 1.8
- OS : SentOS 7+
- Others: seata-all-1.2.0

Contributor guide

Open the contributing guide

Research direction

Reproduce the sequence in the issue: start Seata, add a column, then immediately insert into the table. Trace the metadata and lock-key handling from io.seata.rm.datasource.exec.ExecuteTemplate.execute through PreparedStatementProxy, then inspect client.rm.tableMetaCheckEnable and TABLE_META_CHECKER_INTERVAL. Done means the insert no longer causes a NullPointerException after a schema change and the requested refresh behavior is defined and verified.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
backend, databases
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.