转载自  mybatis源码阅读(一):SqlSession和SqlSessionFactory

一、接口定义

听名字就知道这里使用了工厂方法模式,SqlSessionFactory负责创建SqlSession对象。其中开发人员最常用的就是DefaultSqlSession

(1)SqlSession接口定义

public interface SqlSession extends Closeable {// 泛型方法,参数表示使用的查询SQL语句,返回值为查询的结果对象<T> T selectOne(String statement);// 第二个参数表示需要用户传入的实参,也就是SQL语句绑定的实参<T> T selectOne(String statement, Object parameter);// 查询结果集有多条记录,会封装成结果对象列表返回<E> List<E> selectList(String statement);<E> List<E> selectList(String statement, Object parameter);// 第三个参数用于限制解析结果集的范围<E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);/****  selectMap 方法的原理和参数都与selectList方法类型,但结果集会被映射成Map对象返回*  其中mapKey参数指定了结果集哪一列作为map的key,其他参数同上*/<K, V> Map<K, V> selectMap(String statement, String mapKey);<K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey);<K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds);// 返回值是游标对象,参数同上<T> Cursor<T> selectCursor(String statement);<T> Cursor<T> selectCursor(String statement, Object parameter);<T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds);// 查询的结果对象将由此处指定的handler对象处理,其余参数同上void select(String statement, Object parameter, ResultHandler handler);void select(String statement, ResultHandler handler);void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler);// 执行insert语句int insert(String statement);int insert(String statement, Object parameter);// 执行update语句int update(String statement);int update(String statement, Object parameter);// 执行deleteint delete(String statement);int delete(String statement, Object parameter);// 提交事务void commit();void commit(boolean force);// 事务回滚void rollback();void rollback(boolean force);// 将请求刷新到数据库List<BatchResult> flushStatements();// 关闭当前session@Overridevoid close();// 清空session 缓存void clearCache();// 获取Configuration 对象Configuration getConfiguration();// 获取type 对象的Mapper对象<T> T getMapper(Class<T> type);// 获取该Sqlsession 对象的数据库连接Connection getConnection();
}

SqlSession数据库的C、R、U、D及事务处理接口,你懂的。

(2)SqlSessionFactory

public interface SqlSessionFactory {SqlSession openSession();SqlSession openSession(boolean autoCommit);SqlSession openSession(Connection connection);SqlSession openSession(TransactionIsolationLevel level);SqlSession openSession(ExecutorType execType);SqlSession openSession(ExecutorType execType, boolean autoCommit);SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);SqlSession openSession(ExecutorType execType, Connection connection);Configuration getConfiguration();
}

这个大家也都懂的

SqlSession实现类:DefaultSqlSession和SqlSessionManager

SqlSessionFactory实现类:DefaultSqlSessionFactory和SqlSessionManager

(3)DefaultSqlSession

@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 <E> List<E> 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();}
}

这里主要看这两个方法,因为delete和insert最终执行掉用的都是update方法,查询就更不用说了。从代码上看都是从configuration对象中获取MappedStatement 对象 然后把事情交给小弟Executor去执行,这里用了很典型的策略设计模式,这个关于Executor 后面介绍。

(4)DefaultSqlSessionFactory

/*** 通过数据源获取数据库连接,并创建Executor以及DefaultSqlSession对象*/
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {Transaction tx = null;try {final Environment environment = configuration.getEnvironment();final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);final Executor executor = configuration.newExecutor(tx, execType);return 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();}
}/***  用户提供数据库连接对象,使用该数据库连接对象创建Executor和DefaultSqlSession对象*/
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 won't 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();}
}

DefaultSqlSessionFactory主要提供了两种创建DefaultSqlSession对象的方式,一种是通过数据源获取数据库连接,并创建Executor以及DefaultSqlSession对象,另一种是用户提供数据库连接对象,使用该数据库连接对象创建Executor和DefaultSqlSession对象。

(5)SqlSessionManager

SqlSessionManager同时实现SqlSession接口和SqlSessionFactory接口,也就是同时提供了创建SqlSession对象以及SqlSession对象操作数据库的功能。SqlSessionManager与DefaultSqlSessionFactory的主要不同点是SqlSessionManager提供了两种模式,一种是和DefaultSqlSessionFactory的行为相同,同一线程每次访问数据库就都会创建新的DefaultSqlSession,第二种是通过ThreadLocal变量记录当前线程的SqlSession对象,避免同一线程多次创建SqlSession对象。至于使用动态代理的目的,是为了通过拦截器InvocationHandler,增强目标target的方法调用。

private final SqlSessionFactory sqlSessionFactory;
// SqlSession的代理对象 会使用JDK的动态代理方式实现
private final SqlSession sqlSessionProxy;/*** ThreadLocal 变量,记录一个与当前线程绑定的SqlSession对象* localSqlSession 中记录的SqlSession对象的代理对象,在SqlSessionManager初始化的时候*/
private final ThreadLocal<SqlSession> localSqlSession = new ThreadLocal<SqlSession>();
/*** SqlSessionManager 的私有构造方法*/
private SqlSessionManager(SqlSessionFactory sqlSessionFactory) {this.sqlSessionFactory = sqlSessionFactory;// 使用动态代理生成SqlSession的代理对象this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(),new Class[]{SqlSession.class},new SqlSessionInterceptor());
}/*** 通过newInstance方法创建SqlSessionManager对象* @param reader* @return*/public static SqlSessionManager newInstance(Reader reader) {return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, null, null));}
// 内部类
private class SqlSessionInterceptor implements InvocationHandler {public SqlSessionInterceptor() {// Prevent Synthetic Access}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 获取当前线程绑定的SqlSession对象final SqlSession sqlSession = SqlSessionManager.this.localSqlSession.get();if (sqlSession != null) {// 第二种模式try {return method.invoke(sqlSession, args);} catch (Throwable t) {throw ExceptionUtil.unwrapThrowable(t);}} else {// 第一种模式 创建新的SqlSessionfinal SqlSession autoSqlSession = openSession();try {final Object result = method.invoke(autoSqlSession, args);autoSqlSession.commit();return result;} catch (Throwable t) {autoSqlSession.rollback();throw ExceptionUtil.unwrapThrowable(t);} finally {autoSqlSession.close();}}}
}

mybatis源码阅读(一):SqlSession和SqlSessionFactory相关推荐

  1. mybatis源码阅读(二):mybatis初始化上

    转载自  mybatis源码阅读(二):mybatis初始化上 1.初始化入口 //Mybatis 通过SqlSessionFactory获取SqlSession, 然后才能通过SqlSession与 ...

  2. Mybatis源码阅读(一):Mybatis初始化1.1 解析properties、settings

    *************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如 ...

  3. mybatis源码阅读(五) ---执行器Executor

    转载自  mybatis源码阅读(五) ---执行器Executor 1. Executor接口设计与类结构图 public interface Executor {ResultHandler NO_ ...

  4. mybatis源码阅读(四):mapper(dao)实例化

    转载自   mybatis源码阅读(四):mapper(dao)实例化 在开始分析之前,先来了解一下这个模块中的核心组件之间的关系,如图: 1.MapperRegistry&MapperPro ...

  5. Mybatis源码阅读之二——模板方法模式与Executor

    [系列目录] Mybatis源码阅读之一--工厂模式与SqlSessionFactory 文章目录 一. 模板方法模式 二. 同步回调与匿名函数 三. Executor BaseExecutor与其子 ...

  6. mybatis源码阅读(八) ---Interceptor了解一下

    转载自  mybatis源码阅读(八) ---Interceptor了解一下 1 Intercetor MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用.默认情况下,MyBatis允许 ...

  7. mybatis源码阅读(七) ---ResultSetHandler了解一下

    转载自  mybatis源码阅读(七) ---ResultSetHandler了解一下 1.MetaObject MetaObject用于反射创建对象.反射从对象中获取属性值.反射给对象设置属性值,参 ...

  8. mybatis源码阅读(六) ---StatementHandler了解一下

    转载自  mybatis源码阅读(六) ---StatementHandler了解一下 StatementHandler类结构图与接口设计 BaseStatementHandler:一个抽象类,只是实 ...

  9. mybatis源码阅读(三):mybatis初始化(下)mapper解析

    转载自 mybatis源码阅读(三):mybatis初始化(下)mapper解析 MyBatis 的真正强大在于它的映射语句,也是它的魔力所在.由于它的异常强大,映射器的 XML 文件就显得相对简单. ...

最新文章

  1. Android自定义组合控件
  2. string类型加减_测试人员应该知道的Redis知识(四) String
  3. Linux系统目录结构说明
  4. Docker学习笔记【一】
  5. 算法基础:递归算法知识笔记
  6. java中的4种reference的差别和使用场景(含理论、代码和执行结果)
  7. sharepoint2013用场管理员进行文档库的爬网提示没有权限,拒绝的解决方法
  8. python表单文件请求_python处理multipart/form-data的请求方法
  9. Excel-VBA操作文件四大方法之一(1/4)
  10. 前端工程化和Reactjs的模式
  11. C# ado.net数据库连接池,使用长连接访问数据库
  12. vbs实现微信自动发送消息功能
  13. 盛大如何再次“盛大”
  14. Linux查看网卡ip地址,查看网卡IP地址
  15. Ngnix 搭建视频直播服务器
  16. ODrive0.5.1程序分析#4 闭环控制程序(run_closed_loop_control_loop)
  17. PS 剪切图片到指定大小
  18. iOS设备指纹的前世今生
  19. 用java求水仙花数,适合新手
  20. html5中margin是什么意思,css中margin是什么意思,margin作用是什么?

热门文章

  1. c++十进制转二进制_二进制与十进制如何互相转换?
  2. idea中右侧的Maven框消失了
  3. leetcode 904:水果成篮(滑动窗口)
  4. [SpringBoot2]Thymeleaf
  5. [JavaWeb-MySQL]事务的基本介绍
  6. C++substr()用法
  7. Adapter(适配器)--类对象结构型模式
  8. 食物链 POJ - 1182
  9. win10 64位操作系统安装mysql_win10,64位操作系统安装mysql-8.0.16经验总结(图文详细,保证一次安装成功)...
  10. revit如何根据坐标进行画线_铭成教你如何根据同步带的齿形进行选型