mirror of
https://gitee.com/mybatis-flex/mybatis-flex.git
synced 2025-12-07 00:58:24 +08:00
fix: toMany join性能优化
@RelationOneToMany和@RelationManyToMany的实现存在严重的性能问题。内存join算法的复杂度高达n^2 测试sql脚本init中设置编码格式避免中文乱码
This commit is contained in:
parent
83c3afe542
commit
c61ff5865c
@ -26,9 +26,13 @@ import java.util.*;
|
||||
class ToManyRelation<SelfEntity> extends AbstractRelation<SelfEntity> {
|
||||
|
||||
protected String mapKeyField;
|
||||
|
||||
protected FieldWrapper mapKeyFieldWrapper;
|
||||
|
||||
protected String orderBy;
|
||||
|
||||
protected long limit = 0;
|
||||
|
||||
protected String selfValueSplitBy;
|
||||
|
||||
|
||||
@ -37,12 +41,20 @@ class ToManyRelation<SelfEntity> extends AbstractRelation<SelfEntity> {
|
||||
String dataSource, Class<SelfEntity> selfEntityClass, Field relationField,
|
||||
String extraCondition, String[] selectColumns) {
|
||||
super(selfField, targetSchema, targetTable, targetField, valueField,
|
||||
joinTable, joinSelfColumn, joinTargetColumn,
|
||||
dataSource, selfEntityClass, relationField,
|
||||
extraCondition, selectColumns
|
||||
joinTable, joinSelfColumn, joinTargetColumn,
|
||||
dataSource, selfEntityClass, relationField,
|
||||
extraCondition, selectColumns
|
||||
);
|
||||
}
|
||||
|
||||
public static Class<? extends Map> getMapWrapType(Class<?> type) {
|
||||
if (ClassUtil.canInstance(type.getModifiers())) {
|
||||
return (Class<? extends Map>) type;
|
||||
}
|
||||
|
||||
return HashMap.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建查询目标对象的 QueryWrapper
|
||||
*
|
||||
@ -71,7 +83,6 @@ class ToManyRelation<SelfEntity> extends AbstractRelation<SelfEntity> {
|
||||
return super.buildQueryWrapper(targetValues);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void customizeQueryWrapper(QueryWrapper queryWrapper) {
|
||||
if (StringUtil.isNotBlank(orderBy)) {
|
||||
@ -86,67 +97,131 @@ class ToManyRelation<SelfEntity> extends AbstractRelation<SelfEntity> {
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public void join(List<SelfEntity> selfEntities, List<?> targetObjectList, List<Row> mappingRows) {
|
||||
selfEntities.forEach(selfEntity -> {
|
||||
|
||||
//目标表关联字段->目标表对象
|
||||
Map<String, List<Object>> leftFieldToRightTableMap = new HashMap<>(targetObjectList.size());
|
||||
for (Object targetObject : targetObjectList) {
|
||||
Object targetJoinFieldValue = targetFieldWrapper.get(targetObject);
|
||||
if (targetJoinFieldValue != null) {
|
||||
leftFieldToRightTableMap.computeIfAbsent(targetJoinFieldValue.toString(), k -> new ArrayList<>()).add(targetObject);
|
||||
}
|
||||
}
|
||||
|
||||
//通过中间表
|
||||
if (mappingRows != null) {
|
||||
//当使用中间表时,需要重新映射关联关系
|
||||
Map<String, List<Object>> temp = new HashMap<>(selfEntities.size());
|
||||
for (Row mappingRow : mappingRows) {
|
||||
Object midTableJoinSelfValue = mappingRow.getIgnoreCase(joinSelfColumn);
|
||||
if (midTableJoinSelfValue == null) {
|
||||
continue;
|
||||
}
|
||||
Object midTableJoinTargetValue = mappingRow.getIgnoreCase(joinTargetColumn);
|
||||
if (midTableJoinTargetValue == null) {
|
||||
continue;
|
||||
}
|
||||
List<Object> targetObjects = leftFieldToRightTableMap.get(midTableJoinTargetValue.toString());
|
||||
if (targetObjects == null) {
|
||||
continue;
|
||||
}
|
||||
temp.computeIfAbsent(midTableJoinSelfValue.toString(), k -> new ArrayList<>(targetObjects.size())).addAll(targetObjects);
|
||||
}
|
||||
leftFieldToRightTableMap = temp;
|
||||
}
|
||||
//关联集合的类型
|
||||
Class<?> fieldType = relationFieldWrapper.getFieldType();
|
||||
Class<?> wrapType;
|
||||
if (Map.class.isAssignableFrom(fieldType)) {
|
||||
wrapType = getMapWrapType(fieldType);
|
||||
} else {
|
||||
wrapType = MapperUtil.getCollectionWrapType(fieldType);
|
||||
}
|
||||
|
||||
for (SelfEntity selfEntity : selfEntities) {
|
||||
if (selfEntity == null) {
|
||||
continue;
|
||||
}
|
||||
Object selfValue = selfFieldWrapper.get(selfEntity);
|
||||
if (selfValue != null) {
|
||||
selfValue = selfValue.toString();
|
||||
Set<String> targetMappingValues = new HashSet<>();
|
||||
if (mappingRows != null) {
|
||||
for (Row mappingRow : mappingRows) {
|
||||
if (selfValue.equals(String.valueOf(mappingRow.getIgnoreCase(joinSelfColumn)))) {
|
||||
Object joinValue = mappingRow.getIgnoreCase(joinTargetColumn);
|
||||
if (joinValue != null) {
|
||||
targetMappingValues.add(joinValue.toString());
|
||||
}
|
||||
if (selfValue == null) {
|
||||
continue;
|
||||
}
|
||||
selfValue = selfValue.toString();
|
||||
Set<String> targetMappingValues;//只有当splitBy不为空时才会有多个值
|
||||
boolean splitMode = StringUtil.isNotBlank(selfValueSplitBy);
|
||||
if (splitMode) {
|
||||
String[] splitValues = ((String) selfValue).split(selfValueSplitBy);
|
||||
targetMappingValues = new LinkedHashSet<>(Arrays.asList(splitValues));
|
||||
} else {
|
||||
targetMappingValues = new HashSet<>(1);
|
||||
targetMappingValues.add((String) selfValue);
|
||||
}
|
||||
|
||||
if (targetMappingValues.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//map
|
||||
if (Map.class.isAssignableFrom(fieldType)) {
|
||||
Map map = (Map) ClassUtil.newInstance(wrapType);
|
||||
Set<Object> validateCountSet = new HashSet<>(targetMappingValues.size());
|
||||
for (String targetMappingValue : targetMappingValues) {
|
||||
List<Object> targetObjects = leftFieldToRightTableMap.get(targetMappingValue);
|
||||
//如果非真实外键约束 可能没有对应的对象
|
||||
if (targetObjects == null) {
|
||||
continue;
|
||||
}
|
||||
for (Object targetObject : targetObjects) {
|
||||
Object keyValue = mapKeyFieldWrapper.get(targetObject);
|
||||
Object needKeyValue = ConvertUtil.convert(keyValue, relationFieldWrapper.getKeyType());
|
||||
if (validateCountSet.contains(needKeyValue) ) {
|
||||
//当字段类型为Map时,一个key对应的value只能有一个
|
||||
throw FlexExceptions.wrap("When fieldType is Map, the target entity can only be one,\n" +
|
||||
" current entity type is : " + selfEntity + "\n" +
|
||||
" relation field name is : " + relationField.getName() + "\n" +
|
||||
" target entity is : " + targetObjects);
|
||||
}
|
||||
validateCountSet.add(needKeyValue);
|
||||
map.put(needKeyValue, targetObject);
|
||||
}
|
||||
|
||||
}
|
||||
if (!map.isEmpty()) {
|
||||
relationFieldWrapper.set(map, selfEntity);
|
||||
}
|
||||
|
||||
}
|
||||
//集合
|
||||
else {
|
||||
Collection collection = (Collection) ClassUtil.newInstance(wrapType);
|
||||
if (onlyQueryValueField) {
|
||||
Object first = targetObjectList.iterator().next();
|
||||
//将getter方法用单独的变量存储 FieldWrapper.of虽然有缓存 但每次调用至少有一个HashMap的get开销
|
||||
FieldWrapper fieldValueFieldWrapper = FieldWrapper.of(first.getClass(), valueField);
|
||||
for (String targetMappingValue : targetMappingValues) {
|
||||
List<Object> targetObjects = leftFieldToRightTableMap.get(targetMappingValue);
|
||||
if (targetObjects == null) {
|
||||
continue;
|
||||
}
|
||||
for (Object targetObject : targetObjects) {
|
||||
//仅绑定某个字段
|
||||
collection.add(fieldValueFieldWrapper.get(targetObject));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (StringUtil.isNotBlank(selfValueSplitBy)) {
|
||||
String[] splitValues = ((String) selfValue).split(selfValueSplitBy);
|
||||
targetMappingValues.addAll(Arrays.asList(splitValues));
|
||||
} else {
|
||||
targetMappingValues.add((String) selfValue);
|
||||
}
|
||||
}
|
||||
|
||||
if (targetMappingValues.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Class<?> fieldType = relationFieldWrapper.getFieldType();
|
||||
//map
|
||||
if (Map.class.isAssignableFrom(fieldType)) {
|
||||
Class<?> wrapType = getMapWrapType(fieldType);
|
||||
Map map = (Map) ClassUtil.newInstance(wrapType);
|
||||
for (Object targetObject : targetObjectList) {
|
||||
Object targetValue = targetFieldWrapper.get(targetObject);
|
||||
if (targetValue != null && targetMappingValues.contains(targetValue.toString())) {
|
||||
Object keyValue = mapKeyFieldWrapper.get(targetObject);
|
||||
Object needKeyValue = ConvertUtil.convert(keyValue, relationFieldWrapper.getKeyType());
|
||||
map.put(needKeyValue, targetObject);
|
||||
for (String targetMappingValue : targetMappingValues) {
|
||||
List<Object> targetObjects = leftFieldToRightTableMap.get(targetMappingValue);
|
||||
if (targetObjects == null) {
|
||||
continue;
|
||||
}
|
||||
collection.addAll(targetObjects);
|
||||
}
|
||||
relationFieldWrapper.set(map, selfEntity);
|
||||
}
|
||||
//集合
|
||||
else {
|
||||
Class<?> wrapType = MapperUtil.getCollectionWrapType(fieldType);
|
||||
Collection collection = (Collection) ClassUtil.newInstance(wrapType);
|
||||
for (Object targetObject : targetObjectList) {
|
||||
Object targetValue = targetFieldWrapper.get(targetObject);
|
||||
if (targetValue != null && targetMappingValues.contains(targetValue.toString())) {
|
||||
if (onlyQueryValueField) {
|
||||
//仅绑定某个字段
|
||||
collection.add(FieldWrapper.of(targetObject.getClass(), valueField).get(targetObject));
|
||||
} else {
|
||||
collection.add(targetObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
relationFieldWrapper.set(collection, selfEntity);
|
||||
}
|
||||
relationFieldWrapper.set(collection, selfEntity);
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setMapKeyField(String mapKeyField) {
|
||||
@ -160,12 +235,4 @@ class ToManyRelation<SelfEntity> extends AbstractRelation<SelfEntity> {
|
||||
}
|
||||
}
|
||||
|
||||
public static Class<? extends Map> getMapWrapType(Class<?> type) {
|
||||
if (ClassUtil.canInstance(type.getModifiers())) {
|
||||
return (Class<? extends Map>) type;
|
||||
}
|
||||
|
||||
return HashMap.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ public class ArticleTester {
|
||||
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
.addScript("schema.sql")
|
||||
.addScript("data.sql")
|
||||
.addScript("data.sql").setScriptEncoding("UTF-8")
|
||||
.build();
|
||||
|
||||
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
||||
|
||||
@ -43,7 +43,7 @@ public class BatchTester {
|
||||
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
.addScript("schema.sql")
|
||||
.addScript("data.sql")
|
||||
.addScript("data.sql").setScriptEncoding("UTF-8")
|
||||
.build();
|
||||
|
||||
MybatisFlexBootstrap.getInstance()
|
||||
|
||||
@ -38,7 +38,7 @@ public class CursorTestStarter {
|
||||
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
.addScript("schema.sql")
|
||||
.addScript("data.sql")
|
||||
.addScript("data.sql").setScriptEncoding("UTF-8")
|
||||
.build();
|
||||
|
||||
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
||||
|
||||
@ -49,7 +49,7 @@ public class DbTest {
|
||||
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
.addScript("schema.sql")
|
||||
.addScript("data.sql")
|
||||
.addScript("data.sql").setScriptEncoding("UTF-8")
|
||||
.build();
|
||||
|
||||
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
||||
|
||||
@ -48,7 +48,7 @@ public class DbTest273 {
|
||||
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
.addScript("schema_273.sql")
|
||||
.addScript("data273.sql")
|
||||
.addScript("data273.sql").setScriptEncoding("UTF-8")
|
||||
.build();
|
||||
|
||||
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
||||
|
||||
@ -29,7 +29,7 @@ public class DbTestStarter {
|
||||
public static void main(String[] args) {
|
||||
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
.addScript("schema.sql")
|
||||
.addScript("schema.sql").setScriptEncoding("UTF-8")
|
||||
// .addScript("data.sql")
|
||||
.build();
|
||||
|
||||
|
||||
@ -40,7 +40,7 @@ public class EntityTestStarter {
|
||||
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
.addScript("schema.sql")
|
||||
.addScript("data.sql")
|
||||
.addScript("data.sql").setScriptEncoding("UTF-8")
|
||||
.build();
|
||||
|
||||
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
||||
|
||||
@ -32,7 +32,7 @@ public class InsertWithPkTestStarter {
|
||||
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
.addScript("schema.sql")
|
||||
.addScript("data.sql")
|
||||
.addScript("data.sql").setScriptEncoding("UTF-8")
|
||||
.build();
|
||||
|
||||
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
||||
|
||||
@ -32,7 +32,7 @@ public class JoinTestStarter {
|
||||
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
.addScript("schema.sql")
|
||||
.addScript("data.sql")
|
||||
.addScript("data.sql").setScriptEncoding("UTF-8")
|
||||
.build();
|
||||
|
||||
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
||||
|
||||
@ -33,7 +33,7 @@ public class JoinTester {
|
||||
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
.addScript("schema.sql")
|
||||
.addScript("data.sql")
|
||||
.addScript("data.sql").setScriptEncoding("UTF-8")
|
||||
.build();
|
||||
|
||||
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
||||
|
||||
@ -41,7 +41,7 @@ public class JoinWithDeleteColumnTestStarter {
|
||||
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
.addScript("schema.sql")
|
||||
.addScript("data.sql")
|
||||
.addScript("data.sql").setScriptEncoding("UTF-8")
|
||||
.build();
|
||||
|
||||
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
||||
|
||||
@ -33,7 +33,7 @@ public class MapperProxyCacheTestStarter {
|
||||
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
.addScript("schema.sql")
|
||||
.addScript("data.sql")
|
||||
.addScript("data.sql").setScriptEncoding("UTF-8")
|
||||
.build();
|
||||
|
||||
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
||||
|
||||
@ -30,7 +30,7 @@ public class MaskManagerTest {
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
.setName("db1")
|
||||
.addScript("schema.sql")
|
||||
.addScript("data.sql")
|
||||
.addScript("data.sql").setScriptEncoding("UTF-8")
|
||||
.build();
|
||||
|
||||
MybatisFlexBootstrap.getInstance()
|
||||
|
||||
@ -38,7 +38,7 @@ public class MultiDataSourceTester {
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
.setName("db1")
|
||||
.addScript("schema.sql")
|
||||
.addScript("data.sql")
|
||||
.addScript("data.sql").setScriptEncoding("UTF-8")
|
||||
.build();
|
||||
|
||||
HikariDataSource dataSource2 = new HikariDataSource();
|
||||
|
||||
@ -28,6 +28,7 @@ public class MultiThreadsTest {
|
||||
.setName("db1")
|
||||
.addScript("schema.sql")
|
||||
.addScript("data.sql")
|
||||
.setScriptEncoding("UTF-8")
|
||||
.build();
|
||||
|
||||
HikariDataSource dataSource2 = new HikariDataSource();
|
||||
|
||||
@ -36,7 +36,7 @@ public class UpdateWrapperTest {
|
||||
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
.addScript("schema.sql")
|
||||
.addScript("data.sql")
|
||||
.addScript("data.sql").setScriptEncoding("UTF-8")
|
||||
.build();
|
||||
|
||||
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
||||
|
||||
@ -42,7 +42,7 @@ public class Account6Test implements WithAssertions {
|
||||
this.dataSource = new EmbeddedDatabaseBuilder()
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
.addScript("none_key_schema.sql")
|
||||
.addScript("none_key_data.sql")
|
||||
.addScript("none_key_data.sql").setScriptEncoding("UTF-8")
|
||||
.build();
|
||||
|
||||
MybatisFlexBootstrap bootstrap = new MybatisFlexBootstrap()
|
||||
|
||||
@ -44,7 +44,7 @@ public class Account7Test implements WithAssertions {
|
||||
this.dataSource = new EmbeddedDatabaseBuilder()
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
.addScript("generate_key_schema.sql")
|
||||
.addScript("generate_key_data.sql")
|
||||
.addScript("generate_key_data.sql").setScriptEncoding("UTF-8")
|
||||
.build();
|
||||
|
||||
MybatisFlexBootstrap bootstrap = new MybatisFlexBootstrap()
|
||||
|
||||
@ -48,7 +48,7 @@ public class AccountInsertWithArrayAttrTest implements WithAssertions {
|
||||
this.dataSource = new EmbeddedDatabaseBuilder()
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
.addScript("schema05.sql")
|
||||
.addScript("data05.sql")
|
||||
.addScript("data05.sql").setScriptEncoding("UTF-8")
|
||||
.build();
|
||||
|
||||
MybatisFlexBootstrap bootstrap = new MybatisFlexBootstrap()
|
||||
|
||||
@ -67,7 +67,7 @@ public class AccountNativeTest implements WithAssertions {
|
||||
this.dataSource = new EmbeddedDatabaseBuilder()
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
.addScript("auto_increment_key_schema.sql")
|
||||
.addScript("auto_increment_key_data.sql")
|
||||
.addScript("auto_increment_key_data.sql").setScriptEncoding("UTF-8")
|
||||
.build();
|
||||
|
||||
MybatisFlexBootstrap bootstrap = new MybatisFlexBootstrap()
|
||||
|
||||
@ -59,7 +59,7 @@ public class DbChainTest implements WithAssertions {
|
||||
this.database = new EmbeddedDatabaseBuilder()
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
.addScript("auto_increment_key_schema.sql")
|
||||
.addScript("auto_increment_key_data.sql")
|
||||
.addScript("auto_increment_key_data.sql").setScriptEncoding("UTF-8")
|
||||
.build();
|
||||
|
||||
// Environment environment = new Environment(ENVIRONMENT_ID, new JdbcTransactionFactory(), this.database);
|
||||
|
||||
@ -47,7 +47,7 @@ public class ListenerTest implements WithAssertions {
|
||||
public void init() {
|
||||
dataSource = new EmbeddedDatabaseBuilder()
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
.addScript("auto_increment_key_schema.sql")
|
||||
.addScript("auto_increment_key_schema.sql").setScriptEncoding("UTF-8")
|
||||
.build();
|
||||
// 注册全局监听器
|
||||
FlexGlobalConfig defaultConfig = FlexGlobalConfig.getDefaultConfig();
|
||||
|
||||
@ -70,7 +70,7 @@ public class RelationsTest implements WithAssertions {
|
||||
dataSource = new EmbeddedDatabaseBuilder()
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
.addScript("relation/onetoone/schema.sql")
|
||||
.addScript("relation/onetoone/data.sql")
|
||||
.addScript("relation/onetoone/data.sql").setScriptEncoding("UTF-8")
|
||||
.build();
|
||||
|
||||
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
||||
|
||||
@ -57,6 +57,7 @@ public class RowTest implements WithAssertions {
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
.addScript("schema_row.sql")
|
||||
.addScript("data_row.sql")
|
||||
.setScriptEncoding("UTF-8")
|
||||
.build();
|
||||
|
||||
new MybatisFlexBootstrap().setDataSource(DATA_SOURCE_KEY, dataSource)
|
||||
|
||||
@ -42,11 +42,12 @@ import static com.mybatisflex.test.table.ArticleTableDef.ARTICLE;
|
||||
|
||||
public class UpdateChainTest implements WithAssertions {
|
||||
|
||||
private AccountMapper accountMapper;
|
||||
private EmbeddedDatabase dataSource;
|
||||
|
||||
private static final String DATA_SOURCE_KEY = "ds2";
|
||||
|
||||
private AccountMapper accountMapper;
|
||||
|
||||
private EmbeddedDatabase dataSource;
|
||||
|
||||
@BeforeClass
|
||||
public static void enableAudit() {
|
||||
AuditManager.setAuditEnable(true);
|
||||
@ -56,16 +57,17 @@ public class UpdateChainTest implements WithAssertions {
|
||||
@Before
|
||||
public void init() {
|
||||
this.dataSource = new EmbeddedDatabaseBuilder()
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
.addScript("schema.sql")
|
||||
.addScript("data.sql")
|
||||
.build();
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
.addScript("schema.sql")
|
||||
.addScript("data.sql")
|
||||
.setScriptEncoding("UTF-8")
|
||||
.build();
|
||||
|
||||
MybatisFlexBootstrap bootstrap = new MybatisFlexBootstrap()
|
||||
.setDataSource(DATA_SOURCE_KEY, this.dataSource)
|
||||
.setLogImpl(StdOutImpl.class)
|
||||
.addMapper(AccountMapper.class)
|
||||
.start();
|
||||
.setDataSource(DATA_SOURCE_KEY, this.dataSource)
|
||||
.setLogImpl(StdOutImpl.class)
|
||||
.addMapper(AccountMapper.class)
|
||||
.start();
|
||||
|
||||
DataSourceKey.use(DATA_SOURCE_KEY);
|
||||
accountMapper = bootstrap.getMapper(AccountMapper.class);
|
||||
@ -81,53 +83,53 @@ public class UpdateChainTest implements WithAssertions {
|
||||
@SneakyThrows
|
||||
public void testUpdateChain() {
|
||||
UpdateChain.of(Account.class)
|
||||
.set(Account::getUserName, "张三")
|
||||
.setRaw(Account::getAge, "age + 1")
|
||||
.where(Account::getId).eq(1)
|
||||
.update();
|
||||
.set(Account::getUserName, "张三")
|
||||
.setRaw(Account::getAge, "age + 1")
|
||||
.where(Account::getId).eq(1)
|
||||
.update();
|
||||
|
||||
Account account = accountMapper.selectOneById(1);
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
|
||||
String toParse = "2020-01-11";
|
||||
assertThat(account).isNotNull()
|
||||
.extracting(
|
||||
Account::getUserName, Account::getAge,
|
||||
Account::getSex, Account::getBirthday,
|
||||
Account::getOptions, Account::getDelete,
|
||||
Account::getArticles, Account::getTitle)
|
||||
.containsExactly(
|
||||
"张*", 19,
|
||||
SexEnum.TYPE1, format.parse(toParse),
|
||||
Collections.singletonMap("key", "value1"), false,
|
||||
Collections.emptyList(), null);
|
||||
.extracting(
|
||||
Account::getUserName, Account::getAge,
|
||||
Account::getSex, Account::getBirthday,
|
||||
Account::getOptions, Account::getDelete,
|
||||
Account::getArticles, Account::getTitle)
|
||||
.containsExactly(
|
||||
"张*", 19,
|
||||
SexEnum.TYPE1, format.parse(toParse),
|
||||
Collections.singletonMap("key", "value1"), false,
|
||||
Collections.emptyList(), null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChain1() {
|
||||
UpdateChain.of(Account.class)
|
||||
.set(Account::getAge, ACCOUNT.AGE.add(1))
|
||||
.where(Account::getId).ge(100)
|
||||
.and(Account::getAge).eq(18)
|
||||
.update();
|
||||
.set(Account::getAge, ACCOUNT.AGE.add(1))
|
||||
.where(Account::getId).ge(100)
|
||||
.and(Account::getAge).eq(18)
|
||||
.update();
|
||||
|
||||
List<Account> list = QueryChain.of(accountMapper).list();
|
||||
assertThat(list).hasSize(2)
|
||||
.extracting(Account::getId, Account::getUserName, Account::getAge)
|
||||
.containsExactly(tuple(1L, "张*", 18), tuple(2L, "王麻**叔", 19));
|
||||
.extracting(Account::getId, Account::getUserName, Account::getAge)
|
||||
.containsExactly(tuple(1L, "张*", 18), tuple(2L, "王麻**叔", 19));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChainToSql() {
|
||||
String sql = UpdateChain.of(Account.class)
|
||||
.set(ACCOUNT.AGE, 18)
|
||||
.set(Article::getAccountId, 4)
|
||||
.leftJoin(ARTICLE).as("ar").on(ACCOUNT.ID.eq(ARTICLE.ACCOUNT_ID))
|
||||
.where(ACCOUNT.ID.eq(4))
|
||||
.toSQL();
|
||||
.set(ACCOUNT.AGE, 18)
|
||||
.set(Article::getAccountId, 4)
|
||||
.leftJoin(ARTICLE).as("ar").on(ACCOUNT.ID.eq(ARTICLE.ACCOUNT_ID))
|
||||
.where(ACCOUNT.ID.eq(4))
|
||||
.toSQL();
|
||||
|
||||
String expectSQL = "UPDATE `tb_account` " +
|
||||
"LEFT JOIN `tb_article` AS `ar` ON `tb_account`.`id` = `ar`.`account_id` " +
|
||||
"SET `age` = 18 , `accountId` = 4 WHERE `id` = 4";
|
||||
"LEFT JOIN `tb_article` AS `ar` ON `tb_account`.`id` = `ar`.`account_id` " +
|
||||
"SET `age` = 18 , `accountId` = 4 WHERE `id` = 4";
|
||||
|
||||
assertThat(sql).isEqualTo(expectSQL);
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ public class AppConfig implements ApplicationListener<ContextRefreshedEvent> {
|
||||
return new EmbeddedDatabaseBuilder()
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
.addScript("schema.sql")
|
||||
.addScript("data.sql")
|
||||
.addScript("data.sql").setScriptEncoding("UTF-8")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user