我的编程空间,编程开发者的网络收藏夹
学习永远不晚

基于SqlSessionFactory的openSession方法使用

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

基于SqlSessionFactory的openSession方法使用

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(内存当中的数据与数据库中

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

基于SqlSessionFactory的openSession方法使用

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

基于RestTemplate的使用方法(详解)

1.postForObject :传入一个业务对象,返回是一个String调用方:BaseUser baseUser=new BaseUser();baseUser.setUserid(userid);baseUser.setPass(pa
2023-05-31

node.js基于express使用websocket的方法

本文实例讲述了node.js基于express使用websocket的方法。分享给大家供大家参考,具体如下: 这个效果我也是翻了好长时间的资料,测试才成功的,反正成功,大家看看吧 首先你需要安装socket.io模块npm install
2022-06-04

使用 Golang 探讨基于方法的编程思维

面向方法的编程思维是一种将程序设计从对象的角度转向方法的使用的编程范式。在这种编程思维下,重点不再是对象的属性和数据,而是对象的方法和行为。这种方法可以使代码更加模块化、可复用和可维护。在本文中,我们将以 Golang 为例来探讨面向方法的
使用 Golang 探讨基于方法的编程思维
2024-02-26

关于TransparentBlt的使用方法

TransparentBlt是GDI函数之一,用于在Windows平台上绘制透明图像。它可以将源图像的一部分或全部绘制到目标设备上,并将指定的颜色作为透明色进行处理。使用TransparentBlt函数的一般步骤如下:1. 创建源图像和目标
2023-08-08

GNS3的基本使用方法

GNS3 基本使用方法1.一张基本的拓扑图需要一台路由器,一台交换机,PC一台这里是所有的路由器和交换机及PC,在GNS3里面将路由器直接拖到工作面板中是没有用的,因为每个路由器需要对应的镜像,如图所示:添加镜像的方法在这里面选择对
2023-01-31

基于ScheduledExecutorService的方法有哪些

这篇文章主要介绍基于ScheduledExecutorService的方法有哪些,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!开发中,往往遇到另起线程执行其他代码的情况,用java定时任务接口ScheduledExe
2023-05-31

mybatis的基本使用方法

本篇文章给大家分享的是有关mybatis的基本使用方法,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。具体代码如下所示:
2023-05-31

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录