• java_Springboot_Mybatis-Plus_自定义多数据源MybatisSqlSessionFactoryBean配置


    java_Springboot_Mybatis-Plus_自定义多数据源MybatisSqlSessionFactoryBean配置方法

    一、引言

    需要在服务中集成表结构维护的功能,维护表结构就需要使用具有执行DDL脚本权限的账号。
    为了保证系统的安全性,考虑在工程中配置多个数据源引入不同权限账号,高权限账号只在特定逻辑中使用,其它默认业务使用低权限账号。
    加入新的数据源不能影响已有的功能,保证已有功能继续使用只具有CRUD权限的账号。
    看了几个多数据源接入方案,都不太满足需求。

    • Springboot默认支持的多数据源
    • Mybatis-Plus的多数据源既动态数据源dynamic-datasource插件
    • Alibaba Druid动态数据源

    二、环境

    • JDK 1.0
    • SpringBoot 1.5.6
    • Mybaits 3.5.3
    • Mybatis-plus 3.3.1

    三、集成过程中遇到的问题

    3.1 Invalid bound statement (not found) 错误

    由于系统中调用了Mybatis-plus的BaseMapper中的扩展方法selectBatchIds(),
    调用selectBatchIds()方法的位置都报:Invalid bound statement (not found) 错误。
    一般遇到这种问题基本都是接口中定义的方法名在对应的XML文件中没有定义。
    但是现在使用的是com.baomidou.mybatisplus.core.mapper.BaseMapper中的扩展方法,不需要在XML中定义的!
    问题产生原因是没有使用Mybatis-Plust自定义的MybatisSqlSessionFactoryBean构建 SqlSessionFactory实例导致,
    改用后解决了Invalid bound statement (not found)的问题。

        @Bean(name = "defSqlSessionFactory")
        @Primary
        public SqlSessionFactory defSqlSessionFactory(@Qualifier("defDataSource") DataSource dataSource) throws Exception {
            MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
            //SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
            bean.setDataSource(dataSource);
            //设置mybatis的xml所在位置
            Resource[] resources = new PathMatchingResourcePatternResolver().getResources("classpath:com/.../mapper/**/*Mapper.xml");
            bean.setMapperLocations(resources);
            SqlSessionFactory factory = bean.getObject();
            return factory;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3.2 默认数据源问题

    配置多个数据源时,必须明确声明DataSource、SqlSessionFactory、PlatformTransactionManager、SqlSessionTemplate关键对象!
    在默认的Bean上加@Primary注解,标记为默认配置。以下为同一数据源的Bean配置,多个数据源需要加入多套配置。

    @Configuration
    public class DbDefaultConfig {
    
        @Bean(name = "defDataSource")
        @Primary
        @ConfigurationProperties(prefix = "spring.datasource")
        public DataSource defDataSource() {
            DataSource datasource =  DataSourceBuilder.create().build();
            return datasource;
        }
    
        @Bean(name = "defSqlSessionFactory")
        @Primary
        public SqlSessionFactory defSqlSessionFactory(@Qualifier("defDataSource") DataSource dataSource) throws Exception {
            MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
            //SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
            bean.setDataSource(dataSource);
            //设置mybatis的xml所在位置
            Resource[] resources = new PathMatchingResourcePatternResolver().getResources("classpath:com/.../mapper/**/*Mapper.xml");
            bean.setMapperLocations(resources);
            SqlSessionFactory factory = bean.getObject();
            return factory;
        }
    
        /**
         * JDBC事务管理器
         * @param dataSource
         * @return
         */
        @Bean("defTransactionManager")
        @Primary
        public PlatformTransactionManager txManager(DataSource dataSource) {
            return new DataSourceTransactionManager(dataSource);
        }
    
        @Bean(name = "defSqlSessionTemplate")
        @Primary
        public SqlSessionTemplate defSqlSessionTemplate(@Qualifier("defSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
            SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(sqlSessionFactory);
            return sqlSessionTemplate;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    3.3 Mybatis-Puls分页组件失效问题

    使用com.baomidou.mybatisplus.extension.plugins.pagination.Page插件做分页查询时,发现返回的total、pages两个关键的分页属性值都是0,明显分页插件没有生效。

    {
        "records": [
            ...
        ],
        "total": 0, --!!!
        "size": 10,
        "current": 1,
        "orders": [],
        "hitCount": false,
        "searchCount": true,
        "pages": 0  --!!!
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    分页组件是基于拦截器com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor实现的,该拦截器对StatementHandler的实例方法prepare进行拦截,对total、pages属性赋值,实现的分页查询功能。问题产生原因是由于手动实现了多个SqlSessionFactory实例,但是实例中没有手动注入拦截器导致的问题。解决方法是:

    1.声明一个分页拦截器;

    @Configuration
    public class MybatisPlusConfig {
        @Bean
        public PaginationInterceptor paginationInterceptor(){
            PaginationInterceptor page = new PaginationInterceptor();
            page.setDbType(DbType.POSTGRE_SQL); //这里指明数据库类型
            return page;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2.将拦截器添加到SqlSessionFactory实例中;

    
    @Configuration
    public class MybatisConfig {
        @Autowired
        private List sqlSessionFactoryList;
        @Autowired
        private PaginationInterceptor paginationInterceptor;
    
        @PostConstruct
        public void addSqlInterceptor() {
            SchemaParamsterInterceptor interceptor = new SchemaParamsterInterceptor();
            for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) {
                //mybaits分页拦截器
                sqlSessionFactory.getConfiguration().addInterceptor(paginationInterceptor);
                ...
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    四、测试数据源是否正确

    @RunWith(SpringRunner.class)
    //@Transactional
    @SpringBootTest(classes = StartApplication.class, webEnvironment = SpringBootTest.WebEnvironment.NONE)
    @ActiveProfiles("")
    public class MultiDatasourceTest {
        @Autowired
        private List sqlSessionFactoryList;
    
        @Before
        public void before(){
        }
        @Test
        public void datasourceTest(){
            System.out.println("sqlSessionFactoryList Size = " + sqlSessionFactoryList.size());
            boolean success = true;
            for(SqlSessionFactory f:sqlSessionFactoryList ){
                System.out.println("【工厂】:"+f.toString());
                try {
                    datasourceTest(f);
                    System.out.println("成功!!!");
                }catch (Exception ex){
                    System.out.println("异常:"+ex.toString());
                    if(success)
                        success = false;
                }
            }
            Assert.assertTrue("存在不支持的查询!",success);
        }
    
        private boolean datasourceTest(SqlSessionFactory factory){
            MyTestMapper mapper = factory.openSession(true).getMapper(MyTestMapper.class);
            //xml中的方法
            Object objPk = mapper.selectByPrimaryKey("111");
            //mybatis-plus BaseMapper 中的扩展方法(使用前必须在对象上加 @TableName,pk字段上加@TableId注解)
            Object objIds = mapper.selectBatchIds(Arrays.asList("1","2"));
    
            return true;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    五、总结

    构建SqlSessionFactory必须使用MybatisPlust实现的MybatisSqlSessionFactoryBean对象。
    项目引入Mybatis-Puls依赖包后,会自动化注入一个SqlSessionFactory实例(详见:com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration#sqlSessionFactory()方法),这个实例注入是有条件的,即只在没有SqlSessionFactory实例时注入,使用@ConditionalOnMissingBean注解做的约束。
    梳理了一下Mapper实例的构建过程,发现调用的扩展方法必须继承BaseMapper类,Mapper实例又是通过SqlSessionFactory实例创建的,
    大概率Mapper扩展方法绑定在MybatisSqlSessionFactoryBean的实例方法bean.getObject()中实现的。

  • 相关阅读:
    智慧安防AI视频智能分析云平台EasyCVR加密机授权小tips
    计算机毕业论文java毕业设计选题源代码javaweb企业门户网站官网
    平衡树相关笔记
    Redis魔法:点燃分布式锁的奇妙实现
    Linux系统信息收集
    PIL如何批量给图片添加文字水印?
    【Datawhale】扩散模型学习笔记 第一次打卡
    TensorFlow的transformer类模型文件转换为pytorch
    redis集群主从扩容(docker中)
    设计模式再探——原型模式
  • 原文地址:https://blog.csdn.net/xxj_jing/article/details/133355731