Skip to content

Commit d5b7fc0

Browse files
committed
refactor: 优化upsert去重逻辑
1 parent 854eecd commit d5b7fc0

File tree

3 files changed

+56
-18
lines changed

3 files changed

+56
-18
lines changed

hsweb-easy-orm-rdb/src/main/java/org/hswebframework/ezorm/rdb/operator/builder/fragments/insert/BatchInsertSqlBuilder.java

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.hswebframework.ezorm.rdb.operator.builder.fragments.insert;
22

33
import com.google.common.collect.Maps;
4+
import com.google.common.collect.Sets;
45
import lombok.AllArgsConstructor;
56
import org.apache.commons.lang3.StringUtils;
67
import org.hswebframework.ezorm.core.RuntimeDefaultValue;
@@ -32,6 +33,10 @@ protected int computeSqlSize(int columnSize, int valueSize) {
3233
return (columnSize * valueSize) * 2 + valueSize * 2 + columnSize * 3 + 2;
3334
}
3435

36+
protected boolean isPrimaryKey(RDBColumnMetadata col) {
37+
return col.isPrimaryKey();
38+
}
39+
3540
@Override
3641
public SqlRequest build(InsertOperatorParameter parameter) {
3742
// PrepareSqlFragments fragments = beforeBuild(parameter, PrepareSqlFragments.of()).addSql("(");
@@ -52,7 +57,7 @@ public SqlRequest build(InsertOperatorParameter parameter) {
5257
LinkedHashMap<Integer, SqlFragments> functionValues = Maps.newLinkedHashMapWithExpectedSize(columns.size());
5358

5459
int index = 0;
55-
int primaryIndex = -1;
60+
List<Integer> primaryIndex = new ArrayList<>(1);
5661

5762
//如果只有一条数据则忽略null的列
5863
boolean ignoreNullColumn = parameter.getValues().size() == 1;
@@ -62,8 +67,8 @@ public SqlRequest build(InsertOperatorParameter parameter) {
6267
.flatMap(table::getColumn)
6368
.orElse(null);
6469
if (columnMetadata != null && columnMetadata.isInsertable()) {
65-
if (columnMetadata.isPrimaryKey()) {
66-
primaryIndex = index;
70+
if (isPrimaryKey(columnMetadata)) {
71+
primaryIndex.add(index);
6772
}
6873
//忽略null的列
6974
if (ignoreNullColumn) {
@@ -100,14 +105,31 @@ public SqlRequest build(InsertOperatorParameter parameter) {
100105
// ) values
101106
fragments.add(VALUES);
102107
index = 0;
103-
Set<Object> duplicatePrimary = new HashSet<>(32);
108+
Set<Object> duplicatePrimary = new HashSet<>(8);
104109
for (List<Object> values : valueList) {
105-
if (primaryIndex >= 0) {
106-
//重复的id 则不进行处理
107-
if (values.size() > primaryIndex && !duplicatePrimary.add(values.get(primaryIndex))) {
110+
int indexSize = primaryIndex.size();
111+
int vSize = values.size();
112+
// id
113+
if (indexSize == 1) {
114+
int idx = primaryIndex.get(0);
115+
if (vSize > idx && !duplicatePrimary.add(values.get(idx))) {
116+
continue;
117+
}
118+
}
119+
// 唯一索引?
120+
else if (indexSize >= 1) {
121+
Set<Object> dis = Sets.newHashSetWithExpectedSize(indexSize);
122+
for (Integer i : primaryIndex) {
123+
if (vSize > i) {
124+
dis.add(values.get(i));
125+
}
126+
}
127+
// 存在重复数据 ?
128+
if(!duplicatePrimary.add(dis)){
108129
continue;
109130
}
110131
}
132+
111133
if (index++ != 0) {
112134
fragments.add(SqlFragments.COMMA);
113135
}

hsweb-easy-orm-rdb/src/main/java/org/hswebframework/ezorm/rdb/supports/postgres/PostgresqlBatchUpsertOperator.java

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,7 @@
1818
import org.hswebframework.ezorm.rdb.utils.ExceptionUtils;
1919
import reactor.core.publisher.Mono;
2020

21-
import java.util.ArrayList;
22-
import java.util.List;
23-
import java.util.Objects;
24-
import java.util.Set;
21+
import java.util.*;
2522
import java.util.function.Supplier;
2623
import java.util.stream.Collectors;
2724

@@ -36,6 +33,8 @@ public class PostgresqlBatchUpsertOperator implements SaveOrUpdateOperator {
3633

3734
private SaveOrUpdateOperator fallback;
3835

36+
private Set<String> primaryColumns;
37+
3938
public PostgresqlBatchUpsertOperator(RDBTableMetadata table) {
4039
this.table = table;
4140
this.fallback = new DefaultSaveOrUpdateOperator(table);
@@ -58,14 +57,18 @@ SqlFragments getOrCreateOnConflict() {
5857
}
5958

6059
SqlFragments createOnConflict() {
60+
if (primaryColumns == null) {
61+
primaryColumns = new HashSet<>();
62+
}
6163
RDBColumnMetadata idColumn = table
6264
.getColumns()
6365
.stream()
6466
.filter(RDBColumnMetadata::isPrimaryKey)
6567
.findFirst()
6668
.orElse(null);
6769
if (idColumn != null) {
68-
return SqlFragments.of("on conflict (", idColumn.getName(), ") do ");
70+
primaryColumns.add(idColumn.getName());
71+
return SqlFragments.of("on conflict (", idColumn.getQuoteName(), ") do ");
6972
}
7073
RDBIndexMetadata indexMetadata = table
7174
.getIndexes()
@@ -80,7 +83,10 @@ SqlFragments createOnConflict() {
8083
.stream()
8184
.map(c -> table.getColumn(c.getColumn()).orElse(null))
8285
.filter(Objects::nonNull)
83-
.map(RDBColumnMetadata::getQuoteName)
86+
.map(c -> {
87+
primaryColumns.add(c.getName());
88+
return c.getQuoteName();
89+
})
8490
.collect(Collectors.joining(","));
8591

8692
return SqlFragments.of("on conflict( ", columns, ") do ");
@@ -136,6 +142,15 @@ public PostgresqlUpsertBatchInsertSqlBuilder(RDBTableMetadata table) {
136142
super(table);
137143
}
138144

145+
@Override
146+
protected boolean isPrimaryKey(RDBColumnMetadata col) {
147+
getOrCreateOnConflict();
148+
if (primaryColumns != null && primaryColumns.contains(col.getName())) {
149+
return true;
150+
}
151+
return super.isPrimaryKey(col);
152+
}
153+
139154
@Override
140155
protected int computeSqlSize(int columnSize, int valueSize) {
141156
return super.computeSqlSize(columnSize, valueSize) + columnSize * 3 + 2;

hsweb-easy-orm-rdb/src/test/java/org/hswebframework/ezorm/rdb/supports/BasicReactiveTests.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,15 +138,15 @@ public void init() {
138138
.commit()
139139
.reactive()
140140
.block();
141-
table.<EntityColumnMapping>getFeatureNow(MappingFeatureType.columnPropertyMapping.createFeatureId(BasicTestEntity.class))
141+
table
142+
.<EntityColumnMapping>getFeatureNow(MappingFeatureType.columnPropertyMapping.createFeatureId(BasicTestEntity.class))
142143
.reload();
143144

144145
EntityResultWrapper<BasicTestEntity> wrapper = new EntityResultWrapper<>(BasicTestEntity::new);
145146
wrapper.setMapping(table
146147
.<EntityColumnMapping>getFeature(MappingFeatureType.columnPropertyMapping.createFeatureId(BasicTestEntity.class))
147148
.orElseThrow(NullPointerException::new));
148149

149-
150150
repository = new DefaultReactiveRepository<>(operator, table, BasicTestEntity.class, wrapper);
151151
addressRepository = operator.dml().createReactiveRepository("test_address");
152152

@@ -286,7 +286,7 @@ public void testInsertMerge() {
286286
repository
287287
.createQuery()
288288
.where(BasicTestEntity::getId, first.getId())
289-
.select("id", "name","ext_name")
289+
.select("id", "name", "ext_name")
290290
.fetch()
291291
.doOnNext(System.out::println)
292292
.map(BasicTestEntity::getName)
@@ -310,8 +310,9 @@ public void testInsertDuplicate() {
310310
.stateEnum(StateEnum.enabled)
311311
.enabled(true)
312312
.build())
313-
.collectList()
314-
.as(repository::insertBatch)
313+
// .collectList()
314+
.as(repository::save)
315+
.map(r -> r.getTotal())
315316
.as(StepVerifier::create)
316317
.expectNext(3)
317318
.verifyComplete();

0 commit comments

Comments
 (0)