1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > mybatis之StatementHandler

mybatis之StatementHandler

时间:2019-08-29 06:03:20

相关推荐

mybatis之StatementHandler

StatementHandler接口是MyBatis核心接口之一,它完成了MyBatis最核心的工作。

StatementHandler接口中的功能很多,例如创建Statement对象,为SQL语句绑定实参,执行select、insert、update、delete等多种类型的SQL语句,批量执行SQL语句,将结果集映射成结果对象。

StatementHandler接口的定义如下:

public interface StatementHandler {// 从连接中获取一个StatementStatement prepare(Connection connection, Integer transactionTimeout)throws SQLException;// 参数绑定void parameterize(Statement statement)throws SQLException;// 批量执行void batch(Statement statement)throws SQLException;// 执行update、insert、delete操作int update(Statement statement)throws SQLException;// 执行select操作<E> List<E> query(Statement statement, ResultHandler resultHandler)throws SQLException;<E> Cursor<E> queryCursor(Statement statement)throws SQLException;BoundSql getBoundSql();ParameterHandler getParameterHandler();}

MyBatis中提供了StatementHandler接口的多种实现类。

1.RoutingStatementHandler

RoutingStatementHandler会根据MappedStatement指定的statementTyp字段,创建对应的StatementHandler接口实现。RoutingStatementHandler类的具体实现如下:

public class RoutingStatementHandler implements StatementHandler {// 封装的真正的StatementHandler对象private final StatementHandler delegate;public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {// 根据MappedStatement的配置,生成一个对应的StatementHandler对象,并设置到delegate字段中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());}}//...通过delegate调用对应的方法}

2.BaseStatementHandler

BaseStatementHandler是一个实现了StatementHandler接口的抽象类,它只提供了一些参数绑定相关的方法,并没有实现操作数据库的方法。BaseStatementHandler字段的含义如下:

// 记录使用的ResultSetHandler对象,将结果集映射成结果对象protected final ResultSetHandler resultSetHandler;// 记录使用的ParameterHandler对象,使用传入的实参替换SQL语句的中的?占位符protected final ParameterHandler parameterHandler;// 记录执行SQL语句的Executor对象protected final Executor executor;// 记录SQL语句对应的MappedStatement、BoundSql对象protected final MappedStatement mappedStatement;// RowBounds记录了用户设置的offset,limit,用于在结果集中定位映射的起始位置和结束位置protected final RowBounds rowBounds;

在BaseStatementHandler的构造方 法中,除了初始化上述字段之外,还会调用KeyGenerator.processBefore()方法初始化SQL语句的主键,具体实现如下:

protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {// ...其他字段忽略if (boundSql == null) {// issue #435, get the key before calculating the statement// 调用keyGenerator.processBefore()方法获取主键generateKeys(parameterObject);boundSql = mappedStatement.getBoundSql(parameterObject);}}protected void generateKeys(Object parameter) {KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();ErrorContext.instance().store();keyGenerator.processBefore(executor, mappedStatement, null, parameter);ErrorContext.instance().recall();}

BaseStatementHandler实现了StatementHandler接口中的prepare()方法,该方法首先调instantiateStatement()抽象方法初始化Java.sqI.Statement对象 然后为其配置超时时间以及fetchSize等设置。

3.ParameterHandler

通过前面对动态SQL的介绍可知,在BoundSql中记录的SQL语句中可能包含?占位符,而每个?占位符都对应了BoundSql、parameterMappings集合中的一个元素,在该ParameterMapping中记录了对应参数名称以及该参数的相关属性。

在ParameterHandler接口中只定义了一个setParameters()方法,该方法主要负责调用PreparedStatement.set*()方法为SQL语句绑定实参。MyBatis只为ParameterHandler接口提供了一个实现类DefaultParameterHandler。DefaultParameterHandler中核心字段的含义如下:

// 管理mybatis中的全部TypeHandler对象private final TypeHandlerRegistry typeHandlerRegistry;// 其中记录SQL节点相应的配置信息private final MappedStatement mappedStatement;// 用户传入的实参对象private final Object parameterObject;// 对应的BoundSql对象,需要设置参数的PreparedStatement对象private final BoundSql boundSql;

在DefaultParameterHandler.setParameters()方法中会遍历BoundSql.parameterMappings集合中记录的ParameterMapping对象,井根据其中记录的参数名称查找相应实参,然后与SQL语句绑定。setParameters()方法的具体实现如下:

public void setParameters(PreparedStatement ps) {ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());// 取出sql中的参数映射列表List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();if (parameterMappings != null) {for (int i = 0; i < parameterMappings.size(); i++) {ParameterMapping parameterMapping = parameterMappings.get(i);// 过滤掉存储过程中的输出参数if (parameterMapping.getMode() != ParameterMode.OUT) {Object value;String propertyName = parameterMapping.getProperty();if (boundSql.hasAdditionalParameter(propertyName)) {// issue #448 ask first for additional params// 获取对应的实参值value = boundSql.getAdditionalParameter(propertyName);} else if (parameterObject == null) {// 实参为空value = null;} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {// 根据TypeHandler转换成JdbcTypevalue = parameterObject;} else {// 获取对象中相应的属性位或查找Map对象中值MetaObject metaObject = configuration.newMetaObject(parameterObject);value = metaObject.getValue(propertyName);}// 获取ParameterMapping中设置的TypeHandler对象TypeHandler typeHandler = parameterMapping.getTypeHandler();JdbcType jdbcType = parameterMapping.getJdbcType();if (value == null && jdbcType == null) {jdbcType = configuration.getJdbcTypeForNull();}try {// //通过TypeHandler.setParameters()方法会调用PreparedStatement.set*()方法为SQL语句绑定相应的实参typeHandler.setParameter(ps, i + 1, value, jdbcType);} catch (TypeException | SQLException e) {throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);}}}}}

为SQL语句绑定完实参之后,就可以调用Statement对象相应的execute()方法,将SQL语句交给数据库执行。

4.SimpleStatementHandler

SimpleStatementHandler继承了BaseStatementHandler抽象类。它底层使用java.sql.Statement对象来完成数据库的相关操作,所以SQL语句中不能存在占位符相应的,SimpleStatementHandler.parameterize()方法是空实现。

SimpleStatementHandler.instantiateStatement()方法直接通过JDBCConnection 创建Statement对象,具体实现如下:

@Overrideprotected Statement instantiateStatement(Connection connection) throws SQLException {if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {return connection.createStatement();} else {// 设置结果集是否可以滚动及其游标是否可以上下移动,设置结果集是否可更新return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);}}

上面创建的Statement对象之后会被用于完成数据库操作,SimpleStatementHandler.query()方法等完成了数据库查询的操作,并通过ResultSetHandler将结果集映射成结果对象。

@Overridepublic <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {// 获取SQL语句String sql = boundSql.getSql();// 执行SQL语句statement.execute(sql);// 映射结果集return resultSetHandler.handleResultSets(statement);}

SimpleStatementHandler中的 queryCursor()、batch()方法与query()方法实现类似,也是直接调用Statement对象的相应方法,不再赘述。

SimpleStatementHandler.update()方法负责执行insert、update、delete等类型的SQL语句,并且会根据配置的 KeyGenerator获取数据库生成的主键 具体实现如下:

@Overridepublic int update(Statement statement) throws SQLException {// 获取SQL语句String sql = boundSql.getSql();// 获取实参对象Object parameterObject = boundSql.getParameterObject();// 获取配置的KeyGenerator对象KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();int rows;if (keyGenerator instanceof Jdbc3KeyGenerator) {// 执行SQL语句statement.execute(sql, Statement.RETURN_GENERATED_KEYS);// 获取受影响的行rows = statement.getUpdateCount();// 将数据库生成的主键添加到parameterObject中keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);} else if (keyGenerator instanceof SelectKeyGenerator) {// 执行SQL语句statement.execute(sql);// 获取受影响的行rows = statement.getUpdateCount();// 执行<selectKey>节点中配置的SQL语句获取数据库生成的主键,添加到parameterObject中keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);} else {statement.execute(sql);rows = statement.getUpdateCount();}return rows;}

5.PreparedStatementHandler

PreparedStatementHandler底层依赖于java.sql.PreparedStatement对象来完成数据库的相关操作。在 SimpleStatementHandler.parameterize()方法中, 会调用前面介绍的ParameterHandler.setParameters ()方法完成SQL语句的参数绑定。

PreparedStatementHandler.instantiateStatement()方法直接调用JDBC Connection的prepareStatement()方法创建 PreparedStatement对象, 具体实现如下:

@Overrideprotected Statement instantiateStatement(Connection connection) throws SQLException {// 获取SQL语句String sql = boundSql.getSql();// 获取mappedStatement.getKeyGenerator()创建prepareStatement对象if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {String[] keyColumnNames = mappedStatement.getKeyColumns();if (keyColumnNames == null) {return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);} else {// insert语句执行完成之后,会将keyColumnNames指定的列返回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);}}

PreparedStatementHandler中其他方法的实现与SimpleStatementHandler对应方法的实现类似,这里就不再赘述。

6.CallableStatementHandler

CallableStatementHandler底层依赖于java.sql.CallableStatement存储过程parameterize()方法也会调用ParameterHandler.setParameters ()方法完成SQL语句的参数绑定指定输出参数的索引位置和JDBC类型。其余方法与前面介绍SimpleStatementHandler实现类似,唯一区别是会调用前面介绍的 resultSetHandler.handleOutputParameters()处理输出参数。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。