Merge remote-tracking branch 'origin/main'

This commit is contained in:
Suomm 2023-06-08 15:11:30 +08:00
commit d2f22dae60
31 changed files with 505 additions and 91 deletions

View File

@ -47,6 +47,10 @@ select * from tb_account
where id >= 100
```
::: tip 问题:以上示例中,`ACCOUNT.ID.ge(100)` 中的 `ACCOUNT` 是怎么来的?
MyBatis-Flex 使用了 APT 技术,这个 `ACCOUNT` 是自动生成的。
参考:《[MyBatis-Flex APT 配置](../others/apt.md)》章节。
:::
## select *

View File

@ -24,6 +24,7 @@ MyBatis-Flex 使用了 APTAnnotation Processing Tool技术在项目编
| processor.baseMapperClass | 自定义 Mapper 的父类 | 全路径类名 | com.mybatisflex.core.BaseMapper |
| processor.mappersPackage | 自定义 Mapper 生成的包名 | 合法的包名 | ${entityPackage}.mapper |
| processor.tablesNameStyle | 生成辅助类的字段风格 | upperCase, lowerCase<br />upperCamelCase, lowerCamelCase | upperCase |
| processor.tablesDefSuffix | 生成的表对应的变量后缀 | string | 空字符串 |
| processor.entity.ignoreSuffixes | 过滤 Entity 后缀 | string | - |

View File

@ -73,10 +73,12 @@ public class ControllerGenerator implements IGenerator {
globalConfig.getTemplateConfig().getTemplate().generate(params, templatePath, controllerJavaFile);
}
@Override
public String getTemplatePath() {
return templatePath;
}
@Override
public void setTemplatePath(String templatePath) {
this.templatePath = templatePath;
}

View File

@ -73,10 +73,12 @@ public class EntityGenerator implements IGenerator {
globalConfig.getTemplateConfig().getTemplate().generate(params, templatePath, entityJavaFile);
}
@Override
public String getTemplatePath() {
return templatePath;
}
@Override
public void setTemplatePath(String templatePath) {
this.templatePath = templatePath;
}

View File

@ -73,10 +73,12 @@ public class MapperGenerator implements IGenerator {
globalConfig.getTemplateConfig().getTemplate().generate(params, templatePath, mapperJavaFile);
}
@Override
public String getTemplatePath() {
return templatePath;
}
@Override
public void setTemplatePath(String templatePath) {
this.templatePath = templatePath;
}

View File

@ -70,10 +70,12 @@ public class MapperXmlGenerator implements IGenerator {
globalConfig.getTemplateConfig().getTemplate().generate(params, templatePath, mapperXmlFile);
}
@Override
public String getTemplatePath() {
return templatePath;
}
@Override
public void setTemplatePath(String templatePath) {
this.templatePath = templatePath;
}

View File

@ -88,10 +88,12 @@ public class PackageInfoGenerator implements IGenerator {
});
}
@Override
public String getTemplatePath() {
return templatePath;
}
@Override
public void setTemplatePath(String templatePath) {
this.templatePath = templatePath;
}

View File

@ -73,10 +73,12 @@ public class ServiceGenerator implements IGenerator {
globalConfig.getTemplateConfig().getTemplate().generate(params, templatePath, serviceJavaFile);
}
@Override
public String getTemplatePath() {
return templatePath;
}
@Override
public void setTemplatePath(String templatePath) {
this.templatePath = templatePath;
}

View File

@ -73,10 +73,12 @@ public class ServiceImplGenerator implements IGenerator {
globalConfig.getTemplateConfig().getTemplate().generate(params, templatePath, serviceImplJavaFile);
}
@Override
public String getTemplatePath() {
return templatePath;
}
@Override
public void setTemplatePath(String templatePath) {
this.templatePath = templatePath;
}

View File

@ -73,10 +73,12 @@ public class TableDefGenerator implements IGenerator {
globalConfig.getTemplateConfig().getTemplate().generate(params, templatePath, tableDefJavaFile);
}
@Override
public String getTemplatePath() {
return templatePath;
}
@Override
public void setTemplatePath(String templatePath) {
this.templatePath = templatePath;
}

View File

@ -34,7 +34,7 @@ public class EnjoyTemplate implements ITemplate {
public EnjoyTemplate() {
engine = Engine.create("mybatis-flex", engine -> {
engine.addSharedMethod(StringUtil.class);
engine.addSharedStaticMethod(StringUtil.class);
engine.setSourceFactory(new FileAndClassPathSourceFactory());
});
// 以下配置将支持 user.girl 表达式去调用 user 对象的 boolean isGirl() 方法

View File

@ -41,7 +41,7 @@
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.31</version>
<version>2.0.32</version>
<optional>true</optional>
<scope>compile</scope>
</dependency>
@ -49,7 +49,7 @@
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.31</version>
<version>2.0.32</version>
<optional>true</optional>
<scope>compile</scope>
</dependency>

View File

@ -16,7 +16,6 @@
package com.mybatisflex.core;
import com.mybatisflex.core.exception.FlexExceptions;
import com.mybatisflex.core.field.FieldQuery;
import com.mybatisflex.core.field.FieldQueryBuilder;
import com.mybatisflex.core.mybatis.MappedStatementTypes;
import com.mybatisflex.core.paginate.Page;
@ -27,6 +26,7 @@ import com.mybatisflex.core.table.TableInfoFactory;
import com.mybatisflex.core.util.*;
import org.apache.ibatis.annotations.*;
import org.apache.ibatis.builder.annotation.ProviderContext;
import org.apache.ibatis.cursor.Cursor;
import java.io.Serializable;
import java.util.*;
@ -345,7 +345,7 @@ public interface BaseMapper<T> {
* @return entity 数据
*/
default T selectOneByQuery(QueryWrapper queryWrapper) {
return SqlUtil.getSelectOneResult(selectListByQuery(queryWrapper));
return MapperUtil.getSelectOneResult(selectListByQuery(queryWrapper));
}
@ -357,7 +357,7 @@ public interface BaseMapper<T> {
* @return 数据内容
*/
default <R> R selectOneByQueryAs(QueryWrapper queryWrapper, Class<R> asType) {
return SqlUtil.getSelectOneResult(selectListByQueryAs(queryWrapper, asType));
return MapperUtil.getSelectOneResult(selectListByQueryAs(queryWrapper, asType));
}
/**
@ -435,11 +435,21 @@ public interface BaseMapper<T> {
return Collections.emptyList();
}
__queryFields(list, consumers);
MapperUtil.queryFields(this, list, consumers);
return list;
}
/**
* 根据 query 来构建条件查询游标数据 Cursor
* 该方法必须在事务中才能正常使用非事务下无法获取数据
*
* @param queryWrapper 查询条件
* @return 游标数据 Cursor
*/
@SelectProvider(type = EntitySqlProvider.class, method = "selectListByQuery")
Cursor<T> selectCursorByQuery(@Param(FlexConsts.QUERY) QueryWrapper queryWrapper);
/**
* 根据 query 来构建条件查询数据列表要求返回的数据为 asType
@ -469,7 +479,7 @@ public interface BaseMapper<T> {
if (list == null || list.isEmpty()) {
return Collections.emptyList();
} else {
__queryFields(list, consumers);
MapperUtil.queryFields(this, list, consumers);
return list;
}
}
@ -493,7 +503,7 @@ public interface BaseMapper<T> {
* @return 数据量
*/
default Object selectObjectByQuery(QueryWrapper queryWrapper) {
return SqlUtil.getSelectOneResult(selectObjectListByQuery(queryWrapper));
return MapperUtil.getSelectOneResult(selectObjectListByQuery(queryWrapper));
}
@ -539,6 +549,7 @@ public interface BaseMapper<T> {
*/
default long selectCountByQuery(QueryWrapper queryWrapper) {
List<QueryColumn> selectColumns = CPI.getSelectColumns(queryWrapper);
try {
if (CollectionUtil.isEmpty(selectColumns)) {
queryWrapper.select(count());
}
@ -551,6 +562,10 @@ public interface BaseMapper<T> {
} else {
throw FlexExceptions.wrap("selectCountByQuery error, Can not get number value for queryWrapper: %s", queryWrapper);
}
} finally {
//fixed https://github.com/mybatis-flex/mybatis-flex/issues/49
CPI.setSelectColumns(queryWrapper, selectColumns);
}
}
@ -712,47 +727,15 @@ public interface BaseMapper<T> {
if (asType != null) {
List<R> records = selectListByQueryAs(queryWrapper, asType);
__queryFields(records, consumers);
MapperUtil.queryFields(this, records, consumers);
page.setRecords(records);
} else {
List<R> records = (List<R>) selectListByQuery(queryWrapper);
__queryFields(records, consumers);
MapperUtil.queryFields(this, records, consumers);
page.setRecords(records);
}
return page;
}
default <R> void __queryFields(List<R> list, Consumer<FieldQueryBuilder<R>>[] consumers) {
if (CollectionUtil.isEmpty(list) || ArrayUtil.isEmpty(consumers) || consumers[0] == null) {
return;
}
list.forEach(entity -> {
for (Consumer<FieldQueryBuilder<R>> consumer : consumers) {
FieldQueryBuilder<R> fieldQueryBuilder = new FieldQueryBuilder<>(entity);
consumer.accept(fieldQueryBuilder);
FieldQuery fieldQuery = fieldQueryBuilder.build();
QueryWrapper childQuery = fieldQuery.getQueryWrapper();
FieldWrapper fieldWrapper = FieldWrapper.of(entity.getClass(), fieldQuery.getField());
Class<?> fieldType = fieldWrapper.getFieldType();
Class<?> mappingType = fieldWrapper.getMappingType();
Object value;
if (fieldType.isAssignableFrom(List.class)) {
value = selectListByQueryAs(childQuery, mappingType);
} else if (fieldType.isAssignableFrom(Set.class)) {
value = selectListByQueryAs(childQuery, mappingType);
value = new HashSet<>((Collection<?>) value);
} else if (fieldType.isArray()) {
value = selectListByQueryAs(childQuery, mappingType);
value = ((List<?>) value).toArray();
} else {
value = selectOneByQueryAs(childQuery, mappingType);
}
fieldWrapper.set(value, entity);
}
});
}
}

View File

@ -66,7 +66,7 @@ public interface IDialect {
//////for entity /////
String forInsertEntity(TableInfo tableInfo, Object entity, boolean ignoreNulls);
String forInsertEntityBatch(TableInfo tableInfo, List<Object> entities);
String forInsertEntityBatch(TableInfo tableInfo, List<?> entities);
String forDeleteEntityById(TableInfo tableInfo);

View File

@ -415,7 +415,7 @@ public class CommonsDialectImpl implements IDialect {
}
@Override
public String forInsertEntityBatch(TableInfo tableInfo, List<Object> entities) {
public String forInsertEntityBatch(TableInfo tableInfo, List<?> entities) {
StringBuilder sql = new StringBuilder();
sql.append("INSERT INTO ").append(tableInfo.getWrapSchemaAndTableName(this));
String[] insertColumns = tableInfo.obtainInsertColumns(null, false);

View File

@ -17,9 +17,15 @@ package com.mybatisflex.core.dialect.impl;
import com.mybatisflex.core.dialect.KeywordWrap;
import com.mybatisflex.core.dialect.LimitOffsetProcessor;
import com.mybatisflex.core.row.Row;
import com.mybatisflex.core.table.TableInfo;
import com.mybatisflex.core.util.CollectionUtil;
import com.mybatisflex.core.util.StringUtil;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringJoiner;
public class OracleDialect extends CommonsDialectImpl {
@ -56,8 +62,92 @@ public class OracleDialect extends CommonsDialectImpl {
public OracleDialect() {
this(LimitOffsetProcessor.ORACLE);
}
public OracleDialect(LimitOffsetProcessor limitOffsetProcessor) {
super(new KeywordWrap(keywords, "\"", "\""), limitOffsetProcessor);
}
@Override
public String forInsertEntityBatch(TableInfo tableInfo, List<?> entities) {
/**
* INSERT ALL
* INTO t (col1, col2, col3) VALUES ('val1_1', 'val1_2', 'val1_3')
* INTO t (col1, col2, col3) VALUES ('val2_1', 'val2_2', 'val2_3')
* INTO t (col1, col2, col3) VALUES ('val3_1', 'val3_2', 'val3_3')
* .
* .
* .
* SELECT 1 FROM DUAL;
*/
StringBuilder sql = new StringBuilder();
sql.append("INSERT ALL");
String[] insertColumns = tableInfo.obtainInsertColumns(null, false);
String[] warpedInsertColumns = new String[insertColumns.length];
for (int i = 0; i < insertColumns.length; i++) {
warpedInsertColumns[i] = wrap(insertColumns[i]);
}
Map<String, String> onInsertColumns = tableInfo.getOnInsertColumns();
for (int i = 0; i < entities.size(); i++) {
sql.append(" INTO ").append(tableInfo.getWrapSchemaAndTableName(this));
sql.append(" (").append(StringUtil.join(", ", warpedInsertColumns)).append(")");
sql.append(" VALUES ");
StringJoiner stringJoiner = new StringJoiner(", ", "(", ")");
for (String insertColumn : insertColumns) {
if (onInsertColumns != null && onInsertColumns.containsKey(insertColumn)) {
//直接读取 onInsert 配置的值而不用 "?" 代替
stringJoiner.add(onInsertColumns.get(insertColumn));
} else {
stringJoiner.add("?");
}
}
sql.append(stringJoiner);
}
return sql.append(" SELECT 1 FROM DUAL").toString();
}
@Override
public String forInsertBatchWithFirstRowColumns(String schema, String tableName, List<Row> rows) {
/**
* INSERT ALL
* INTO t (col1, col2, col3) VALUES ('val1_1', 'val1_2', 'val1_3')
* INTO t (col1, col2, col3) VALUES ('val2_1', 'val2_2', 'val2_3')
* INTO t (col1, col2, col3) VALUES ('val3_1', 'val3_2', 'val3_3')
* .
* .
* .
* SELECT 1 FROM DUAL;
*/
StringBuilder fields = new StringBuilder();
Row firstRow = rows.get(0);
Set<String> attrs = firstRow.obtainModifyAttrs();
int index = 0;
for (String column : attrs) {
fields.append(wrap(column));
if (index != attrs.size() - 1) {
fields.append(", ");
}
index++;
}
StringBuilder sql = new StringBuilder();
sql.append("INSERT ALL");
String tableNameWrap = StringUtil.isNotBlank(schema)
? wrap(getRealSchema(schema)) + "." + wrap(getRealTable(tableName))
: wrap(getRealTable(tableName));
String questionStrings = buildQuestion(attrs.size(), true);
for (int i = 0; i < rows.size(); i++) {
sql.append(" INTO ").append(tableNameWrap);
sql.append(" (").append(fields).append(")");
sql.append(" VALUES ").append(questionStrings);
}
return sql.append(" SELECT 1 FROM DUAL").toString();
}
}

View File

@ -34,6 +34,7 @@ import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.keygen.NoKeyGenerator;
import org.apache.ibatis.executor.keygen.SelectKeyGenerator;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.*;
import org.apache.ibatis.session.*;
@ -93,6 +94,17 @@ public class FlexConfiguration extends Configuration {
}
}
@Override
public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement
, RowBounds rowBounds, ParameterHandler parameterHandler, ResultHandler resultHandler, BoundSql boundSql) {
// ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler,
// resultHandler, boundSql, rowBounds);
ResultSetHandler resultSetHandler = new FlexResultSetHandler(executor, mappedStatement, parameterHandler,
resultHandler, boundSql, rowBounds);
return (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
}
/**
* 替换为 FlexStatementHandler主要用来为实体类的多主键做支持和数据审计
* FlexStatementHandler 原生的 RoutingStatementHandler 对比没有任何性能影响

View File

@ -0,0 +1,90 @@
/*
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mybatisflex.core.mybatis;
import com.mybatisflex.core.transaction.TransactionContext;
import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.cursor.defaults.DefaultCursor;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.resultset.DefaultResultSetHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Iterator;
public class FlexResultSetHandler extends DefaultResultSetHandler {
public FlexResultSetHandler(Executor executor, MappedStatement mappedStatement, ParameterHandler parameterHandler, ResultHandler<?> resultHandler, BoundSql boundSql, RowBounds rowBounds) {
super(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
}
@Override
public <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException {
return new FlexCursor<>(super.handleCursorResultSets(stmt));
}
static class FlexCursor<T> extends DefaultCursor<T> {
private Cursor originalCursor;
public FlexCursor(Cursor cursor) {
super(null, null, null, null);
this.originalCursor = cursor;
TransactionContext.holdCursor(cursor);
}
@Override
public void close() {
//非事务场景下通过 releaseCursor cursor 进行 close
if (TransactionContext.getXID() == null) {
TransactionContext.releaseCursor();
}
//else 在事务的场景下由事务主动关闭
}
@Override
public boolean isOpen() {
return originalCursor.isOpen();
}
@Override
public boolean isConsumed() {
return originalCursor.isConsumed();
}
@Override
public int getCurrentIndex() {
return originalCursor.getCurrentIndex();
}
@Override
public Iterator<T> iterator() {
try {
return originalCursor.iterator();
} catch (IllegalStateException e) {
if (TransactionContext.getXID() == null) {
throw new IllegalStateException(e.getMessage() + " Cursor must use in transaction.");
}
throw e;
}
}
}
}

View File

@ -37,7 +37,7 @@ public class FlexSqlSessionFactoryBuilder extends SqlSessionFactoryBuilder {
@Override
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
// 需要 mybaits v3.5.13+
// 需要 mybatis v3.5.13+
// https://github.com/mybatis/mybatis-3/commit/d7826d71a7005a8b4d4e0e7a020db0f6c7e253a4
XMLConfigBuilder parser = new XMLConfigBuilder(FlexConfiguration.class, reader, environment, properties);
return build(parser.parse());
@ -59,7 +59,7 @@ public class FlexSqlSessionFactoryBuilder extends SqlSessionFactoryBuilder {
@Override
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
// 需要 mybaits v3.5.13+
// 需要 mybatis v3.5.13+
// https://github.com/mybatis/mybatis-3/commit/d7826d71a7005a8b4d4e0e7a020db0f6c7e253a4
XMLConfigBuilder parser = new XMLConfigBuilder(FlexConfiguration.class, inputStream, environment, properties);
return build(parser.parse());

View File

@ -54,6 +54,12 @@ public class QueryColumn implements Serializable {
this.name = name;
}
public QueryColumn(QueryTable queryTable, String name) {
SqlUtil.keepColumnSafely(name);
this.table = queryTable;
this.name = name;
}
public QueryTable getTable() {
return table;

View File

@ -16,11 +16,16 @@
package com.mybatisflex.core.transaction;
import org.apache.ibatis.cursor.Cursor;
import java.io.IOException;
public class TransactionContext {
private TransactionContext() {}
private static final ThreadLocal<String> XID_HOLDER = new ThreadLocal<>();
private static final ThreadLocal<Cursor<?>> CURSOR_HOLDER = new ThreadLocal<>();
public static String getXID() {
return XID_HOLDER.get();
@ -28,10 +33,29 @@ public class TransactionContext {
public static void release() {
XID_HOLDER.remove();
releaseCursor();
}
public static void hold(String xid) {
public static void releaseCursor() {
try {
Cursor<?> cursor = CURSOR_HOLDER.get();
if (cursor != null){
try {
cursor.close();
} catch (IOException e) {
}
}
}finally {
CURSOR_HOLDER.remove();
}
}
public static void holdXID(String xid) {
XID_HOLDER.set(xid);
}
public static void holdCursor(Cursor<?> cursor) {
CURSOR_HOLDER.set(cursor);
}
}

View File

@ -113,7 +113,7 @@ public class TransactionalManager {
} finally {
//恢复上一级事务
if (currentXID != null) {
TransactionContext.hold(currentXID);
TransactionContext.holdXID(currentXID);
}
}
}
@ -147,7 +147,7 @@ public class TransactionalManager {
public static String startTransactional() {
String xid = UUID.randomUUID().toString();
TransactionContext.hold(xid);
TransactionContext.holdXID(xid);
return xid;
}

View File

@ -0,0 +1,82 @@
/*
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mybatisflex.core.util;
import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.core.field.FieldQuery;
import com.mybatisflex.core.field.FieldQueryBuilder;
import com.mybatisflex.core.query.QueryWrapper;
import org.apache.ibatis.exceptions.TooManyResultsException;
import org.apache.ibatis.session.defaults.DefaultSqlSession;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
public class MapperUtil {
public static <R> void queryFields(BaseMapper<?> mapper, List<R> list, Consumer<FieldQueryBuilder<R>>[] consumers) {
if (CollectionUtil.isEmpty(list) || ArrayUtil.isEmpty(consumers) || consumers[0] == null) {
return;
}
list.forEach(entity -> {
for (Consumer<FieldQueryBuilder<R>> consumer : consumers) {
FieldQueryBuilder<R> fieldQueryBuilder = new FieldQueryBuilder<>(entity);
consumer.accept(fieldQueryBuilder);
FieldQuery fieldQuery = fieldQueryBuilder.build();
QueryWrapper childQuery = fieldQuery.getQueryWrapper();
FieldWrapper fieldWrapper = FieldWrapper.of(entity.getClass(), fieldQuery.getField());
Class<?> fieldType = fieldWrapper.getFieldType();
Class<?> mappingType = fieldWrapper.getMappingType();
Object value;
if (fieldType.isAssignableFrom(List.class)) {
value = mapper.selectListByQueryAs(childQuery, mappingType);
} else if (fieldType.isAssignableFrom(Set.class)) {
value = mapper.selectListByQueryAs(childQuery, mappingType);
value = new HashSet<>((Collection<?>) value);
} else if (fieldType.isArray()) {
value = mapper.selectListByQueryAs(childQuery, mappingType);
value = ((List<?>) value).toArray();
} else {
value = mapper.selectOneByQueryAs(childQuery, mappingType);
}
fieldWrapper.set(value, entity);
}
});
}
/**
* 搬运加改造 {@link DefaultSqlSession#selectOne(String, Object)}
*/
public static <T> T getSelectOneResult(List<T> list) {
if (list == null || list.isEmpty()) {
return null;
}
int size = list.size();
if (size == 1) {
return list.get(0);
}
throw new TooManyResultsException(
"Expected one result (or null) to be returned by selectOne(), but found: " + size);
}
}

View File

@ -15,12 +15,8 @@
*/
package com.mybatisflex.core.util;
import org.apache.ibatis.exceptions.TooManyResultsException;
import org.apache.ibatis.session.defaults.DefaultSqlSession;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
public class SqlUtil {
@ -83,6 +79,12 @@ public class SqlUtil {
}
/**
* 替换 sql 中的问号
* @param sql sql 内容
* @param params 参数
* @return 完整的 sql
*/
public static String replaceSqlParams(String sql, Object[] params) {
if (params != null && params.length > 0) {
for (Object value : params) {
@ -113,19 +115,6 @@ public class SqlUtil {
return sql;
}
/**
* 搬运加改造 {@link DefaultSqlSession#selectOne(String, Object)}
*/
public static <T> T getSelectOneResult(List<T> list) {
if (list == null || list.isEmpty()) {
return null;
}
int size = list.size();
if (size == 1) {
return list.get(0);
}
throw new TooManyResultsException(
"Expected one result (or null) to be returned by selectOne(), but found: " + size);
}
}

View File

@ -0,0 +1,84 @@
package com.mybatisflex.coretest;
import com.mybatisflex.core.dialect.IDialect;
import com.mybatisflex.core.dialect.impl.OracleDialect;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Row;
import com.mybatisflex.core.table.TableInfoFactory;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import static com.mybatisflex.coretest.table.AccountTableDef.ACCOUNT;
public class OracleDialectTester {
@Test
public void testSelectSql() {
QueryWrapper query = new QueryWrapper()
.select()
.from(ACCOUNT);
IDialect dialect = new OracleDialect();
String sql = dialect.forSelectByQuery(query);
System.out.println(sql);
}
@Test
public void testInsertBatchSql() {
List<Account> accounts = new ArrayList<>();
Account account1 = new Account();
account1.setUserName("michael1");
account1.setAge(18);
account1.setSex(1);
accounts.add(account1);
Account account2 = new Account();
account2.setUserName("michael2");
account2.setAge(19);
account2.setSex(2);
accounts.add(account2);
Account account3 = new Account();
account3.setUserName("michael3");
account3.setAge(20);
account3.setSex(3);
accounts.add(account3);
IDialect dialect = new OracleDialect();
String sql = dialect.forInsertEntityBatch(TableInfoFactory.ofEntityClass(Account.class),accounts);
System.out.println(sql);
}
@Test
public void testInsertRowBatchSql() {
List<Row> accounts = new ArrayList<>();
Row account1 = new Row();
account1.set("username","michael1");
account1.set("age",18);
account1.set("sex",1);
accounts.add(account1);
Row account2 = new Row();
account2.set("username","michael2");
account2.set("age",18);
account2.set("sex",1);
accounts.add(account2);
Row account3 = new Row();
account3.set("username","michael3");
account3.set("age",18);
account3.set("sex",1);
accounts.add(account3);
IDialect dialect = new OracleDialect();
String sql = dialect.forInsertBatchWithFirstRowColumns(null,"tb_account",accounts);
System.out.println(sql);
}
}

View File

@ -156,6 +156,9 @@ public class QueryEntityProcessor extends AbstractProcessor {
//upperCase, lowerCase, upperCamelCase, lowerCamelCase
String tablesNameStyle = props.getProperties().getProperty("processor.tablesNameStyle", "upperCase");
//包名对应的变量后缀
String tablesDefSuffix = props.getProperties().getProperty("processor.tablesDefSuffix", "");
String[] entityIgnoreSuffixes = props.getProperties().getProperty("processor.entity.ignoreSuffixes", "").split(",");
@ -207,13 +210,15 @@ public class QueryEntityProcessor extends AbstractProcessor {
}
if (allInTables) {
String content = buildTablesClass(entitySimpleName, schema, tableName, propertyAndColumns, defaultColumns, tablesNameStyle, null, allInTables);
String content = buildTablesClass(entitySimpleName, schema, tableName, propertyAndColumns, defaultColumns, tablesNameStyle
, tablesDefSuffix, null, allInTables);
tablesContent.append(content);
}
//每一个 entity 生成一个独立的文件
else {
String realGenPackage = genTablesPackage == null || genTablesPackage.trim().length() == 0 ? guessPackage.toString() : genTablesPackage;
String content = buildTablesClass(entitySimpleName, schema, tableName, propertyAndColumns, defaultColumns, tablesNameStyle, realGenPackage, allInTables);
String content = buildTablesClass(entitySimpleName, schema, tableName, propertyAndColumns, defaultColumns, tablesNameStyle
, tablesDefSuffix, realGenPackage, allInTables);
genClass(genPath, realGenPackage, entitySimpleName + "TableDef", content);
}
@ -332,13 +337,14 @@ public class QueryEntityProcessor extends AbstractProcessor {
private String buildTablesClass(String entityClass, String schema, String tableName, Map<String, String> propertyAndColumns
, List<String> defaultColumns, String tablesNameStyle, String realGenPackage, boolean allInTables) {
, List<String> defaultColumns, String tablesNameStyle, String tablesDefSuffix, String realGenPackage, boolean allInTables) {
// tableDefTemplate = " public static final @entityClassTableDef @tableField = new @entityClassTableDef(\"@tableName\");\n";
String tableDef = tableDefTemplate.replace("@entityClass", entityClass)
.replace("@schema", schema)
.replace("@tableField", buildName(entityClass, tablesNameStyle))
.replace("@tableField", buildName(entityClass, tablesNameStyle)
+ (tablesDefSuffix != null ? tablesDefSuffix.trim() : ""))
.replace("@tableName", tableName);

View File

@ -68,7 +68,7 @@
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.17</version>
<version>1.2.18</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>

View File

@ -46,7 +46,7 @@ public class FlexTransactionManager extends AbstractPlatformTransactionManager {
@Override
protected void doResume(Object transaction, Object suspendedResources) throws TransactionException {
String xid = (String) suspendedResources;
TransactionContext.hold(xid);
TransactionContext.holdXID(xid);
}
@Override

View File

@ -19,13 +19,16 @@ import com.mybatisflex.core.MybatisFlexBootstrap;
import com.mybatisflex.core.audit.AuditManager;
import com.mybatisflex.core.audit.ConsoleMessageCollector;
import com.mybatisflex.core.audit.MessageCollector;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Db;
import org.apache.ibatis.cursor.Cursor;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import javax.sql.DataSource;
import java.util.function.Supplier;
import static com.mybatisflex.test.table.AccountTableDef.ACCOUNT;
import static com.mybatisflex.test.table.ArticleTableDef.ARTICLE;
@ -138,8 +141,30 @@ public class EntityTestStarter {
//
// List<ArticleDTO> articleDTOS = accountMapper.selectListByQueryAs(asWrapper, ArticleDTO.class);
// System.out.println(articleDTOS);
Page<ArticleDTO01> paginate = accountMapper.paginateAs(Page.of(1, 10), asWrapper, ArticleDTO01.class);
System.out.println(paginate);
// Page<ArticleDTO01> paginate = accountMapper.paginateAs(Page.of(1, 10), asWrapper, ArticleDTO01.class);
// System.out.println(paginate);
Db.tx(new Supplier<Boolean>() {
@Override
public Boolean get() {
Cursor<Account> accounts = accountMapper.selectCursorByQuery(asWrapper);
System.out.println(accounts.isOpen());
for (Account account : accounts) {
System.out.println(accounts.isOpen());
System.out.println(account);
}
System.out.println(accounts.isOpen());
return true;
}
});
// Cursor<Account> accounts = accountMapper.selectCursorByQuery(asWrapper);
// System.out.println(accounts.isOpen());
// for (Account account : accounts) {
// System.out.println(accounts.isOpen());
// System.out.println(account);
// }
// System.out.println(accounts.isOpen());
// QueryWrapper queryWrapper = new QueryWrapper();

View File

@ -1 +1,3 @@
processor.mappersGenerateEnable = true
processor.tablesNameStyle = lowerCase
processor.tablesDefSuffix = Def

View File

@ -14,7 +14,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
import static com.mybatisflex.test.model.table.AccountTableDef.ACCOUNT;
import static com.mybatisflex.test.model.table.AccountTableDef.accountDef;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
@ -33,7 +33,7 @@ public class AccountTest implements WithAssertions {
@Test
public void testSelectByQuery() {
QueryWrapper queryWrapper = QueryWrapper.create()
.where(ACCOUNT.AGE.eq(18));
.where(accountDef.age.eq(18));
List<Account> accounts = accountMapper.selectListByQuery(queryWrapper);
assertThat(accounts.size()).isEqualTo(1);
assertThat(accounts.get(0).getAge()).isEqualTo(18);