SqlSession与SqlSessionFactory到底是什么关系?
1. SqlSession和SqlSessionFactory的接口定义
SqlSession:
public interface SqlSession extends Closeable {
<T> T selectOne(String var1);
<T> T selectOne(String var1, Object var2);
<E> List<E> selectList(String var1);
<E> List<E> selectList(String var1, Object var2);
<E> List<E> selectList(String var1, Object var2, RowBounds var3);
<K, V> Map<K, V> selectMap(String var1, String var2);
<K, V> Map<K, V> selectMap(String var1, Object var2, String var3);
<K, V> Map<K, V> selectMap(String var1, Object var2, String var3, RowBounds var4);
void select(String var1, Object var2, ResultHandler var3);
void select(String var1, ResultHandler var2);
void select(String var1, Object var2, RowBounds var3, ResultHandler var4);
int insert(String var1);
int insert(String var1, Object var2);
int update(String var1);
int update(String var1, Object var2);
int delete(String var1);
int delete(String var1, Object var2);
void commit();
void commit(boolean var1);
void rollback();
void rollback(boolean var1);
List<BatchResult> flushStatements();
void close();
void clearCache();
Configuration getConfiguration();
<T> T getMapper(Class<T> var1);
Connection getConnection();
}
SqlSession,数据库的C、R、U、D及事务处理接口,你懂的。
SqlSessionFactory:
public interface SqlSessionFactory {
SqlSession openSession();
SqlSession openSession(boolean var1);
SqlSession openSession(Connection var1);
SqlSession openSession(TransactionIsolationLevel var1);
SqlSession openSession(ExecutorType var1);
SqlSession openSession(ExecutorType var1, boolean var2);
SqlSession openSession(ExecutorType var1, TransactionIsolationLevel var2);
SqlSession openSession(ExecutorType var1, Connection var2);
Configuration getConfiguration();
}
不解释,你懂的。
2. SqlSession和SqlSessionFactory的类结构图

(Made In Intellij Idea IDE)
SqlSession实现类:DefaultSqlSession和SqlSessionManager
SqlSessionFactory实现类:DefaultSqlSessionFactory和SqlSessionManager
3. DefaultSqlSession和DefaultSqlSessionFactory源码分析
org.apache.ibatis.session.defaults.DefaultSqlSession.java部分源码:
private Configuration configuration;
private Executor executor;
@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();
}
}
总结:似乎一切的一切,都是从配置对象Configuration中取出材料来,委托给执行器Executor去处理。
org.apache.ibatis.session.defaults.DefaultSqlSessionFactory.java部分源码:
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private final Configuration configuration;
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
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();
}
}
//...
创建一个DefaultSqlSession并返回,这里出现了那个贯穿Mybatis执行流程的Executor接口,非常重要的接口,后续会对其进行仔细分析。
4. SqlSessionManager源码分析(重点)
SqlSessionManager同时实现了SqlSession和SqlSessionFactory接口。
org.apache.ibatis.session.SqlSessionManager.java部分源码。
public class SqlSessionManager implements SqlSessionFactory, SqlSession {
private final SqlSessionFactory sqlSessionFactory;
// proxy
private final SqlSession sqlSessionProxy;
// 保持线程局部变量SqlSession的地方
private ThreadLocal<SqlSession> localSqlSession = new ThreadLocal<SqlSession>();
private SqlSessionManager(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
// 这个proxy是重点
this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(
SqlSessionFactory.class.getClassLoader(),
new Class[]{SqlSession.class},
new SqlSessionInterceptor());
}
public static SqlSessionManager newInstance(Reader reader) {
return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, null, null));
}
public static SqlSessionManager newInstance(Reader reader, String environment) {
return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, environment, null));
}
//...
// 设置线程局部变量sqlSession的方法
public void startManagedSession() {
this.localSqlSession.set(openSession());
}
public void startManagedSession(boolean autoCommit) {
this.localSqlSession.set(openSession(autoCommit));
}
//...
@Override
public <T> T selectOne(String statement, Object parameter) {
return sqlSessionProxy.<T> selectOne(statement, parameter);
}
@Override
public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
return sqlSessionProxy.<K, V> selectMap(statement, mapKey);
}
//...
变量sqlSessionFactory:相当于DefaultSqlSessionFactory的实例(不是proxy)。
变量sqlSessionProxy:是JDK动态代理出来的proxy(是proxy)。
动态代理的目的,是为了通过拦截器InvocationHandler,增强目标target的方法调用。
target:DefaultSqlSession的实例。
所有的调用sqlSessionProxy代理对象的C、R、U、D及事务方法,都将经过SqlSessionInterceptor拦截器,并最终由目标对象target实际完成数据库操作。
org.apache.ibatis.session.SqlSessionInterceptor.java的源码。
private class SqlSessionInterceptor implements InvocationHandler {
public SqlSessionInterceptor() {
// Prevent Synthetic Access
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
final SqlSession sqlSession = SqlSessionManager.this.localSqlSession.get();
if (sqlSession != null) {
try {
// 1、存在线程局部变量sqlSession(不提交、不回滚、不关闭,可在线程生命周期内,自定义sqlSession的提交、回滚、关闭时机,达到复用sqlSession的效果)
return method.invoke(sqlSession, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
} else {
// 2、不存在线程局部变量sqlSession,创建一个自动提交、回滚、关闭的SqlSession(提交、回滚、关闭,将sqlSession的生命周期完全限定在方法内部)
final 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();
}
}
}
}
注意:SqlSession的生命周期,必须严格限制在方法内部或者request范围(也称之为Thread范围),线程不安全,线程之间不能共享。(官方文档有明确说明)
1、request范围使用SqlSession
sqlSessionManager.startManagedSession();
try {
sqlSessionManager.query1();
sqlSessionManager.query2();
sqlSessionManager.update1();
sqlSessionManager.update2();
//...
}catch (Throwable t) {
sqlSessionManager.rollback();
} finally {
sqlSessionManager.close();
}
一次性执行了一系列的方法业务,最后统一异常回滚,统一关闭sqlSession,全程创建1次sqlSession,销毁1次sqlSession。只是个例子,具体如何使用线程本地变量sqlSession,完全取决于你自己。
2、method范围使用SqlSession
SqlSessionManager.query1();
SqlSessionManager.query2();
以上伪代码,各自分别开启了一个SqlSession,并销毁了各自的SqlSession。即,创建了2次SqlSession,销毁了2次SqlSession。
注:SqlSessionManager似乎是废弃不使用的了,但是,它并不妨碍我们探究其源码
原文:https://my.oschina.net/zudajun/blog/665956
SqlSession与SqlSessionFactory到底是什么关系?的更多相关文章
- JS原型的问题Object和Function到底是什么关系
var F = function(){}; Objcert.prototype.a = function(){}; Function.prototype.b = function(){}; F 既能访 ...
- 内核与ramdisk到底是什么关系
转自:http://www.lupaworld.com/forum.php?mod=viewthread&tid=61425 原名:内核与ramdisk到底是什么关系? 个人Notes: ...
- SOA和微服务到底是什么关系
本文原创,原文地址为:http://www.cnblogs.com/fengzheng/p/5847441.html SOA和微服务到底是什么关系? 说实话,我确实不明白SOA和微服务到底有什么本质上 ...
- SOA和微服务到底是什么关系?
SOA和微服务到底是什么关系? 说实话,我确实不明白SOA和微服务到底有什么本质上的区别,两者说到底都是对外提供接口的一种架构设计方式.我倒觉得微服务其实就是随着互联网的发展,复杂的平台.业务的出现, ...
- Unicode,UTF-32,UTF-16,UTF-8到底是啥关系?
编码的目的,就是给抽象的字符赋予一个数值,好在计算机里面表示.常见的ASCII使用8bit给字符编码,但是实际只使用了7bit,最高位没有使用,因此,只能表示128个字符:ISO-8859-1(也叫L ...
- [转载]javaEE规范和SSH三大框架到底有什么关系
转载自: http://blog.csdn.net/bingjing12345/article/details/20641891 1994-2000 年是互联网的大航海时代. 请注意,下面的时间点及其 ...
- javaEE规范和SSH三大框架到底有什么关系
转自博客:http://blog.csdn.net/bingjing12345/article/details/20641891 1994-2000 年是互联网的大航海时代. 请注意,下面的时间点及其 ...
- ARM内核和架构都是什么意思,它们到底是什么关系?
ARM产品越来越丰富,命名也越来越多.很多朋友提问: ARM内核和架构都是什么意思?内核和架构的关系是什么?比如ARMv7架构,这个架构指的是什么?小编选出了几个精彩回答!希望对嵌友们在选择设计电路时 ...
- Zend与PHP之间到底是什么关系
Zend与PHP之间是什么关系 What is Zend's relationship with PHP? 每次看到PHP虚拟机中出现zend.zendvar之类的都很困惑,特意查了一下... PHP ...
随机推荐
- shell 中的判断
一.if的基本语法: if [ command ];then 符合该条件执行的语句 elif [ command ];then 符合该条件执行的语句 else 符合该条件执行的语句 ...
- 微服务之十四如何在 Ocelot 网关中配置多实例 Swagger 访问
一.介绍 当我们开发基于微服务的应用程序的时候,有一个环节总是跳不过去的,那就是要创建 WebApi,然后,我们的应用程序基于 WebApi 接口去访问.在没有 Swagger 以前,我们开发好了 W ...
- Swift进阶-内存管理
本文的主要目的是探索 RefCount 的内存结构及强/弱引用计数管理 Swift 中也是采用 ARC 编译器自动内存管理机制. Swift 对象的内存结构是 HeapObject, 有两个属性 Me ...
- 在 macOS 上运行无限许可的 Nessus 10
请访问原文链接:https://sysin.org/blog/nessus-unlimited-on-macos/,查看最新版.原创作品,转载请保留出处. 作者:gc(at)sysin.org,主页: ...
- 基于ABP开发框架的技术点分析和项目快速开发实现
在我们开发各种项目应用的时候,往往都是基于一定框架进行,同时配合专用的代码生成工具,都是为了快速按照固定模式开发项目,事半功倍,本篇随笔对基于ABP开发框架的技术点进行分析和ABP框架项目快速开发实现 ...
- SpringBoot 整合 Mybatis-Plus + Mysql
mybatis-plus是mybatis的一款插件,它的主要作用是快速开发,省略mybatis的配置,具体的功能请参照官网. 开发环境: springboot,maven,mybatis-plus,m ...
- Bean_sprout的第一次编程作业
第一次编程作业 一.PSP表格 PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟) Planning 计划 60 120 · Estim ...
- 第二周PTA笔记 均等笔+旋转骰子+两个日期相差天数
均等笔 n个人围成一圈,每人有ai支笔.每人可以向左右相邻的人传递笔,每人每次传递一支笔消耗的能量为1.求使所有人获得均等数量的笔的最小能量. 输入格式: 第一行一个整数n ,表示人的个数(30%的数 ...
- 14-1-Unsupervised Learning ---dimension reduction
无监督学习(Unsupervised Learning)可以分为两种: 化繁为简 聚类(Clustering) 降维(Dimension Reduction) 无中生有(Generation) 所谓的 ...
- vue3 学习笔记 (五)——vue3 的 setup 如何实现响应式功能?
setup 是用来写组合式 api ,内部的数据和方法需要通过 return 之后,模板才能使用.在之前 vue2 中,data 返回的数据,可以直接进行双向绑定使用,如果我们把 setup 中数据类 ...