手写Mybatis:第7章-SQL执行器的定义和实现

文章目录

  • 一、目标:SQL执行的定义和实现
  • 二、设计:SQL执行的定义和实现
  • 三、实现:SQL执行的定义和实现
    • 3.1 工程结构
    • 3.2 SQL执行实现的关系图
    • 3.3 执行器的定义和实现
      • 3.3.1 Executor 接口
      • 3.3.2 BaseExecutor 抽象基类
      • 3.3.3 SimpleExecutor 简单执行器实现
    • 3.4 语句处理器
      • 3.4.1 StatementHandler 语句处理器接口
      • 3.4.2 BaseStatementHandler 抽象基类
      • 3.4.3 SimpleStatementHandler 简单语句处理器
      • 3.4.4 PreparedStatementHandler 预处理语句处理器
    • 3.5 结果处理器
      • 3.5.1 结果处理器接口
      • 3.5.2 结果集处理器接口
      • 3.5.3 默认Map结果集处理器实现类
    • 3.6 在配置项中添加执行器、语句处理器、结果处理器
    • 3.7 执行器创建和使用
      • 3.7.1 在 DefaultSqlSession 中开启执行器
      • 3.7.2 在 DefaultSqlSession 使用执行器
  • 四、测试:SQL执行的定义和实现
  • 五、总结:SQL执行的定义和实现

一、目标:SQL执行的定义和实现

💡 上一章节中关于池化数据源的调用、执行和结果封装,都是在 DefaultSqlSession 中进行发起。这样写死不利于扩展,也不利于 SqlSession 中每一个新增定义的方法对池化数据源的调用。怎么利于扩展呢?

在这里插入图片描述

  • 解耦 DefaultSqlSession#selectOne 方法中关于对数据源的调用、执行和结果封装,提供新的功能模块替代这部分编码的逻辑处理。
  • 只有提供单独的执行方法入口,才能更好的扩展和应对这部分内容的需求变化,包括:各类入参、结果封装、执行器类型、批处理等。

二、设计:SQL执行的定义和实现

💡 解耦:数据源的操作硬捆绑到 DefaultSqlSession 的执行方法上。

  • 单独提出一块执行器的服务功能,之后将执行器的功能随着 DefaultSqlSession 创建时传入执行器功能。
  • 之后具体的方法调用就可以调用执行器来处理,从而解耦这部分功能模块。

在这里插入图片描述

  • 首先提取出执行器的接口 Executor,定义出执行方法、事务获取和相应提交、回滚、关闭的定义。
    • 同时由于执行器是一种标准的执行过程,所以可以由抽象类进行实现,对过程内容进行 模板模式 的过程包装。
    • 在包装过程中定义抽象类 BaseExecutor,由具体的子类 SimpleExecutor 来实现。
  • 之后就是对 SQL 的处理,JDBC 在处理 SQL 时,分为简单处理和预处理。
    • 预处理:包括准备语句、参数化传递、执行查询,以及最后的结果封装和返回。
    • 所以这里把 JDBC 的这部分步骤,分为结构化的类过程实现,便于功能的扩展。
    • 结构化类:语句处理器 StatementHandler

三、实现:SQL执行的定义和实现

3.1 工程结构

mybatis-step-06
|-src|-main|	|-java|		|-com.lino.mybatis|			|-binding|			|	|-MapperMethod.java|			|	|-MapperProxy.java|			|	|-MapperProxyFactory.java|			|	|-MapperRegistry.java|			|-builder|			|	|-xml|			|	|	|-XMLConfigBuilder.java|			|	|-BaseBuilder.java|			|-datasource|			|	|-druid|			|	|	|-DruidDataSourceFacroty.java|			|	|-pooled|			|	|	|-PooledConnection.java|			|	|	|-PooledDataSource.java|			|	|	|-PooledDataSourceFacroty.java|			|	|	|-PoolState.java|			|	|-unpooled|			|	|	|-UnpooledDataSource.java|			|	|	|-UnpooledDataSourceFacroty.java|			|	|-DataSourceFactory.java|			|-executor|			|	|-resultset|			|	|	|-DefaultResultSetHandler.java|			|	|	|-ResultSetHandler.java|			|	|-statement|			|	|	|-BaseStatementHandler.java|			|	|	|-PreparedStatementHandler.java|			|	|	|-SimpleStatementHandler.java|			|	|	|-StatementHandler.java|			|	|-BaseExecutor.java|			|	|-Executor.java|			|	|-SimpleExecutor.java|			|-io|			|	|-Resources.java|			|-mapping|			|	|-BoundSql.java|			|	|-Environment.java|			|	|-MappedStatement.java|			|	|-ParameterMapping.java|			|	|-SqlCommandType.java|			|-session|			|	|-defaults|			|	|	|-DefaultSqlSession.java|			|	|	|-DefaultSqlSessionFactory.java|			|	|-Configuration.java|			|	|-ResultHandler.java|			|	|-SqlSession.java|			|	|-SqlSessionFactory.java|			|	|-SqlSessionFactoryBuilder.java|			|	|-TransactionIsolationLevel.java|			|-transaction|			|	|-jdbc|			|	|	|-JdbcTransaction.java|			|	|	|-JdbcTransactionFactory.java|			|	|-Transaction.java|			|	|-TransactionFactory.java|			|-type|			|	|-JdbcType.java|			|	|-TypeAliasRegistry.java|-test|-java|	|-com.lino.mybatis.test|	|-dao|	|	|-IUserDao.java|	|-po|	|	|-User.java|	|-ApiTest.java|-resources|-mapper|	|-User_Mapper.xml|-mybatis-config-datasource.xml

3.2 SQL执行实现的关系图

在这里插入图片描述

  • Executor 接口定义为执行器入口,确定出事务和操作和 SQL 执行的统一标准接口。
    • 并以执行器接口定义实现抽象类 BaseExecutor,也就是用抽象类处理统一共用的事务和执行 SQL 的标准流程。
    • 也就是这里定义的执行 SQL 的抽象接口由子类 SimpleExecutor 实现。
  • 在具体的简单 SQL 执行器实现类中,处理 doQuery 方法的具体操作过程。
    • 这个过程中则会引入进来 SQL 语句处理器的创建,创建过程仍由 Configuration 配置项提供。
  • 当执行器开发完成之后,接下来就交给 DefaultSqlSessionFactory 开启 openSession 的时候随着构造函数参数传递给 DefaultSqlSession 中,这样在执行 DefaultSqlSession#selectOne 的时候就可以调用执行器进行处理。这也就完成 解耦 操作。

3.3 执行器的定义和实现

  • 执行器分为接口、抽象类、简单执行器实现类三部分。这就是 模板模式
  • 模板模式:通常在框架的源码中对于一些标准流程的处理,都会有抽象类的存在。它负责提供共性功能逻辑,以及对接口方法的执行过程进行定义和处理,并提取抽象接口交由子类实现。

3.3.1 Executor 接口

Executor.java

package com.lino.mybatis.executor;import com.lino.mybatis.mapping.BoundSql;
import com.lino.mybatis.mapping.MappedStatement;
import com.lino.mybatis.session.ResultHandler;
import com.lino.mybatis.transaction.Transaction;
import java.sql.SQLException;
import java.util.List;/*** @description: 执行器*/
public interface Executor {/*** 结果处理器*/ResultHandler NO_RESULT_HANDLER = null;/*** 查询** @param ms            映射器语句* @param parameter     参数* @param resultHandler 结果处理器* @param boundSql      SQL对象* @param <E>           返回的类型* @return List<E>*/<E> List<E> query(MappedStatement ms, Object parameter, ResultHandler resultHandler, BoundSql boundSql);/*** 获取事务** @return 事务对象*/Transaction getTransaction();/*** 提交** @param required 是否请求执行* @throws SQLException SQL异常*/void commit(boolean required) throws SQLException;/*** 回滚** @param required 是否请求执行* @throws SQLException SQL异常*/void rollback(boolean required) throws SQLException;/*** 关闭** @param forceRollback 是否强制回滚*/void close(boolean forceRollback);
}
  • 在执行器中的定义的接口包括:事务相关的处理方法、执行 SQL 查询的操作。

3.3.2 BaseExecutor 抽象基类

BaseExecutor.java

package com.lino.mybatis.executor;import com.lino.mybatis.mapping.BoundSql;
import com.lino.mybatis.mapping.MappedStatement;
import com.lino.mybatis.session.Configuration;
import com.lino.mybatis.session.ResultHandler;
import com.lino.mybatis.transaction.Transaction;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
import java.util.List;/*** @description: 执行器抽象基类*/
public abstract class BaseExecutor implements Executor {private org.slf4j.Logger logger = LoggerFactory.getLogger(BaseExecutor.class);protected Configuration configuration;protected Transaction transaction;protected Executor wrapper;private boolean closed;public BaseExecutor(Configuration configuration, Transaction transaction) {this.configuration = configuration;this.transaction = transaction;this.wrapper = this;}@Overridepublic <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);@Overridepublic Transaction getTransaction() {if (closed) {throw new RuntimeException("Executor was closed.");}return transaction;}@Overridepublic void commit(boolean required) throws SQLException {if (closed) {throw new RuntimeException("Cannot commit, transaction is already closed.");}if (required) {transaction.commit();}}@Overridepublic void rollback(boolean required) throws SQLException {if (!closed) {if (required) {transaction.rollback();}}}@Overridepublic 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;}}
}
  • 在抽象基类中封装了执行器的全部接口,这样具体的子类继承抽象类后,就不用处理这些共性的方法。
  • 与此同时在 query 查询方法中,封装了一些必要的流程处理,如检测关闭等。

3.3.3 SimpleExecutor 简单执行器实现

SimpleExecutor.java

package com.lino.mybatis.executor;import com.lino.mybatis.executor.statement.StatementHandler;
import com.lino.mybatis.mapping.BoundSql;
import com.lino.mybatis.mapping.MappedStatement;
import com.lino.mybatis.session.Configuration;
import com.lino.mybatis.session.ResultHandler;
import com.lino.mybatis.transaction.Transaction;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;/*** @description: 简单执行器*/
public class SimpleExecutor extends BaseExecutor {public SimpleExecutor(Configuration configuration, Transaction transaction) {super(configuration, transaction);}@Overrideprotected <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;}}
}
  • 简单执行器 SimpleExecutor 继承抽象基类,实现抽象方法 doQuery
    • 这个方法包装:数据源的获取、语句处理器的创建,以及对 Statement 的实例化和相关参数设置。最后执行 SQL 的处理和结果的返回操作。

3.4 语句处理器

  • 语句处理器是 SQL 执行器中依赖的部分,SQL 执行器封装事务、连接和检测环境等。
  • 而语句处理器则是准备语句、参数化传递、执行 SQL、封装结果的处理。

3.4.1 StatementHandler 语句处理器接口

StatementHandler.java

package com.lino.mybatis.executor.statement;import com.lino.mybatis.session.ResultHandler;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;/*** @description: 语句处理器*/
public interface StatementHandler {/*** 准备语句** @param connection 链接* @return Statement语句*/Statement prepare(Connection connection);/*** 参数化** @param statement 语句*/void parameterize(Statement statement) throws SQLException;/*** 执行查询** @param statement     语句* @param resultHandler 结果处理器* @param <E>           泛型类型* @return 泛型集合*/<E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException;
}
  • 语句处理器的核心包括:准备语句、参数化传递参数、执行查询的操作。
  • Mybatis 源码中还包括 update、批处理、获取参数处理器等。

3.4.2 BaseStatementHandler 抽象基类

BaseStatementHandler.java

package com.lino.mybatis.executor.statement;import com.lino.mybatis.executor.Executor;
import com.lino.mybatis.executor.resultset.ResultSetHandler;
import com.lino.mybatis.mapping.BoundSql;
import com.lino.mybatis.mapping.MappedStatement;
import com.lino.mybatis.session.Configuration;
import com.lino.mybatis.session.ResultHandler;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;/*** @description: 语句处理器抽象基类*/
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.parameterObject = parameterObject;this.boundSql = boundSql;this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, boundSql);}@Overridepublic Statement prepare(Connection connection) {Statement statement = null;try {// 实例化 Statementstatement = instantiateStatement(connection);// 参数设置,可以被抽取,提供配置statement.setQueryTimeout(350);statement.setFetchSize(10000);return statement;} catch (Exception e) {throw new RuntimeException("Error prepare statement. Cause: " + e, e);}}protected abstract Statement instantiateStatement(Connection connection) throws SQLException;}
  • 在语句处理器基类中,将参数信息、结果信息进行封装处理。
  • 之后是对 BaseStatementHandler#prepare 方法的处理,包括定义实例化抽象方法,这个方法交由各个具体的子类进行处理。
    • SimpleStatementHandler 简单语句处理器:只是对 SQL 的最基本执行,没有参数的设置。
    • PreparedStatementHandler 预处理语句处理器:是我们在 JDBC 中使用的最多的操作方式,PreparedStatement 设置 SQL,传递参数的设置过程。

3.4.3 SimpleStatementHandler 简单语句处理器

SimpleStatementHandler.java

package com.lino.mybatis.executor.statement;import com.lino.mybatis.executor.Executor;
import com.lino.mybatis.executor.resultset.ResultSetHandler;
import com.lino.mybatis.mapping.BoundSql;
import com.lino.mybatis.mapping.MappedStatement;
import com.lino.mybatis.session.ResultHandler;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;/*** @description: 简单语句处理器(STATEMENT)*/
public class SimpleStatementHandler extends BaseStatementHandler {public SimpleStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, ResultHandler resultHandler, BoundSql boundSql) {super(executor, mappedStatement, parameterObject, resultHandler, boundSql);}@Overrideprotected Statement instantiateStatement(Connection connection) throws SQLException {return connection.createStatement();}@Overridepublic void parameterize(Statement statement) {}@Overridepublic <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {String sql = boundSql.getSql();statement.execute(sql);return resultSetHandler.handleResultSets(statement);}
}
  • 简单语句处理器:只是对 SQL 的最基本执行,没有参数的设置。

3.4.4 PreparedStatementHandler 预处理语句处理器

PreparedStatementHandler.java

package com.lino.mybatis.executor.statement;import com.lino.mybatis.executor.Executor;
import com.lino.mybatis.executor.resultset.ResultSetHandler;
import com.lino.mybatis.mapping.BoundSql;
import com.lino.mybatis.mapping.MappedStatement;
import com.lino.mybatis.session.ResultHandler;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;/*** @description: 预处理语句处理器(PREPARED)* @author: lingjian* @createDate: 2022/11/8 14:13*/
public class PreparedStatementHandler extends BaseStatementHandler {public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, ResultHandler resultSetHandler, BoundSql boundSql) {super(executor, mappedStatement, parameterObject, resultSetHandler, boundSql);}@Overrideprotected Statement instantiateStatement(Connection connection) throws SQLException {String sql = boundSql.getSql();return connection.prepareStatement(sql);}@Overridepublic void parameterize(Statement statement) throws SQLException {PreparedStatement ps = (PreparedStatement) statement;ps.setLong(1, Long.parseLong(((Object[]) parameterObject)[0].toString()));}@Overridepublic <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {PreparedStatement ps = (PreparedStatement) statement;ps.execute();return resultSetHandler.handleResultSets(ps);}
}
  • 在预处理语句处理器中包括 instantiateStatement 预处理 SQLparameterize 设置参数,以及 query 查询的执行操作。
  • parameterize 暂时是写死的处理,后续再完善。
  • query 是执行查询和对结果的封装,结果的封装,后续再完善。

3.5 结果处理器

💡 定义结果处理器接口,结果集处理器接口,默认Map结果集处理器实现类

3.5.1 结果处理器接口

ResultHandler.java

package com.lino.mybatis.session;/*** @description: 结果处理器*/
public interface ResultHandler {/*** 处理结果*/void handleResult();
}

3.5.2 结果集处理器接口

ResultSetHandler.java

package com.lino.mybatis.executor.resultset;import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;/*** @description: 结果集处理器*/
public interface ResultSetHandler {/*** 处理结果集** @param stmt 语句* @param <E>  泛型* @return 泛型集合* @throws SQLException SQL异常*/<E> List<E> handleResultSets(Statement stmt) throws SQLException;
}

3.5.3 默认Map结果集处理器实现类

DefaultResultSetHandler.java

package com.lino.mybatis.executor.resultset;import com.lino.mybatis.executor.Executor;
import com.lino.mybatis.mapping.BoundSql;
import com.lino.mybatis.mapping.MappedStatement;
import java.lang.reflect.Method;
import java.sql.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;/*** @description: 默认Map结果处理器*/
public class DefaultResultSetHandler implements ResultSetHandler {private final BoundSql boundSql;public DefaultResultSetHandler(Executor executor, MappedStatement mappedStatement, BoundSql boundSql) {this.boundSql = boundSql;}@Overridepublic <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, LocalDateTime.class);} else {method = clazz.getMethod(setMethod, value.getClass());}method.invoke(obj, value);}list.add(obj);}} catch (Exception e) {e.printStackTrace();}return list;}
}

3.6 在配置项中添加执行器、语句处理器、结果处理器

Configuration.java

package com.lino.mybatis.session;import com.lino.mybatis.binding.MapperRegistry;
import com.lino.mybatis.datasource.druid.DruidDataSourceFactory;
import com.lino.mybatis.datasource.pooled.PooledDataSourceFactory;
import com.lino.mybatis.datasource.unpooled.UnpooledDataSourceFactory;
import com.lino.mybatis.executor.Executor;
import com.lino.mybatis.executor.SimpleExecutor;
import com.lino.mybatis.executor.resultset.DefaultResultSetHandler;
import com.lino.mybatis.executor.resultset.ResultSetHandler;
import com.lino.mybatis.executor.statement.PreparedStatementHandler;
import com.lino.mybatis.executor.statement.StatementHandler;
import com.lino.mybatis.mapping.BoundSql;
import com.lino.mybatis.mapping.Environment;
import com.lino.mybatis.mapping.MappedStatement;
import com.lino.mybatis.transaction.Transaction;
import com.lino.mybatis.transaction.jdbc.JdbcTransactionFactory;
import com.lino.mybatis.type.TypeAliasRegistry;
import java.util.HashMap;
import java.util.Map;/*** @description: 配置项* @author: lingjian* @createDate: 2022/11/7 21:32*/
public class Configuration {//省略.../*** 生产执行器** @param transaction 事务* @return 执行器*/public Executor newExecutor(Transaction transaction) {return new SimpleExecutor(this, transaction);}/*** 创建语句处理器** @param executor        执行器* @param mappedStatement 映射器语句类* @param parameter       参数* @param resultHandler   结果处理器* @param boundSql        SQL语句* @return StatementHandler 语句处理器*/public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, ResultHandler resultHandler, BoundSql boundSql) {return new PreparedStatementHandler(executor, mappedStatement, parameter, resultHandler, boundSql);}/*** 创建结果集处理器** @param executor        执行器* @param mappedStatement 映射器语句类* @param boundSql        SQL语句* @return ResultSetHandler 结果集处理器*/public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, BoundSql boundSql) {return new DefaultResultSetHandler(executor, mappedStatement, boundSql);}
}

3.7 执行器创建和使用

  • 执行器开发完成以后,则需要串联到 DefaultSqlSession 中进行使用。
  • 串联过程:在创建 DefaultSqlSession 的时候,构建出执行器并作为参数传递进去。这里涉及到 DefaultSqlSessionFactory#openSession 的处理。

3.7.1 在 DefaultSqlSession 中开启执行器

DefaultSqlSession.java

package com.lino.mybatis.session.defaults;import com.lino.mybatis.executor.Executor;
import com.lino.mybatis.mapping.Environment;
import com.lino.mybatis.session.Configuration;
import com.lino.mybatis.session.SqlSession;
import com.lino.mybatis.session.SqlSessionFactory;
import com.lino.mybatis.session.TransactionIsolationLevel;
import com.lino.mybatis.transaction.Transaction;
import com.lino.mybatis.transaction.TransactionFactory;
import java.sql.SQLException;/*** @description: 默认的SqlSessionFactory实现类*/
public class DefaultSqlSessionFactory implements SqlSessionFactory {private final Configuration configuration;public DefaultSqlSessionFactory(Configuration configuration) {this.configuration = configuration;}@Overridepublic SqlSession openSession() {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);// 创建 DefaultSqlSessionreturn new DefaultSqlSession(configuration, executor);} catch (Exception e) {try {assert tx != null;tx.close();} catch (SQLException ignore) {}throw new RuntimeException("Error opening session. Cause: " + e);}}
}
  • openSession 中开启事务传递给执行器的创建。并在执行器创建完毕后,作为参数传递给 DefaultSqlSession

3.7.2 在 DefaultSqlSession 使用执行器

DefaultSqlSession.java

package com.lino.mybatis.session.defaults;import com.lino.mybatis.executor.Executor;
import com.lino.mybatis.mapping.BoundSql;
import com.lino.mybatis.mapping.Environment;
import com.lino.mybatis.mapping.MappedStatement;
import com.lino.mybatis.session.Configuration;
import com.lino.mybatis.session.SqlSession;
import java.lang.reflect.Method;
import java.sql.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;/*** @description: 默认sqlSession实现类*/
public class DefaultSqlSession implements SqlSession {private Configuration configuration;private Executor executor;public DefaultSqlSession(Configuration configuration, Executor executor) {this.configuration = configuration;this.executor = executor;}@Overridepublic <T> T selectOne(String statement) {return (T) ("你被代理了!" + statement);}@Overridepublic <T> T selectOne(String statement, Object parameter) {MappedStatement ms = configuration.getMappedStatement(statement);List<T> list = executor.query(ms, parameter, Executor.NO_RESULT_HANDLER, ms.getBoundSql());return list.get(0);}@Overridepublic <T> T getMapper(Class<T> type) {return configuration.getMapper(type, this);}@Overridepublic Configuration getConfiguration() {return configuration;}
}
  • DefaultSqlSession#selectOne 中获取 MappedStatement 映射语句后,则传递给执行器进行处理。
  • 那么现在这些类经过设计思想的解耦后,就变得更加干净整洁了,也易于维护和扩展了。

四、测试:SQL执行的定义和实现

ApiTest.java

@Test
public void test_SqlSessionFactoryExecutor() throws IOException {// 1.从SqlSessionFactory中获取SqlSessionSqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config-datasource.xml"));SqlSession sqlSession = sqlSessionFactory.openSession();// 2.获取映射器对象IUserDao userDao = sqlSession.getMapper(IUserDao.class);// 3.测试验证User user = userDao.queryUserInfoById(1L);logger.info("测试结果:{}", JSON.toJSONString(user));
}

测试结果

16:40:58.484 [main] INFO  c.l.m.d.pooled.PooledDataSource - PooledDataSource forcefully closed/removed all connections.
16:40:59.195 [main] INFO  c.l.m.d.pooled.PooledDataSource - Created connention 1436664465.
16:40:59.262 [main] INFO  com.lino.mybatis.test.ApiTest - 测试结果:{"id":1,"userHead":"1_04","userId":"10001","userName":"小灵哥"}
  • 从测试结果看我们已经把 DefaultSqlSession#selectOne 中的调用,换成执行器完成整个过程的处理,解耦了部分的逻辑操作,方便后续的扩展。

五、总结:SQL执行的定义和实现

  • 整个实现都是处理解耦这件事情,从 DefaultSqlSession#selectOne 对数据源的处理解耦到执行器中进行操作。而执行器中又包括了对 JDBC 处理的拆解,链接、准备语句、封装参数、处理结果,所有的这些过程经过解耦后的类和方法,在后续方便进行扩展。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/62812.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GPU版本pytorch(Cuda12.1)安装教程

我们通过Pytorch官网安装torch的时候&#xff0c;会发现常常由于网速问题安装不成功&#xff0c;下面提供一种简单的方法可以成功安装Cuda12.1&#xff0c;亲测有效。 目录 一、常规方法 二、有效方法 2.1 创建并激活虚拟环境 2.2 添加清华源 2.3 安装torch 一、常规方法…

xsschallenge通关(11-15)

level 11 老规矩&#xff0c;先查看源码&#xff0c;做代码审计&#xff1a; <?php ini_set("display_errors", 0); $str $_GET["keyword"]; $str00 $_GET["t_sort"]; $str11$_SERVER[HTTP_REFERER]; $str22str_replace(">&quo…

Linux centos7 bash编程(小练习)

一、打印九九乘法口诀 这一个for循环嵌套的小练习&#xff0c;难度不大。提供一种写法&#xff0c;供参考&#xff1a; #!/bin/bash # 文件名&#xff1a;99table.sh # 打印输出九九乘法口诀表 for i in {1..9} do for ((j1;j<$i;j)) do …

雅思写作 三小时浓缩学习顾家北 笔记总结(三)

目录 顾家北饥饿网100个句子翻译 "Heritage sites threatened by urban development" "Heritage sites are threatened by urban development." We should not ignore face-to-face communication. We cannot ignore face-to-face communication. So…

使用Python对数据的操作转换

1、列表加值转字典 在Python中&#xff0c;将列表的值转换为字典的键可以使用以下代码&#xff1a; myList ["name", "age", "location"] myDict {k: None for k in myList} print(myDict) 输出&#xff1a; {name: None, age: None, loca…

给oracle逻辑导出clob大字段、大数据量表提提速

文章目录 前言一、大表数据附&#xff1a;查询大表 二、解题思路1.导出排除大表的数据2.rowid切片导出大表数据Linux代码如下&#xff08;示例&#xff09;&#xff1a;Windows代码如下&#xff08;示例&#xff09;&#xff1a;手工执行代码如下&#xff08;示例&#xff09;&…

C++11——右值引用和移动语义

✅<1>主页&#xff1a;&#xff1a;我的代码爱吃辣 &#x1f4c3;<2>知识讲解&#xff1a;C11——右值引用 ☂️<3>开发环境&#xff1a;Visual Studio 2022 &#x1f4ac;<4>前言&#xff1a;右值引用&#xff0c;是C11更新的一个非常有价值的语法&am…

【网络安全防护】上海道宁与Bitdefender帮助您构建弹性网络并降低安全运营成本

在网络的世界中 风险变得更加常见与复杂 企业需要从网络安全转向网络弹性 复杂的网络攻击已非常普遍 在面临攻击时 企业如何保持业务连续性&#xff1f; Bitdefender GravityZone将 风险分析、安全加固、威胁预防 检测和响应功能相结合 帮助您构建弹性网络 并降低安全…

LinkedHashMap实现LRU缓存cache机制,Kotlin

LinkedHashMap实现LRU缓存cache机制&#xff0c;Kotlin LinkedHashMap的accessOrdertrue后&#xff0c;访问LinkedHashMap里面存储的元素&#xff0c;LinkedHashMap就会把该元素移动到最尾部。利用这一点&#xff0c;可以设置一个缓存的上限值&#xff0c;当存入的缓存数理超过…

手摸手2-springboot编写基础的增删改查

目录 手摸手2-springboot编写基础的增删改查创建controller层添加service层接口service层实现添加mapper层mapper层对应的sql添加扫描注解,对应sql文件的目录 手摸手2-springboot编写基础的增删改查 创建controller层 实现 test 表中的添加、修改、删除及列表查询接口&#x…

Unity——工程与资源

本文将详细介绍Unity工程的文件夹结构&#xff0c;以及动态加载资源的技术要点 一、Unity项目的文件夹结构 1.工程文件夹 在新建工程时&#xff0c;Unity会创建所有必要的文件夹。第一级文件夹有Assets,Library,Logs,Packages,ProjectSettings。 Assets&#xff1a;最主要的文…

stable diffusion实践操作-提示词插件安装与使用

本文专门开一节写提示词相关的内容&#xff0c;在看之前&#xff0c;可以同步关注&#xff1a; stable diffusion实践操作 正文 1、提示词插件安装 1.1、 安装 1.2 加载【应用更改并重载前端】 1.3 界面展示 1.3.-4 使用 里面有个收藏列表&#xff0c;可以收藏以前的所有提示…

CSC2121A

半桥架构的栅极驱动电路CSC2121A CSC2121系列是一款高性价比的半桥架构的栅极驱动专用电路&#xff0c;用于大功率MOS管、IGBT管栅极驱动。IC内部集成了逻辑信号处理电路、死区时间控制电路、欠压保护电路、电平位移电路、脉冲滤波电路及输出驱动电路&#xff0c;专用于无刷电…

10 行代码能做什么?

10 行代码能做什么&#xff1f; 写一串 SQL Join&#xff0c;统计全渠道市场营销的 ROI 用 JS 画个饼图&#xff0c;展示最有效的广告投放策略 用 Python 写段算法&#xff0c;分析销量骤降的原因是什么 …… 数据出错了&#xff0c;写个对数脚本 -_-|| AI 时代&#xff0c;…

Zookeeper的使用

一、Zookeeper简介 分布式协调框架&#xff0c;小型的树形结构数据共享储存系统。 zookeeper的应用场景 集群管理 注册中心 配置中心 发布者将数据发布到ZooKeeper一系列节点上面&#xff0c;订阅者进行数据订阅&#xff0c;当数据有变化时&#xff0c;可及时得到数据的变…

指针(个人学习笔记黑马学习)

1、指针的定义和使用 #include <iostream> using namespace std;int main() {int a 10;int* p;p &a;cout << "a的地址为&#xff1a;" << &a << endl;cout << "a的地址为&#xff1a;" << p << endl;…

promethues监控postgres,emqx,redis

一、监控postgres 1、安装监控 docker pull wrouesnel/postgres_exporter2、执行 docker run -d -p 9187:9187 --name postgres_exporter --nethost -d -e DATA_SOURCE_NAME"postgresql://postgres:123456192.168.12.116:5432/rcc-manage?sslmodedisable" wroues…

centos 7的超详细安装教程

打开虚拟机&#xff0c;创建一个新电脑 我们选择经典&#xff0c;然后选择下一步 我们选择稍后安装&#xff0c;我们在后面进行改设备 因为centos系统是linux系统的一个版本&#xff0c;所有我们选择linux&#xff0c;版本选择centos 7 64位&#xff0c;然后就是点击下一步 这一…

四、MySQL(表操作)如何添加字段?修改表?删除字段?修改表名?删除表?格式化某张表?

1、添加字段 &#xff08;1&#xff09;基础语法&#xff1a; alter table 表名 add 字段名 类型名(长度) [comment注释] [约束]; &#xff08;2&#xff09;示例&#xff1a;添加nickname这个字段 2、修改表 修改表中某个字段的【数据类型】/【数据类型&字段名】 &…

Microsoft Edge 主页启动diy以及常用的扩展、收藏夹的网站

一、Microsoft Edge 主页启动diy 二、常用的扩展 1、去广告&#xff1a;uBlock Origin 2、翻译&#xff1a; 页面翻译&#xff1a;右键就有了&#xff0c;已经内置了划词翻译 3、超级复制 三、收藏夹的网站