This is an automated email from the ASF dual-hosted git repository.
jimin pushed a commit to branch 2.x
in repository https://gitbox.apache.org/repos/asf/incubator-seata.git
The following commit(s) were added to refs/heads/2.x by this push:
new 50879a40d7 bugfix: fix Byte[] type to ensure the correct primary key
value. (#7761)
50879a40d7 is described below
commit 50879a40d7eab0510533a00809c0b00956396fdc
Author: maple <[email protected]>
AuthorDate: Mon Nov 3 00:02:21 2025 +0800
bugfix: fix Byte[] type to ensure the correct primary key value. (#7761)
---
changes/en-us/2.x.md | 1 +
changes/zh-cn/2.x.md | 1 +
.../datasource/exec/BaseTransactionalExecutor.java | 8 +-
.../exec/BaseTransactionalExecutorTest.java | 102 +++++++++++++++++++++
4 files changed, 111 insertions(+), 1 deletion(-)
diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md
index 34a72ed01c..3eb083e537 100644
--- a/changes/en-us/2.x.md
+++ b/changes/en-us/2.x.md
@@ -49,6 +49,7 @@ Add changes here for all PR submitted to the 2.x branch.
- [[#7643](https://github.com/apache/incubator-seata/pull/7643)] fix DM
transaction rollback not using database auto-increment primary keys
- [[#7747](https://github.com/apache/incubator-seata/pull/7747)] undo log
table name dynamic derivation
- [[#7749](https://github.com/apache/incubator-seata/pull/7749)] fix error
parsing application/x-www-form-urlencoded requests in Http2HttpHandler
+- [[#7761](https://github.com/apache/incubator-seata/pull/7761)] special
handling is applied to the Byte[] type to ensure the correct primary key value
### optimize:
diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md
index b36e869049..ffd72bba25 100644
--- a/changes/zh-cn/2.x.md
+++ b/changes/zh-cn/2.x.md
@@ -49,6 +49,7 @@
- [[#7643](https://github.com/apache/incubator-seata/pull/7643)] 修复 DM
事务回滚不使用数据库自动增量主键
- [[#7747](https://github.com/apache/incubator-seata/pull/7747)]
支持undo_log序列名动态推导
- [[#7749](https://github.com/apache/incubator-seata/pull/7749)] 修复
Http2HttpHandler 解析 application/x-www-form-urlencoded 请求失败的问题
+- [[#7761](https://github.com/apache/incubator-seata/pull/7761)] 对 Byte[]
类型进行了特殊处理,以确保主键值正确
### optimize:
diff --git
a/rm-datasource/src/main/java/org/apache/seata/rm/datasource/exec/BaseTransactionalExecutor.java
b/rm-datasource/src/main/java/org/apache/seata/rm/datasource/exec/BaseTransactionalExecutor.java
index 330ef46ad6..47e7644760 100644
---
a/rm-datasource/src/main/java/org/apache/seata/rm/datasource/exec/BaseTransactionalExecutor.java
+++
b/rm-datasource/src/main/java/org/apache/seata/rm/datasource/exec/BaseTransactionalExecutor.java
@@ -18,6 +18,7 @@ package org.apache.seata.rm.datasource.exec;
import org.apache.seata.common.DefaultValues;
import org.apache.seata.common.exception.ShouldNeverHappenException;
+import org.apache.seata.common.util.ArrayUtils;
import org.apache.seata.common.util.CollectionUtils;
import org.apache.seata.common.util.IOUtil;
import org.apache.seata.common.util.StringUtils;
@@ -457,7 +458,12 @@ public abstract class BaseTransactionalExecutor<T, S
extends Statement> implemen
}
Object pkVal = rowMap.get(pkName).getValue();
validPk(String.valueOf(pkVal));
- sb.append(pkVal);
+ // Handle byte[] primary keys properly to avoid using memory
address as lock key
+ if (pkVal instanceof byte[]) {
+ sb.append(ArrayUtils.toString(pkVal));
+ } else {
+ sb.append(pkVal);
+ }
pkSplitIndex++;
}
rowSequence++;
diff --git
a/rm-datasource/src/test/java/org/apache/seata/rm/datasource/exec/BaseTransactionalExecutorTest.java
b/rm-datasource/src/test/java/org/apache/seata/rm/datasource/exec/BaseTransactionalExecutorTest.java
index 71c52c8926..209bee55f8 100644
---
a/rm-datasource/src/test/java/org/apache/seata/rm/datasource/exec/BaseTransactionalExecutorTest.java
+++
b/rm-datasource/src/test/java/org/apache/seata/rm/datasource/exec/BaseTransactionalExecutorTest.java
@@ -171,4 +171,106 @@ public class BaseTransactionalExecutorTest {
when(executor.getTableMeta()).thenReturn(tableMeta);
assertThat(executor.buildLockKey(tableRecords)).isEqualTo(buildLockKeyExpect);
}
+
+ @Test
+ public void testBuildLockKeyWithBinaryPrimaryKey() {
+ // Test binary (byte[]) primary key handling
+ String tableName = "test_binary_table";
+ byte[] binaryPkValue1 = new byte[] {1, 2, 3, 15, -1}; // -1 represents
0xFF in signed byte
+ byte[] binaryPkValue2 = new byte[] {10, 20, 30};
+ String pkColumnName = "binary_id";
+
+ // Expected: test_binary_table:[1, 2, 3, 15, -1],[10, 20, 30]
+ // Using ArrayUtils.toString() format instead of memory address like
[B@1b57bff9]
+ // Note: byte is signed in Java, so 0xFF (255) is represented as -1
+ String expectedLockKey = tableName + ":[1, 2, 3, 15, -1],[10, 20, 30]";
+
+ // Mock fields with byte[] values
+ Field binaryField1 = mock(Field.class);
+ when(binaryField1.getValue()).thenReturn(binaryPkValue1);
+ Field binaryField2 = mock(Field.class);
+ when(binaryField2.getValue()).thenReturn(binaryPkValue2);
+
+ List<Map<String, Field>> pkRows = new ArrayList<>();
+ pkRows.add(Collections.singletonMap(pkColumnName, binaryField1));
+ pkRows.add(Collections.singletonMap(pkColumnName, binaryField2));
+
+ // Mock tableMeta
+ TableMeta tableMeta = mock(TableMeta.class);
+ when(tableMeta.getTableName()).thenReturn(tableName);
+ when(tableMeta.getPrimaryKeyOnlyName()).thenReturn(Arrays.asList(new
String[] {pkColumnName}));
+
+ // Mock tableRecords
+ TableRecords tableRecords = mock(TableRecords.class);
+ when(tableRecords.getTableMeta()).thenReturn(tableMeta);
+ when(tableRecords.size()).thenReturn(pkRows.size());
+ when(tableRecords.pkRows()).thenReturn(pkRows);
+
+ // Mock executor
+ BaseTransactionalExecutor executor =
mock(BaseTransactionalExecutor.class);
+ when(executor.buildLockKey(tableRecords)).thenCallRealMethod();
+ when(executor.getTableMeta()).thenReturn(tableMeta);
+
+ String actualLockKey = executor.buildLockKey(tableRecords);
+
+ // Verify that byte[] is properly converted to readable format
+ assertThat(actualLockKey).isEqualTo(expectedLockKey);
+ // Ensure it's not using memory address format
+ assertThat(actualLockKey).doesNotContain("[B@]");
+ assertThat(actualLockKey).contains("[1, 2, 3, 15, -1]");
+ assertThat(actualLockKey).contains("[10, 20, 30]");
+ }
+
+ @Test
+ public void testBuildLockKeyWithMixedPrimaryKeys() {
+ // Test mixed primary keys: one regular string and one binary
+ String tableName = "test_mixed_table";
+ String stringPkValue = "user123";
+ byte[] binaryPkValue = new byte[] {16, 32, 48, 64};
+ String stringPkColumnName = "user_id";
+ String binaryPkColumnName = "session_id";
+
+ // Expected: test_mixed_table:user123_[16, 32, 48, 64]
+ String expectedLockKey = tableName + ":user123_[16, 32, 48, 64]";
+
+ // Mock fields
+ Field stringField = mock(Field.class);
+ when(stringField.getValue()).thenReturn(stringPkValue);
+ Field binaryField = mock(Field.class);
+ when(binaryField.getValue()).thenReturn(binaryPkValue);
+
+ List<Map<String, Field>> pkRows = new ArrayList<>();
+ Map<String, Field> row = new HashMap<String, Field>() {
+ {
+ put(stringPkColumnName, stringField);
+ put(binaryPkColumnName, binaryField);
+ }
+ };
+ pkRows.add(row);
+
+ // Mock tableMeta
+ TableMeta tableMeta = mock(TableMeta.class);
+ when(tableMeta.getTableName()).thenReturn(tableName);
+ when(tableMeta.getPrimaryKeyOnlyName())
+ .thenReturn(Arrays.asList(new String[] {stringPkColumnName,
binaryPkColumnName}));
+
+ // Mock tableRecords
+ TableRecords tableRecords = mock(TableRecords.class);
+ when(tableRecords.getTableMeta()).thenReturn(tableMeta);
+ when(tableRecords.size()).thenReturn(pkRows.size());
+ when(tableRecords.pkRows()).thenReturn(pkRows);
+
+ // Mock executor
+ BaseTransactionalExecutor executor =
mock(BaseTransactionalExecutor.class);
+ when(executor.buildLockKey(tableRecords)).thenCallRealMethod();
+ when(executor.getTableMeta()).thenReturn(tableMeta);
+
+ String actualLockKey = executor.buildLockKey(tableRecords);
+
+ // Verify mixed types are handled correctly
+ assertThat(actualLockKey).isEqualTo(expectedLockKey);
+ assertThat(actualLockKey).doesNotContain("[B@]");
+ assertThat(actualLockKey).contains("user123");
+ assertThat(actualLockKey).contains("[16, 32, 48, 64]");
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]