mybatis中其他数据源也使用XML进行操作(SqlSessionFactory.openSession(Connection connection)方法)

news2024/11/15 10:00:13

文章目录

  • 1. 前言
  • 2. 先说结论
  • 3. 例子
    • 1. 准备数据
    • 2. 思考过程
    • 3. 结论

1. 前言

  1. 当前在使用springboot+mybatis的时候,通常会先在配置文件中配置好数据源,并在Mapper.xml文件编写好相关SQL,使用mybatis进行对数据库进行所谓的crud操作。

  2. 有时候会出现一个项目需要跟多个数据源进行相关操作,通常是使用JdbcTemplate对另一个数据源进行crud相关操作:
    在这里插入图片描述

  3. 虽也可以实现功能,但将SQL写在类里面,与本数据源将SQL写到了XML文件中,总是感觉格格不入,为了统一项目SQL的存放位置,进而研究了SqlSessionFactory.openSession(Connection connection)方法。

2. 先说结论

  1. 在mybatis中SqlSessionFactory中有个方法是 SqlSessionFactory.openSession(Connection connection)方法,可以直接给个数据库连接创建SqlSession

  2. 当拥有了SqlSession,可以使用SqlSession.getMapper(Class clazz) 来获取所谓的Mapper对应的dao层。

  3. 但遗憾的是,无法使用springboot帮我们创建的bean对象SqlSessionFactory,因为其默认是使用SpringManagedTransaction事务,在SqlSessionFactory.openSession(Connection connection)会报错:New spring transactions require a DataSource.

  4. 所以只能自己创建如下:

      @org.junit.Test
        public void selectAll() throws Exception{
            // 其他数据源
            DriverManagerDataSource dataSource = new DriverManagerDataSource();
            dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC");
            dataSource.setUsername("root");
            dataSource.setPassword("HelloWorld");
    
            // 生成SqlSessionFactoryBean对象,为了创建SqlSessionFactory
            SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
            // 数据源
            sqlSessionFactoryBean.setDataSource(dataSource);
            // 接口对应mapper的路径
            sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mappers/*.xml"));
            // 设置事务工厂类,不使用SpringManagedTransaction,原因思考过程已说
            sqlSessionFactoryBean.setTransactionFactory(new JdbcTransactionFactory());
            
            // 获取SqlSessionFactory对象,为了创建SqlSession对象
            final SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBean.getObject();
            // 创建SqlSession
            final SqlSession sqlSession = sqlSessionFactory.openSession(dataSource.getConnection());
            // 获取mapper对应的dao层接口
            final UserDao userDao = sqlSession.getMapper(UserDao.class);
            final List<User> users = userDao.selectAll();
            System.out.println(users);
        }
    
  5. 封装为工具类

     private <T> T getMapper(DataSource dataSource, Class<T> clazz) throws Exception {
            SqlSession sqlSession = createSqlSession(dataSource);
            return sqlSession.getMapper(clazz);
        }
    
        private SqlSession createSqlSession(DataSource dataSource) throws Exception {
            // 生成SqlSessionFactoryBean对象,为了创建SqlSessionFactory
            SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
            // 数据源
            sqlSessionFactoryBean.setDataSource(dataSource);
            // 接口对应mapper的路径
            sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mappers/*.xml"));
            // 设置事务工厂类,不使用SpringManagedTransaction,原因思考过程已说
            sqlSessionFactoryBean.setTransactionFactory(new JdbcTransactionFactory());
    
            // 获取SqlSessionFactory对象,为了创建SqlSession对象
            final SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBean.getObject();
            // 创建SqlSession
            return sqlSessionFactory.openSession(dataSource.getConnection());
        }
    

3. 例子

1. 准备数据

  1. 准备一张表如下:
    在这里插入图片描述

  2. 准备好项目并写好对应的Mapper,如下:

    // dao层
    @Mapper
    public interface UserDao {
        List<User> selectAll();
    }
    
    <!--UserDao.xml -->
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.example.csdn2.mybatis_sqlSession_test.dao.UserDao">
        <select id="selectAll" resultType="com.example.csdn2.mybatis_sqlSession_test.User">
            select * from user2
        </select>
    </mapper>
    

    在这里插入图片描述

2. 思考过程

  1. 一般我们使用mybatis会如下:
    先将yml配置文件配置数据源,mybatis的Mapper位置

    mybatis:
      mapper-locations: classpath:mappers/*.xml
      type-aliases-package: com.example.csdn2
    
    spring:
      datasource:
        username: root
        password: HelloWorld
        url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
    
    

    然后在需要的service层注入dao层的bean对象,直接使用:

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class Test {
    
        @Autowired
        private UserDao userDao;
    
        @org.junit.Test
        public void selectAll() throws Exception{
            System.out.println(userDao.selectAll());
        }
    }
    

    在这里插入图片描述

  2. 上述过程中,是在springboot启动的时候,扫描启动类下的包带有@Mapper的接口,生成其代理的bean对象放入spring容器中,当我们需要使用相关dao层的crud的时候,直接注入即可使用。

  3. 而发现,spring启动帮忙生成的dao层的bean对象已经是跟本项目配置文件中配置的数据源绑定起来了,而我们最开始的目的是将其他数据源也可以使用mybatis的xml方式(sql写入其内),这里固然是无法直接使用spring提供好的dao层bean对象啦,毕竟数据源都来自不一样的内容。

  4. 所以现在的问题:我们要如何创建dao层接口的代理bean对象呢?

  5. mybatis的核心重要类之一:SqlSession,当点进去看该类(接口)的时候,我们惊奇发现mybatis中还可以允许手动创建dao层的bean对象,即在SqlSession接口中有这样子的一个方法:

     /**
       * Retrieves a mapper.
       * @param <T> the mapper type
       * @param type Mapper interface class 
       * @return a mapper bound to this SqlSession 
       */
       // 根据注释推理:
       // 1. Mapper interface class 一个接口且是mapper接口
       // 2. 返回一个mapper对象且绑定这次的sql连接
      <T> T getMapper(Class<T> type);
    

    具体用法如下:

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class Test {
        @Autowired
        private SqlSession sqlSession;
    
        @org.junit.Test
        public void selectAll() throws Exception{
        	// 创建dao层的对象
            final UserDao userDao = sqlSession.getMapper(UserDao.class);
            // 使用方法,查询出内容
            System.out.println(userDao.selectAll());
        }
    }
    

    在这里插入图片描述
    (温馨小提示: 这里的内容是涉及mybatis部分内容,若不熟悉可以先自行百度,或者先认为有这个结论)

  6. 这里我们先小结一下,上述主要是讲了:

    1. 在springboot中一般使用mybatis的方式:知道spring启动会帮我们生成对应dao层的bean对象提供给我们使用。
    2. mybatis可以允许我们手动创建dao层的bean对象,并且使用
  7. 到这里,有的人可能会提问,你怎么知道上述代码中getMapper()方法出来的userDao是新的bean对象,而不是spring容器里面的呢?好问题,来证明一下:

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class Test {
    
        @Autowired
        private UserDao userDao;
    
        @Autowired
        private SqlSession sqlSession;
    
    
        @org.junit.Test
        public void selectAll() throws Exception{
            final UserDao userDao = sqlSession.getMapper(UserDao.class);
            System.out.println("get出来的对象:" + userDao);
            System.out.println("注入出来的对象:" + this.userDao);
        }
    }
    

    在这里插入图片描述

  8. 根据上述使用得知,mybatis可以允许我们手动创建dao层的bean对象,并且使用,但仍然发现,似乎还是使用与本项目配置文件中的数据源,固然还是有问题。这是时候我们知道在spring容器中的SqlSession对象也是用配置文件数据源,那么也就是说明该对象我们无法使用了,得自己创建该对象

  9. 现在的问题则抛到了:如何自己创建SqlSession对象呢?

  10. 当搜索源码的时候,无意中发现SqlSessionFactory类,一看到Factory,这是什么,工厂呀!!!,固然是创建SqlSession的东西,经过一番寻找,发现其方法中有openSession()方法
    在这里插入图片描述

  11. 看我们发现了什么:为一个连接创建 SqlSession

    1. 参数是一个连接:我们可以得到,可以输入其他数据库连接,然后返回SqlSession。
    2. 如果我们得到了SqlSession,岂不是可以直接生成dao层的代理bean对象,卧槽,直接可以使用mapper了。
  12. 迅速编写代码测试一波:

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class Test {
    
        @Autowired
        private SqlSessionFactory sqlSessionFactory;
    
        @org.junit.Test
        public void selectAll() throws Exception{
            // 其他数据源
            DriverManagerDataSource dataSource = new DriverManagerDataSource();
            dataSource.setUrl("jdbc:mysql://localhost:3308/mybatis?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC");
            dataSource.setUsername("root");
            dataSource.setPassword("root_pwd");
    
            // 创建SqlSession
            final SqlSession sqlSession = sqlSessionFactory.openSession(dataSource.getConnection());
            final UserDao userDao = sqlSession.getMapper(UserDao.class);
            final List<User> users = userDao.selectAll();
            System.out.println(users);
        }
    }
    

    在这里插入图片描述

  13. 可恶呀,这里会报错,报错内容是spring的事务要求一个数据源,引起我们思考,我们传入的是一个connection,难道是这里传错内容了?但是根据SqlSessionFactory.openSession()确实可以给个连接?奇怪,完全不懂,没办法了,只能使用绝招,跟源码。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  14. 当时我看到这里就有点懵了,为啥这里会跟事务扯上关系了呢?难道这个是必须的吗?没办法,后来查阅资源后,得到这一句话:

    1. mybatis操作的时候跟数据库的每一次连接,都需要创建一个会话,我们用openSession()方法来创建。这个会话里面需要包含一个Executor用来执行 SQL。
    2. Executor又要指定事务类型和执行器的类型
  15. 很好,非常好,看来是无法绕过这个事务了,当我们点击TransactionFactory接口(创建Transaction事务的接口):
    在这里插入图片描述
    可以看到有三种实现类,我们知道上述源码跟踪发现,刚刚抛异常的是 第三个工厂创建出来的springManagedTransaction事务,点击其他类型工厂发现,其他两种不会报错:
    在这里插入图片描述

  16. 现在的问题就到了:springboot启动的时候,是如何指定这个事务工厂类型呢,如果我们让它使用其他两种类型,岂不是可以实现为一个连接创建 SqlSession,得到了SqlSession,可以直接生成dao层的代理bean对象,直接可以使用mapper了

  17. 很遗憾,我翻阅资料发现,如果是使用了springboot整合mybatis的话,那还真没办法,如果是单独使用mybatis就可以,在单独使用mybatis的时候,可以从配置文件入手,这是我觉得比较好的一篇文章:https://blog.csdn.net/niujifei/article/details/125519028。

  18. 其实到了这里就是有关于springboot整合mybatis的相关知识点了,这里还是不详细说明了,只是看个结果:
    在这里插入图片描述

    在这里插入图片描述

  19. 也就是说 spring自带生成的SqlSessionFactory工厂里面的事务就是用SpringManagedTransaction工厂创建的,固然没办法按照我们一开始预想的实现方案,可恶啊。

  20. 要放弃了吗?不,既然spring帮我们生成的bean对象无法实现,我们直接自己new 需要的对象出来,给我冲。

3. 结论

  1. 根据上述思考过程,spring生成的无论是SqlSessionFactoryBean,SqlSessionFactory,SqlSession都无法现实我们需要的,那么我们就自己构建

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class Test {
        
        @org.junit.Test
        public void selectAll() throws Exception{
            // 其他数据源
            DriverManagerDataSource dataSource = new DriverManagerDataSource();
            dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC");
            dataSource.setUsername("root");
            dataSource.setPassword("HelloWorld");
    
            // 生成SqlSessionFactoryBean对象,为了创建SqlSessionFactory
            SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
            // 数据源
            sqlSessionFactoryBean.setDataSource(dataSource);
            // 接口对应mapper的路径
            sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mappers/*.xml"));
            // 设置事务工厂类,不使用SpringManagedTransaction,原因思考过程已说
            sqlSessionFactoryBean.setTransactionFactory(new JdbcTransactionFactory());
    
            // 获取SqlSessionFactory对象,为了创建SqlSession对象
            final SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBean.getObject();
            // 创建SqlSession
            final SqlSession sqlSession = sqlSessionFactory.openSession(dataSource.getConnection());
            // 获取mapper对应的dao层接口
            final UserDao userDao = sqlSession.getMapper(UserDao.class);
            final List<User> users = userDao.selectAll();
            System.out.println(users);
        }
    }
    

    在这里插入图片描述

  2. 我们只要稍微封装一下该方法,就可以作为工具类了,如下:

    
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class Test {
    
        @org.junit.Test
        public void selectAll() throws Exception {
            // 其他数据源
            DriverManagerDataSource dataSource = new DriverManagerDataSource();
            dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC");
            dataSource.setUsername("root");
            dataSource.setPassword("HelloWorld");
    
            // 获取mapper对应的dao层接口
            final UserDao userDao = getMapper(dataSource, UserDao.class);
            final List<User> users = userDao.selectAll();
            System.out.println(users);
        }
    
        private <T> T getMapper(DataSource dataSource, Class<T> clazz) throws Exception {
            SqlSession sqlSession = createSqlSession(dataSource);
            return sqlSession.getMapper(clazz);
        }
    
        private SqlSession createSqlSession(DataSource dataSource) throws Exception {
            // 生成SqlSessionFactoryBean对象,为了创建SqlSessionFactory
            SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
            // 数据源
            sqlSessionFactoryBean.setDataSource(dataSource);
            // 接口对应mapper的路径
            sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mappers/*.xml"));
            // 设置事务工厂类,不使用SpringManagedTransaction,原因思考过程已说
            sqlSessionFactoryBean.setTransactionFactory(new JdbcTransactionFactory());
    
            // 获取SqlSessionFactory对象,为了创建SqlSession对象
            final SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBean.getObject();
            // 创建SqlSession
            return sqlSessionFactory.openSession(dataSource.getConnection());
        }
    }
    
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/69540.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

nginx代理https妈妈级手册

目录 背景说明 相关地址 https证书生成 nginx安装及配置 结果展示​编辑 背景说明 为了保证传输加密、访问安全&#xff0c;我们采用nginx服务器将http服务代理为https。所需材料&#xff1a;openssl&#xff08;用来生成证书&#xff09;、http服务、nginx自身。 相关地址…

C/C++第三方库zeromq、log4cpp交叉编译、本地安装ubuntu180.04

一、zeromq的编译安装 1&#xff09;ubuntu下命令 apt-get install libzmq3-dev不推荐这种方式&#xff0c;因为很可能安装的版本并不是最新的&#xff1b; 2&#xff09;自己编译安装&#xff08;推荐&#xff09; 地址&#xff1a;https://github.com/zeromq/libzmq/relea…

设计模式--装饰者模式

文章目录前言一、未使用设计模式二、装饰者模式1.定义2.角色三、应用场景四、优缺点优缺前言 晓子&#xff08;咖啡店员&#xff09;&#xff0c;来一杯美式&#xff0c;加点威士忌和砂糖。 抱歉啊&#xff0c;猫。收银系统还没有你说的组合&#xff0c;要不换一个&#x1f60…

React 的调度系统 Scheduler

大家好&#xff0c;我是前端西瓜哥。今天来学习 React 的调度系统 Scheduler。 React 版本为 18.2.0 React 使用了全新的 Fiber 架构&#xff0c;将原本需要一次性递归找出所有的改变&#xff0c;并一次性更新真实 DOM 的流程&#xff0c;改成通过时间分片&#xff0c;先分成一…

nnUnet测试

https://github.com/MIC-DKFZ/nnUNet nnUnet要在Windows上跑起来有点麻烦&#xff0c;主要是项目路径的问题&#xff0c;我目前测试了2分类遥感数据&#xff08;其实只要是二分类都行&#xff0c;无所谓什么数据&#xff09;&#xff0c;我这里说难是因为我没有安装&#xff0…

【SQL】MVCC 多版本并发控制

MVCC多版本并发控制快照读与当前读隔离级别隐藏字段&#xff0c;undo log 版本链隐藏字段trx_id版本链read view举例说明read committed&#xff08;读已提交&#xff09;隔离级别下repeatable read&#xff08;可重复读&#xff09;隔离级别下innodb如何解决幻读总结并发问题的…

LaTex使用技巧9:argmin / argmax下标写法

记录两种写法 1.arg⁡max⁡θ\mathop{\arg\max}\limits_{\theta}θargmax​的写法 写法1&#xff1a; $\mathop{\arg\max}\limits_{\theta}$ 写法2&#xff1a; $\sideset{}{}{\arg\max}_{\theta}^{} $ 2.arg⁡min⁡θ\mathop{\arg\min}\limits_{\theta}θargmin​的写法 写法…

STL常用生成算法和集合算法(20221207)

STL的常用算法 概述&#xff1a; 算法主要是由头文件<algorithm> <functional> <numeric> 组成。 <algorithm>是所有STL头文件中最大的一个&#xff0c;涉及比较、交换、查找、遍历等等&#xff1b; <functional>定义了一些模板类&#xff0…

做一个公司网站大概要多少钱?

做一个公司网站大概要多少钱&#xff0c;很多公司在做网站之前可能已经简单了解过费用&#xff0c;但是费用差距都会比较大&#xff0c;为什么的呢&#xff0c;因为一般都是受到制作方式因素的影响。下面给大家说说不同的方式做一个公司网站大概要多少钱。 一、自己/团队做公司…

SQLyog —— 图形化工具使用

SQLyog下载链接&#xff1a; 点击跳转 在这一篇内容MySQL数据库 —— 常用语句当中讲到关于MySQL数据库命令的基本使用&#xff0c;这一篇是关于SQLyog数据库图形化工具的内容&#xff0c;先进行安装演示后在通过SQLyog进行操作数据库&#xff1a; SQLyog 安装 下载完成之后双击…

pageoffice在线打开word文件加盖电子印章

一、加盖印章的 js 方法 js方法 二、常见使用场景 1、常规盖章。弹出用户名、密码输入框&#xff0c;选择对应印章。 点击盖章按钮弹出用户名密码登录框&#xff0c;登录以后显示选择电子印章。 document.getElementById("PageOfficeCtrl1").ZoomSeal.AddSeal(…

Python模块pathlib操作文件和目录操作总结

前言 目前大家常用的对于文件和操作的操作使用 os.path 较多&#xff0c;比如 获取当前路径os.getcwd()&#xff0c;判断文件路径是否存在os.path.exists(folder) 等等。 在Python3.4开始&#xff0c;官方提供了 pathlib 面向对象的文件系统路径&#xff0c;核心的点在于 面向…

chatGPT代码写的有点好啊,程序员要失业了?

AI神器ChatGPT 火了。 能直接生成代码、会自动修复bug、在线问诊、模仿莎士比亚风格写作……各种话题都能hold住&#xff0c;它就是OpenAI刚刚推出的——ChatGPT。 有脑洞大开的网友甚至用它来设计游戏&#xff1a;先用ChatGPT生成游戏设定&#xff0c;再用Midjourney出图&…

element-plus elplus el-tree三种图标自定义 并且点击图标展开收起 点击文字获取数据

前言 公司需求,需要实现如下样式的树形列表 (基于vue3 element-plus) 当节点展开时,显示展开的文件夹图标,当节点收起时显示收起的文件夹,最后一级显示文件样式 废话没有了, 代码如下 <!-- 树形列表组件 --> <template><div class"tree-input" v-i…

Vue学习:回顾Object.defineProperty(给对象添加或者定义属性的)

<script>//定义对象let person{name:李四,sex:"男"}Object.defineProperty(person,age,{value:18});//参数:添加属性的对象 添加的属性名 配置项console.log(person)</script> 颜色不同&#xff1a;说明了age不可以枚举age属性不参与遍历 Object.keys(…

电脑屏幕录制怎么弄?电脑上怎么录制屏幕, 3个实用方法

对于日常办公的小伙伴来说&#xff0c;电脑、键盘、鼠标等办公设备都是不可分割的。事实上&#xff0c;不仅仅是在日常办公&#xff0c;在很多业余的活动中&#xff0c;也会使用到电脑设备。在使用电脑的时候&#xff0c;会经常有需要录制电脑屏幕的情况&#xff0c;比如记录会…

阿里云Linux热扩容云盘(growpart和resize2fs工具)

阿里云linux机器系统盘空间不够进行扩容 一、扩容物理盘 阿里云控制台在线扩容完成 二、安装growpart工具和resize2fs工具 [rootA ~]# yum install cloud-utils-growpart [rootA ~]# yum install xfsprogs 三、检查扩容磁盘属性 1、检查云盘大小 /dev/vda1显示容量为20G(在线…

Properties类的使用

Properties类是一个配置文件类&#xff0c;主要作用就是用来封装配置文件&#xff0c;将配置文件加载成为一个Properties对象。 注意&#xff1a;Properties类一般用来加载 .properties配置文件 首先看一下.properties配置文件的样子 driverClassNamecom.mysql.cj.jdbc.Drive…

电力系统潮流【牛顿-拉夫逊法】(4节点、5节点、6节点、9节点)(Matlab代码实现)

目录 1 概述 2 电力系统潮流计算概述 2.1 电力潮流发展进程 2.2牛顿拉夫逊法潮流计算 3 仿真结果 4 Matlab代码及文章讲解 &#x1f4cb;&#x1f4cb;&#x1f4cb;本文目录如下&#xff1a;⛳️⛳️⛳️ ​ 1 概述 最初&#xff0c;电力系统潮流计算是通过人工手算的。后…

Java内存区域与内存分配策略

java很聪明&#xff0c;它将手动改为自动&#xff0c;把内存的控制权交给了虚拟机&#xff0c;下面我们就来探究一下JVM是怎么进行自动内存管理的。 手动内存管理分为两部分&#xff1a;给对象分配内存和回收分配给对象的内存。 一、运行时数据区域 线程公有 在运行时数据区中…