Introduce mybatis-plus to report an Invalid bound statement error. Move your finger to change one place

error

Mybatis-Plus (MP) is an enhancement tool for mybatis. On the basis of mybatis, only enhancements are made without changes, which simplifies the development efficiency.This is to help us encapsulate some simple curd methods that can be called directly without rewriting these simple sql statements, just like JPA.

A new project was created the first two days. The persistence framework uses mybatis, and mybatis-plus was introduced as an enhancement tool. After the project started, the calling interface found an error. The error warning is as follows:

The error message is "Invalid Binding Sentence". The error is the way to operate the sql statement. I checked the answer from the internet. The error is mainly about the configuration of data source binding. So I groped around and started from where I configured the data source.

Find Reasons

Because the project has read-write separation for multiple data sources, I have integrated the dynamic configuration of data sources into a class DataSourceConfig, which is the code for that class:

@Configuration
@MapperScan(basePackages = "com.xjt.proxy.mapper", sqlSessionTemplateRef = "sqlTemplate")
public class DataSourceConfig {
    /**
     * Main Library
     */
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.master")
    public DataSource masterDb() {
        return DruidDataSourceBuilder.create().build();
    }

    /**
     * From Library
     */
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.slave")
    public DataSource slaveDb() {
        return DruidDataSourceBuilder.create().build();
    }

    /**
     * Master-Slave Dynamic Configuration
     */
    @Bean
    public DynamicDataSource dynamicDb(@Qualifier("masterDb") DataSource masterDataSource,
                                       @Autowired(required = false) @Qualifier("slaveDb") DataSource slaveDataSource) {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DynamicDataSourceEnum.MASTER.getDataSourceName(), masterDataSource);
        if (slaveDataSource != null) {
            targetDataSources.put(DynamicDataSourceEnum.SLAVE.getDataSourceName(), slaveDataSource);
        }
        dynamicDataSource.setTargetDataSources(targetDataSources);
        dynamicDataSource.setDefaultTargetDataSource(masterDataSource);
        return dynamicDataSource;
    }

    @Bean
    public SqlSessionFactory sessionFactory(@Qualifier("dynamicDb") DataSource dynamicDataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setMapperLocations(
                new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*Mapper.xml"));
        bean.setDataSource(dynamicDataSource);
        return bean.getObject();
    }

    @Bean
    public SqlSessionTemplate sqlTemplate(@Qualifier("sessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

    @Bean(name = "dataSourceTx")
    public DataSourceTransactionManager dataSourceTx(@Qualifier("dynamicDb") DataSource dynamicDataSource) {
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dynamicDataSource);
        return dataSourceTransactionManager;
    }
}

It's not complicated. It's mainly about mapping the master-slave database's data source configuration and injecting the data source into the SqlSessionFactory object. If you're confused about this part of the code or the read-write separation, you can see my previous articles Is it difficult to separate reading from writing?springboot combined with aop is easy to implement"

There is no objection to the master-slave library mapping of the data source. Think about what step should be injected. Then look at the sessionFactory method, which returns a SqlSessionFactory object, which is returned by creating a new SqlSessionFactoryBean object and injecting the data source. The problem should be on this SqlSessionFactoryBean class.Later, when Pingo (the big guy next to me) reminded me, I would switch to another Bean factory class in mybatis-plus, called MybatisSqlSessionFactoryBean. When I opened the source code of this class, I found that it copied SqlSessionFactoryBean and rewritten my own custom loading method, buildSqlSessionFactory,

Jump to the source code of the method and find that one of the codes is more important. If you omit this step in the configuration, injection fails.

change

That is, where you inject the data source, you also need to configure the mapper's scan path, so it is clear where you change the SqlSessionFactoryBean to MybatisSqlSessionFactoryBean and configure the path to the mapper file, that is, to change the sessionFactory method to the following code:

@Bean
    public SqlSessionFactory sessionFactory(@Qualifier("dynamicDb") DataSource dynamicDataSource) throws Exception {
        MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dynamicDataSource);
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();        sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath*:mapper/*Mapper.xml"));
        return sqlSessionFactoryBean.getObject();
    }

This way, starting the project again will allow the sql statement to operate properly.

Keywords: Java Mybatis SQL Spring xml

Added by zenix on Thu, 28 May 2020 06:02:40 +0300