背景

在维护公司一个老项目时,出于方便的考虑,准备在项目中引入Mybatis-plus作为持久层,那么这就涉及到新老代码共存的问题。随后由于该项目是一个数据产品相关项目,有一个日志模块会记录用户的调用记录,该日志数据落库在MySQL现已存储8kw+数据,已经不堪重负了,同时产品同学期望完善一下这块的数据统计相关功能,如日流水调用量,调用趋势、商户账单相关功能,因此准备对这块日志存储进行改造,将后续日志请求落库到Clickhouse中。

改造过程

持久层采用Mybatis-plus

在用easy-code生成了mybatisplus模板信息后启动项目抛出异常如下

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)

这是因为Mybatis-plus未动态生成SQL导致无绑定的statement

解决方案

  1. 将XML路径及其实体别名映射实体配置名称修改为适配Mybatis-plus配置

    mybatis-plus.type-aliases-package=com.baidu.pojo
    mybatis-plus.mapper-locations=classpath:mybatis/mapper/*.xml
    
  2. 手动设置SqlSessionFactory为MybatisSqlSessionFactoryBean(该工厂类是经过Mybatis-plus增强的类,通过此类才能动态生成SQL)

    
        @Primary
        @Bean(name = "mysqlSessionFactory")
        public SqlSessionFactory mysqlSessionFactory(@Qualifier("mysqlDataSource") DataSource dataSource) throws Exception {
            // MP需要使用MybatisSqlSessionFactoryBean,否则无法动态生成SQL
            final MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean();
            sessionFactory.setDataSource(dataSource);
            sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:com/***/***/***/dal/mapper/*.xml"));
            MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
            mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
            sessionFactory.setPlugins(mybatisPlusInterceptor);
            return sessionFactory.getObject();
        }
    

同时有一点需要主要,如果主键ID需要采用主键自增方式生成ID,需要设置,默认是IdType.NONE(若是未指定主键 ID 在调用com.baomidou.mybatisplus.core.mapper.BaseMapper#selectById 根据主键查询的话也会出现找到对应 statement 情况)

@TableId(type = IdType.INPUT)

对于需要调用分页查询时,还需设置分页插件,如上SqlSessionFactory配置设置PaginationInnerInterceptor

集成Clickhouse,同时与MySQL共存

Clickhouse数据源配置


@Configuration
@EnableConfigurationProperties(ClickHouseDruidProperties.class)
@MapperScan(basePackages = "com.***.clickhouse", sqlSessionTemplateRef = "clickHouseSqlSessionTemplate")
public class ClickHouseDataSourceConfig {

    /**
     * clickHouse数据源
     *
     * @param clickHouseDruidProperties
     * @return
     */
    @Bean(name = "clickHouseDataSource")
    public DataSource clickHouseDataSource(ClickHouseDruidProperties clickHouseDruidProperties) {
        DruidConnectionProperties defaultProperties = DruidConnectionProperties.withDefault(new DefaultConnectionProperties());
        BeanUtils.copyProperties(clickHouseDruidProperties, defaultProperties, CommonUtils
                .getNullPropertyNames(clickHouseDruidProperties));
        DruidDataSource dataSource = DatasourceConfigUtils.createDataSource(defaultProperties);
        dataSource.setName("merchantdb");
        return dataSource;
    }

    /**
     * session factory
     *
     * @param dataSource
     * @return
     * @throws Exception
     */
    @Bean(name = "clickHouseSqlSessionFactory")
    public SqlSessionFactory clickHouseSqlSessionFactory(@Qualifier("clickHouseDataSource") DataSource dataSource) throws Exception {
        final MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.CLICK_HOUSE));
        bean.setPlugins(mybatisPlusInterceptor);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:com/***/clickhouse/*.xml"));
        return bean.getObject();
    }

    /**
     * transaction manager
     *
     * @param dataSource
     * @return
     */
    @Bean(name = "clickHouseTransactionManager")
    public DataSourceTransactionManager clickHouseTransactionManager(@Qualifier("clickHouseDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    /**
     * build sql session template
     *
     * @param sqlSessionFactory
     * @return
     */
    @Bean(name = "clickHouseSqlSessionTemplate")
    public SqlSessionTemplate clickHouseSqlSessionTemplate(@Qualifier("clickHouseSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

MySQL数据源配置

@Configuration
@MapperScan(basePackages = "com.***.dao", sqlSessionTemplateRef = "mySqlSessionTemplate")
@EnableConfigurationProperties(MySQLDruidProperties.class)
public class MybatisConfiguration {

    /**
     * tplinker mysql数据源
     *
     * @param properties
     * @return
     */
    @Bean(name = "mysqlDataSource")
    public DataSource mysqlDataSource(MySQLDruidProperties properties) {
        DruidConnectionProperties defaultProperties = DruidConnectionProperties.withDefault(new DefaultConnectionProperties());
        BeanUtils.copyProperties(properties, defaultProperties, CommonUtils.getNullPropertyNames(properties));
        DruidDataSource dataSource = DatasourceConfigUtils.createDataSource(defaultProperties);
        dataSource.setName("merchantdb");
        return dataSource;
    }

    @Primary
    @Bean(name = "mysqlSessionFactory")
    public SqlSessionFactory mysqlSessionFactory(@Qualifier("mysqlDataSource") DataSource dataSource) throws Exception {
        // MP需要使用MybatisSqlSessionFactoryBean,否则无法动态生成SQL
        final MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);
        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:com/***/mapper/*.xml"));
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        sessionFactory.setPlugins(mybatisPlusInterceptor);
        return sessionFactory.getObject();
    }

    /**
     * transaction manager
     *
     * @param dataSource
     * @return
     */
    @Bean(name = "mysqlTransactionManager")
    @Primary
    public DataSourceTransactionManager mysqlTransactionManager(@Qualifier("mysqlDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    /**
     * build sql session template
     *
     * @param sqlSessionFactory
     * @return
     */
    @Bean(name = "mySqlSessionTemplate")
    @Primary
    public SqlSessionTemplate mySqlSessionTemplate(@Qualifier("mysqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

标题:记一次mybatis与mybatisplus及mysql与cilickhouse共存遇到的问题
作者:JonLv
地址:http://39.108.183.139:8080/articles/2024/01/15/1705305378342.html