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

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

目录

  • java_Springboot_Mybatis-Plus_自定义多数据源MybatisSqlSessionFactoryBean配置方法
  • 引言
  • 环境
  • 集成过程中遇到的问题
    • Invalid bound statement (not found) 错误
    • 默认数据源问题
  • 测试数据源是否正确
  • 总结

引言

需要在服务中集成表结构维护的功能,维护表结构就需要使用具有执行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

集成过程中遇到的问题

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;
    }

默认数据源问题

配置多个数据源时,必须明确声明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;
    }
}

测试数据源是否正确

@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;
    }
}

总结

构建SqlSessionFactory必须使用MybatisPlust实现的MybatisSqlSessionFactoryBean对象,原理没有深入的去看。
梳理了一下Mapper实例的构建过程,发现调用的扩展方法必须继承BaseMapper类,Mapper实例又是通过SqlSessionFactory实例创建的,
大概率Mapper扩展方法绑定在MybatisSqlSessionFactoryBean的实例方法bean.getObject()中实现的。

你可能感兴趣的:(java,mybatis,java,spring,boot)