MyBatis 之 StatementHandler 来执行 SQL 语句
2021/7/22 19:11:40
本文主要是介绍MyBatis 之 StatementHandler 来执行 SQL 语句,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
MyBatis 之 StatementHandler 来执行 SQL 语句
- 简介
- 类图
- 方法解读
- RountingStatementHandler
- BaseStatementHandler
- SimpleStatementHandler
- PreparedStatementHandler
- CallableStatementHandler
简介
使用原生的 JDBC API 来执行 SQL,需要经历加、连、语、执、释
步骤。如下:
private static void query() throws Exception { // 加载驱动(可以不显示加载,因为引入 MySQL 驱动之后会通过 SPI自动加载) Class.forName("com.mysql.jdbc.Driver"); // 获取连接 Connection connection = DriverManager.getConnection("jdbc:mysql:///test", "root", "admin"); // 预编译语句 PreparedStatement statement = connection.prepareStatement("SELECT * FROM user WHERE id = ?"); // 设置参数 statement.setLong(1, 1); // 执行 SQL ResultSet resultSet = statement.executeQuery(); ResultSetMetaData metaData = resultSet.getMetaData(); int columnCount = metaData.getColumnCount(); while (resultSet.next()) { for (int i = 1; i <= columnCount; i++) { String columnName = metaData.getColumnName(i); String columnValue = resultSet.getString(columnName); System.out.println(columnName + " : " + columnValue); } } // 关闭 statement.close(); connection.close(); }
在使用 MyBatis 框架的时候我们无感知,并没有如上一系列操作。只需要编写 Mapper.xml 中的 SQL 语句即可。在前面我们已经学习了 SQL 语句抽象 和 根据实参获取 SQL 语句 ,现在我们学习在获取 SQL 之后用 StatementHandler 来处理 。
类图
- RoutingStatementHandler:如其类名具有路由功能,MyBatis 框架内部根据 MappedStatement 中的 StatementType 类型来获取对应的 PreparedStatementHandler、CallableStatementHandler 和 SimpleStatementHandler 实例。
- BaseStatementHandler:实现了 prepare 方法通用逻辑,通过定义 instantiateStatement 模板方法以获得不同的 Statement 实例并设置超时时间和从数据库获取数据数量。
- SimpleStatementHandler:对应 JDBC Statement(静态 SQL 语句)
- PreparedStatementHandler:对应 JDBC PreparedStatement(预编译 SQL 语句)
- CallableStatementHandler:对应 JDBC CallableStatement(存储过程)
方法解读
- Statement prepare(Connection connection, Integer transactionTimeout):通过 Connection 实例获取 Statement 对象
- void parameterize(Statement statement):为 Statement 对象设置参数,特别是 PreparedStatement 设置 ? 占位符对应的实参
- void batch(Statement statement):添加批量数据
- int update(Statement statement):通过 Statement 实例来执行修改(增、删、改)操作
- <E> List<E> query(Statement statement, ResultHandler resultHandler):查询并处理结果集
- <E> List<E> queryCursor(Statement statement):游标
- BoundSql getBoundSql():获取底层关联的 SQL与参数元信息对象
- ParameterHandler getParameterHandler():获取底层关联的参数处理器
RountingStatementHandler
MyBatis 框架内部使用此类来处理 Statement, 内部通过创建 SimpleStatementHandler、PreparedStatementHandler 和 CallableStatementHandler 对象进行正真的处理
// 通过构造 RoutingStatementHandler 时候根据 StatementType 来创建对应的 StatementHandler // 在 Mapper.xml 中 insert/update/delete/select 标签中有 statementType 属性进行设置,默认是 PREPARED public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { switch (ms.getStatementType()) { case STATEMENT: delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; case PREPARED: delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; case CALLABLE: delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; default: throw new ExecutorException("Unknown statement type: " + ms.getStatementType()); } }
BaseStatementHandler
StatementHandler 通用实现,如 getBoundSql、getParameterHandler 以及 prepare 方法,通过定义 instantiateStatement(Connection connection) 模板方法来获取不同类型的 Statment 实例。
public abstract class BaseStatementHandler implements StatementHandler { // MyBatis 全局配置对象 protected final Configuration configuration; // 对象工厂 protected final ObjectFactory objectFactory; // 类型处理器注册表 protected final TypeHandlerRegistry typeHandlerRegistry; // 结果集处理器 protected final ResultSetHandler resultSetHandler; // 参数处理器 protected final ParameterHandler parameterHandler; // 执行器 protected final Executor executor; // XML insert/update/select/delete 标签所有元信息对象 protected final MappedStatement mappedStatement; // 分页设置 protected final RowBounds rowBounds; // SQL 语句和参数映射等元信息 protected BoundSql boundSql; protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { this.configuration = mappedStatement.getConfiguration(); this.executor = executor; this.mappedStatement = mappedStatement; this.rowBounds = rowBounds; this.typeHandlerRegistry = configuration.getTypeHandlerRegistry(); this.objectFactory = configuration.getObjectFactory(); if (boundSql == null) { generateKeys(parameterObject); boundSql = mappedStatement.getBoundSql(parameterObject); } this.boundSql = boundSql; this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql); this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql); } }
SimpleStatementHandler
简单语句处理,对应 JDBC Statement(静态 SQL),所有涉及数据库操作则通过调用 Statement API
public class SimpleStatementHandler extends BaseStatementHandler { public SimpleStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql); } @Override public int update(Statement statement) throws SQLException { // 通过 BoundSql 获取 SQL 语句,然后调用 JDBC Statement API 执行操作 // 根据主键生成策略不同回填主键值 String sql = boundSql.getSql(); Object parameterObject = boundSql.getParameterObject(); KeyGenerator keyGenerator = mappedStatement.getKeyGenerator(); int rows; if (keyGenerator instanceof Jdbc3KeyGenerator) { statement.execute(sql, Statement.RETURN_GENERATED_KEYS); rows = statement.getUpdateCount(); keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject); } else if (keyGenerator instanceof SelectKeyGenerator) { statement.execute(sql); rows = statement.getUpdateCount(); keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject); } else { statement.execute(sql); rows = statement.getUpdateCount(); } return rows; } @Override public void batch(Statement statement) throws SQLException { String sql = boundSql.getSql(); statement.addBatch(sql); } @Override public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException { // 通过 BoundSql 获取 SQL 语句,然后调用 JDBC Statement API 执行操作并对结果集进行处理 String sql = boundSql.getSql(); statement.execute(sql); return resultSetHandler.handleResultSets(statement); } @Override public <E> Cursor<E> queryCursor(Statement statement) throws SQLException { // 通过 BoundSql 获取 SQL 语句,然后调用 JDBC Statement API 执行操作并对结果集进行处理 String sql = boundSql.getSql(); statement.execute(sql); return resultSetHandler.handleCursorResultSets(statement); } @Override protected Statement instantiateStatement(Connection connection) throws SQLException { // 通过原生 JDBC Connectio API 创建 Statement 对象设置相应的结果集类型 // select 标签可以设置 resultSetType 属性为 FORWARD_ONLY、SCROLL_INSENSITIVE 、SCROLL_SENSITIVE if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) { return connection.createStatement(); } else { // 设置 select 标签里面的 resultSetType,并把结果集的并发模型设置为只读 return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY); } } @Override public void parameterize(Statement statement) { // N/A // 静态 SQL 不存在设置参数空实现 } }
PreparedStatementHandler
public class PreparedStatementHandler extends BaseStatementHandler { public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql); } @Override public int update(Statement statement) throws SQLException { // 调用 JDBC PreparedStatement API 执行操作 // 根据主键生成策略不同回填主键值 PreparedStatement ps = (PreparedStatement) statement; ps.execute(); int rows = ps.getUpdateCount(); Object parameterObject = boundSql.getParameterObject(); KeyGenerator keyGenerator = mappedStatement.getKeyGenerator(); keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject); return rows; } @Override public void batch(Statement statement) throws SQLException { PreparedStatement ps = (PreparedStatement) statement; ps.addBatch(); } @Override public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException { // 调用 JDBC PreparedStatement API 执行操作 // 使用结果处理器对结果集进行处理 PreparedStatement ps = (PreparedStatement) statement; ps.execute(); return resultSetHandler.handleResultSets(ps); } @Override public <E> Cursor<E> queryCursor(Statement statement) throws SQLException { // 调用 JDBC PreparedStatement API 执行操作 // 使用结果处理器对结果集进行处理 PreparedStatement ps = (PreparedStatement) statement; ps.execute(); return resultSetHandler.handleCursorResultSets(ps); } @Override protected Statement instantiateStatement(Connection connection) throws SQLException { // 通过 BoundSql 获取 SQL 语句,通过 MappedStatement 对象获取主键生成策略以及主键列, // 然后调用 JDBC Connection API 获得 PreparedStatement 实例 String sql = boundSql.getSql(); if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) { String[] keyColumnNames = mappedStatement.getKeyColumns(); if (keyColumnNames == null) { return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS); } else { return connection.prepareStatement(sql, keyColumnNames); } } else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) { return connection.prepareStatement(sql); } else { return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY); } } @Override public void parameterize(Statement statement) throws SQLException { // 通过参数处理器对预编译中的 ? 占位符进行值设置 parameterHandler.setParameters((PreparedStatement) statement); } }
CallableStatementHandler
与上面的 PreparedStatementHandler 源码差不多,只是要设置存储过程输出参数。通过 JDBC 原生 Connection API 获取 CallableStatement 实例,然后通过该实例操作数据库。
这篇关于MyBatis 之 StatementHandler 来执行 SQL 语句的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-26大厂数据结构与算法教程:入门级详解
- 2024-12-26大厂算法与数据结构教程:新手入门指南
- 2024-12-26Python编程入门指南
- 2024-12-26数据结构高级教程:新手入门及初级提升指南
- 2024-12-26并查集入门教程:从零开始学会并查集
- 2024-12-26大厂数据结构与算法入门指南
- 2024-12-26大厂算法与数据结构入门教程
- 2024-12-26二叉树入门教程:轻松掌握基础概念与操作
- 2024-12-26初学者指南:轻松掌握链表
- 2024-12-26平衡树入门教程:轻松理解与应用