-
Notifications
You must be signed in to change notification settings - Fork 8.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feature: support multi pk for mysql #2398
Conversation
…1.1.0 # Conflicts: # pom.xml
Codecov Report
@@ Coverage Diff @@
## develop #2398 +/- ##
=============================================
+ Coverage 51.06% 51.25% +0.18%
- Complexity 2812 2859 +47
=============================================
Files 557 557
Lines 17825 18017 +192
Branches 2105 2144 +39
=============================================
+ Hits 9103 9234 +131
- Misses 7858 7907 +49
- Partials 864 876 +12 |
Please fix the conflict. |
Ok, I will resolve the conflict this week. |
…1.3.0 # Conflicts: # rm-datasource/src/main/java/io/seata/rm/datasource/AbstractConnectionProxy.java # rm-datasource/src/main/java/io/seata/rm/datasource/exec/InsertExecutor.java # rm-datasource/src/test/java/io/seata/rm/datasource/exec/InsertExecutorTest.java
…1.1.0 # Conflicts: # rm-datasource/src/main/java/io/seata/rm/datasource/exec/MultiUpdateExecutor.java # rm-datasource/src/main/java/io/seata/rm/datasource/exec/UpdateExecutor.java
@l81893521 The conflict has been resolved. |
.collect(Collectors.toList()); | ||
String whereSql = buildWhereConditionByPKs(pkNameList,keywordChecker); | ||
|
||
return String.format(UPDATE_SQL_TEMPLATE, keywordChecker.checkAndReplace(sqlUndoLog.getTableName()),updateColumns, whereSql); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sqlUndoLog.getTableName() always has escape.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
.stream().map(e -> e.getName()) | ||
.collect(Collectors.toList()); | ||
String whereSql = buildWhereConditionByPKs(pkNameList,keywordChecker); | ||
return String.format(DELETE_SQL_TEMPLATE,keywordChecker.checkAndReplace(sqlUndoLog.getTableName()), whereSql); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sqlUndoLog.getTableName() always has escape.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
.collect(Collectors.toList()); | ||
String whereSql = buildWhereConditionByPKs(pkNameList,keywordChecker); | ||
|
||
return String.format(UPDATE_SQL_TEMPLATE, keywordChecker.checkAndReplace(sqlUndoLog.getTableName()),updateColumns, whereSql); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sqlUndoLog.getTableName() always has escape.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
whereConditionAppender.add("?"); | ||
protected String buildWhereConditionByPKs(List<Map<String,Field>> pkRows) throws SQLException { | ||
StringBuilder sql = new StringBuilder(); | ||
List<String> pkColumnNameList = getTableMeta().getPrimaryKeyOnlyName(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as another buildWhereConditionByPKs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
for (int i = 0;i < pkColumnNameList.size();i++) | ||
{ | ||
if (i > 0) | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as another buildWhereConditionByPKs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
Field field = row.getFields().get(j); | ||
if (field.getName().equalsIgnoreCase(primaryKey)) { | ||
rowKey = String.valueOf(field.getValue()); | ||
String rowKey = new String(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
StringUtils.empty
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
…multi-pk_based_on_1.1.0
…multi-pk_based_on_1.1.0
fix comments
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, Test case:
MYSQL
//insert
insert into account_tbl(user_id, money, information, create_time) values (?, ?, ?, now())
insert into account_tbl(USER_ID, money, information, create_time) values (?, ?, ?, now())
insert into account_tbl(create_time, money, information, user_id) values (now(), ?, ?, ?)
insert into account_tbl(id, user_id, money, information) values (?, ?, ?, ?)
insert into account_tbl(id, user_id, money, information) values (null, ?, ?, ?)
//insert multi pk
insert into account_tbl_multi_pk(user_id, sex, money) values (?, ?, ?)
insert into account_tbl_multi_pk(USER_ID, sex, money) values (?, ?, ?)
//update
update account_tbl set money = money - ?, sex = 1 where user_id = ?
//update multi pk
update account_tbl_multi_pk set money = money - ?, sex = 1 where user_id = ? or user_id = ?
//delete
delete from account_tbl where user_id = ?
//delete multi pk
delete from account_tbl_multi_pk where user_id = ?
//select
select * from account_tbl where id = ? for update
//select multi pk
select * from account_tbl_multi_pk where id = ? for update
ORACLE
//insert
insert into account_tbl(id, user_id, money, information, description) values (1, ?, ?, ?, ?)
insert into account_tbl(id, user_id, money, information, description) values (?, ?, ?, ?, ?)
insert into account_tbl(id, user_id, money, information, description) values (account_tbl_seq.nextval, ?, ?, ?, ?)
//update
update account_tbl set money = money - ? where user_id = ?
//delete
delete from account_tbl where user_id = ?
//select
select * from account_tbl where id = ? for update
POSTGRE
//insert
insert into account_tbl(id, user_id, money) values (11, trim(both ?), ?)
insert into account_tbl(id, user_id, money) values (?, trim(both ?), ?)
insert into account_tbl(id, user_id, money) values (nextval('seq_account_tbl_id'), trim(both ?), ?)
insert into public.account_tbl(user_id, money, id) values (trim(both ?), ?, nextval('seq_account_tbl_id'))
insert into account_tbl(id, user_id, money) values (default, ?, ?)
//update
update account_tbl set money = money - ? where user_id = ?
//delete
delete from account_tbl where user_id = ?
//select
select * from account_tbl where id = ?
rm-datasource/src/main/java/io/seata/rm/datasource/exec/BaseInsertExecutor.java
Show resolved
Hide resolved
@@ -83,6 +85,10 @@ public T doExecute(Object... args) throws Throwable { | |||
* @throws Exception the exception | |||
*/ | |||
protected T executeAutoCommitFalse(Object[] args) throws Exception { | |||
if (!JdbcConstants.MYSQL.equalsIgnoreCase(getDbType()) && getTableMeta().getPrimaryKeyOnlyName().size() > 1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why only mysql?
rm-datasource/src/test/java/io/seata/rm/datasource/undo/h2/keyword/H2KeywordChecker.java
Show resolved
Hide resolved
@@ -83,7 +83,6 @@ | |||
<dependency> | |||
<groupId>com.google.guava</groupId> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove guava dependency, cause rm already add.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- single pk with DML for mysql is ok.
- multi-pk cases for mysql is ok.
jdbcTemplate.update("insert into tb_multi(KEY2,comment1) values('2','3')");
jdbcTemplate.update("update tb_multi set comment1='8' where key1 < 5 ");
jdbcTemplate.update("delete from tb_multi where key1 < 5 ");
CREATE TABLE IF NOT EXISTS tb_multi_1
(
key1
int(11) NOT NULL,
key2
VARCHAR(100) NOT NULL,
comment1
VARCHAR(40) NOT NULL,
PRIMARY KEY ( key1
,key2
)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
composite primary key.
CREATE TABLE `test_multi_pk` (
`id1` int(11) NOT NULL AUTO_INCREMENT,
`id2` int(255) NOT NULL,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id1`,`id2`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;
insert into test_multi_pk(id1, id2, name) values(?, ?, ?)
insert into test_multi_pk(id1, id2, name) values(1, 1, 'xx')
insert into test_multi_pk(id1, id2, name) values(null, 1, ?)
insert into test_multi_pk(id1, id2, name) values(null, FLOOR(RAND() * 10000), ?) not support is right.
insert into test_multi_pk(id1, id2, name) values(null, 1, ?), (null, 2, ?)
oracle single pk:
insert into test1(id, name) values(test1_seq.nextval, ?)
insert into test1(id, name) values(10000, ?)
insert into test1(id, name) values(floor(dbms_random.value(900,1000)), ?)
insert into test1(id, name) values(test1_seq.nextval, 'xx')
insert into test1(id, name) values(10002, 'xx')
insert into test1(id, name) values(floor(dbms_random.value(900,1000)), 'xx') not support is right.
postgresql single pk:
insert into test1(id, name) values(nextval('test1_seq'), ?), (nextval('test1_seq'), ?)
insert into test1(id, name) values(10000, ?), (10001, ?)
insert into test1(id, name) values(floor(random()*1000), ?), (floor(random()*1000), ?)
insert into test1(id, name) values(default, ?), (default, ?)
insert into test1(id, name) values(nextval('test1_seq'), 'xx')
insert into test1(id, name) values(10002, 'xx'), (10003, 'xx1')
insert into test1(id, name) values(floor(random()*1000), 'xx') not support is right.
insert into test1(id, name) values(default, 'xx')
mysql single pk:
insert into test1(name2, name, id) values(?, 'xx', ?)
insert into test1(name2, name, id) values(?, 'xx', ?), (?, 'xx', ?)
insert into test1(id) values(?)
insert into test1(id) values(?), (?)
insert into test1(id, name) values(?, 'xx')
insert into test1(id, name) values(?, 'xx'), (?, 'xx')
insert into test1(name, id) values(?, ?)
insert into test1(name, id) values(?, ?), (?, ?)
insert into test1(id, name) values(1, ?), (2, ?)
insert into test1(name, id) values(?, 1), (?, 2)
insert into test1 values(1, ?, 'x2'), (2, ?, 'x2')
insert into test1 values(?, 'xx', 'xx2'), (?, 'xx', 'xx2')
LGTM, Tests Pass
Why does the feature support multi pk only for mysql? |
Sorry @sabersword , My company only uses MySQL. And I don't have time to support other databases. |
请签署Seata社区 cla https://cla-assistant.io/seata/seata 谢谢配合 |
Ⅰ. Describe what this PR did
pr content: To support multiple primary key.
It's a lot of work to support multiple primary keys for seata. Because this related to the base structure of seata.
I spend one month to do it. But It just works fine in mysql so far.
Because I don't have the time to compatible the seata with postgresql or oracle. And I‘m not good at PostgreSQL and oracle. I tried to compatible the seata with PostgreSQL and oracle, But I met some problems.
So I gave up.
It would be wonderful if someone can continue my work.
There are several bugs that I found when I implement this future. This fix is breaking changes.
1, Rollback will not work if update SQL changed the pk value. So I forbid the execution of this SQL.
2, We can't obtain the auto-increment value if the program run batch inserts SQL in the form of the statement. So I also forbid the execution of this SQL.
Ⅱ. Does this pull request fix one issue?
Ⅲ. Why don't you add test cases (unit test/integration test)?
Ⅳ. Describe how to verify it
Ⅴ. Special notes for reviews