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 ...
随机推荐
- RabbitMQ多消费者顺序性消费消息实现
最近起了个项目消息中心,用来中转各个系统中产生的消息,用到的是RabbitMQ,由于UAT环境.生产环境每台消费者服务都是多台,有些消息要求按顺序消费,所以需要采取一定的措施保证消息的顺序消费,下面讲 ...
- Laravel 中输出 SQL 语句的到 log 日志
在 AppServiceProvider.php 中的 boot 方法中添加如下代码 即可 public function boot() { //数据库监听 DB::listen(function ( ...
- Matlab 中 arburg 函数的理解与实际使用方法
1. 理解 1.1 Matlab 帮助: a = arburg(x,p)返回与输入数组x的p阶模型相对应的归一化自回归(AR)参数. 如果x是一个向量,则输出数组a是一个行向量. 如果x是矩阵,则参数 ...
- linux下go环境配置
环境申明: centos 7.4 1.go下载最新的版本(linux) 下载本地后rz到服务器,然后tar -zxvf go1.9.2.linux-amd64.tar.gz 解压出go文件放在 ...
- hive 权限排查
show grant role role_username id username
- web页面自动化总结。selenium
web自动化测试终篇:总结我理解的ui自动化,整理归纳: https://blog.csdn.net/CCGGAAG/article/details/89669592 web页面自动化知识点 1.we ...
- 微信小程序(二)
创建项目: hello.wxml hello world 每个学习的开始 <view>hello world!</view> hello.js 像 app.js 一样 Page ...
- [loj2850]无进位加法
(似乎漏了一个数据范围,cf上的题面中还有$\sum L\le 3\cdot 10^{5}$) 考虑$a_{i}=2^{k_{i}}$时(不妨$k_{1}\ge k_{2}\ge ...\ge k_{ ...
- JdbcTemplate 、Mybatis、ORM 、Druid 、HikariCP 、Hibernate是什么?它们有什么关系?
JdbcTemplate .Mybatis.ORM .Druid .HikariCP .Hibernate是什么?它们有什么关系? 学完Spring和SpringMVC之后,就急于求成的开始学习起Sp ...
- PHP 日期详细介绍
简介 你可以使用这些函数获取运行 PHP 的服务器的日期和时间, 也可以使用这些函数把日期和时间 格式化成不同格式的字符串. 日期和时间信息在 PHP 内部是以 64 位数字存储的, 它可以覆盖当前时 ...