feat: add BaseMapper.selectCursorByQuery()

This commit is contained in:
开源海哥 2023-06-08 13:06:14 +08:00
parent dc39e6083b
commit 7eaab96e35
8 changed files with 172 additions and 9 deletions

View File

@ -27,6 +27,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.*;
@ -442,6 +443,17 @@ public interface BaseMapper<T> {
return list;
}
/**
* 根据 query 来构建条件查询游标数据 Cursor
* 该方法必须在事务中才能正常使用非事务下无法获取数据
*
* @param queryWrapper 查询条件
* @return 游标数据 Cursor
*/
@SelectProvider(type = EntitySqlProvider.class, method = "selectListByQuery")
Cursor<T> selectCursorByQuery(@Param(FlexConsts.QUERY) QueryWrapper queryWrapper);
/**
* 根据 query 来构建条件查询数据列表要求返回的数据为 asType

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

@ -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

@ -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();