提交 f9aeb86c 编写于 作者: 木远

7、SQL执行器的定义和实现

上级 ecc7e2d6
/*
* Ant Group
* Copyright (c) 2004-2023 All Rights Reserved.
*/
package cn.muyuan.mybatis.executor;
import cn.muyuan.mybatis.mapping.BoundSql;
import cn.muyuan.mybatis.mapping.MappedStatement;
import cn.muyuan.mybatis.session.Configuration;
import cn.muyuan.mybatis.session.ResultHandler;
import cn.muyuan.mybatis.transaction.Transaction;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
import java.util.List;
/**
* 执行器抽象基类
*
* @author muyuan
* @version BaseExecutor.java, v 0.1 2023年03月07日 19:54 muyuan
*/
public abstract class BaseExecutor implements Executor {
private final org.slf4j.Logger logger = LoggerFactory.getLogger(BaseExecutor.class);
protected Configuration configuration;
protected Transaction transaction;
protected Executor wrapper;
private boolean closed;
protected BaseExecutor(Configuration configuration, Transaction transaction) {
this.configuration = configuration;
this.transaction = transaction;
this.wrapper = this;
}
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, ResultHandler resultHandler, BoundSql boundSql) {
if (closed) {
throw new RuntimeException("Executor was closed.");
}
return doQuery(ms, parameter, resultHandler, boundSql);
}
protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, ResultHandler resultHandler, BoundSql boundSql);
@Override
public Transaction getTransaction() {
if (closed) {
throw new RuntimeException("Executor was closed.");
}
return transaction;
}
@Override
public void commit(boolean required) throws SQLException {
if (closed) {
throw new RuntimeException("Cannot commit, transaction is already closed");
}
if (required) {
transaction.commit();
}
}
@Override
public void rollback(boolean required) throws SQLException {
if (!closed) {
if (required) {
transaction.rollback();
}
}
}
@Override
public void close(boolean forceRollback) {
try {
try {
rollback(forceRollback);
} finally {
transaction.close();
}
} catch (SQLException e) {
logger.warn("Unexpected exception on closing transaction. Cause: " + e);
} finally {
transaction = null;
closed = true;
}
}
}
\ No newline at end of file
/*
* Ant Group
* Copyright (c) 2004-2023 All Rights Reserved.
*/
package cn.muyuan.mybatis.executor;
import cn.muyuan.mybatis.mapping.BoundSql;
import cn.muyuan.mybatis.mapping.MappedStatement;
import cn.muyuan.mybatis.session.ResultHandler;
import cn.muyuan.mybatis.transaction.Transaction;
import java.sql.SQLException;
import java.util.List;
/**
* 执行器
*
* @author muyuan
* @version Executor.java, v 0.1 2023年03月07日 19:53 muyuan
*/
public interface Executor {
ResultHandler NO_RESULT_HANDLER = null;
/**
* 执行查询语句
*
* @param ms 映射语句类
* @param parameter 查询参数
* @param resultHandler 结果处理器
* @param boundSql 绑定的sql语句
* @param <E> 参数泛型
* @return 查询结果
*/
<E> List<E> query(MappedStatement ms, Object parameter, ResultHandler resultHandler, BoundSql boundSql);
/**
* 获取事务
*
* @return Transaction
*/
Transaction getTransaction();
/**
* 提交
*
* @param required boolean
* @throws SQLException 异常
*/
void commit(boolean required) throws SQLException;
/**
* 回滚
*
* @param required boolean
* @throws SQLException 异常
*/
void rollback(boolean required) throws SQLException;
/**
* 关闭
*
* @param forceRollback boolean
* @throws SQLException 异常
*/
void close(boolean forceRollback) throws SQLException;
}
\ No newline at end of file
/*
* Ant Group
* Copyright (c) 2004-2023 All Rights Reserved.
*/
package cn.muyuan.mybatis.executor;
import cn.muyuan.mybatis.executor.statement.StatementHandler;
import cn.muyuan.mybatis.mapping.BoundSql;
import cn.muyuan.mybatis.mapping.MappedStatement;
import cn.muyuan.mybatis.session.Configuration;
import cn.muyuan.mybatis.session.ResultHandler;
import cn.muyuan.mybatis.transaction.Transaction;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
/**
* 简单执行器
*
* @author muyuan
* @version SimpleExecutor.java, v 0.1 2023年03月07日 19:56 muyuan
*/
public class SimpleExecutor extends BaseExecutor {
public SimpleExecutor(Configuration configuration, Transaction transaction) {
super(configuration, transaction);
}
@Override
protected <E> List<E> doQuery(MappedStatement ms, Object parameter, ResultHandler resultHandler, BoundSql boundSql) {
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, resultHandler, boundSql);
Connection connection = transaction.getConnection();
Statement stmt = handler.prepare(connection);
handler.parameterize(stmt);
return handler.query(stmt, resultHandler);
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
}
\ No newline at end of file
/*
* Ant Group
* Copyright (c) 2004-2023 All Rights Reserved.
*/
package cn.muyuan.mybatis.executor.resultset;
import cn.muyuan.mybatis.executor.Executor;
import cn.muyuan.mybatis.mapping.BoundSql;
import cn.muyuan.mybatis.mapping.MappedStatement;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* 默认结果集处理器
*
* @author muyuan
* @version DefaultResultSetHandler.java, v 0.1 2023年03月07日 19:52 muyuan
*/
public class DefaultResultSetHandler implements ResultSetHandler {
private final BoundSql boundSql;
public DefaultResultSetHandler(Executor executor, MappedStatement mappedStatement, BoundSql boundSql) {
this.boundSql = boundSql;
}
@Override
public <E> List<E> handleResultSets(Statement stmt) throws SQLException {
ResultSet resultSet = stmt.getResultSet();
try {
return resultSet2Obj(resultSet, Class.forName(boundSql.getResultType()));
} catch (ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}
private <T> List<T> resultSet2Obj(ResultSet resultSet, Class<?> clazz) {
List<T> list = new ArrayList<>();
try {
ResultSetMetaData metaData = resultSet.getMetaData();
int columnCount = metaData.getColumnCount();
// 每次遍历行值
while (resultSet.next()) {
T obj = (T) clazz.newInstance();
for (int i = 1; i <= columnCount; i++) {
Object value = resultSet.getObject(i);
String columnName = metaData.getColumnName(i);
String setMethod = "set" + columnName.substring(0, 1).toUpperCase() + columnName.substring(1);
Method method;
if (value instanceof Timestamp) {
method = clazz.getMethod(setMethod, Date.class);
} else {
method = clazz.getMethod(setMethod, value.getClass());
}
method.invoke(obj, value);
}
list.add(obj);
}
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
}
\ No newline at end of file
/*
* Ant Group
* Copyright (c) 2004-2023 All Rights Reserved.
*/
package cn.muyuan.mybatis.executor.resultset;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
/**
* 结果集处理器
*
* @author muyuan
* @version ResultSetHandler.java, v 0.1 2023年03月07日 19:52 muyuan
*/
public interface ResultSetHandler {
<E> List<E> handleResultSets(Statement stmt) throws SQLException;
}
\ No newline at end of file
/*
* Ant Group
* Copyright (c) 2004-2023 All Rights Reserved.
*/
package cn.muyuan.mybatis.executor.statement;
import cn.muyuan.mybatis.executor.Executor;
import cn.muyuan.mybatis.executor.resultset.ResultSetHandler;
import cn.muyuan.mybatis.mapping.BoundSql;
import cn.muyuan.mybatis.mapping.MappedStatement;
import cn.muyuan.mybatis.session.Configuration;
import cn.muyuan.mybatis.session.ResultHandler;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
/**
* 语句处理器抽象基类
*
* @author muyuan
* @version BaseStatementHandler.java, v 0.1 2023年03月07日 19:48 muyuan
*/
public abstract class BaseStatementHandler implements StatementHandler {
protected final Configuration configuration;
protected final Executor executor;
protected final MappedStatement mappedStatement;
protected final Object parameterObject;
protected final ResultSetHandler resultSetHandler;
protected BoundSql boundSql;
public BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, ResultHandler resultHandler,
BoundSql boundSql) {
this.configuration = mappedStatement.getConfiguration();
this.executor = executor;
this.mappedStatement = mappedStatement;
this.boundSql = boundSql;
this.parameterObject = parameterObject;
this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, boundSql);
}
@Override
public Statement prepare(Connection connection) throws SQLException {
Statement statement = null;
try {
// 实例化 Statement
statement = instantiateStatement(connection);
// 参数设置,可以被抽取,提供配置
statement.setQueryTimeout(350);
statement.setFetchSize(10000);
return statement;
} catch (Exception e) {
throw new RuntimeException("Error preparing statement. Cause: " + e, e);
}
}
/**
* 实例化 Statement
*
* @param connection Connection
* @return Statement
* @throws SQLException SQLException
*/
protected abstract Statement instantiateStatement(Connection connection) throws SQLException;
}
\ No newline at end of file
/*
* Ant Group
* Copyright (c) 2004-2023 All Rights Reserved.
*/
package cn.muyuan.mybatis.executor.statement;
import cn.muyuan.mybatis.executor.Executor;
import cn.muyuan.mybatis.mapping.BoundSql;
import cn.muyuan.mybatis.mapping.MappedStatement;
import cn.muyuan.mybatis.session.ResultHandler;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
/**
* 预处理语句处理器(PREPARED)
*
* @author muyuan
* @version PreparedStatementHandler.java, v 0.1 2023年03月07日 19:50 muyuan
*/
public class PreparedStatementHandler extends BaseStatementHandler {
public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement,
Object parameterObject, ResultHandler resultHandler, BoundSql boundSql) {
super(executor, mappedStatement, parameterObject, resultHandler, boundSql);
}
@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
String sql = boundSql.getSql();
return connection.prepareStatement(sql);
}
@Override
public void parameterize(Statement statement) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.setLong(1, Long.parseLong(((Object[]) parameterObject)[0].toString()));
}
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
return resultSetHandler.<E>handleResultSets(ps);
}
}
\ No newline at end of file
/*
* Ant Group
* Copyright (c) 2004-2023 All Rights Reserved.
*/
package cn.muyuan.mybatis.executor.statement;
import cn.muyuan.mybatis.executor.Executor;
import cn.muyuan.mybatis.mapping.BoundSql;
import cn.muyuan.mybatis.mapping.MappedStatement;
import cn.muyuan.mybatis.session.ResultHandler;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
/**
* 简单语句处理器(STATEMENT)
*
* @author muyuan
* @version SimpleStatementHandler.java, v 0.1 2023年03月07日 19:49 muyuan
*/
public class SimpleStatementHandler extends BaseStatementHandler {
public SimpleStatementHandler(Executor executor, MappedStatement mappedStatement,
Object parameterObject, ResultHandler resultHandler, BoundSql boundSql) {
super(executor, mappedStatement, parameterObject, resultHandler, boundSql);
}
@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
return connection.createStatement();
}
@Override
public void parameterize(Statement statement) throws SQLException {
}
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
String sql = boundSql.getSql();
statement.execute(sql);
return resultSetHandler.handleResultSets(statement);
}
}
\ No newline at end of file
/*
* Ant Group
* Copyright (c) 2004-2023 All Rights Reserved.
*/
package cn.muyuan.mybatis.executor.statement;
import cn.muyuan.mybatis.session.ResultHandler;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
/**
* 语句处理器
*
* @author muyuan
* @version StatementHandler.java, v 0.1 2023年03月07日 19:47 muyuan
*/
public interface StatementHandler {
/**
* 准备语句
*
* @param connection Connection
* @return Statement
* @throws SQLException SQLException
*/
Statement prepare(Connection connection) throws SQLException;
/**
* 参数化
*
* @param statement Statement
* @throws SQLException SQLException
*/
void parameterize(Statement statement) throws SQLException;
/**
* 执行查询
*
* @param statement Statement
* @param resultHandler ResultHandler
* @param <E> E
* @return List<E>
* @throws SQLException SQLException
*/
<E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException;
}
\ No newline at end of file
...@@ -8,8 +8,16 @@ import cn.muyuan.mybatis.binding.MapperRegistry; ...@@ -8,8 +8,16 @@ import cn.muyuan.mybatis.binding.MapperRegistry;
import cn.muyuan.mybatis.datasource.druid.DruidDataSourceFactory; import cn.muyuan.mybatis.datasource.druid.DruidDataSourceFactory;
import cn.muyuan.mybatis.datasource.pooled.PooledDataSourceFactory; import cn.muyuan.mybatis.datasource.pooled.PooledDataSourceFactory;
import cn.muyuan.mybatis.datasource.unpooled.UnpooledDataSourceFactory; import cn.muyuan.mybatis.datasource.unpooled.UnpooledDataSourceFactory;
import cn.muyuan.mybatis.executor.Executor;
import cn.muyuan.mybatis.executor.SimpleExecutor;
import cn.muyuan.mybatis.executor.resultset.DefaultResultSetHandler;
import cn.muyuan.mybatis.executor.resultset.ResultSetHandler;
import cn.muyuan.mybatis.executor.statement.PreparedStatementHandler;
import cn.muyuan.mybatis.executor.statement.StatementHandler;
import cn.muyuan.mybatis.mapping.BoundSql;
import cn.muyuan.mybatis.mapping.Environment; import cn.muyuan.mybatis.mapping.Environment;
import cn.muyuan.mybatis.mapping.MappedStatement; import cn.muyuan.mybatis.mapping.MappedStatement;
import cn.muyuan.mybatis.transaction.Transaction;
import cn.muyuan.mybatis.transaction.jdbc.JdbcTransactionFactory; import cn.muyuan.mybatis.transaction.jdbc.JdbcTransactionFactory;
import cn.muyuan.mybatis.type.TypeAliasRegistry; import cn.muyuan.mybatis.type.TypeAliasRegistry;
...@@ -101,4 +109,25 @@ public class Configuration { ...@@ -101,4 +109,25 @@ public class Configuration {
public void setEnvironment(Environment environment) { public void setEnvironment(Environment environment) {
this.environment = environment; this.environment = environment;
} }
/**
* 创建结果集处理器
*/
public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, BoundSql boundSql) {
return new DefaultResultSetHandler(executor, mappedStatement, boundSql);
}
/**
* 生产执行器
*/
public Executor newExecutor(Transaction transaction) {
return new SimpleExecutor(this, transaction);
}
/**
* 创建语句处理器
*/
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, ResultHandler resultHandler, BoundSql boundSql) {
return new PreparedStatementHandler(executor, mappedStatement, parameter, resultHandler, boundSql);
}
} }
\ No newline at end of file
/*
* Ant Group
* Copyright (c) 2004-2023 All Rights Reserved.
*/
package cn.muyuan.mybatis.session;
/**
* 结果处理器
*
* @author muyuan
* @version ResultHandler.java, v 0.1 2023年03月07日 20:03 muyuan
*/
public interface ResultHandler {
void handleResult();
}
\ No newline at end of file
...@@ -4,19 +4,11 @@ ...@@ -4,19 +4,11 @@
*/ */
package cn.muyuan.mybatis.session.defaults; package cn.muyuan.mybatis.session.defaults;
import cn.muyuan.mybatis.mapping.BoundSql; import cn.muyuan.mybatis.executor.Executor;
import cn.muyuan.mybatis.mapping.Environment;
import cn.muyuan.mybatis.mapping.MappedStatement; import cn.muyuan.mybatis.mapping.MappedStatement;
import cn.muyuan.mybatis.session.Configuration; import cn.muyuan.mybatis.session.Configuration;
import cn.muyuan.mybatis.session.SqlSession; import cn.muyuan.mybatis.session.SqlSession;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
/** /**
...@@ -29,63 +21,23 @@ public class DefaultSqlSession implements SqlSession { ...@@ -29,63 +21,23 @@ public class DefaultSqlSession implements SqlSession {
private Configuration configuration; private Configuration configuration;
public DefaultSqlSession(Configuration configuration) { private Executor executor;
public DefaultSqlSession(Configuration configuration, Executor executor) {
this.configuration = configuration; this.configuration = configuration;
this.executor = executor;
} }
@Override @Override
public <T> T selectOne(String statement) { public <T> T selectOne(String statement) {
return (T) ("你被代理了!" + statement); return this.selectOne(statement, null);
} }
@Override @Override
public <T> T selectOne(String statement, Object parameter) { public <T> T selectOne(String statement, Object parameter) {
try { MappedStatement ms = configuration.getMappedStatement(statement);
Environment environment = configuration.getEnvironment(); List<T> list = executor.query(ms, parameter, Executor.NO_RESULT_HANDLER, ms.getBoundSql());
Connection connection = environment.getDataSource().getConnection(); return list.get(0);
MappedStatement mappedStatement = configuration.getMappedStatement(statement);
BoundSql boundSql = mappedStatement.getBoundSql();
PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSql());
preparedStatement.setLong(1, Long.parseLong(((Object[]) parameter)[0].toString()));
ResultSet resultSet = preparedStatement.executeQuery();
List<T> objList = resultSet2Obj(resultSet, Class.forName(boundSql.getResultType()));
return objList.get(0);
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
private <T> List<T> resultSet2Obj(ResultSet resultSet, Class<?> clazz) {
List<T> list = new ArrayList<>();
try {
ResultSetMetaData metaData = resultSet.getMetaData();
int columnCount = metaData.getColumnCount();
// 每次遍历行值
while (resultSet.next()) {
T obj = (T) clazz.newInstance();
for (int i = 1; i <= columnCount; i++) {
Object value = resultSet.getObject(i);
String columnName = metaData.getColumnName(i);
String setMethod = "set" + columnName.substring(0, 1).toUpperCase() + columnName.substring(1);
Method method;
if (value instanceof Date) {
method = clazz.getMethod(setMethod, Date.class);
} else {
method = clazz.getMethod(setMethod, value.getClass());
}
method.invoke(obj, value);
}
list.add(obj);
}
} catch (Exception ex) {
ex.printStackTrace();
}
return list;
} }
@Override @Override
......
...@@ -4,9 +4,16 @@ ...@@ -4,9 +4,16 @@
*/ */
package cn.muyuan.mybatis.session.defaults; package cn.muyuan.mybatis.session.defaults;
import cn.muyuan.mybatis.executor.Executor;
import cn.muyuan.mybatis.mapping.Environment;
import cn.muyuan.mybatis.session.Configuration; import cn.muyuan.mybatis.session.Configuration;
import cn.muyuan.mybatis.session.SqlSession; import cn.muyuan.mybatis.session.SqlSession;
import cn.muyuan.mybatis.session.SqlSessionFactory; import cn.muyuan.mybatis.session.SqlSessionFactory;
import cn.muyuan.mybatis.session.TransactionIsolationLevel;
import cn.muyuan.mybatis.transaction.Transaction;
import cn.muyuan.mybatis.transaction.TransactionFactory;
import java.sql.SQLException;
/** /**
* 默认SqlSessionFactory实现类 * 默认SqlSessionFactory实现类
...@@ -24,6 +31,23 @@ public class DefaultSqlSessionFactory implements SqlSessionFactory { ...@@ -24,6 +31,23 @@ public class DefaultSqlSessionFactory implements SqlSessionFactory {
@Override @Override
public SqlSession openSession() { public SqlSession openSession() {
return new DefaultSqlSession(configuration); Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
TransactionFactory transactionFactory = environment.getTransactionFactory();
tx = transactionFactory.newTransaction(configuration.getEnvironment().getDataSource(), TransactionIsolationLevel.READ_COMMITTED,
false);
// 创建执行器
final Executor executor = configuration.newExecutor(tx);
// 创建DefaultSqlSession
return new DefaultSqlSession(configuration, executor);
} catch (Exception e) {
try {
assert tx != null;
tx.close();
} catch (SQLException ignore) {
}
throw new RuntimeException("Error opening session. Cause: " + e);
}
} }
} }
\ No newline at end of file
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
*/ */
package cn.muyuan.mybatis.test; package cn.muyuan.mybatis.test;
import cn.muyuan.mybatis.datasource.pooled.PooledDataSource;
import cn.muyuan.mybatis.io.Resources; import cn.muyuan.mybatis.io.Resources;
import cn.muyuan.mybatis.session.SqlSession; import cn.muyuan.mybatis.session.SqlSession;
import cn.muyuan.mybatis.session.SqlSessionFactory; import cn.muyuan.mybatis.session.SqlSessionFactory;
...@@ -17,8 +16,6 @@ import org.slf4j.Logger; ...@@ -17,8 +16,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
/** /**
* @author muyuan * @author muyuan
...@@ -39,25 +36,7 @@ public class ApiTest { ...@@ -39,25 +36,7 @@ public class ApiTest {
IUserDao userDao = sqlSession.getMapper(IUserDao.class); IUserDao userDao = sqlSession.getMapper(IUserDao.class);
// 3. 测试验证 // 3. 测试验证
for (int i = 0; i < 50; i++) { User user = userDao.queryUserInfoById(1L);
User user = userDao.queryUserInfoById(1L); LOGGER.info("测试结果:{}", JSON.toJSONString(user));
LOGGER.info("测试结果:{}", JSON.toJSONString(user));
}
}
@Test
public void test_pooled() throws SQLException, InterruptedException {
PooledDataSource pooledDataSource = new PooledDataSource();
pooledDataSource.setDriver("com.mysql.jdbc.Driver");
pooledDataSource.setUrl("jdbc:mysql://101.133.169.61:3306/mybatis?useUnicode=true&useSSL=false");
pooledDataSource.setUsername("root");
pooledDataSource.setPassword("123456");
// 持续获得链接
while (true){
Connection connection = pooledDataSource.getConnection();
System.out.println(connection);
Thread.sleep(1000);
connection.close();
}
} }
} }
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册