mirror of
https://gitee.com/mybatis-flex/mybatis-flex.git
synced 2025-12-06 16:48: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> {
|
class ToManyRelation<SelfEntity> extends AbstractRelation<SelfEntity> {
|
||||||
|
|
||||||
protected String mapKeyField;
|
protected String mapKeyField;
|
||||||
|
|
||||||
protected FieldWrapper mapKeyFieldWrapper;
|
protected FieldWrapper mapKeyFieldWrapper;
|
||||||
|
|
||||||
protected String orderBy;
|
protected String orderBy;
|
||||||
|
|
||||||
protected long limit = 0;
|
protected long limit = 0;
|
||||||
|
|
||||||
protected String selfValueSplitBy;
|
protected String selfValueSplitBy;
|
||||||
|
|
||||||
|
|
||||||
@ -37,12 +41,20 @@ class ToManyRelation<SelfEntity> extends AbstractRelation<SelfEntity> {
|
|||||||
String dataSource, Class<SelfEntity> selfEntityClass, Field relationField,
|
String dataSource, Class<SelfEntity> selfEntityClass, Field relationField,
|
||||||
String extraCondition, String[] selectColumns) {
|
String extraCondition, String[] selectColumns) {
|
||||||
super(selfField, targetSchema, targetTable, targetField, valueField,
|
super(selfField, targetSchema, targetTable, targetField, valueField,
|
||||||
joinTable, joinSelfColumn, joinTargetColumn,
|
joinTable, joinSelfColumn, joinTargetColumn,
|
||||||
dataSource, selfEntityClass, relationField,
|
dataSource, selfEntityClass, relationField,
|
||||||
extraCondition, selectColumns
|
extraCondition, selectColumns
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Class<? extends Map> getMapWrapType(Class<?> type) {
|
||||||
|
if (ClassUtil.canInstance(type.getModifiers())) {
|
||||||
|
return (Class<? extends Map>) type;
|
||||||
|
}
|
||||||
|
|
||||||
|
return HashMap.class;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建查询目标对象的 QueryWrapper
|
* 构建查询目标对象的 QueryWrapper
|
||||||
*
|
*
|
||||||
@ -71,7 +83,6 @@ class ToManyRelation<SelfEntity> extends AbstractRelation<SelfEntity> {
|
|||||||
return super.buildQueryWrapper(targetValues);
|
return super.buildQueryWrapper(targetValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void customizeQueryWrapper(QueryWrapper queryWrapper) {
|
public void customizeQueryWrapper(QueryWrapper queryWrapper) {
|
||||||
if (StringUtil.isNotBlank(orderBy)) {
|
if (StringUtil.isNotBlank(orderBy)) {
|
||||||
@ -86,67 +97,131 @@ class ToManyRelation<SelfEntity> extends AbstractRelation<SelfEntity> {
|
|||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
@Override
|
@Override
|
||||||
public void join(List<SelfEntity> selfEntities, List<?> targetObjectList, List<Row> mappingRows) {
|
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);
|
Object selfValue = selfFieldWrapper.get(selfEntity);
|
||||||
if (selfValue != null) {
|
if (selfValue == null) {
|
||||||
selfValue = selfValue.toString();
|
continue;
|
||||||
Set<String> targetMappingValues = new HashSet<>();
|
}
|
||||||
if (mappingRows != null) {
|
selfValue = selfValue.toString();
|
||||||
for (Row mappingRow : mappingRows) {
|
Set<String> targetMappingValues;//只有当splitBy不为空时才会有多个值
|
||||||
if (selfValue.equals(String.valueOf(mappingRow.getIgnoreCase(joinSelfColumn)))) {
|
boolean splitMode = StringUtil.isNotBlank(selfValueSplitBy);
|
||||||
Object joinValue = mappingRow.getIgnoreCase(joinTargetColumn);
|
if (splitMode) {
|
||||||
if (joinValue != null) {
|
String[] splitValues = ((String) selfValue).split(selfValueSplitBy);
|
||||||
targetMappingValues.add(joinValue.toString());
|
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 {
|
} else {
|
||||||
if (StringUtil.isNotBlank(selfValueSplitBy)) {
|
for (String targetMappingValue : targetMappingValues) {
|
||||||
String[] splitValues = ((String) selfValue).split(selfValueSplitBy);
|
List<Object> targetObjects = leftFieldToRightTableMap.get(targetMappingValue);
|
||||||
targetMappingValues.addAll(Arrays.asList(splitValues));
|
if (targetObjects == null) {
|
||||||
} else {
|
continue;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
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) {
|
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()
|
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||||
.setType(EmbeddedDatabaseType.H2)
|
.setType(EmbeddedDatabaseType.H2)
|
||||||
.addScript("schema.sql")
|
.addScript("schema.sql")
|
||||||
.addScript("data.sql")
|
.addScript("data.sql").setScriptEncoding("UTF-8")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
||||||
|
|||||||
@ -43,7 +43,7 @@ public class BatchTester {
|
|||||||
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||||
.setType(EmbeddedDatabaseType.H2)
|
.setType(EmbeddedDatabaseType.H2)
|
||||||
.addScript("schema.sql")
|
.addScript("schema.sql")
|
||||||
.addScript("data.sql")
|
.addScript("data.sql").setScriptEncoding("UTF-8")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
MybatisFlexBootstrap.getInstance()
|
MybatisFlexBootstrap.getInstance()
|
||||||
|
|||||||
@ -38,7 +38,7 @@ public class CursorTestStarter {
|
|||||||
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||||
.setType(EmbeddedDatabaseType.H2)
|
.setType(EmbeddedDatabaseType.H2)
|
||||||
.addScript("schema.sql")
|
.addScript("schema.sql")
|
||||||
.addScript("data.sql")
|
.addScript("data.sql").setScriptEncoding("UTF-8")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
||||||
|
|||||||
@ -49,7 +49,7 @@ public class DbTest {
|
|||||||
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||||
.setType(EmbeddedDatabaseType.H2)
|
.setType(EmbeddedDatabaseType.H2)
|
||||||
.addScript("schema.sql")
|
.addScript("schema.sql")
|
||||||
.addScript("data.sql")
|
.addScript("data.sql").setScriptEncoding("UTF-8")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
||||||
|
|||||||
@ -48,7 +48,7 @@ public class DbTest273 {
|
|||||||
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||||
.setType(EmbeddedDatabaseType.H2)
|
.setType(EmbeddedDatabaseType.H2)
|
||||||
.addScript("schema_273.sql")
|
.addScript("schema_273.sql")
|
||||||
.addScript("data273.sql")
|
.addScript("data273.sql").setScriptEncoding("UTF-8")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
||||||
|
|||||||
@ -29,7 +29,7 @@ public class DbTestStarter {
|
|||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||||
.setType(EmbeddedDatabaseType.H2)
|
.setType(EmbeddedDatabaseType.H2)
|
||||||
.addScript("schema.sql")
|
.addScript("schema.sql").setScriptEncoding("UTF-8")
|
||||||
// .addScript("data.sql")
|
// .addScript("data.sql")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|||||||
@ -40,7 +40,7 @@ public class EntityTestStarter {
|
|||||||
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||||
.setType(EmbeddedDatabaseType.H2)
|
.setType(EmbeddedDatabaseType.H2)
|
||||||
.addScript("schema.sql")
|
.addScript("schema.sql")
|
||||||
.addScript("data.sql")
|
.addScript("data.sql").setScriptEncoding("UTF-8")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
||||||
|
|||||||
@ -32,7 +32,7 @@ public class InsertWithPkTestStarter {
|
|||||||
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||||
.setType(EmbeddedDatabaseType.H2)
|
.setType(EmbeddedDatabaseType.H2)
|
||||||
.addScript("schema.sql")
|
.addScript("schema.sql")
|
||||||
.addScript("data.sql")
|
.addScript("data.sql").setScriptEncoding("UTF-8")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
||||||
|
|||||||
@ -32,7 +32,7 @@ public class JoinTestStarter {
|
|||||||
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||||
.setType(EmbeddedDatabaseType.H2)
|
.setType(EmbeddedDatabaseType.H2)
|
||||||
.addScript("schema.sql")
|
.addScript("schema.sql")
|
||||||
.addScript("data.sql")
|
.addScript("data.sql").setScriptEncoding("UTF-8")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
||||||
|
|||||||
@ -33,7 +33,7 @@ public class JoinTester {
|
|||||||
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||||
.setType(EmbeddedDatabaseType.H2)
|
.setType(EmbeddedDatabaseType.H2)
|
||||||
.addScript("schema.sql")
|
.addScript("schema.sql")
|
||||||
.addScript("data.sql")
|
.addScript("data.sql").setScriptEncoding("UTF-8")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
||||||
|
|||||||
@ -41,7 +41,7 @@ public class JoinWithDeleteColumnTestStarter {
|
|||||||
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||||
.setType(EmbeddedDatabaseType.H2)
|
.setType(EmbeddedDatabaseType.H2)
|
||||||
.addScript("schema.sql")
|
.addScript("schema.sql")
|
||||||
.addScript("data.sql")
|
.addScript("data.sql").setScriptEncoding("UTF-8")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
||||||
|
|||||||
@ -33,7 +33,7 @@ public class MapperProxyCacheTestStarter {
|
|||||||
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||||
.setType(EmbeddedDatabaseType.H2)
|
.setType(EmbeddedDatabaseType.H2)
|
||||||
.addScript("schema.sql")
|
.addScript("schema.sql")
|
||||||
.addScript("data.sql")
|
.addScript("data.sql").setScriptEncoding("UTF-8")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
||||||
|
|||||||
@ -30,7 +30,7 @@ public class MaskManagerTest {
|
|||||||
.setType(EmbeddedDatabaseType.H2)
|
.setType(EmbeddedDatabaseType.H2)
|
||||||
.setName("db1")
|
.setName("db1")
|
||||||
.addScript("schema.sql")
|
.addScript("schema.sql")
|
||||||
.addScript("data.sql")
|
.addScript("data.sql").setScriptEncoding("UTF-8")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
MybatisFlexBootstrap.getInstance()
|
MybatisFlexBootstrap.getInstance()
|
||||||
|
|||||||
@ -38,7 +38,7 @@ public class MultiDataSourceTester {
|
|||||||
.setType(EmbeddedDatabaseType.H2)
|
.setType(EmbeddedDatabaseType.H2)
|
||||||
.setName("db1")
|
.setName("db1")
|
||||||
.addScript("schema.sql")
|
.addScript("schema.sql")
|
||||||
.addScript("data.sql")
|
.addScript("data.sql").setScriptEncoding("UTF-8")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
HikariDataSource dataSource2 = new HikariDataSource();
|
HikariDataSource dataSource2 = new HikariDataSource();
|
||||||
|
|||||||
@ -28,6 +28,7 @@ public class MultiThreadsTest {
|
|||||||
.setName("db1")
|
.setName("db1")
|
||||||
.addScript("schema.sql")
|
.addScript("schema.sql")
|
||||||
.addScript("data.sql")
|
.addScript("data.sql")
|
||||||
|
.setScriptEncoding("UTF-8")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
HikariDataSource dataSource2 = new HikariDataSource();
|
HikariDataSource dataSource2 = new HikariDataSource();
|
||||||
|
|||||||
@ -36,7 +36,7 @@ public class UpdateWrapperTest {
|
|||||||
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||||
.setType(EmbeddedDatabaseType.H2)
|
.setType(EmbeddedDatabaseType.H2)
|
||||||
.addScript("schema.sql")
|
.addScript("schema.sql")
|
||||||
.addScript("data.sql")
|
.addScript("data.sql").setScriptEncoding("UTF-8")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
||||||
|
|||||||
@ -42,7 +42,7 @@ public class Account6Test implements WithAssertions {
|
|||||||
this.dataSource = new EmbeddedDatabaseBuilder()
|
this.dataSource = new EmbeddedDatabaseBuilder()
|
||||||
.setType(EmbeddedDatabaseType.H2)
|
.setType(EmbeddedDatabaseType.H2)
|
||||||
.addScript("none_key_schema.sql")
|
.addScript("none_key_schema.sql")
|
||||||
.addScript("none_key_data.sql")
|
.addScript("none_key_data.sql").setScriptEncoding("UTF-8")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
MybatisFlexBootstrap bootstrap = new MybatisFlexBootstrap()
|
MybatisFlexBootstrap bootstrap = new MybatisFlexBootstrap()
|
||||||
|
|||||||
@ -44,7 +44,7 @@ public class Account7Test implements WithAssertions {
|
|||||||
this.dataSource = new EmbeddedDatabaseBuilder()
|
this.dataSource = new EmbeddedDatabaseBuilder()
|
||||||
.setType(EmbeddedDatabaseType.H2)
|
.setType(EmbeddedDatabaseType.H2)
|
||||||
.addScript("generate_key_schema.sql")
|
.addScript("generate_key_schema.sql")
|
||||||
.addScript("generate_key_data.sql")
|
.addScript("generate_key_data.sql").setScriptEncoding("UTF-8")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
MybatisFlexBootstrap bootstrap = new MybatisFlexBootstrap()
|
MybatisFlexBootstrap bootstrap = new MybatisFlexBootstrap()
|
||||||
|
|||||||
@ -48,7 +48,7 @@ public class AccountInsertWithArrayAttrTest implements WithAssertions {
|
|||||||
this.dataSource = new EmbeddedDatabaseBuilder()
|
this.dataSource = new EmbeddedDatabaseBuilder()
|
||||||
.setType(EmbeddedDatabaseType.H2)
|
.setType(EmbeddedDatabaseType.H2)
|
||||||
.addScript("schema05.sql")
|
.addScript("schema05.sql")
|
||||||
.addScript("data05.sql")
|
.addScript("data05.sql").setScriptEncoding("UTF-8")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
MybatisFlexBootstrap bootstrap = new MybatisFlexBootstrap()
|
MybatisFlexBootstrap bootstrap = new MybatisFlexBootstrap()
|
||||||
|
|||||||
@ -67,7 +67,7 @@ public class AccountNativeTest implements WithAssertions {
|
|||||||
this.dataSource = new EmbeddedDatabaseBuilder()
|
this.dataSource = new EmbeddedDatabaseBuilder()
|
||||||
.setType(EmbeddedDatabaseType.H2)
|
.setType(EmbeddedDatabaseType.H2)
|
||||||
.addScript("auto_increment_key_schema.sql")
|
.addScript("auto_increment_key_schema.sql")
|
||||||
.addScript("auto_increment_key_data.sql")
|
.addScript("auto_increment_key_data.sql").setScriptEncoding("UTF-8")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
MybatisFlexBootstrap bootstrap = new MybatisFlexBootstrap()
|
MybatisFlexBootstrap bootstrap = new MybatisFlexBootstrap()
|
||||||
|
|||||||
@ -59,7 +59,7 @@ public class DbChainTest implements WithAssertions {
|
|||||||
this.database = new EmbeddedDatabaseBuilder()
|
this.database = new EmbeddedDatabaseBuilder()
|
||||||
.setType(EmbeddedDatabaseType.H2)
|
.setType(EmbeddedDatabaseType.H2)
|
||||||
.addScript("auto_increment_key_schema.sql")
|
.addScript("auto_increment_key_schema.sql")
|
||||||
.addScript("auto_increment_key_data.sql")
|
.addScript("auto_increment_key_data.sql").setScriptEncoding("UTF-8")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Environment environment = new Environment(ENVIRONMENT_ID, new JdbcTransactionFactory(), this.database);
|
// Environment environment = new Environment(ENVIRONMENT_ID, new JdbcTransactionFactory(), this.database);
|
||||||
|
|||||||
@ -47,7 +47,7 @@ public class ListenerTest implements WithAssertions {
|
|||||||
public void init() {
|
public void init() {
|
||||||
dataSource = new EmbeddedDatabaseBuilder()
|
dataSource = new EmbeddedDatabaseBuilder()
|
||||||
.setType(EmbeddedDatabaseType.H2)
|
.setType(EmbeddedDatabaseType.H2)
|
||||||
.addScript("auto_increment_key_schema.sql")
|
.addScript("auto_increment_key_schema.sql").setScriptEncoding("UTF-8")
|
||||||
.build();
|
.build();
|
||||||
// 注册全局监听器
|
// 注册全局监听器
|
||||||
FlexGlobalConfig defaultConfig = FlexGlobalConfig.getDefaultConfig();
|
FlexGlobalConfig defaultConfig = FlexGlobalConfig.getDefaultConfig();
|
||||||
|
|||||||
@ -70,7 +70,7 @@ public class RelationsTest implements WithAssertions {
|
|||||||
dataSource = new EmbeddedDatabaseBuilder()
|
dataSource = new EmbeddedDatabaseBuilder()
|
||||||
.setType(EmbeddedDatabaseType.H2)
|
.setType(EmbeddedDatabaseType.H2)
|
||||||
.addScript("relation/onetoone/schema.sql")
|
.addScript("relation/onetoone/schema.sql")
|
||||||
.addScript("relation/onetoone/data.sql")
|
.addScript("relation/onetoone/data.sql").setScriptEncoding("UTF-8")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
||||||
|
|||||||
@ -57,6 +57,7 @@ public class RowTest implements WithAssertions {
|
|||||||
.setType(EmbeddedDatabaseType.H2)
|
.setType(EmbeddedDatabaseType.H2)
|
||||||
.addScript("schema_row.sql")
|
.addScript("schema_row.sql")
|
||||||
.addScript("data_row.sql")
|
.addScript("data_row.sql")
|
||||||
|
.setScriptEncoding("UTF-8")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
new MybatisFlexBootstrap().setDataSource(DATA_SOURCE_KEY, dataSource)
|
new MybatisFlexBootstrap().setDataSource(DATA_SOURCE_KEY, dataSource)
|
||||||
|
|||||||
@ -42,11 +42,12 @@ import static com.mybatisflex.test.table.ArticleTableDef.ARTICLE;
|
|||||||
|
|
||||||
public class UpdateChainTest implements WithAssertions {
|
public class UpdateChainTest implements WithAssertions {
|
||||||
|
|
||||||
private AccountMapper accountMapper;
|
|
||||||
private EmbeddedDatabase dataSource;
|
|
||||||
|
|
||||||
private static final String DATA_SOURCE_KEY = "ds2";
|
private static final String DATA_SOURCE_KEY = "ds2";
|
||||||
|
|
||||||
|
private AccountMapper accountMapper;
|
||||||
|
|
||||||
|
private EmbeddedDatabase dataSource;
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void enableAudit() {
|
public static void enableAudit() {
|
||||||
AuditManager.setAuditEnable(true);
|
AuditManager.setAuditEnable(true);
|
||||||
@ -56,16 +57,17 @@ public class UpdateChainTest implements WithAssertions {
|
|||||||
@Before
|
@Before
|
||||||
public void init() {
|
public void init() {
|
||||||
this.dataSource = new EmbeddedDatabaseBuilder()
|
this.dataSource = new EmbeddedDatabaseBuilder()
|
||||||
.setType(EmbeddedDatabaseType.H2)
|
.setType(EmbeddedDatabaseType.H2)
|
||||||
.addScript("schema.sql")
|
.addScript("schema.sql")
|
||||||
.addScript("data.sql")
|
.addScript("data.sql")
|
||||||
.build();
|
.setScriptEncoding("UTF-8")
|
||||||
|
.build();
|
||||||
|
|
||||||
MybatisFlexBootstrap bootstrap = new MybatisFlexBootstrap()
|
MybatisFlexBootstrap bootstrap = new MybatisFlexBootstrap()
|
||||||
.setDataSource(DATA_SOURCE_KEY, this.dataSource)
|
.setDataSource(DATA_SOURCE_KEY, this.dataSource)
|
||||||
.setLogImpl(StdOutImpl.class)
|
.setLogImpl(StdOutImpl.class)
|
||||||
.addMapper(AccountMapper.class)
|
.addMapper(AccountMapper.class)
|
||||||
.start();
|
.start();
|
||||||
|
|
||||||
DataSourceKey.use(DATA_SOURCE_KEY);
|
DataSourceKey.use(DATA_SOURCE_KEY);
|
||||||
accountMapper = bootstrap.getMapper(AccountMapper.class);
|
accountMapper = bootstrap.getMapper(AccountMapper.class);
|
||||||
@ -81,53 +83,53 @@ public class UpdateChainTest implements WithAssertions {
|
|||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public void testUpdateChain() {
|
public void testUpdateChain() {
|
||||||
UpdateChain.of(Account.class)
|
UpdateChain.of(Account.class)
|
||||||
.set(Account::getUserName, "张三")
|
.set(Account::getUserName, "张三")
|
||||||
.setRaw(Account::getAge, "age + 1")
|
.setRaw(Account::getAge, "age + 1")
|
||||||
.where(Account::getId).eq(1)
|
.where(Account::getId).eq(1)
|
||||||
.update();
|
.update();
|
||||||
|
|
||||||
Account account = accountMapper.selectOneById(1);
|
Account account = accountMapper.selectOneById(1);
|
||||||
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
|
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
|
||||||
String toParse = "2020-01-11";
|
String toParse = "2020-01-11";
|
||||||
assertThat(account).isNotNull()
|
assertThat(account).isNotNull()
|
||||||
.extracting(
|
.extracting(
|
||||||
Account::getUserName, Account::getAge,
|
Account::getUserName, Account::getAge,
|
||||||
Account::getSex, Account::getBirthday,
|
Account::getSex, Account::getBirthday,
|
||||||
Account::getOptions, Account::getDelete,
|
Account::getOptions, Account::getDelete,
|
||||||
Account::getArticles, Account::getTitle)
|
Account::getArticles, Account::getTitle)
|
||||||
.containsExactly(
|
.containsExactly(
|
||||||
"张*", 19,
|
"张*", 19,
|
||||||
SexEnum.TYPE1, format.parse(toParse),
|
SexEnum.TYPE1, format.parse(toParse),
|
||||||
Collections.singletonMap("key", "value1"), false,
|
Collections.singletonMap("key", "value1"), false,
|
||||||
Collections.emptyList(), null);
|
Collections.emptyList(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateChain1() {
|
public void testUpdateChain1() {
|
||||||
UpdateChain.of(Account.class)
|
UpdateChain.of(Account.class)
|
||||||
.set(Account::getAge, ACCOUNT.AGE.add(1))
|
.set(Account::getAge, ACCOUNT.AGE.add(1))
|
||||||
.where(Account::getId).ge(100)
|
.where(Account::getId).ge(100)
|
||||||
.and(Account::getAge).eq(18)
|
.and(Account::getAge).eq(18)
|
||||||
.update();
|
.update();
|
||||||
|
|
||||||
List<Account> list = QueryChain.of(accountMapper).list();
|
List<Account> list = QueryChain.of(accountMapper).list();
|
||||||
assertThat(list).hasSize(2)
|
assertThat(list).hasSize(2)
|
||||||
.extracting(Account::getId, Account::getUserName, Account::getAge)
|
.extracting(Account::getId, Account::getUserName, Account::getAge)
|
||||||
.containsExactly(tuple(1L, "张*", 18), tuple(2L, "王麻**叔", 19));
|
.containsExactly(tuple(1L, "张*", 18), tuple(2L, "王麻**叔", 19));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateChainToSql() {
|
public void testUpdateChainToSql() {
|
||||||
String sql = UpdateChain.of(Account.class)
|
String sql = UpdateChain.of(Account.class)
|
||||||
.set(ACCOUNT.AGE, 18)
|
.set(ACCOUNT.AGE, 18)
|
||||||
.set(Article::getAccountId, 4)
|
.set(Article::getAccountId, 4)
|
||||||
.leftJoin(ARTICLE).as("ar").on(ACCOUNT.ID.eq(ARTICLE.ACCOUNT_ID))
|
.leftJoin(ARTICLE).as("ar").on(ACCOUNT.ID.eq(ARTICLE.ACCOUNT_ID))
|
||||||
.where(ACCOUNT.ID.eq(4))
|
.where(ACCOUNT.ID.eq(4))
|
||||||
.toSQL();
|
.toSQL();
|
||||||
|
|
||||||
String expectSQL = "UPDATE `tb_account` " +
|
String expectSQL = "UPDATE `tb_account` " +
|
||||||
"LEFT JOIN `tb_article` AS `ar` ON `tb_account`.`id` = `ar`.`account_id` " +
|
"LEFT JOIN `tb_article` AS `ar` ON `tb_account`.`id` = `ar`.`account_id` " +
|
||||||
"SET `age` = 18 , `accountId` = 4 WHERE `id` = 4";
|
"SET `age` = 18 , `accountId` = 4 WHERE `id` = 4";
|
||||||
|
|
||||||
assertThat(sql).isEqualTo(expectSQL);
|
assertThat(sql).isEqualTo(expectSQL);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,7 +41,7 @@ public class AppConfig implements ApplicationListener<ContextRefreshedEvent> {
|
|||||||
return new EmbeddedDatabaseBuilder()
|
return new EmbeddedDatabaseBuilder()
|
||||||
.setType(EmbeddedDatabaseType.H2)
|
.setType(EmbeddedDatabaseType.H2)
|
||||||
.addScript("schema.sql")
|
.addScript("schema.sql")
|
||||||
.addScript("data.sql")
|
.addScript("data.sql").setScriptEncoding("UTF-8")
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user