基于SqlSessionFactory的openSession方法使用
作者:服务器端的cookie 发布时间:2023-02-26 23:10:15
SqlSessionFactory的openSession方法
正如其名,Sqlsession对应着一次数据库会话。
由于数据库回话不是永久的,因此Sqlsession的生命周期也不应该是永久的,相反,在你每次访问数据库时都需要创建它(当然并不是说在Sqlsession里只能执行一次sql,你可以执行多次,当一旦关闭了Sqlsession就需要重新创建它)。
创建Sqlsession的地方只有一个
那就是SqlsessionFactory的openSession方法
public SqlSessionopenSession() {
returnopenSessionFromDataSource(configuration.getDefaultExecutorType(),null, false);
}
我们可以看到实际创建SqlSession的地方
是openSessionFromDataSource,如下:
private SqlSessionopenSessionFromDataSource(ExecutorType execType, TransactionIsolationLevellevel, boolean autoCommit) {
Connectionconnection = null;
try {
finalEnvironment environment = configuration.getEnvironment();
final DataSourcedataSource = getDataSourceFromEnvironment(environment);
TransactionFactory transactionFactory =getTransactionFactoryFromEnvironment(environment);
connection = dataSource.getConnection();
if (level != null) {
connection.setTransactionIsolation(level.getLevel());
}
connection = wrapConnection(connection);
Transaction tx = transactionFactory.newTransaction(connection,autoCommit);
Executorexecutor = configuration.newExecutor(tx, execType);
returnnewDefaultSqlSession(configuration, executor, autoCommit);
} catch (Exceptione) {
closeConnection(connection);
throwExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
可以看出,创建sqlsession经过了以下几个主要步骤:
1) 从配置中获取Environment;
2) 从Environment中取得DataSource;
3) 从Environment中取得TransactionFactory;
4) 从DataSource里获取数据库连接对象Connection;
5) 在取得的数据库连接上创建事务对象Transaction;
6) 创建Executor对象(该对象非常重要,事实上sqlsession的所有操作都是通过它完成的);
7) 创建sqlsession对象。
Executor的创建
Executor与Sqlsession的关系就像市长与书记,Sqlsession只是个门面,真正干事的是Executor,Sqlsession对数据库的操作都是通过Executor来完成的。与Sqlsession一样,Executor也是动态创建的:
public ExecutornewExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType :executorType;
executorType = executorType == null ?ExecutorType.SIMPLE : executorType;
Executor executor;
if(ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this,transaction);
} elseif(ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this,transaction);
} else {
executor = newSimpleExecutor(this, transaction);
}
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
executor =(Executor) interceptorChain.pluginAll(executor);
return executor;
}
可以看出,如果不开启cache的话,创建的Executor只是3中基础类型之一,BatchExecutor专门用于执行批量sql操作,ReuseExecutor会重用statement执行sql操作,SimpleExecutor只是简单执行sql没有什么特别的。开启cache的话(默认是开启的并且没有任何理由去关闭它),就会创建CachingExecutor,它以前面创建的Executor作为唯一参数。CachingExecutor在查询数据库前先查找缓存,若没找到的话调用delegate(就是构造时传入的Executor对象)从数据库查询,并将查询结果存入缓存中。
Executor对象是可以 * 件拦截的,如果定义了针对Executor类型的插件,最终生成的Executor对象是被各个插件插入后的代理对象
Mapper
Mybatis官方手册建议通过mapper对象访问mybatis,因为使用mapper看起来更优雅,就像下面这样:
session = sqlSessionFactory.openSession();
UserDao userDao= session.getMapper(UserDao.class);
UserDto user =new UserDto();
user.setUsername("iMbatis");
user.setPassword("iMbatis");
userDao.insertUser(user);
看起来没什么特别的,和其他代理类的创建一样,我们重点关注一下MapperProxy的invoke方法
MapperProxy的invoke
我们知道对被代理对象的方法的访问都会落实到代理者的invoke上来,MapperProxy的invoke如下:
public Objectinvoke(Object proxy, Method method, Object[] args) throws Throwable{
if (method.getDeclaringClass()== Object.class) {
return method.invoke(this, args);
}
finalClass<?> declaringInterface = findDeclaringInterface(proxy, method);
finalMapperMethod mapperMethod = newMapperMethod(declaringInterface, method, sqlSession);
final Objectresult = mapperMethod.execute(args);
if (result ==null && method.getReturnType().isPrimitive()&& !method.getReturnType().equals(Void.TYPE)) {
thrownewBindingException("Mapper method '" + method.getName() + "'(" + method.getDeclaringClass()
+ ") attempted toreturn null from a method with a primitive return type ("
+ method.getReturnType() + ").");
}
return result;
}
可以看到invoke把执行权转交给了MapperMethod,我们来看看MapperMethod里又是怎么运作的:
public Objectexecute(Object[] args) {
Objectresult = null;
if(SqlCommandType.INSERT == type) {
Objectparam = getParam(args);
result= sqlSession.insert(commandName, param);
} elseif(SqlCommandType.UPDATE == type) {
Object param = getParam(args);
result= sqlSession.update(commandName, param);
} elseif(SqlCommandType.DELETE == type) {
Objectparam = getParam(args);
result= sqlSession.delete(commandName, param);
} elseif(SqlCommandType.SELECT == type) {
if (returnsVoid &&resultHandlerIndex != null) {
executeWithResultHandler(args);
} elseif (returnsList) {
result = executeForList(args);
} elseif (returnsMap) {
result = executeForMap(args);
} else {
Object param = getParam(args);
result = sqlSession.selectOne(commandName, param);
}
} else {
thrownewBindingException("Unknown execution method for: " + commandName);
}
return result;
}
可以看到, MapperMethod 就像是一个分发者,他根据参数和返回值类型选择不同的 sqlsession 方法来执行。这样 mapper 对象与 sqlsession 就真正的关联起来了
openSession()到底做了什么
从环境中获取事务的工厂,返回一个environment对象获取事务工厂
事务工厂创建事务
通过configuration拿到一个执行器传入事务(Transaction)和类型(execType(枚举))
最后返回一个DefaultSqlSession
openSession底层就是做各种成员变量的初始化
例如:configuration,executor,dirty(内存当中的数据与数据库中
来源:https://blog.csdn.net/qq_35854462/article/details/74004441


猜你喜欢
- 目前有两种流行Spring定时器配置:Java的Timer类和OpenSymphony的Quartz。1.Java Timer定时首先继承j
- IDEA自定义pom依赖抽离公共代码,代码解耦,减少重复第一步: 抽离公共部分的代码第二步: 点击右侧工具栏的maven,刷新,点击skip
- mybatis自动生成实体类、mapper文件、mapper.xml文件若采用mybatis框架,数据库新建表,手动编写的话,需要编写大量的
- XY个人记SparkSQL是spark的一个模块,主入口是SparkSession,将SQL查询与Spark程序无缝混合。DataFrame
- 有了上一节中得到的正则表达式,那么就可以用来构造 NFA 了。NFA 可以很容易的从正则表达式转换而来,也有助于理解正则表达式表示的模式。一
- 前言我们在首次使用内容类 App 的时候,不少都会让我们选择个人偏好。这种通常是通过标签来实现,比如列举出一系列的技术栈,然后让我们选择。通
- 一,JDK环境变量;下载地址:HTTP://pan.baidu.com/s/1bpG3KYz1,新建变量名:JAVA_HOME,变量值:C:
- Spring与Hiberante整合通过hibernate的学习,我们知道,hibernate主要在hibernate.cfg.xml配置文
- 一、什么是CharacterEncodingFilter官方解释如下是spring内置过滤器的一种,用来指定请求或者响应的编码格式。在web
- 关联篇:深入Android的消息机制源码详解-Handler,MessageQueue与Looper关系关联篇:Handler内存泄漏及其
- 前言之前采取项目中嵌套html页面,实现基本的登录校验、权限校验、登出操作、记住我等功能试下。但是,现在的开发基本都是前后分离样式,后端并不
- 在Controller层时,往往会需要校验或验证某些操作,而在每个Controller写重复代码,工作量比较大,这里在Springboot项
- 一:问题描述 在已经root过的android设备下,app执行一个linux命令,app需要获取su权限,在某些a
- 前言;Apache common-pool对象池介绍:对象生命周期、Config详解、代码说明对象生命周期Config详解maxActive
- 这篇文章主要介绍了简单了解Spring中BeanFactory与FactoryBean的区别,文中通过示例代码介绍的非常详细,对大家的学习或
- 本文实例为大家分享了Android实现京东首页效果的具体代码,供大家参考,具体内容如下1.效果图:2.布局源码链接<?xml vers
- 这篇博客主要介绍的是 Android 主流各种机型和各种版本的悬浮窗权限适配,但是由于碎片化的问题,所以在适配方面也无法做到完全的主流机型适
- java8的stream流能完美解对象集合去重问题. List<UserCar> list1 = new ArrayList()
- 程序员讨厌写文档, 讨厌写注释, 而我还讨厌写日志, 输出一个 "Id=5, 姓名=王大锤
- 当屏幕变为横屏的时候,系统会重新呼叫当前Activity的OnCreate方法,你可以把以下方法放在你的OnCreate中来检查当前的方向,