石家庄最好的网站建设公司排名,c 网站开发人员工具,wordpress好用么,网站设计公司合肥*************************************优雅的分割线 **********************************
分享一波:程序员赚外快-必看的巅峰干货
如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程
请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…*************************************优雅的分割线 **********************************
分享一波:程序员赚外快-必看的巅峰干货
如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程
请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更新 *************************************优雅的分割线 ********************************** SimpleExecutor SqlSession
SqlSession是Mybatis的核心接口之一对外提供常用的数据库操作api。mybatis提供了两个SqlSession的实现其中最常用的是DefaultSqlSession。
SqlSession的代码如下
/** 接口层也是开发人员使用mybatis去操作sql所使用的主要的接口 author Clinton Begin */ public interface SqlSession extends Closeable { /** 查询sql单条数据param 返回的数据类型param statement sqlreturn Mapped object */ T selectOne(String statement); /** 指定sql并传入实参去查单条数据param 返回的数据类型param statement 预编译的带有?的sqlparam parameter 用户传入的实参与前面sql绑定return Mapped object */ T selectOne(String statement, Object parameter); /** 执行sql查询多条数据param 返回的数据类型param statement sqlreturn List of mapped object */ List selectList(String statement); /** 指定sql并传入实参去查多条数据param 返回的数据类型param statement 预编译的带有问号的sqlparam parameter 用户传入的实参与前面的sql绑定return List of mapped object */ List selectList(String statement, Object parameter); /** 使用预编译的sql指定传入的实参以及结果集范围查询指定范围的所有数据param 返回的数据类型param statement 预编译的带有问号的sqlparam parameter 用户传入的实参与前面的sql绑定param rowBounds 指定查询范围return List of mapped object */ List selectList(String statement, Object parameter, RowBounds rowBounds); /** 执行sql返回map对象param the returned Map keys typeparam the returned Map values typeparam statement Unique identifier matching the statement to use.param mapKey The property to use as key for each value in the list.return Map containing key pair data. */ K, V MapK, V selectMap(String statement, String mapKey); /** 指定sql和实参返回mapparam the returned Map keys typeparam the returned Map values typeparam statement Unique identifier matching the statement to use.param parameter A parameter object to pass to the statement.param mapKey The property to use as key for each value in the list.return Map containing key pair data. */ K, V MapK, V selectMap(String statement, Object parameter, String mapKey); /** 指定sql、实参、范围返回mapparam the returned Map keys typeparam the returned Map values typeparam statement Unique identifier matching the statement to use.param parameter A parameter object to pass to the statement.param mapKey The property to use as key for each value in the list.param rowBounds Bounds to limit object retrievalreturn Map containing key pair data. */ K, V MapK, V selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds); /** A Cursor offers the same results as a List, except it fetches data lazily using an Iterator.param the returned cursor element type.param statement Unique identifier matching the statement to use.return Cursor of mapped objects */ Cursor selectCursor(String statement); /** A Cursor offers the same results as a List, except it fetches data lazily using an Iterator.param the returned cursor element type.param statement Unique identifier matching the statement to use.param parameter A parameter object to pass to the statement.return Cursor of mapped objects */ Cursor selectCursor(String statement, Object parameter); /** A Cursor offers the same results as a List, except it fetches data lazily using an Iterator.param the returned cursor element type.param statement Unique identifier matching the statement to use.param parameter A parameter object to pass to the statement.param rowBounds Bounds to limit object retrievalreturn Cursor of mapped objects */ Cursor selectCursor(String statement, Object parameter, RowBounds rowBounds); /** 将查询结果通过此处的ResultHandler对象封装成对应的对象param statement Unique identifier matching the statement to use.param parameter A parameter object to pass to the statement.param handler ResultHandler that will handle each retrieved row */ void select(String statement, Object parameter, ResultHandler handler); /** Retrieve a single row mapped from the statementusing a {code ResultHandler}.param statement Unique identifier matching the statement to use.param handler ResultHandler that will handle each retrieved row */ void select(String statement, ResultHandler handler); /** Retrieve a single row mapped from the statement key and parameterusing a {code ResultHandler} and {code RowBounds}.param statement Unique identifier matching the statement to use.param rowBounds RowBound instance to limit the query resultsparam handler ResultHandler that will handle each retrieved row */ void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler); /** 执行insertparam statement Unique identifier matching the statement to execute.return int The number of rows affected by the insert. */ int insert(String statement); /** Execute an insert statement with the given parameter object. Any generatedautoincrement values or selectKey entries will modify the given parameterobject properties. Only the number of rows affected will be returned.param statement Unique identifier matching the statement to execute.param parameter A parameter object to pass to the statement.return int The number of rows affected by the insert. */ int insert(String statement, Object parameter); /** 执行updateparam statement Unique identifier matching the statement to execute.return int The number of rows affected by the update. */ int update(String statement); /** Execute an update statement. The number of rows affected will be returned.param statement Unique identifier matching the statement to execute.param parameter A parameter object to pass to the statement.return int The number of rows affected by the update. */ int update(String statement, Object parameter); /** 执行deleteparam statement Unique identifier matching the statement to execute.return int The number of rows affected by the delete. */ int delete(String statement); /** Execute a delete statement. The number of rows affected will be returned.param statement Unique identifier matching the statement to execute.param parameter A parameter object to pass to the statement.return int The number of rows affected by the delete. */ int delete(String statement, Object parameter); /** 提交事务 */ void commit(); /** Flushes batch statements and commits database connection.param force forces connection commit */ void commit(boolean force); /** 回滚事务 */ void rollback(); /** Discards pending batch statements and rolls database connection back.Note that database connection will not be rolled back if no updates/deletes/inserts were called.param force forces connection rollback */ void rollback(boolean force); /** 将请求刷新到数据库return BatchResult list of updated recordssince 3.0.6 */ List flushStatements(); /** 关闭SqlSession */ Override void close(); /** 清空 缓存 */ void clearCache(); /** Retrieves current configuration.return Configuration */ Configuration getConfiguration(); /** 使用type获取对应的Mapperparam the mapper typeparam type Mapper interface classreturn a mapper bound to this SqlSession */ T getMapper(Class type); /** 获取该SqlSession对应的数据库连接return Connection */ Connection getConnection(); }
DefaultSqlSession
在mybatis单独使用的时候DefaultSqlSession是最常使用的SqlSession实现。DefaultSqlSession核心字段如下其中已经过多介绍的类将不再注释。
private final Configuration configuration;
private final Executor executor;/*** 是否自动提交事务*/
private final boolean autoCommit;/*** 当前缓存是否有脏数据*/
private boolean dirty;DefaultSqlSession中使用到了策略模式不知道策略模式的请看我以前的帖子。DefaultSqlSession扮演了上下文只是通过executor字段的不同而选择不同的Executor去操作数据库。
DefaultSqlSession为每种SQL操作都提供了大量的重载对于不同的参数都提供了一个重载方法 便于开发者去调用。这里只贴出核心的方法对于重载方法将不进行介绍。 * 根据sql和实参查询一条数据* param statement 预编译的带有?的sql* param parameter 用户传入的实参与前面sql绑定* param T* return*/
Override
public T T selectOne(String statement, Object parameter) {// 调用selectList查询多条ListT list this.selectList(statement, parameter);// 如果查询到的数据长度1是或者0就正常否则抛出异常if (list.size() 1) {return list.get(0);} else if (list.size() 1) {// 这里的异常信息是不是很熟悉呢throw new TooManyResultsException(Expected one result (or null) to be returned by selectOne(), but found: list.size());} else {return null;}
}/*** 查询结果封装成map返回* 阅读源码发现这里的selectMap貌似并不是将结果集按照属性映射成map* 而是把map当做list去使用。* 查询出多条数据使用不同的key去封装到map* 这里的V应该是这一条数据映射的对象或者是MapString, Object* param statement Unique identifier matching the statement to use.* param parameter A parameter object to pass to the statement.* param mapKey The property to use as key for each value in the list.* param rowBounds Bounds to limit object retrieval* param K* param V* return*/
Override
public K, V MapK, V selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {// 查询列表final List? extends V list selectList(statement, parameter, rowBounds);// 创建Map返回集处理器final DefaultMapResultHandlerK, V mapResultHandler new DefaultMapResultHandler(mapKey,configuration.getObjectFactory(), configuration.getObjectWrapperFactory(), configuration.getReflectorFactory());final DefaultResultContextV context new DefaultResultContext();for (V o : list) {// 暂存一下当前结果对象context.nextResultObject(o);// 处理上下文中的结果对象mapResultHandler.handleResult(context);}// 将map返回回去return mapResultHandler.getMappedResults();
}/*** 根据传入的sql、实参、查询范围去查询一个列表* param statement 预编译的带有问号的sql* param parameter 用户传入的实参与前面的sql绑定* param rowBounds 指定查询范围* param E* return*/
Override
public E ListE selectList(String statement, Object parameter, RowBounds rowBounds) {try {MappedStatement ms configuration.getMappedStatement(statement);return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);} catch (Exception e) {throw ExceptionFactory.wrapException(Error querying database. Cause: e, e);} finally {ErrorContext.instance().reset();}
}/*** 根据sql、实参、范围查询* 将查询结果交给指定的ResultHandler去处理* param statement Unique identifier matching the statement to use.* param parameter* param rowBounds RowBound instance to limit the query results* param handler ResultHandler that will handle each retrieved row*/
Override
public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {try {MappedStatement ms configuration.getMappedStatement(statement);executor.query(ms, wrapCollection(parameter), rowBounds, handler);} catch (Exception e) {throw ExceptionFactory.wrapException(Error querying database. Cause: e, e);} finally {ErrorContext.instance().reset();}
}Override
public int update(String statement, Object parameter) {try {dirty true;MappedStatement ms configuration.getMappedStatement(statement);return executor.update(ms, wrapCollection(parameter));} catch (Exception e) {throw ExceptionFactory.wrapException(Error updating database. Cause: e, e);} finally {ErrorContext.instance().reset();}
}Override
public void commit(boolean force) {try {// 提交事务。提交之后将dirty设为false// 此时的缓存中视为没有脏数据executor.commit(isCommitOrRollbackRequired(force));dirty false;} catch (Exception e) {throw ExceptionFactory.wrapException(Error committing transaction. Cause: e, e);} finally {ErrorContext.instance().reset();}
}Override
public void rollback(boolean force) {try {executor.rollback(isCommitOrRollbackRequired(force));dirty false;} catch (Exception e) {throw ExceptionFactory.wrapException(Error rolling back transaction. Cause: e, e);} finally {ErrorContext.instance().reset();}
}Override
public ListBatchResult flushStatements() {try {return executor.flushStatements();} catch (Exception e) {throw ExceptionFactory.wrapException(Error flushing statements. Cause: e, e);} finally {ErrorContext.instance().reset();}
}代码比较简单就不做过多的介绍。 DefaultSqlSessionFactory
DefaultSqlSessionFactory是一个工厂类提供了两种创建DefaultSqlSession的方式一种是通过数据源创建SqlSession一种是通过用户传入的数据库连接对象来创建SqlSession。另外代码里有大量的openSession都是用于创建SqlSession对象的但是其实现都是基于这两种方式因此这里只把两种创建SqlSession的方式的代码贴出来如下。
/*** 通过数据源去创建SqlSession* param execType* param level* param autoCommit* return*/
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {Transaction tx null;try {// 获取environment。这个是mybatis中配置的环境final Environment environment configuration.getEnvironment();// 根据环境去获取TransactionFactory对象final TransactionFactory transactionFactory getTransactionFactoryFromEnvironment(environment);// 创建Transaction对象tx transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);// 创建Executor对象final Executor executor configuration.newExecutor(tx, execType);// 创建DefaultSqlSessionreturn new DefaultSqlSession(configuration, executor, autoCommit);} catch (Exception e) {closeTransaction(tx);// may have fetched a connection so lets call close()throw ExceptionFactory.wrapException(Error opening session. Cause: e, e);} finally {ErrorContext.instance().reset();}
}/*** 通过用户提供的Connection对象去创建* param execType* param connection* return*/
private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {try {boolean autoCommit;try {autoCommit connection.getAutoCommit();} catch (SQLException e) {// Failover to true, as most poor drivers// or databases wont support transactionsautoCommit true;}final Environment environment configuration.getEnvironment();final TransactionFactory transactionFactory getTransactionFactoryFromEnvironment(environment);final Transaction tx transactionFactory.newTransaction(connection);final Executor executor configuration.newExecutor(tx, execType);return new DefaultSqlSession(configuration, executor, autoCommit);} catch (Exception e) {throw ExceptionFactory.wrapException(Error opening session. Cause: e, e);} finally {ErrorContext.instance().reset();}
}SqlSessionManager
SqlSessionManager同时实现了SqlSession接口和SQLSessionFactory接口因此它拥有操作数据库的能力以及创建SqlSession的功能。
SQLSessionManager核心字段如下
private final SqlSessionFactory sqlSessionFactory;/*** localSqlSession中记录的SqlSession对象的代理对象*/
private final SqlSession sqlSessionProxy;/*** 记录当前线程的SqlSession对象*/
private final ThreadLocalSqlSession localSqlSession new ThreadLocal();其中ThreadLocal的作用往往是作为当前线程的上下文可以为当前线程提供全局变量。对ThreadLocal不了解的朋友也请查看我以前的文章。
SqlSessionManager提供了两种模式。一种是同一线程每次通过SqlSessionManager对象访问数据库时都会创建一个DefaultSqlSession对象完成数据库操作另一种则是使用localSqlSession绑定当前线程的SqlSession在当前线程中循环使用同一个SqlSession。后者使用往往居多这也是大家经常说的“SqlSession与线程绑定 每个请求都会创建SqlSession”的原因。
sqlSessionProxy是一个代理对象在SqlSessionmanager的构造方法中使用JDK的动态代理创建完成代码如下。
private SqlSessionManager(SqlSessionFactory sqlSessionFactory) {this.sqlSessionFactory sqlSessionFactory;// 使用动态代理去创建 SqlSessionthis.sqlSessionProxy (SqlSession) Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(),new Class[]{SqlSession.class},new SqlSessionInterceptor());
}SqlSessionManager中实现的SqlSession 接口方法都是直接调用sqlSessionProxy字段记录的SqlSession代理对象的方法实现的。在创建该代理对象时使用到的SqlSessionInterceptor是SqlSessionManager的内部类代码如下。
private class SqlSessionInterceptor implements InvocationHandler {public SqlSessionInterceptor() {// Prevent Synthetic Access}Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 获取当前线程的SqlSessionfinal SqlSession sqlSession SqlSessionManager.this.localSqlSession.get();if (sqlSession ! null) {try {// SqlSession不为空就调用真正的SqlSession去完成数据库的操作return method.invoke(sqlSession, args);} catch (Throwable t) {throw ExceptionUtil.unwrapThrowable(t);}} else {try (SqlSession autoSqlSession openSession()) {// 如果当前线程的SqlSession为空就创建新的SqlSession对象try {// 使用创建的SqlSession对象完成数据库操作final Object result method.invoke(autoSqlSession, args);// 提交事务autoSqlSession.commit();return result;} catch (Throwable t) {autoSqlSession.rollback();throw ExceptionUtil.unwrapThrowable(t);}}}}
}总结
SqlSession是单体mybatis使用最多的一个接口可能我们在整合SSM之后就看不到这个接口了但是其底层实现的时候也是会创建SqlSession的虽然这个比较简单但是也是相当重要的一个模块。 *************************************优雅的分割线 **********************************
分享一波:程序员赚外快-必看的巅峰干货
如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程
请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更新 *************************************优雅的分割线 ********************************** SimpleExecutor