From 545da7388f774b54e2b3809d46c0c73c1b55fd7f Mon Sep 17 00:00:00 2001 From: jimin Date: Fri, 17 Nov 2023 16:59:04 +0800 Subject: [PATCH 01/10] optimize: optimize derivative product check base on mysql (#6045) Signed-off-by: slievrly --- changes/en-us/2.0.0.md | 1 + changes/zh-cn/2.0.0.md | 1 + .../seata/rm/datasource/DataSourceProxy.java | 85 +++++++++++++------ .../exec/mysql/MySQLUpdateJoinExecutor.java | 2 +- 4 files changed, 60 insertions(+), 29 deletions(-) diff --git a/changes/en-us/2.0.0.md b/changes/en-us/2.0.0.md index 6f565947176..9596c8fcf63 100644 --- a/changes/en-us/2.0.0.md +++ b/changes/en-us/2.0.0.md @@ -152,6 +152,7 @@ The version is updated as follows: - [[#5951](https://github.com/seata/seata/pull/5951)] remove un support config in jdk17 - [[#5959](https://github.com/seata/seata/pull/5959)] modify code style and remove unused import - [[#6002](https://github.com/seata/seata/pull/6002)] remove fst serialization +- [[#6045](https://github.com/seata/seata/pull/6045)] optimize derivative product check base on mysql ### security: diff --git a/changes/zh-cn/2.0.0.md b/changes/zh-cn/2.0.0.md index ef63a7db76c..bd2b578be60 100644 --- a/changes/zh-cn/2.0.0.md +++ b/changes/zh-cn/2.0.0.md @@ -153,6 +153,7 @@ Seata 是一款开源的分布式事务解决方案,提供高性能和简单 - [[#5951](https://github.com/seata/seata/pull/5951)] 删除在 jdk17 中不支持的配置项 - [[#5959](https://github.com/seata/seata/pull/5959)] 修正代码风格问题及去除无用的类引用 - [[#6002](https://github.com/seata/seata/pull/6002)] 移除fst序列化模块 +- [[#6045](https://github.com/seata/seata/pull/6045)] 优化MySQL衍生数据库判断逻辑 ### security: diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/DataSourceProxy.java b/rm-datasource/src/main/java/io/seata/rm/datasource/DataSourceProxy.java index 48317a83516..6d930ea4009 100644 --- a/rm-datasource/src/main/java/io/seata/rm/datasource/DataSourceProxy.java +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/DataSourceProxy.java @@ -19,7 +19,6 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.sql.Statement; import javax.sql.DataSource; @@ -31,6 +30,7 @@ import io.seata.rm.datasource.sql.struct.TableMetaCacheFactory; import io.seata.rm.datasource.util.JdbcUtils; import io.seata.sqlparser.util.JdbcConstants; +import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -55,7 +55,16 @@ public class DataSourceProxy extends AbstractDataSourceProxy implements Resource private String userName; - private String version; + private String kernelVersion; + + private String productVersion; + + /** + * POLARDB-X 1.X -> TDDL + * POLARDB-X 2.X & MySQL 5.6 -> PXC + * POLARDB-X 2.X & MySQL 5.7 -> AliSQL-X + */ + private static final String[] POLARDB_X_PRODUCT_KEYWORD = {"TDDL","AliSQL-X","PXC"}; /** * Instantiates a new Data source proxy. @@ -89,9 +98,9 @@ private void init(DataSource dataSource, String resourceGroupId) { if (JdbcConstants.ORACLE.equals(dbType)) { userName = connection.getMetaData().getUserName(); } else if (JdbcConstants.MYSQL.equals(dbType)) { - getMySQLAdaptiveType(connection); + validMySQLVersion(connection); + checkDerivativeProduct(); } - version = selectDbVersion(connection); } catch (SQLException e) { throw new IllegalStateException("can not init dataSource", e); } @@ -107,17 +116,31 @@ private void init(DataSource dataSource, String resourceGroupId) { } /** - * get mysql adaptive type for PolarDB-X + * Define derivative product version for MySQL Kernel * - * @param connection db connection */ - private void getMySQLAdaptiveType(Connection connection) { - try (Statement statement = connection.createStatement()) { - statement.executeQuery("show rule"); + private void checkDerivativeProduct() { + if (!JdbcConstants.MYSQL.equals(dbType)) { + return; + } + // check for polardb-x + if (isPolardbXProduct()) { dbType = JdbcConstants.POLARDBX; - } catch (SQLException e) { - dbType = JdbcConstants.MYSQL; + return; + } + // check for other products base on mysql kernel + } + + private boolean isPolardbXProduct() { + if (StringUtils.isBlank(productVersion)) { + return false; + } + for (String keyword : POLARDB_X_PRODUCT_KEYWORD) { + if (productVersion.contains(keyword)) { + return true; + } } + return false; } /** @@ -335,27 +358,33 @@ public BranchType getBranchType() { return BranchType.AT; } - public String getVersion() { - return version; + public String getKernelVersion() { + return kernelVersion; } - private String selectDbVersion(Connection connection) { - if (JdbcConstants.MYSQL.equals(dbType) || JdbcConstants.POLARDBX.equals(dbType)) { - try (PreparedStatement preparedStatement = connection.prepareStatement("SELECT VERSION()"); - ResultSet versionResult = preparedStatement.executeQuery()) { - if (versionResult.next()) { - String version = versionResult.getString("VERSION()"); - if (version == null) { - return null; - } - int dashIdx = version.indexOf('-'); - // in mysql: 5.6.45, in polardb-x: 5.6.45-TDDL-xxx - return dashIdx > 0 ? version.substring(0, dashIdx) : version; + private void validMySQLVersion(Connection connection) { + if (!JdbcConstants.MYSQL.equals(dbType)) { + return; + } + try (PreparedStatement preparedStatement = connection.prepareStatement("SELECT VERSION()"); + ResultSet versionResult = preparedStatement.executeQuery()) { + if (versionResult.next()) { + String version = versionResult.getString("VERSION()"); + if (StringUtils.isBlank(version)) { + return; + } + int dashIdx = version.indexOf('-'); + // in mysql: 5.6.45, in polardb-x: 5.6.45-TDDL-xxx + if (dashIdx > 0) { + kernelVersion = version.substring(0, dashIdx); + productVersion = version.substring(dashIdx + 1); + } else { + kernelVersion = version; + productVersion = version; } - } catch (Exception e) { - LOGGER.error("get mysql version fail error: {}", e.getMessage()); } + } catch (Exception e) { + LOGGER.error("check mysql version fail error: {}", e.getMessage()); } - return ""; } } diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/mysql/MySQLUpdateJoinExecutor.java b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/mysql/MySQLUpdateJoinExecutor.java index 50cac9fa611..e307bc4f371 100644 --- a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/mysql/MySQLUpdateJoinExecutor.java +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/mysql/MySQLUpdateJoinExecutor.java @@ -310,6 +310,6 @@ private String buildGroupBy(List pkColumns,List allSelectColumns } private String getDbVersion() { - return statementProxy.getConnectionProxy().getDataSourceProxy().getVersion(); + return statementProxy.getConnectionProxy().getDataSourceProxy().getKernelVersion(); } } From 1686c6af7711e54961aea3003f2d95d9a03856ec Mon Sep 17 00:00:00 2001 From: Xiangkun Yin <32592585+ptyin@users.noreply.github.com> Date: Sat, 18 Nov 2023 13:53:33 +0800 Subject: [PATCH 02/10] bugfix: change RaftServer#destroy to wait all shutdown procedures done (#6050) --- changes/en-us/2.0.0.md | 1 + changes/zh-cn/2.0.0.md | 1 + .../java/io/seata/server/cluster/raft/RaftServer.java | 9 ++++++++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/changes/en-us/2.0.0.md b/changes/en-us/2.0.0.md index 9596c8fcf63..f288b4be280 100644 --- a/changes/en-us/2.0.0.md +++ b/changes/en-us/2.0.0.md @@ -88,6 +88,7 @@ The version is updated as follows: - [[#6018](https://github.com/seata/seata/pull/6018)] fix incorrect metric report - [[#6024](https://github.com/seata/seata/pull/6024)] fix the white screen after click the "View Global Lock" button on the transaction info page in the console - [[#6015](https://github.com/seata/seata/pull/6015)] fix can't integrate dubbo with spring +- [[#6050](https://github.com/seata/seata/pull/6050)] change RaftServer#destroy to wait all shutdown procedures done ### optimize: - [[#6033](https://github.com/seata/seata/pull/6033)] optimize the isReference judgment logic in HSFRemotingParser, remove unnecessary judgment about FactoryBean diff --git a/changes/zh-cn/2.0.0.md b/changes/zh-cn/2.0.0.md index bd2b578be60..92caa74b913 100644 --- a/changes/zh-cn/2.0.0.md +++ b/changes/zh-cn/2.0.0.md @@ -87,6 +87,7 @@ Seata 是一款开源的分布式事务解决方案,提供高性能和简单 - [[#6018](https://github.com/seata/seata/pull/6018)] 修复错误的 metric 上报 - [[#6024](https://github.com/seata/seata/pull/6024)] 修复控制台点击事务信息页面中的"查看全局锁"按钮之后白屏的问题 - [[#6015](https://github.com/seata/seata/pull/6015)] 修复在spring环境下无法集成dubbo +- [[#6050](https://github.com/seata/seata/pull/6050)] 修改 RaftServer#destroy 为等待所有关闭流程结束 ### optimize: diff --git a/server/src/main/java/io/seata/server/cluster/raft/RaftServer.java b/server/src/main/java/io/seata/server/cluster/raft/RaftServer.java index 32872460bea..8ae7ee10a35 100644 --- a/server/src/main/java/io/seata/server/cluster/raft/RaftServer.java +++ b/server/src/main/java/io/seata/server/cluster/raft/RaftServer.java @@ -105,7 +105,14 @@ public void close() { @Override public void destroy() { - Optional.ofNullable(raftGroupService).ifPresent(RaftGroupService::shutdown); + Optional.ofNullable(raftGroupService).ifPresent(r -> { + r.shutdown(); + try { + r.join(); + } catch (InterruptedException e) { + logger.warn("Interrupted when RaftServer destroying", e); + } + }); } } From 27fc7aebcb178435f708530dcba1b637876b433e Mon Sep 17 00:00:00 2001 From: funkye Date: Sat, 18 Nov 2023 14:05:00 +0800 Subject: [PATCH 03/10] bugfix: fix the issue of Raft registry exception without waiting for retries (#6049) --- changes/en-us/2.0.0.md | 1 + changes/zh-cn/2.0.0.md | 1 + common/pom.xml | 5 + .../io/seata/common/util/HttpClientUtil.java | 127 ++++++++++++++++++ .../raft/RaftRegistryServiceImpl.java | 97 +------------ 5 files changed, 139 insertions(+), 92 deletions(-) create mode 100644 common/src/main/java/io/seata/common/util/HttpClientUtil.java diff --git a/changes/en-us/2.0.0.md b/changes/en-us/2.0.0.md index f288b4be280..6768f6311cb 100644 --- a/changes/en-us/2.0.0.md +++ b/changes/en-us/2.0.0.md @@ -88,6 +88,7 @@ The version is updated as follows: - [[#6018](https://github.com/seata/seata/pull/6018)] fix incorrect metric report - [[#6024](https://github.com/seata/seata/pull/6024)] fix the white screen after click the "View Global Lock" button on the transaction info page in the console - [[#6015](https://github.com/seata/seata/pull/6015)] fix can't integrate dubbo with spring +- [[#6049](https://github.com/seata/seata/pull/6049)] fix registry type for raft under the network interruption did not carry out the sleep 1s - [[#6050](https://github.com/seata/seata/pull/6050)] change RaftServer#destroy to wait all shutdown procedures done ### optimize: diff --git a/changes/zh-cn/2.0.0.md b/changes/zh-cn/2.0.0.md index 92caa74b913..08559915448 100644 --- a/changes/zh-cn/2.0.0.md +++ b/changes/zh-cn/2.0.0.md @@ -87,6 +87,7 @@ Seata 是一款开源的分布式事务解决方案,提供高性能和简单 - [[#6018](https://github.com/seata/seata/pull/6018)] 修复错误的 metric 上报 - [[#6024](https://github.com/seata/seata/pull/6024)] 修复控制台点击事务信息页面中的"查看全局锁"按钮之后白屏的问题 - [[#6015](https://github.com/seata/seata/pull/6015)] 修复在spring环境下无法集成dubbo +- [[#6049](https://github.com/seata/seata/pull/6049)] 修复客户端在raft注册中心类型下,网络中断时,watch线程未暂停一秒等待重试的问题 - [[#6050](https://github.com/seata/seata/pull/6050)] 修改 RaftServer#destroy 为等待所有关闭流程结束 diff --git a/common/pom.xml b/common/pom.xml index 85f38fc87bf..0d1d756ebbc 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -40,5 +40,10 @@ commons-lang commons-lang + + org.apache.httpcomponents + httpclient + provided + diff --git a/common/src/main/java/io/seata/common/util/HttpClientUtil.java b/common/src/main/java/io/seata/common/util/HttpClientUtil.java new file mode 100644 index 00000000000..d31a4580707 --- /dev/null +++ b/common/src/main/java/io/seata/common/util/HttpClientUtil.java @@ -0,0 +1,127 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.seata.common.util; + + +import org.apache.http.NameValuePair; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.client.utils.URLEncodedUtils; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.message.BasicNameValuePair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author funkye + */ +public class HttpClientUtil { + + private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientUtil.class); + + private static final Map HTTP_CLIENT_MAP = new ConcurrentHashMap<>(); + + private static final PoolingHttpClientConnectionManager POOLING_HTTP_CLIENT_CONNECTION_MANAGER = + new PoolingHttpClientConnectionManager(); + + static { + POOLING_HTTP_CLIENT_CONNECTION_MANAGER.setMaxTotal(10); + POOLING_HTTP_CLIENT_CONNECTION_MANAGER.setDefaultMaxPerRoute(10); + Runtime.getRuntime().addShutdownHook(new Thread(() -> HTTP_CLIENT_MAP.values().parallelStream().forEach(client -> { + try { + client.close(); + } catch (IOException e) { + LOGGER.error(e.getMessage(), e); + } + }))); + } + + // post request + public static CloseableHttpResponse doPost(String url, Map params, Map header, + int timeout) throws IOException { + try { + URIBuilder builder = new URIBuilder(url); + URI uri = builder.build(); + HttpPost httpPost = new HttpPost(uri); + if (header != null) { + header.forEach(httpPost::addHeader); + } + List nameValuePairs = new ArrayList<>(); + params.forEach((k, v) -> { + nameValuePairs.add(new BasicNameValuePair(k, v)); + }); + String requestBody = URLEncodedUtils.format(nameValuePairs, StandardCharsets.UTF_8); + + StringEntity stringEntity = new StringEntity(requestBody, ContentType.APPLICATION_FORM_URLENCODED); + httpPost.setEntity(stringEntity); + httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded"); + CloseableHttpClient client = HTTP_CLIENT_MAP.computeIfAbsent(timeout, + k -> HttpClients.custom().setConnectionManager(POOLING_HTTP_CLIENT_CONNECTION_MANAGER) + .setDefaultRequestConfig(RequestConfig.custom().setConnectionRequestTimeout(timeout) + .setSocketTimeout(timeout).setConnectTimeout(timeout).build()) + .build()); + return client.execute(httpPost); + } catch (URISyntaxException | ClientProtocolException e) { + LOGGER.error(e.getMessage(), e); + } + return null; + } + + // get request + public static CloseableHttpResponse doGet(String url, Map param, Map header, + int timeout) throws IOException { + try { + URIBuilder builder = new URIBuilder(url); + if (param != null) { + for (String key : param.keySet()) { + builder.addParameter(key, param.get(key)); + } + } + URI uri = builder.build(); + HttpGet httpGet = new HttpGet(uri); + if (header != null) { + header.forEach(httpGet::addHeader); + } + CloseableHttpClient client = HTTP_CLIENT_MAP.computeIfAbsent(timeout, + k -> HttpClients.custom().setConnectionManager(POOLING_HTTP_CLIENT_CONNECTION_MANAGER) + .setDefaultRequestConfig(RequestConfig.custom().setConnectionRequestTimeout(timeout) + .setSocketTimeout(timeout).setConnectTimeout(timeout).build()) + .build()); + return client.execute(httpGet); + } catch (URISyntaxException | ClientProtocolException e) { + LOGGER.error(e.getMessage(), e); + } + return null; + } + +} \ No newline at end of file diff --git a/discovery/seata-discovery-raft/src/main/java/io/seata/discovery/registry/raft/RaftRegistryServiceImpl.java b/discovery/seata-discovery-raft/src/main/java/io/seata/discovery/registry/raft/RaftRegistryServiceImpl.java index feb512bdda8..2a51b1fcedf 100644 --- a/discovery/seata-discovery-raft/src/main/java/io/seata/discovery/registry/raft/RaftRegistryServiceImpl.java +++ b/discovery/seata-discovery-raft/src/main/java/io/seata/discovery/registry/raft/RaftRegistryServiceImpl.java @@ -17,7 +17,6 @@ import java.io.IOException; import java.net.InetSocketAddress; -import java.net.URI; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; @@ -41,26 +40,15 @@ import io.seata.common.metadata.Node; import io.seata.common.thread.NamedThreadFactory; import io.seata.common.util.CollectionUtils; +import io.seata.common.util.HttpClientUtil; import io.seata.common.util.StringUtils; import io.seata.config.ConfigChangeListener; import io.seata.config.Configuration; import io.seata.config.ConfigurationFactory; import io.seata.discovery.registry.RegistryService; import org.apache.http.HttpStatus; -import org.apache.http.NameValuePair; import org.apache.http.StatusLine; -import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.utils.URIBuilder; -import org.apache.http.client.utils.URLEncodedUtils; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; -import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -90,11 +78,6 @@ public class RaftRegistryServiceImpl implements RegistryService HTTP_CLIENT_MAP = new ConcurrentHashMap<>(); - private static volatile String CURRENT_TRANSACTION_SERVICE_GROUP; private static volatile String CURRENT_TRANSACTION_CLUSTER_NAME; @@ -108,11 +91,6 @@ public class RaftRegistryServiceImpl implements RegistryService> ALIVE_NODES = new ConcurrentHashMap<>(); - static { - POOLING_HTTP_CLIENT_CONNECTION_MANAGER.setMaxTotal(10); - POOLING_HTTP_CLIENT_CONNECTION_MANAGER.setDefaultMaxPerRoute(10); - } - private RaftRegistryServiceImpl() {} /** @@ -191,13 +169,6 @@ protected static void startQueryMetadata() { Runtime.getRuntime().addShutdownHook(new Thread(() -> { CLOSED.compareAndSet(false, true); REFRESH_METADATA_EXECUTOR.shutdown(); - HTTP_CLIENT_MAP.values().parallelStream().forEach(client -> { - try { - client.close(); - } catch (IOException e) { - LOGGER.error(e.getMessage(), e); - } - }); })); } } @@ -274,13 +245,13 @@ private static boolean watch() { for (String group : groupTerms.keySet()) { String tcAddress = queryHttpAddress(clusterName, group); try (CloseableHttpResponse response = - doPost("http://" + tcAddress + "/metadata/v1/watch", param, null, 30000)) { + HttpClientUtil.doPost("http://" + tcAddress + "/metadata/v1/watch", param, null, 30000)) { if (response != null) { StatusLine statusLine = response.getStatusLine(); return statusLine != null && statusLine.getStatusCode() == HttpStatus.SC_OK; } - } catch (Exception e) { - LOGGER.error("watch cluster fail: {}", e.getMessage()); + } catch (IOException e) { + LOGGER.error("watch cluster node: {}, fail: {}", tcAddress, e.getMessage()); try { Thread.sleep(1000); } catch (InterruptedException ignored) { @@ -320,7 +291,7 @@ private static void acquireClusterMetaData(String clusterName, String group) { param.put("group", group); String response = null; try (CloseableHttpResponse httpResponse = - doGet("http://" + tcAddress + "/metadata/v1/cluster", param, null, 1000)) { + HttpClientUtil.doGet("http://" + tcAddress + "/metadata/v1/cluster", param, null, 1000)) { if (httpResponse != null && httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { response = EntityUtils.toString(httpResponse.getEntity(), StandardCharsets.UTF_8); } @@ -339,64 +310,6 @@ private static void acquireClusterMetaData(String clusterName, String group) { } } - public static CloseableHttpResponse doGet(String url, Map param, Map header, - int timeout) { - CloseableHttpClient client; - try { - URIBuilder builder = new URIBuilder(url); - if (param != null) { - for (String key : param.keySet()) { - builder.addParameter(key, param.get(key)); - } - } - URI uri = builder.build(); - HttpGet httpGet = new HttpGet(uri); - if (header != null) { - header.forEach(httpGet::addHeader); - } - client = HTTP_CLIENT_MAP.computeIfAbsent(timeout, - k -> HttpClients.custom().setConnectionManager(POOLING_HTTP_CLIENT_CONNECTION_MANAGER) - .setDefaultRequestConfig(RequestConfig.custom().setConnectionRequestTimeout(timeout) - .setSocketTimeout(timeout).setConnectTimeout(timeout).build()) - .build()); - return client.execute(httpGet); - } catch (Exception e) { - LOGGER.error(e.getMessage(), e); - } - return null; - } - - public static CloseableHttpResponse doPost(String url, Map params, Map header, - int timeout) { - CloseableHttpClient client = null; - try { - URIBuilder builder = new URIBuilder(url); - URI uri = builder.build(); - HttpPost httpPost = new HttpPost(uri); - if (header != null) { - header.forEach(httpPost::addHeader); - } - List nameValuePairs = new ArrayList<>(); - params.forEach((k, v) -> { - nameValuePairs.add(new BasicNameValuePair(k, v)); - }); - String requestBody = URLEncodedUtils.format(nameValuePairs, StandardCharsets.UTF_8); - - StringEntity stringEntity = new StringEntity(requestBody, ContentType.APPLICATION_FORM_URLENCODED); - httpPost.setEntity(stringEntity); - httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded"); - client = HTTP_CLIENT_MAP.computeIfAbsent(timeout, - k -> HttpClients.custom().setConnectionManager(POOLING_HTTP_CLIENT_CONNECTION_MANAGER) - .setDefaultRequestConfig(RequestConfig.custom().setConnectionRequestTimeout(timeout) - .setSocketTimeout(timeout).setConnectTimeout(timeout).build()) - .build()); - return client.execute(httpPost); - } catch (Exception e) { - LOGGER.error(e.getMessage(), e); - } - return null; - } - @Override public List lookup(String key) throws Exception { String clusterName = getServiceGroup(key); From b6d71593510c968f334b82a7fd25a4d2baa50613 Mon Sep 17 00:00:00 2001 From: Xiangkun Yin <32592585+ptyin@users.noreply.github.com> Date: Sun, 19 Nov 2023 22:10:32 +0800 Subject: [PATCH 04/10] test: upgrade springboot and spring version for server (#6052) --- .github/workflows/test.yml | 8 ++++---- build/pom.xml | 9 +++++++++ pom.xml | 1 + 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4e966b77d82..9295d149903 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -47,9 +47,9 @@ jobs: # https://docs.github.com/cn/free-pro-team@latest/actions/reference/context-and-expression-syntax-for-github-actions#github-context run: | if [ "${{ matrix.java }}" == "8" ]; then - ./mvnw -T 4C clean test -Dspring-boot.version=${{ matrix.springboot }} -Dcheckstyle.skip=false -Dlicense.skip=false -e -B -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn; + ./mvnw -T 4C clean test -P args-for-client-test -Dspring-boot.version=${{ matrix.springboot }} -Dcheckstyle.skip=false -Dlicense.skip=false -e -B -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn; else - ./mvnw -T 4C clean test -Dspring-boot.version=${{ matrix.springboot }} -Dcheckstyle.skip=true -Dlicense.skip=true -e -B -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn; + ./mvnw -T 4C clean test -P args-for-client-test -Dspring-boot.version=${{ matrix.springboot }} -Dcheckstyle.skip=true -Dlicense.skip=true -e -B -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn; fi # job 2 @@ -80,7 +80,7 @@ jobs: # step 4 - name: "Test with Maven" run: | - ./mvnw -T 4C clean test -Dspring-boot.version=${{ matrix.springboot }} -Dspring-boot-for-server.version=2.5.14 -Dspring-framework-for-server.version=5.3.20 -Dkotlin-maven-plugin.version=1.7.22 -Dcheckstyle.skip=true -Dlicense.skip=true -e -B -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn; + ./mvnw -T 4C clean test -P args-for-client-test -Dspring-boot.version=${{ matrix.springboot }} -Dkotlin-maven-plugin.version=1.7.22 -Dcheckstyle.skip=true -Dlicense.skip=true -e -B -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn; # job 3 arm64-test: @@ -125,4 +125,4 @@ jobs: # step 5 - name: "test-arm64" run: | - ./mvnw -T 4C clean test -Dspring-boot.version=${{ matrix.springboot }} -Dcheckstyle.skip=true -Dlicense.skip=true -e -B -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn + ./mvnw -T 4C clean test -P args-for-client-test -Dspring-boot.version=${{ matrix.springboot }} -Dcheckstyle.skip=true -Dlicense.skip=true -e -B -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn diff --git a/build/pom.xml b/build/pom.xml index 32401ff7795..18d084d7c15 100644 --- a/build/pom.xml +++ b/build/pom.xml @@ -125,6 +125,7 @@ true false + 37F181C60AACE24BD5C1D3925583F79497E8E293 @@ -405,5 +406,13 @@ + + + + args-for-client-test + + io/seata/server/**/*.java,io/seata/console/**/*.java + + diff --git a/pom.xml b/pom.xml index 88ca8e537cf..f2371a43ce7 100644 --- a/pom.xml +++ b/pom.xml @@ -360,6 +360,7 @@ ${maven-surefire-plugin.version} ${maven.surefire.argLine} + ${maven.surefire.excludes} From a421a777e1f16148fd547ce9871f272059d28fbd Mon Sep 17 00:00:00 2001 From: jimin Date: Mon, 20 Nov 2023 21:01:24 +0800 Subject: [PATCH 05/10] release: release for 2.0.0 (#6047) --- README.md | 2 +- build/pom.xml | 2 +- changes/en-us/2.x.md | 26 ++++++++++++++++++++++++++ changes/zh-cn/2.x.md | 25 +++++++++++++++++++++++++ 4 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 changes/en-us/2.x.md create mode 100644 changes/zh-cn/2.x.md diff --git a/README.md b/README.md index 6f430ed2ef2..cdda84c1f64 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ For more details about principle and design, please go to [Seata wiki page](http Depending on the scenario, choose one of the two dependencies: `io.seata:seata-all` or `io.seata:seata-spring-boot-starter`. ```xml - 1.8.0 + 2.0.0 diff --git a/build/pom.xml b/build/pom.xml index 18d084d7c15..ebbb35c5910 100644 --- a/build/pom.xml +++ b/build/pom.xml @@ -63,7 +63,7 @@ - 2.0.0-SNAPSHOT + 2.0.0 1.8 diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md new file mode 100644 index 00000000000..af9ed444f59 --- /dev/null +++ b/changes/en-us/2.x.md @@ -0,0 +1,26 @@ +Add changes here for all PR submitted to the 2.x branch. + + + +### feature: +- [[#PR_NO](https://github.com/seata/seata/pull/PR_NO)] A brief and accurate description of PR + +### bugfix: +- [[#PR_NO](https://github.com/seata/seata/pull/PR_NO)] A brief and accurate description of PR + +### optimize: +- [[#PR_NO](https://github.com/seata/seata/pull/PR_NO)] A brief and accurate description of PR + +### security: +- [[#PR_NO](https://github.com/seata/seata/pull/PR_NO)] A brief and accurate description of PR + +### test: +- [[#PR_NO](https://github.com/seata/seata/pull/PR_NO)] A brief and accurate description of PR + +Thanks to these contributors for their code commits. Please report an unintended omission. + + +- [slievrly](https://github.com/slievrly) + + +Also, we receive many valuable issues, questions and advices from our community. Thanks for you all. diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md new file mode 100644 index 00000000000..dba99a3d98e --- /dev/null +++ b/changes/zh-cn/2.x.md @@ -0,0 +1,25 @@ +所有提交到 2.x 分支的 PR 请在此处登记。 + + + +### feature: +- [[#PR_NO](https://github.com/seata/seata/pull/PR_NO)] 准确简要的PR描述 + +### bugfix: +- [[#PR_NO](https://github.com/seata/seata/pull/PR_NO)] 准确简要的PR描述 + +### optimize: +- [[#PR_NO](https://github.com/seata/seata/pull/PR_NO)] 准确简要的PR描述 + +### security: +- [[#PR_NO](https://github.com/seata/seata/pull/PR_NO)] 准确简要的PR描述 + +### test: +- [[#PR_NO](https://github.com/seata/seata/pull/PR_NO)] 准确简要的PR描述 + +非常感谢以下 contributors 的代码贡献。若有无意遗漏,请报告。 + + +- [slievrly](https://github.com/slievrly) + +同时,我们收到了社区反馈的很多有价值的issue和建议,非常感谢大家。 From a91c88e047f585ca385fb71a0838120e13c97d25 Mon Sep 17 00:00:00 2001 From: jimin Date: Mon, 20 Nov 2023 21:42:15 +0800 Subject: [PATCH 06/10] optimize: add pom description (#6063) Signed-off-by: slievrly --- integration-tx-api/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integration-tx-api/pom.xml b/integration-tx-api/pom.xml index 12cc16bc2d6..f23b8f321a0 100644 --- a/integration-tx-api/pom.xml +++ b/integration-tx-api/pom.xml @@ -24,9 +24,9 @@ 4.0.0 seata-integration-tx-api - seata-integration-tx-api ${project.version} jar - + seata-integration-tx-api ${project.version} + integration transaction API for Seata built with Maven From ded33d1603495b5365b81494b2cc2a5465f17200 Mon Sep 17 00:00:00 2001 From: jimin Date: Tue, 21 Nov 2023 00:25:22 +0800 Subject: [PATCH 07/10] version: change version to 2.1.0-SNAPSHOT (#6066) Signed-off-by: slievrly --- README.md | 2 +- build/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cdda84c1f64..0b8d6bbc91d 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ [![Build Status](https://github.com/seata/seata/workflows/build/badge.svg?branch=develop)](https://github.com/seata/seata/actions) [![codecov](https://codecov.io/gh/seata/seata/branch/develop/graph/badge.svg)](https://codecov.io/gh/seata/seata) [![license](https://img.shields.io/github/license/seata/seata.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) -[![maven](https://img.shields.io/maven-central/v/io.seata/seata-parent?versionSuffix=1.8.0)](https://search.maven.org/search?q=io.seata) +[![maven](https://img.shields.io/maven-central/v/io.seata/seata-parent?versionSuffix=2.0.0)](https://search.maven.org/search?q=io.seata) [![Language grade: Java](https://img.shields.io/lgtm/grade/java/g/seata/seata.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/seata/seata/context:java) diff --git a/build/pom.xml b/build/pom.xml index ebbb35c5910..87db43f9677 100644 --- a/build/pom.xml +++ b/build/pom.xml @@ -63,7 +63,7 @@ - 2.0.0 + 2.1.0-SNAPSHOT 1.8 From 09097aaa0ac225d4b9221dbada336b4518668ebc Mon Sep 17 00:00:00 2001 From: cmai Date: Sat, 25 Nov 2023 23:35:27 +0800 Subject: [PATCH 08/10] security: upgrade com.google.guava:guava to 32.0.0-jre (#6069) --- changes/en-us/2.x.md | 4 ++-- changes/zh-cn/2.x.md | 3 ++- dependencies/pom.xml | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md index af9ed444f59..bd36a279c2b 100644 --- a/changes/en-us/2.x.md +++ b/changes/en-us/2.x.md @@ -12,7 +12,7 @@ Add changes here for all PR submitted to the 2.x branch. - [[#PR_NO](https://github.com/seata/seata/pull/PR_NO)] A brief and accurate description of PR ### security: -- [[#PR_NO](https://github.com/seata/seata/pull/PR_NO)] A brief and accurate description of PR +- [[#6069](https://github.com/seata/seata/pull/6069)] Upgrade Guava dependencies to fix security vulnerabilities ### test: - [[#PR_NO](https://github.com/seata/seata/pull/PR_NO)] A brief and accurate description of PR @@ -21,6 +21,6 @@ Thanks to these contributors for their code commits. Please report an unintended - [slievrly](https://github.com/slievrly) - +- [imcmai](https://github.com/imcmai) Also, we receive many valuable issues, questions and advices from our community. Thanks for you all. diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md index dba99a3d98e..f155efa1195 100644 --- a/changes/zh-cn/2.x.md +++ b/changes/zh-cn/2.x.md @@ -12,7 +12,7 @@ - [[#PR_NO](https://github.com/seata/seata/pull/PR_NO)] 准确简要的PR描述 ### security: -- [[#PR_NO](https://github.com/seata/seata/pull/PR_NO)] 准确简要的PR描述 +- [[#6069](https://github.com/seata/seata/pull/6069)] 升级Guava依赖版本,修复安全漏洞 ### test: - [[#PR_NO](https://github.com/seata/seata/pull/PR_NO)] 准确简要的PR描述 @@ -21,5 +21,6 @@ - [slievrly](https://github.com/slievrly) +- [imcmai](https://github.com/imcmai) 同时,我们收到了社区反馈的很多有价值的issue和建议,非常感谢大家。 diff --git a/dependencies/pom.xml b/dependencies/pom.xml index 8c557cc288d..d82345a1f4b 100644 --- a/dependencies/pom.xml +++ b/dependencies/pom.xml @@ -56,7 +56,7 @@ 1.4.2 0.5.0 1.11.2 - 30.1-jre + 32.0.0-jre 1 1.3.2 4.0.1 From 960c298938a783404cb576e25cc7d177eaf6d46a Mon Sep 17 00:00:00 2001 From: laywin Date: Sun, 26 Nov 2023 23:00:41 +0800 Subject: [PATCH 09/10] optimize: undo_log table check optimize (#6031) --- changes/en-us/2.x.md | 4 +- changes/zh-cn/2.x.md | 3 +- .../io/seata/config/ConfigFutureTest.java | 4 +- .../java/io/seata/core/constants/DBType.java | 1 - dependencies/pom.xml | 7 ++- pom.xml | 5 ++ .../main/java/io/seata/rm/RMHandlerAT.java | 23 ------- .../seata/rm/datasource/DataSourceProxy.java | 34 ++++++++++ .../java/io/seata/rm/RMHandlerATTest.java | 30 +++++---- .../rm/datasource/DataSourceProxyTest.java | 62 ++++++++++++++++++- .../PreparedStatementProxyTest.java | 11 +++- .../rm/datasource/StatementProxyTest.java | 8 ++- .../datasource/exec/DeleteExecutorTest.java | 13 +++- .../rm/datasource/exec/MultiExecutorTest.java | 14 ++++- .../rm/datasource/exec/PlainExecutorTest.java | 4 +- .../exec/SelectForUpdateExecutorTest.java | 10 ++- .../datasource/exec/UpdateExecutorTest.java | 12 +++- .../exec/UpdateJoinExecutorTest.java | 9 ++- .../sql/struct/TableRecordsTest.java | 30 ++++----- .../struct/cache/DmTableMetaCacheTest.java | 3 +- .../cache/MariadbTableMetaCacheTest.java | 11 +++- .../struct/cache/MysqlTableMetaCacheTest.java | 14 ++++- .../cache/OracleTableMetaCacheTest.java | 9 ++- .../cache/PostgresqlTableMetaCacheTest.java | 11 +++- .../cache/SqlServerTableMetaCacheTest.java | 12 +++- .../seata/rm/datasource/undo/BaseH2Test.java | 8 ++- .../mariadb/MariadbUndoLogManagerTest.java | 17 +++-- .../undo/mysql/MySQLUndoLogManagerTest.java | 16 +++-- .../polardbx/PolarDBXUndoLogManagerTest.java | 16 +++-- 29 files changed, 306 insertions(+), 95 deletions(-) diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md index bd36a279c2b..13c6ed085d5 100644 --- a/changes/en-us/2.x.md +++ b/changes/en-us/2.x.md @@ -9,7 +9,7 @@ Add changes here for all PR submitted to the 2.x branch. - [[#PR_NO](https://github.com/seata/seata/pull/PR_NO)] A brief and accurate description of PR ### optimize: -- [[#PR_NO](https://github.com/seata/seata/pull/PR_NO)] A brief and accurate description of PR +- [[#6031](https://github.com/seata/seata/pull/6031)] add a check for the existence of the undolog table ### security: - [[#6069](https://github.com/seata/seata/pull/6069)] Upgrade Guava dependencies to fix security vulnerabilities @@ -21,6 +21,8 @@ Thanks to these contributors for their code commits. Please report an unintended - [slievrly](https://github.com/slievrly) +- [laywin](https://github.com/laywin) - [imcmai](https://github.com/imcmai) + Also, we receive many valuable issues, questions and advices from our community. Thanks for you all. diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md index f155efa1195..749d418cf23 100644 --- a/changes/zh-cn/2.x.md +++ b/changes/zh-cn/2.x.md @@ -9,7 +9,7 @@ - [[#PR_NO](https://github.com/seata/seata/pull/PR_NO)] 准确简要的PR描述 ### optimize: -- [[#PR_NO](https://github.com/seata/seata/pull/PR_NO)] 准确简要的PR描述 +- [[#6031](https://github.com/seata/seata/pull/6031)] 添加undo_log表的存在性校验 ### security: - [[#6069](https://github.com/seata/seata/pull/6069)] 升级Guava依赖版本,修复安全漏洞 @@ -21,6 +21,7 @@ - [slievrly](https://github.com/slievrly) +- [laywin](https://github.com/laywin) - [imcmai](https://github.com/imcmai) 同时,我们收到了社区反馈的很多有价值的issue和建议,非常感谢大家。 diff --git a/config/seata-config-core/src/test/java/io/seata/config/ConfigFutureTest.java b/config/seata-config-core/src/test/java/io/seata/config/ConfigFutureTest.java index 60ffb299527..57daca70fb5 100644 --- a/config/seata-config-core/src/test/java/io/seata/config/ConfigFutureTest.java +++ b/config/seata-config-core/src/test/java/io/seata/config/ConfigFutureTest.java @@ -21,7 +21,6 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.mockito.Mockito; -import org.mockito.internal.util.reflection.FieldSetter; import java.lang.reflect.Field; import java.util.concurrent.CompletableFuture; @@ -44,7 +43,8 @@ void testGet() throws NoSuchFieldException, IllegalAccessException, ExecutionExc // mock field origin = Mockito.spy(origin); // set mocked field to object - FieldSetter.setField(configFuture, originField, origin); + originField.setAccessible(true); + originField.set(configFuture, origin); Mockito.doThrow(ExecutionException.class).when(origin).get(Mockito.anyLong(), Mockito.any()); Assertions.assertThrows(ShouldNeverHappenException.class, configFuture::get); diff --git a/core/src/main/java/io/seata/core/constants/DBType.java b/core/src/main/java/io/seata/core/constants/DBType.java index 49063bb802e..a0171474033 100644 --- a/core/src/main/java/io/seata/core/constants/DBType.java +++ b/core/src/main/java/io/seata/core/constants/DBType.java @@ -208,5 +208,4 @@ public static DBType valueof(String dbType) { } throw new IllegalArgumentException("unknown dbtype:" + dbType); } - } diff --git a/dependencies/pom.xml b/dependencies/pom.xml index d82345a1f4b..166b1aa298d 100644 --- a/dependencies/pom.xml +++ b/dependencies/pom.xml @@ -118,7 +118,7 @@ 1.4.3 - 2.23.4 + 4.5.1 3.12.2 9.4.38.v20210224 3.1.7 @@ -701,6 +701,11 @@ mockito-junit-jupiter ${mockito.version} + + org.mockito + mockito-inline + ${mockito.version} + org.assertj assertj-core diff --git a/pom.xml b/pom.xml index f2371a43ce7..4d7b21b35e8 100644 --- a/pom.xml +++ b/pom.xml @@ -92,6 +92,11 @@ mockito-junit-jupiter test + + org.mockito + mockito-inline + test + org.assertj assertj-core diff --git a/rm-datasource/src/main/java/io/seata/rm/RMHandlerAT.java b/rm-datasource/src/main/java/io/seata/rm/RMHandlerAT.java index 333a121a295..cc9d1971890 100644 --- a/rm-datasource/src/main/java/io/seata/rm/RMHandlerAT.java +++ b/rm-datasource/src/main/java/io/seata/rm/RMHandlerAT.java @@ -19,8 +19,6 @@ import java.sql.SQLException; import java.text.ParseException; import java.util.Date; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import io.seata.common.util.DateUtil; import io.seata.core.model.BranchType; @@ -44,8 +42,6 @@ public class RMHandlerAT extends AbstractRMHandler { private static final int LIMIT_ROWS = 3000; - private final Map undoLogTableExistRecord = new ConcurrentHashMap<>(); - @Override public void handle(UndoLogDeleteRequest request) { String resourceId = request.getResourceId(); @@ -56,12 +52,6 @@ public void handle(UndoLogDeleteRequest request) { return; } - boolean hasUndoLogTable = undoLogTableExistRecord.computeIfAbsent(resourceId, id -> checkUndoLogTableExist(dataSourceProxy)); - if (!hasUndoLogTable) { - LOGGER.debug("resource({}) has no undo_log table, UndoLogDeleteRequest will be ignored", resourceId); - return; - } - Date division = getLogCreated(request.getSaveDays()); UndoLogManager manager = getUndoLogManager(dataSourceProxy); @@ -80,19 +70,6 @@ public void handle(UndoLogDeleteRequest request) { } } - boolean checkUndoLogTableExist(DataSourceProxy dataSourceProxy) { - UndoLogManager manager = getUndoLogManager(dataSourceProxy); - try (Connection connection = getConnection(dataSourceProxy)) { - if (connection == null) { - return false; - } - return manager.hasUndoLogTable(connection); - } catch (Exception e) { - // should never happen, hasUndoLogTable method had catch all Exception - return false; - } - } - Connection getConnection(DataSourceProxy dataSourceProxy) { try { return dataSourceProxy.getPlainConnection(); diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/DataSourceProxy.java b/rm-datasource/src/main/java/io/seata/rm/datasource/DataSourceProxy.java index 6d930ea4009..295a22e77b5 100644 --- a/rm-datasource/src/main/java/io/seata/rm/datasource/DataSourceProxy.java +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/DataSourceProxy.java @@ -22,18 +22,25 @@ import javax.sql.DataSource; +import io.seata.common.ConfigurationKeys; import io.seata.common.Constants; +import io.seata.common.loader.EnhancedServiceNotFoundException; +import io.seata.config.ConfigurationFactory; import io.seata.core.context.RootContext; import io.seata.core.model.BranchType; import io.seata.core.model.Resource; import io.seata.rm.DefaultResourceManager; import io.seata.rm.datasource.sql.struct.TableMetaCacheFactory; +import io.seata.rm.datasource.undo.UndoLogManager; +import io.seata.rm.datasource.undo.UndoLogManagerFactory; import io.seata.rm.datasource.util.JdbcUtils; import io.seata.sqlparser.util.JdbcConstants; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static io.seata.common.DefaultValues.DEFAULT_TRANSACTION_UNDO_LOG_TABLE; + /** * The type Data source proxy. * @@ -101,6 +108,8 @@ private void init(DataSource dataSource, String resourceGroupId) { validMySQLVersion(connection); checkDerivativeProduct(); } + checkUndoLogTableExist(connection); + } catch (SQLException e) { throw new IllegalStateException("can not init dataSource", e); } @@ -143,6 +152,31 @@ private boolean isPolardbXProduct() { return false; } + /** + * check existence of undolog table + * + * if the table not exist fast fail, or else keep silence + * + * @param conn db connection + */ + private void checkUndoLogTableExist(Connection conn) { + UndoLogManager undoLogManager; + try { + undoLogManager = UndoLogManagerFactory.getUndoLogManager(dbType); + } catch (EnhancedServiceNotFoundException e) { + String errMsg = String.format("AT mode don't support the the dbtype: %s", dbType); + throw new IllegalStateException(errMsg, e); + } + + boolean undoLogTableExist = undoLogManager.hasUndoLogTable(conn); + if (!undoLogTableExist) { + String undoLogTableName = ConfigurationFactory.getInstance() + .getConfig(ConfigurationKeys.TRANSACTION_UNDO_LOG_TABLE, DEFAULT_TRANSACTION_UNDO_LOG_TABLE); + String errMsg = String.format("in AT mode, %s table not exist", undoLogTableName); + throw new IllegalStateException(errMsg); + } + } + /** * publish tableMeta refresh event */ diff --git a/rm-datasource/src/test/java/io/seata/rm/RMHandlerATTest.java b/rm-datasource/src/test/java/io/seata/rm/RMHandlerATTest.java index 3ae96f51d0d..f3d34f25c22 100644 --- a/rm-datasource/src/test/java/io/seata/rm/RMHandlerATTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/RMHandlerATTest.java @@ -22,7 +22,10 @@ import org.junit.jupiter.api.Test; import java.sql.Connection; +import java.sql.SQLException; +import java.util.Date; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.times; @@ -41,30 +44,26 @@ class RMHandlerATTest { @Test - void hasUndoLogTableTest() { - RMHandlerAT handler = buildHandler(true); + void testNormalDeleteUndoLogTable() throws SQLException { + RMHandlerAT handler = buildHandler(false); UndoLogDeleteRequest request = buildRequest(); int testTimes = 5; for (int i = 0; i < testTimes; i++) { handler.handle(request); } - verify(handler, times(1)).checkUndoLogTableExist(any()); verify(handler, times(testTimes)).deleteUndoLog(any(), any(), any()); } @Test - void noUndoLogTableTest() { - RMHandlerAT handler = buildHandler(false); + void testErrorDeleteUndoLogTable() throws SQLException { + RMHandlerAT handler = buildHandler(true); UndoLogDeleteRequest request = buildRequest(); - int testTimes = 5; - for (int i = 0; i < testTimes; i++) { - handler.handle(request); - } - verify(handler, times(1)).checkUndoLogTableExist(any()); - verify(handler, never()).deleteUndoLog(any(), any(), any()); + request.setSaveDays((short) -1); + handler.handle(request); + verify(handler, times(1)).deleteUndoLog(any(), any(), any()); } - private RMHandlerAT buildHandler(boolean hasUndoLogTable) { + private RMHandlerAT buildHandler(boolean errorDeleteUndologTable) throws SQLException { RMHandlerAT handler = spy(new RMHandlerAT()); DataSourceManager dataSourceManager = mock(DataSourceManager.class); doReturn(dataSourceManager).when(handler).getResourceManager(); @@ -78,9 +77,14 @@ private RMHandlerAT buildHandler(boolean hasUndoLogTable) { }); UndoLogManager manager = mock(UndoLogManager.class); - when(manager.hasUndoLogTable(any())).thenReturn(hasUndoLogTable); + when(manager.hasUndoLogTable(any())).thenReturn(true); doReturn(manager).when(handler).getUndoLogManager(any()); + if (errorDeleteUndologTable) { + when(manager.deleteUndoLogByLogCreated(any(Date.class), anyInt(), any(Connection.class))) + .thenThrow(new SQLException()); + } + return handler; } diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/DataSourceProxyTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/DataSourceProxyTest.java index d8da5d26acf..e351f674bee 100644 --- a/rm-datasource/src/test/java/io/seata/rm/datasource/DataSourceProxyTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/DataSourceProxyTest.java @@ -16,6 +16,7 @@ package io.seata.rm.datasource; import java.lang.reflect.Field; +import java.sql.Connection; import java.sql.SQLException; import javax.sql.DataSource; @@ -23,8 +24,17 @@ import io.seata.rm.datasource.mock.MockDataSource; import io.seata.rm.datasource.mock.MockDriver; import io.seata.rm.datasource.sql.struct.TableMetaCacheFactory; +import io.seata.rm.datasource.undo.UndoLogManagerFactory; +import io.seata.rm.datasource.undo.mysql.MySQLUndoLogManager; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.*; /** * @author ph3636 @@ -34,7 +44,6 @@ public class DataSourceProxyTest { @Test public void test_constructor() { DataSource dataSource = new MockDataSource(); - DataSourceProxy dataSourceProxy = new DataSourceProxy(dataSource); Assertions.assertEquals(dataSourceProxy.getTargetDataSource(), dataSource); @@ -42,6 +51,42 @@ public void test_constructor() { Assertions.assertEquals(dataSourceProxy2.getTargetDataSource(), dataSource); } + @Test + public void testNotSupportDb() { + final MockDriver mockDriver = new MockDriver(); + final String username = "username"; + final String jdbcUrl = "jdbc:mock:xxx"; + + // create data source + final DruidDataSource dataSource = new DruidDataSource(); + dataSource.setUrl(jdbcUrl); + dataSource.setDriver(mockDriver); + dataSource.setUsername(username); + dataSource.setPassword("password"); + + Throwable throwable = Assertions.assertThrows(IllegalStateException.class, () -> new DataSourceProxy(dataSource)); + assertThat(throwable).hasMessageContaining("AT mode don't support the the dbtype"); + } + + + @Test + public void testUndologTableNotExist() { + DataSource dataSource = new MockDataSource(); + + MockedStatic undoLogManagerFactoryMockedStatic = Mockito.mockStatic(UndoLogManagerFactory.class); + + MySQLUndoLogManager mysqlUndoLogManager = mock(MySQLUndoLogManager.class); + undoLogManagerFactoryMockedStatic.when(()->UndoLogManagerFactory.getUndoLogManager(anyString())) + .thenReturn(mysqlUndoLogManager); + + doReturn(false).when(mysqlUndoLogManager).hasUndoLogTable(any(Connection.class)); + + Throwable throwable = Assertions.assertThrows(IllegalStateException.class, () -> new DataSourceProxy(dataSource)); + undoLogManagerFactoryMockedStatic.close(); + + assertThat(throwable).hasMessageContaining("table not exist"); + } + @Test public void getResourceIdTest() throws SQLException, NoSuchFieldException, IllegalAccessException { // Disable 'DataSourceProxy.tableMetaExecutor' to prevent unit tests from being affected @@ -62,7 +107,7 @@ public void getResourceIdTest() throws SQLException, NoSuchFieldException, Illeg dataSource.setPassword("password"); // create data source proxy - final DataSourceProxy proxy = new DataSourceProxy(dataSource); + final DataSourceProxy proxy = getDataSourceProxy(dataSource); // get fields Field resourceIdField = proxy.getClass().getDeclaredField("resourceId"); @@ -124,4 +169,17 @@ public void getResourceIdTest() throws SQLException, NoSuchFieldException, Illeg jdbcUrlField.set(proxy, jdbcUrl); } } + + // to skip the db & undolog table check + public static DataSourceProxy getDataSourceProxy(DataSource dataSource) { + try (MockedStatic undoLogManagerFactoryMockedStatic = Mockito.mockStatic(UndoLogManagerFactory.class)) { + MySQLUndoLogManager mysqlUndoLogManager = mock(MySQLUndoLogManager.class); + undoLogManagerFactoryMockedStatic.when(() -> UndoLogManagerFactory.getUndoLogManager(anyString())).thenReturn(mysqlUndoLogManager); + + doReturn(true).when(mysqlUndoLogManager).hasUndoLogTable(any(Connection.class)); + + // create data source proxy + return new DataSourceProxy(dataSource); + } + } } diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/PreparedStatementProxyTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/PreparedStatementProxyTest.java index cd7c58cb9df..3ef88b2e1c8 100644 --- a/rm-datasource/src/test/java/io/seata/rm/datasource/PreparedStatementProxyTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/PreparedStatementProxyTest.java @@ -44,6 +44,8 @@ import io.seata.rm.datasource.mock.MockClob; import io.seata.rm.datasource.mock.MockConnection; import io.seata.rm.datasource.mock.MockDriver; +import io.seata.rm.datasource.undo.UndoLogManagerFactory; +import io.seata.rm.datasource.undo.mysql.MySQLUndoLogManager; import io.seata.sqlparser.SQLRecognizerFactory; import io.seata.sqlparser.SqlParserType; import io.seata.sqlparser.druid.DruidDelegatingSQLRecognizerFactory; @@ -54,6 +56,12 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import javax.sql.DataSource; + +import static org.mockito.ArgumentMatchers.anyString; /** * @author will @@ -86,8 +94,7 @@ public static void init() throws SQLException { DruidDataSource dataSource = new DruidDataSource(); dataSource.setUrl("jdbc:mock:xxx"); dataSource.setDriver(mockDriver); - - DataSourceProxy dataSourceProxy = new DataSourceProxy(dataSource); + DataSourceProxy dataSourceProxy = DataSourceProxyTest.getDataSourceProxy(dataSource); ConnectionProxy connectionProxy = new ConnectionProxy(dataSourceProxy, dataSource.getConnection().getConnection()); diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/StatementProxyTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/StatementProxyTest.java index 8260ef81e7e..54646a9ddc3 100644 --- a/rm-datasource/src/test/java/io/seata/rm/datasource/StatementProxyTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/StatementProxyTest.java @@ -31,6 +31,8 @@ import io.seata.rm.datasource.mock.MockConnection; import io.seata.rm.datasource.mock.MockDriver; +import io.seata.rm.datasource.undo.UndoLogManagerFactory; +import io.seata.rm.datasource.undo.mysql.MySQLUndoLogManager; import io.seata.sqlparser.SQLRecognizerFactory; import io.seata.sqlparser.SqlParserType; import io.seata.sqlparser.druid.DruidDelegatingSQLRecognizerFactory; @@ -44,6 +46,10 @@ import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import static org.mockito.ArgumentMatchers.anyString; /** * @author will @@ -78,7 +84,7 @@ public static void init() throws SQLException { dataSource.setUrl("jdbc:mock:xxx"); dataSource.setDriver(mockDriver); - DataSourceProxy dataSourceProxy = new DataSourceProxy(dataSource); + DataSourceProxy dataSourceProxy = DataSourceProxyTest.getDataSourceProxy(dataSource); ConnectionProxy connectionProxy = new ConnectionProxy(dataSourceProxy, dataSource.getConnection().getConnection()); diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/exec/DeleteExecutorTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/exec/DeleteExecutorTest.java index 838e73a3448..b3b5ed10554 100644 --- a/rm-datasource/src/test/java/io/seata/rm/datasource/exec/DeleteExecutorTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/exec/DeleteExecutorTest.java @@ -29,13 +29,23 @@ import com.google.common.collect.Lists; import io.seata.rm.datasource.ConnectionProxy; import io.seata.rm.datasource.DataSourceProxy; +import io.seata.rm.datasource.DataSourceProxyTest; import io.seata.rm.datasource.StatementProxy; import io.seata.rm.datasource.mock.MockDriver; import io.seata.rm.datasource.sql.struct.TableRecords; +import io.seata.rm.datasource.undo.UndoLogManagerFactory; +import io.seata.rm.datasource.undo.mysql.MySQLUndoLogManager; import io.seata.sqlparser.druid.mysql.MySQLDeleteRecognizer; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import javax.sql.DataSource; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; /** * @author will @@ -66,7 +76,7 @@ public static void init() { dataSource.setUrl("jdbc:mock:xxx"); dataSource.setDriver(mockDriver); - DataSourceProxy dataSourceProxy = new DataSourceProxy(dataSource); + DataSourceProxy dataSourceProxy = DataSourceProxyTest.getDataSourceProxy(dataSource); try { Field field = dataSourceProxy.getClass().getDeclaredField("dbType"); field.setAccessible(true); @@ -101,4 +111,5 @@ public void testAfterImage() throws SQLException { TableRecords tableRecords = deleteExecutor.beforeImage(); Assertions.assertEquals(0, deleteExecutor.afterImage(tableRecords).size()); } + } diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/exec/MultiExecutorTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/exec/MultiExecutorTest.java index 332bde4985d..980aee46f69 100644 --- a/rm-datasource/src/test/java/io/seata/rm/datasource/exec/MultiExecutorTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/exec/MultiExecutorTest.java @@ -24,6 +24,9 @@ import java.util.Set; import java.util.stream.Collectors; +import io.seata.rm.datasource.DataSourceProxyTest; +import io.seata.rm.datasource.undo.UndoLogManagerFactory; +import io.seata.rm.datasource.undo.mysql.MySQLUndoLogManager; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -44,6 +47,14 @@ import io.seata.sqlparser.SQLRecognizer; import io.seata.sqlparser.SQLType; import io.seata.sqlparser.util.JdbcConstants; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import javax.sql.DataSource; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class MultiExecutorTest { @@ -73,7 +84,8 @@ public static void init() throws Throwable { dataSource.setUrl("jdbc:mock:xxx"); dataSource.setDriver(mockDriver); - DataSourceProxy dataSourceProxy = new DataSourceProxy(dataSource); + DataSourceProxy dataSourceProxy = DataSourceProxyTest.getDataSourceProxy(dataSource); + try { Field field = dataSourceProxy.getClass().getDeclaredField("dbType"); field.setAccessible(true); diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/exec/PlainExecutorTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/exec/PlainExecutorTest.java index 7a2e545b65c..22b18549ca5 100644 --- a/rm-datasource/src/test/java/io/seata/rm/datasource/exec/PlainExecutorTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/exec/PlainExecutorTest.java @@ -24,6 +24,7 @@ import com.google.common.collect.Lists; import io.seata.rm.datasource.ConnectionProxy; import io.seata.rm.datasource.DataSourceProxy; +import io.seata.rm.datasource.DataSourceProxyTest; import io.seata.rm.datasource.StatementProxy; import io.seata.rm.datasource.mock.MockDriver; import org.junit.jupiter.api.BeforeEach; @@ -56,7 +57,8 @@ public void init() throws SQLException { dataSource.setUrl("jdbc:mock:xxx"); dataSource.setDriver(mockDriver); - DataSourceProxy dataSourceProxy = new DataSourceProxy(dataSource); + DataSourceProxy dataSourceProxy = DataSourceProxyTest.getDataSourceProxy(dataSource); + ConnectionProxy connectionProxy = new ConnectionProxy(dataSourceProxy, dataSource.getConnection().getConnection()); MockStatementBase mockStatement = new MockStatement(dataSource.getConnection().getConnection()); StatementProxy statementProxy = new StatementProxy(connectionProxy, mockStatement); diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/exec/SelectForUpdateExecutorTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/exec/SelectForUpdateExecutorTest.java index 46d4ca0f75a..c53d382f1dd 100644 --- a/rm-datasource/src/test/java/io/seata/rm/datasource/exec/SelectForUpdateExecutorTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/exec/SelectForUpdateExecutorTest.java @@ -28,14 +28,21 @@ import io.seata.core.context.RootContext; import io.seata.rm.datasource.ConnectionProxy; import io.seata.rm.datasource.DataSourceProxy; +import io.seata.rm.datasource.DataSourceProxyTest; import io.seata.rm.datasource.StatementProxy; import io.seata.rm.datasource.mock.MockConnectionProxy; import io.seata.rm.datasource.mock.MockDriver; import io.seata.rm.datasource.mock.MockLockConflictConnectionProxy; +import io.seata.rm.datasource.undo.UndoLogManagerFactory; +import io.seata.rm.datasource.undo.mysql.MySQLUndoLogManager; import io.seata.sqlparser.druid.mysql.MySQLSelectForUpdateRecognizer; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import static org.mockito.ArgumentMatchers.anyString; /** * @author will @@ -69,7 +76,8 @@ public static void init() { dataSource.setUrl("jdbc:mock:xxx"); dataSource.setDriver(mockDriver); - DataSourceProxy dataSourceProxy = new DataSourceProxy(dataSource); + DataSourceProxy dataSourceProxy = DataSourceProxyTest.getDataSourceProxy(dataSource); + try { Field field = dataSourceProxy.getClass().getDeclaredField("dbType"); field.setAccessible(true); diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/exec/UpdateExecutorTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/exec/UpdateExecutorTest.java index c25df6f4e37..973ae530ad1 100644 --- a/rm-datasource/src/test/java/io/seata/rm/datasource/exec/UpdateExecutorTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/exec/UpdateExecutorTest.java @@ -30,13 +30,22 @@ import com.google.common.collect.Lists; import io.seata.rm.datasource.ConnectionProxy; import io.seata.rm.datasource.DataSourceProxy; +import io.seata.rm.datasource.DataSourceProxyTest; import io.seata.rm.datasource.StatementProxy; import io.seata.rm.datasource.mock.MockDriver; import io.seata.rm.datasource.sql.struct.TableRecords; +import io.seata.rm.datasource.undo.UndoLogManagerFactory; +import io.seata.rm.datasource.undo.mysql.MySQLUndoLogManager; import io.seata.sqlparser.druid.mysql.MySQLUpdateRecognizer; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import javax.sql.DataSource; + +import static org.mockito.ArgumentMatchers.anyString; /** * @author will @@ -68,7 +77,8 @@ public static void init() { dataSource.setUrl("jdbc:mock:xxx"); dataSource.setDriver(mockDriver); - DataSourceProxy dataSourceProxy = new DataSourceProxy(dataSource); + DataSourceProxy dataSourceProxy = DataSourceProxyTest.getDataSourceProxy(dataSource); + try { Field field = dataSourceProxy.getClass().getDeclaredField("dbType"); field.setAccessible(true); diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/exec/UpdateJoinExecutorTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/exec/UpdateJoinExecutorTest.java index 971dfd03373..fbde0a4bd96 100644 --- a/rm-datasource/src/test/java/io/seata/rm/datasource/exec/UpdateJoinExecutorTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/exec/UpdateJoinExecutorTest.java @@ -29,13 +29,20 @@ import com.google.common.collect.Lists; import io.seata.rm.datasource.ConnectionProxy; import io.seata.rm.datasource.DataSourceProxy; +import io.seata.rm.datasource.DataSourceProxyTest; import io.seata.rm.datasource.StatementProxy; import io.seata.rm.datasource.exec.mysql.MySQLUpdateJoinExecutor; import io.seata.rm.datasource.mock.MockDriver; import io.seata.rm.datasource.sql.struct.TableRecords; +import io.seata.rm.datasource.undo.UndoLogManagerFactory; +import io.seata.rm.datasource.undo.mysql.MySQLUndoLogManager; import io.seata.sqlparser.druid.mysql.MySQLUpdateRecognizer; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import static org.mockito.ArgumentMatchers.anyString; /** * @author renliangyu857 @@ -81,7 +88,7 @@ private StatementProxy mockStatementProxy(List returnValueColumnLabels, dataSource.setUrl("jdbc:mock:xxx"); dataSource.setDriver(mockDriver); - DataSourceProxy dataSourceProxy = new DataSourceProxy(dataSource); + DataSourceProxy dataSourceProxy = DataSourceProxyTest.getDataSourceProxy(dataSource); try { Field field = dataSourceProxy.getClass().getDeclaredField("dbType"); field.setAccessible(true); diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/TableRecordsTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/TableRecordsTest.java index 61714ca7778..bc02c64016a 100644 --- a/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/TableRecordsTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/TableRecordsTest.java @@ -15,26 +15,25 @@ */ package io.seata.rm.datasource.sql.struct; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Types; -import java.util.List; - -import io.seata.rm.datasource.exception.TableMetaException; -import io.seata.sqlparser.struct.TableMeta; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - import com.alibaba.druid.mock.MockStatement; import com.alibaba.druid.mock.MockStatementBase; import com.alibaba.druid.pool.DruidDataSource; import com.google.common.collect.Lists; - import io.seata.common.exception.ShouldNeverHappenException; import io.seata.rm.datasource.DataSourceProxy; +import io.seata.rm.datasource.DataSourceProxyTest; +import io.seata.rm.datasource.exception.TableMetaException; import io.seata.rm.datasource.mock.MockDriver; +import io.seata.sqlparser.struct.TableMeta; import io.seata.sqlparser.util.JdbcConstants; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.List; /** * the table records test @@ -102,8 +101,9 @@ public void testPkRow() throws SQLException { DruidDataSource dataSource = new DruidDataSource(); dataSource.setUrl("jdbc:mock:xxx"); dataSource.setDriver(mockDriver); + MockStatementBase mockStatement = new MockStatement(dataSource.getConnection().getConnection()); - DataSourceProxy proxy = new DataSourceProxy(dataSource); + DataSourceProxy proxy = DataSourceProxyTest.getDataSourceProxy(dataSource); TableMeta tableMeta = TableMetaCacheFactory.getTableMetaCache(JdbcConstants.MYSQL).getTableMeta(proxy.getPlainConnection(), "table_records_test", proxy.getResourceId()); @@ -122,7 +122,7 @@ public void testBuildRecords() throws SQLException { dataSource.setUrl("jdbc:mock:xxx"); dataSource.setDriver(mockDriver); MockStatementBase mockStatement = new MockStatement(dataSource.getConnection().getConnection()); - DataSourceProxy proxy = new DataSourceProxy(dataSource); + DataSourceProxy proxy = DataSourceProxyTest.getDataSourceProxy(dataSource); TableMeta tableMeta = TableMetaCacheFactory.getTableMetaCache(JdbcConstants.MYSQL).getTableMeta(proxy.getPlainConnection(), "table_records_test", proxy.getResourceId()); @@ -141,7 +141,7 @@ public void testBuildRecordsNewFeild() throws SQLException { dataSource.setUrl("jdbc:mock:xxx"); dataSource.setDriver(mockDriver); MockStatementBase mockStatement = new MockStatement(dataSource.getConnection().getConnection()); - DataSourceProxy proxy = new DataSourceProxy(dataSource); + DataSourceProxy proxy = DataSourceProxyTest.getDataSourceProxy(dataSource); TableMeta tableMeta = TableMetaCacheFactory.getTableMetaCache(JdbcConstants.MYSQL).getTableMeta(proxy.getPlainConnection(), "table_records_test", proxy.getResourceId()); diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/DmTableMetaCacheTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/DmTableMetaCacheTest.java index e4319ea5b3f..8973b130516 100644 --- a/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/DmTableMetaCacheTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/DmTableMetaCacheTest.java @@ -17,6 +17,7 @@ import com.alibaba.druid.pool.DruidDataSource; import io.seata.rm.datasource.DataSourceProxy; +import io.seata.rm.datasource.DataSourceProxyTest; import io.seata.rm.datasource.mock.MockDriver; import io.seata.rm.datasource.sql.struct.TableMetaCacheFactory; import io.seata.sqlparser.struct.TableMeta; @@ -65,7 +66,7 @@ public void getTableMetaTest() throws SQLException { dataSource.setUrl("jdbc:mock:xxx"); dataSource.setDriver(mockDriver); - DataSourceProxy proxy = new DataSourceProxy(dataSource); + DataSourceProxy proxy = DataSourceProxyTest.getDataSourceProxy(dataSource); TableMetaCache tableMetaCache = TableMetaCacheFactory.getTableMetaCache(JdbcConstants.DM); diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/MariadbTableMetaCacheTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/MariadbTableMetaCacheTest.java index a13c9991c8c..01144502bc9 100644 --- a/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/MariadbTableMetaCacheTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/MariadbTableMetaCacheTest.java @@ -19,6 +19,9 @@ import java.sql.Types; import java.util.Collections; +import io.seata.rm.datasource.DataSourceProxyTest; +import io.seata.rm.datasource.undo.UndoLogManagerFactory; +import io.seata.rm.datasource.undo.mysql.MySQLUndoLogManager; import io.seata.sqlparser.struct.ColumnMeta; import io.seata.sqlparser.struct.IndexMeta; import io.seata.sqlparser.struct.IndexType; @@ -34,6 +37,10 @@ import io.seata.rm.datasource.mock.MockDriver; import io.seata.rm.datasource.sql.struct.TableMetaCacheFactory; import io.seata.sqlparser.util.JdbcConstants; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import static org.mockito.ArgumentMatchers.anyString; /** * The table meta fetch test. @@ -84,7 +91,7 @@ public void getTableMetaTest_0() throws SQLException { dataSource.setUrl("jdbc:mock:xxx"); dataSource.setDriver(mockDriver); - DataSourceProxy proxy = new DataSourceProxy(dataSource); + DataSourceProxy proxy = DataSourceProxyTest.getDataSourceProxy(dataSource); TableMeta tableMeta = getTableMetaCache().getTableMeta(proxy.getPlainConnection(), "mt1", proxy.getResourceId()); @@ -133,7 +140,7 @@ public void refreshTest_0() throws SQLException { druidDataSource.setUrl("jdbc:mock:xxx"); druidDataSource.setDriver(mockDriver); - DataSourceProxy dataSourceProxy = new DataSourceProxy(druidDataSource); + DataSourceProxy dataSourceProxy = DataSourceProxyTest.getDataSourceProxy(druidDataSource); TableMeta tableMeta = getTableMetaCache().getTableMeta(dataSourceProxy.getPlainConnection(), "t1", dataSourceProxy.getResourceId()); diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/MysqlTableMetaCacheTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/MysqlTableMetaCacheTest.java index 56928aa6d70..0dbe2400ef7 100644 --- a/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/MysqlTableMetaCacheTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/MysqlTableMetaCacheTest.java @@ -19,6 +19,9 @@ import java.sql.Types; import java.util.Collections; +import io.seata.rm.datasource.DataSourceProxyTest; +import io.seata.rm.datasource.undo.UndoLogManagerFactory; +import io.seata.rm.datasource.undo.mysql.MySQLUndoLogManager; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -34,6 +37,13 @@ import io.seata.sqlparser.struct.TableMetaCache; import io.seata.rm.datasource.sql.struct.TableMetaCacheFactory; import io.seata.sqlparser.util.JdbcConstants; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import javax.sql.DataSource; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; /** * The table meta fetch test. @@ -84,7 +94,7 @@ public void getTableMetaTest_0() throws SQLException { dataSource.setUrl("jdbc:mock:xxx"); dataSource.setDriver(mockDriver); - DataSourceProxy proxy = new DataSourceProxy(dataSource); + DataSourceProxy proxy = DataSourceProxyTest.getDataSourceProxy(dataSource); TableMeta tableMeta = getTableMetaCache().getTableMeta(proxy.getPlainConnection(), "mt1", proxy.getResourceId()); @@ -133,7 +143,7 @@ public void refreshTest_0() throws SQLException { druidDataSource.setUrl("jdbc:mock:xxx"); druidDataSource.setDriver(mockDriver); - DataSourceProxy dataSourceProxy = new DataSourceProxy(druidDataSource); + DataSourceProxy dataSourceProxy = DataSourceProxyTest.getDataSourceProxy(druidDataSource); TableMeta tableMeta = getTableMetaCache().getTableMeta(dataSourceProxy.getPlainConnection(), "t1", dataSourceProxy.getResourceId()); diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/OracleTableMetaCacheTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/OracleTableMetaCacheTest.java index 8d3aa2abccd..fd7877acac9 100644 --- a/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/OracleTableMetaCacheTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/OracleTableMetaCacheTest.java @@ -18,6 +18,9 @@ import java.sql.SQLException; import java.sql.Types; +import io.seata.rm.datasource.DataSourceProxyTest; +import io.seata.rm.datasource.undo.UndoLogManagerFactory; +import io.seata.rm.datasource.undo.mysql.MySQLUndoLogManager; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -29,6 +32,10 @@ import io.seata.sqlparser.struct.TableMetaCache; import io.seata.rm.datasource.sql.struct.TableMetaCacheFactory; import io.seata.sqlparser.util.JdbcConstants; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import static org.mockito.ArgumentMatchers.anyString; /** * @author will.zjw @@ -65,7 +72,7 @@ public void getTableMetaTest() throws SQLException { dataSource.setUrl("jdbc:mock:xxx"); dataSource.setDriver(mockDriver); - DataSourceProxy proxy = new DataSourceProxy(dataSource); + DataSourceProxy proxy = DataSourceProxyTest.getDataSourceProxy(dataSource); TableMetaCache tableMetaCache = TableMetaCacheFactory.getTableMetaCache(JdbcConstants.ORACLE); diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/PostgresqlTableMetaCacheTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/PostgresqlTableMetaCacheTest.java index 2098629e824..bf1a116c47f 100644 --- a/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/PostgresqlTableMetaCacheTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/PostgresqlTableMetaCacheTest.java @@ -18,6 +18,9 @@ import java.sql.SQLException; import java.sql.Types; +import io.seata.rm.datasource.DataSourceProxyTest; +import io.seata.rm.datasource.undo.UndoLogManagerFactory; +import io.seata.rm.datasource.undo.mysql.MySQLUndoLogManager; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -29,6 +32,12 @@ import io.seata.sqlparser.struct.TableMetaCache; import io.seata.rm.datasource.sql.struct.TableMetaCacheFactory; import io.seata.sqlparser.util.JdbcConstants; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import javax.sql.DataSource; + +import static org.mockito.ArgumentMatchers.anyString; /** * @author will.zjw @@ -65,7 +74,7 @@ public void getTableMetaTest() throws SQLException { dataSource.setUrl("jdbc:mock:xxx"); dataSource.setDriver(mockDriver); - DataSourceProxy proxy = new DataSourceProxy(dataSource); + DataSourceProxy proxy = DataSourceProxyTest.getDataSourceProxy(dataSource); TableMetaCache tableMetaCache = TableMetaCacheFactory.getTableMetaCache(JdbcConstants.POSTGRESQL); diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/SqlServerTableMetaCacheTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/SqlServerTableMetaCacheTest.java index cb0b49e2f79..4cb0f26d85c 100644 --- a/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/SqlServerTableMetaCacheTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/sql/struct/cache/SqlServerTableMetaCacheTest.java @@ -22,7 +22,10 @@ import com.alibaba.druid.pool.DruidDataSource; import io.seata.common.exception.ShouldNeverHappenException; import io.seata.rm.datasource.DataSourceProxy; +import io.seata.rm.datasource.DataSourceProxyTest; import io.seata.rm.datasource.mock.MockDriver; +import io.seata.rm.datasource.undo.UndoLogManagerFactory; +import io.seata.rm.datasource.undo.mysql.MySQLUndoLogManager; import io.seata.sqlparser.struct.ColumnMeta; import io.seata.sqlparser.struct.IndexMeta; import io.seata.sqlparser.struct.IndexType; @@ -32,6 +35,13 @@ import io.seata.sqlparser.util.JdbcConstants; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import javax.sql.DataSource; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; /** * @author GoodBoyCoder @@ -82,7 +92,7 @@ public void getTableMetaTest_0() throws SQLException { dataSource.setUrl("jdbc:mock:xxx"); dataSource.setDriver(mockDriver); - DataSourceProxy proxy = new DataSourceProxy(dataSource); + DataSourceProxy proxy = DataSourceProxyTest.getDataSourceProxy(dataSource); TableMeta tableMeta = getTableMetaCache().getTableMeta(proxy.getPlainConnection(), "m.mt1", proxy.getResourceId()); diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/undo/BaseH2Test.java b/rm-datasource/src/test/java/io/seata/rm/datasource/undo/BaseH2Test.java index 9a84c5e08e5..412cc06bbbb 100644 --- a/rm-datasource/src/test/java/io/seata/rm/datasource/undo/BaseH2Test.java +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/undo/BaseH2Test.java @@ -18,6 +18,8 @@ import io.seata.common.util.IOUtil; import io.seata.rm.datasource.ConnectionProxy; import io.seata.rm.datasource.DataSourceProxy; +import io.seata.rm.datasource.DataSourceProxyTest; +import io.seata.rm.datasource.undo.mysql.MySQLUndoLogManager; import io.seata.sqlparser.struct.ColumnMeta; import io.seata.rm.datasource.sql.struct.Field; import io.seata.rm.datasource.sql.struct.KeyType; @@ -29,14 +31,17 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; +import org.mockito.MockedStatic; import org.mockito.Mockito; +import javax.sql.DataSource; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.sql.Types; import java.util.Arrays; +import static org.mockito.ArgumentMatchers.anyString; /** * @author Geng Zhang @@ -58,7 +63,8 @@ public static void start() throws SQLException { dataSource.setUrl("jdbc:h2:./db_store/test_undo"); dataSource.setUsername("sa"); dataSource.setPassword(""); - dataSourceProxy = new DataSourceProxy(dataSource); + dataSourceProxy = DataSourceProxyTest.getDataSourceProxy(dataSource); + connection = dataSourceProxy.getConnection(); tableMeta = mockTableMeta(); diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/undo/mariadb/MariadbUndoLogManagerTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/undo/mariadb/MariadbUndoLogManagerTest.java index 9af77f5eb63..a80799cdbe6 100644 --- a/rm-datasource/src/test/java/io/seata/rm/datasource/undo/mariadb/MariadbUndoLogManagerTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/undo/mariadb/MariadbUndoLogManagerTest.java @@ -25,6 +25,8 @@ import java.util.Date; import java.util.List; +import io.seata.rm.datasource.DataSourceProxyTest; +import io.seata.rm.datasource.undo.*; import io.seata.sqlparser.struct.TableMeta; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; @@ -42,11 +44,6 @@ import io.seata.rm.datasource.mock.MockDriver; import io.seata.rm.datasource.sql.struct.Row; import io.seata.rm.datasource.sql.struct.TableRecords; -import io.seata.rm.datasource.undo.AbstractUndoLogManager; -import io.seata.rm.datasource.undo.BranchUndoLog; -import io.seata.rm.datasource.undo.SQLUndoLog; -import io.seata.rm.datasource.undo.UndoLogParser; -import io.seata.rm.datasource.undo.UndoLogParserFactory; import io.seata.rm.datasource.undo.mysql.MySQLUndoLogManager; import io.seata.rm.datasource.undo.parser.JacksonUndoLogParser; import io.seata.sqlparser.SQLRecognizerFactory; @@ -56,6 +53,13 @@ import io.seata.sqlparser.druid.SQLOperateRecognizerHolder; import io.seata.sqlparser.druid.SQLOperateRecognizerHolderFactory; import io.seata.sqlparser.util.JdbcConstants; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import javax.sql.DataSource; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; /** * @author funkye @@ -100,7 +104,8 @@ public void init() throws SQLException { dataSource.setUrl("jdbc:mock:xxx"); dataSource.setDriver(mockDriver); - dataSourceProxy = new DataSourceProxy(dataSource); + dataSourceProxy = DataSourceProxyTest.getDataSourceProxy(dataSource); + connectionProxy = new ConnectionProxy(dataSourceProxy, dataSource.getConnection().getConnection()); undoLogManager = new MariadbUndoLogManager(); tableMeta = new TableMeta(); diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/undo/mysql/MySQLUndoLogManagerTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/undo/mysql/MySQLUndoLogManagerTest.java index 367dc94a82e..aa6ceeb168a 100644 --- a/rm-datasource/src/test/java/io/seata/rm/datasource/undo/mysql/MySQLUndoLogManagerTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/undo/mysql/MySQLUndoLogManagerTest.java @@ -33,15 +33,12 @@ import io.seata.rm.datasource.ConnectionContext; import io.seata.rm.datasource.ConnectionProxy; import io.seata.rm.datasource.DataSourceProxy; +import io.seata.rm.datasource.DataSourceProxyTest; import io.seata.rm.datasource.mock.MockDriver; import io.seata.rm.datasource.sql.struct.Row; +import io.seata.rm.datasource.undo.*; import io.seata.sqlparser.struct.TableMeta; import io.seata.rm.datasource.sql.struct.TableRecords; -import io.seata.rm.datasource.undo.AbstractUndoLogManager; -import io.seata.rm.datasource.undo.BranchUndoLog; -import io.seata.rm.datasource.undo.SQLUndoLog; -import io.seata.rm.datasource.undo.UndoLogParser; -import io.seata.rm.datasource.undo.UndoLogParserFactory; import io.seata.rm.datasource.undo.parser.JacksonUndoLogParser; import io.seata.sqlparser.SQLRecognizerFactory; import io.seata.sqlparser.SQLType; @@ -54,6 +51,12 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import javax.sql.DataSource; + +import static org.mockito.ArgumentMatchers.anyString; /** * @author will @@ -98,7 +101,8 @@ public void init() throws SQLException { dataSource.setUrl("jdbc:mock:xxx"); dataSource.setDriver(mockDriver); - dataSourceProxy = new DataSourceProxy(dataSource); + dataSourceProxy = DataSourceProxyTest.getDataSourceProxy(dataSource); + connectionProxy = new ConnectionProxy(dataSourceProxy, dataSource.getConnection().getConnection()); undoLogManager = new MySQLUndoLogManager(); tableMeta = new TableMeta(); diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/undo/polardbx/PolarDBXUndoLogManagerTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/undo/polardbx/PolarDBXUndoLogManagerTest.java index e80575b7e09..cb8b2a41a76 100644 --- a/rm-datasource/src/test/java/io/seata/rm/datasource/undo/polardbx/PolarDBXUndoLogManagerTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/undo/polardbx/PolarDBXUndoLogManagerTest.java @@ -32,15 +32,13 @@ import io.seata.rm.datasource.ConnectionContext; import io.seata.rm.datasource.ConnectionProxy; import io.seata.rm.datasource.DataSourceProxy; +import io.seata.rm.datasource.DataSourceProxyTest; import io.seata.rm.datasource.mock.MockDriver; import io.seata.rm.datasource.sql.struct.Row; import io.seata.rm.datasource.sql.struct.TableRecords; -import io.seata.rm.datasource.undo.AbstractUndoLogManager; -import io.seata.rm.datasource.undo.BranchUndoLog; -import io.seata.rm.datasource.undo.SQLUndoLog; -import io.seata.rm.datasource.undo.UndoLogParser; -import io.seata.rm.datasource.undo.UndoLogParserFactory; +import io.seata.rm.datasource.undo.*; +import io.seata.rm.datasource.undo.mysql.MySQLUndoLogManager; import io.seata.rm.datasource.undo.parser.JacksonUndoLogParser; import io.seata.sqlparser.SQLType; import io.seata.sqlparser.druid.SQLOperateRecognizerHolder; @@ -51,6 +49,12 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import javax.sql.DataSource; + +import static org.mockito.ArgumentMatchers.anyString; /** * Undo log manager test for PolarDB-X @@ -95,7 +99,7 @@ public void init() throws SQLException { dataSource.setUrl("jdbc:mock:xxx"); dataSource.setDriver(mockDriver); - dataSourceProxy = new DataSourceProxy(dataSource); + dataSourceProxy = DataSourceProxyTest.getDataSourceProxy(dataSource); connectionProxy = new ConnectionProxy(dataSourceProxy, dataSource.getConnection().getConnection()); undoLogManager = new PolarDBXUndoLogManager(); tableMeta = new TableMeta(); From 7894473dcf8e53bdb3f685295fee8a313679d0e8 Mon Sep 17 00:00:00 2001 From: Xiangkun Yin <32592585+ptyin@users.noreply.github.com> Date: Sun, 26 Nov 2023 23:33:44 +0800 Subject: [PATCH 10/10] bugfix: fix missing table alias for on update column of image SQL (#6075) --- changes/en-us/2.x.md | 4 +-- changes/zh-cn/2.x.md | 4 ++- .../exec/BaseTransactionalExecutor.java | 14 +++++++++-- .../datasource/exec/UpdateExecutorTest.java | 25 ++++++++++++++++--- 4 files changed, 38 insertions(+), 9 deletions(-) diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md index 13c6ed085d5..6c62b0e123c 100644 --- a/changes/en-us/2.x.md +++ b/changes/en-us/2.x.md @@ -6,7 +6,7 @@ Add changes here for all PR submitted to the 2.x branch. - [[#PR_NO](https://github.com/seata/seata/pull/PR_NO)] A brief and accurate description of PR ### bugfix: -- [[#PR_NO](https://github.com/seata/seata/pull/PR_NO)] A brief and accurate description of PR +- [[#6075](https://github.com/seata/seata/pull/6075)] fix missing table alias for on update column of image SQL ### optimize: - [[#6031](https://github.com/seata/seata/pull/6031)] add a check for the existence of the undolog table @@ -21,8 +21,8 @@ Thanks to these contributors for their code commits. Please report an unintended - [slievrly](https://github.com/slievrly) +- [ptyin](https://github.com/ptyin) - [laywin](https://github.com/laywin) - [imcmai](https://github.com/imcmai) - Also, we receive many valuable issues, questions and advices from our community. Thanks for you all. diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md index 749d418cf23..45a59e183fd 100644 --- a/changes/zh-cn/2.x.md +++ b/changes/zh-cn/2.x.md @@ -6,7 +6,7 @@ - [[#PR_NO](https://github.com/seata/seata/pull/PR_NO)] 准确简要的PR描述 ### bugfix: -- [[#PR_NO](https://github.com/seata/seata/pull/PR_NO)] 准确简要的PR描述 +- [[#6075](https://github.com/seata/seata/pull/6075)] 修复镜像SQL对于on update列没有添加表别名的问题 ### optimize: - [[#6031](https://github.com/seata/seata/pull/6031)] 添加undo_log表的存在性校验 @@ -21,7 +21,9 @@ - [slievrly](https://github.com/slievrly) +- [ptyin](https://github.com/ptyin) - [laywin](https://github.com/laywin) - [imcmai](https://github.com/imcmai) + 同时,我们收到了社区反馈的很多有价值的issue和建议,非常感谢大家。 diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/BaseTransactionalExecutor.java b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/BaseTransactionalExecutor.java index 303cff94146..ffd809dcf56 100644 --- a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/BaseTransactionalExecutor.java +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/BaseTransactionalExecutor.java @@ -24,6 +24,7 @@ import java.util.Map; import java.util.StringJoiner; import java.util.stream.Collectors; +import java.util.stream.Stream; import io.seata.common.DefaultValues; import io.seata.common.exception.ShouldNeverHappenException; @@ -535,13 +536,22 @@ protected List getNeedColumns(String table, String tableAlias, List onUpdateColumns = tableMeta.getOnUpdateColumnsOnlyName(); + if (StringUtils.isNotBlank(tableAlias)) { + onUpdateColumns = onUpdateColumns.stream() + .map(onUpdateColumn -> getColumnNameWithTablePrefix(table, tableAlias, onUpdateColumn)) + .collect(Collectors.toList()); + } onUpdateColumns.removeAll(unescapeColumns); needUpdateColumns.addAll(onUpdateColumns.stream() .map(onUpdateColumn -> ColumnUtils.addEscape(onUpdateColumn, getDbType(), tableMeta)) .collect(Collectors.toList())); } else { - needUpdateColumns.addAll(tableMeta.getAllColumns().keySet().stream() - .map(columnName -> ColumnUtils.addEscape(columnName, getDbType(), tableMeta)).collect(Collectors.toList())); + Stream allColumns = tableMeta.getAllColumns().keySet().stream(); + if (StringUtils.isNotBlank(tableAlias)) { + allColumns = allColumns.map(columnName -> getColumnNameWithTablePrefix(table, tableAlias, columnName)); + } + allColumns = allColumns.map(columnName -> ColumnUtils.addEscape(columnName, getDbType(), tableMeta)); + allColumns.forEach(needUpdateColumns::add); } return needUpdateColumns; } diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/exec/UpdateExecutorTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/exec/UpdateExecutorTest.java index 973ae530ad1..a25fdfa7fa1 100644 --- a/rm-datasource/src/test/java/io/seata/rm/datasource/exec/UpdateExecutorTest.java +++ b/rm-datasource/src/test/java/io/seata/rm/datasource/exec/UpdateExecutorTest.java @@ -18,6 +18,7 @@ import java.lang.reflect.Field; import java.sql.SQLException; import java.sql.Types; +import java.util.ArrayList; import java.util.List; import com.alibaba.druid.mock.MockStatement; @@ -58,21 +59,25 @@ public class UpdateExecutorTest { @BeforeAll public static void init() { - List returnValueColumnLabels = Lists.newArrayList("id", "name", "all"); + List returnValueColumnLabels = Lists.newArrayList("id", "name", "all", "updated"); Object[][] returnValue = new Object[][] { - new Object[] {1, "Tom", "keyword"}, - new Object[] {2, "Jack", "keyword"}, + new Object[] {1, "Tom", "keyword", 0}, + new Object[] {2, "Jack", "keyword", 0}, }; Object[][] columnMetas = new Object[][] { new Object[] {"", "", "table_update_executor_test", "id", Types.INTEGER, "INTEGER", 64, 0, 10, 1, "", "", 0, 0, 64, 1, "NO", "YES"}, new Object[] {"", "", "table_update_executor_test", "name", Types.VARCHAR, "VARCHAR", 64, 0, 10, 0, "", "", 0, 0, 64, 2, "YES", "NO"}, new Object[] {"", "", "table_update_executor_test", "ALL", Types.VARCHAR, "VARCHAR", 64, 0, 10, 0, "", "", 0, 0, 64, 2, "YES", "NO"}, + new Object[] {"", "", "table_update_executor_test", "updated", Types.INTEGER, "INTEGER", 64, 0, 10, 0, "", "", 0, 0, 64, 2, "YES", "NO"}, }; Object[][] indexMetas = new Object[][] { new Object[] {"PRIMARY", "id", false, "", 3, 1, "A", 34}, }; + Object[][] onUpdateColumnsReturnValue = new Object[][] { + new Object[]{0, "updated", Types.INTEGER, "INTEGER", 64, 10, 0, 0} + }; - MockDriver mockDriver = new MockDriver(returnValueColumnLabels, returnValue, columnMetas, indexMetas); + MockDriver mockDriver = new MockDriver(returnValueColumnLabels, returnValue, columnMetas, indexMetas, null, onUpdateColumnsReturnValue); DruidDataSource dataSource = new DruidDataSource(); dataSource.setUrl("jdbc:mock:xxx"); dataSource.setDriver(mockDriver); @@ -108,6 +113,18 @@ public void testBeforeImage() throws SQLException { Assertions.assertNotNull(updateExecutor.beforeImage()); } + @Test + public void testBeforeImageWithTableAlias() throws SQLException { + Assertions.assertNotNull(updateExecutor.beforeImage()); + + String sql = "update table_update_executor_test t set t.name = 'WILL' where t.id = 1"; + List asts = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL); + MySQLUpdateRecognizer recognizer = new MySQLUpdateRecognizer(sql, asts.get(0)); + updateExecutor = new UpdateExecutor(statementProxy, (statement, args) -> null, recognizer); + String builtSql = updateExecutor.buildBeforeImageSQL(updateExecutor.getTableMeta(), new ArrayList<>()); + Assertions.assertTrue(builtSql.contains("t.updated")); + } + @Test public void testKeyword() throws SQLException { String sql = "update table_update_executor_test set `all` = '1234' where id = 1";