The saveBatch of mybatis-plus reports an error, but there is no problem with save? Null pointer Caused by: java.lang.NullPointerException

Null pointer problem in batch operations such as saveBatch in mybatis-plus

  • describe:
    • Error message
    • Solutions
    • solution
    • doubt
    • Reference blog

Description:

It’s almost time to get off work again, haha. I hope I can help you. I’ll explain it in a scribble.
Null pointers will appear in batch operations, but there is no problem in a single save operation. You must be confused. What is going on?

Error message

Caused by: java.lang.NullPointerException: null
at com.baomidou.mybatisplus.extension.toolkit.SqlHelper.sqlSessionBatch(SqlHelper.java:53) ~[mybatis-plus-extension-3.1.0.jar:3.1.0]
at com.baomidou.mybatisplus.extension.service.impl.ServiceImpl.sqlSessionBatch(ServiceImpl.java:81) ~[mybatis-plus-extension-3.1.0.jar:3.1.0]
at com.baomidou.mybatisplus.extension.service.impl.ServiceImpl.saveOrUpdateBatch(ServiceImpl.java:163) ~[mybatis-plus-extension-3.1.0.jar:3.1.0]
at com.baomidou.mybatisplus.extension.service.IService.saveOrUpdateBatch(IService.java:76) ~[mybatis-plus-extension-3.1.0.jar:3.1.0]
at com.baomidou.mybatisplus.extension.service.IService$$FastClassBySpringCGLIB$$f8525d18.invoke(<generated>) ~[mybatis-plus-extension-3.1.0.jar:3.1.0]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749) ~[spring-aop-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294) ~[spring-tx-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) ~[spring-tx-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) ~[spring-aop-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at com.jx.cnhb.service.hiddenDanger.impl.YhEnterpriseInfoServiceImpl$$EnhancerBySpringCGLIB$$3ee24b2a.saveOrUpdateBatch(<generated>) ~[classes/:na]

Solution ideas

At first it was suspected that the bean was not injected
Suddenly I found that the bean has been injected and I can get the baseMapper. Then I tried the save and other methods separately and found that there was no problem at all.

So, based on the source code, we found the reason step by step.

The hard work pays off. The reason is found. The sqlsession factory is null, so the null pointer is reported.

Solution

Now that we know the problem, we can prescribe the right remedy.
Then search globally for SqlSessionFactory

Sure enough, I found it
It turns out to be a configuration issue with multiple data sources.

@Configuration
//Specify the mapper storage directory, and change the mapper under the package to use this datasource
@MapperScan(basePackages = {<!-- -->"com.jx.cnhb.mapper", "com.jx.cnhb.hiddenDanger"},sqlSessionTemplateRef = "damengSqlSessionTemplate")
public class DMConfiguration {<!-- -->
    @Bean(name = "damengDataSource")
    //Required for multiple data sources
    @Primary
    public DataSource setDataSource(DMConfig dmConfig){<!-- -->
        DruidDataSource dds = new DruidDataSource();
        dds.setUrl(dmConfig.getUrl());
        dds.setDriverClassName(dmConfig.getDriverClassName());
        dds.setUsername(dmConfig.getUsername());
        dds.setPassword(dmConfig.getPassword());
        return dds;
    }

    @Bean(name = "damengSqlSessionFactory")
    @Primary
    public SqlSessionFactory setSqlSessionFactory(@Qualifier("damengDataSource") DataSource dataSource) throws Exception{<!-- -->
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
// sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:com/jx/cnhb/mapper/*.xml"));
        MybatisConfiguration configuration = new MybatisConfiguration();
        configuration.setDefaultScriptingLanguage(MybatisXMLLanguageDriver.class);
        configuration.setJdbcTypeForNull(JdbcType.NULL);
        sqlSessionFactoryBean.setConfiguration(configuration);
        return sqlSessionFactoryBean.getObject();
    }
    @Bean(name = "damengSqlSessionTemplate")
    @Primary
    public SqlSessionTemplate setSqlSessionTemplate(@Qualifier("damengSqlSessionFactory")SqlSessionFactory sqlSessionFactory){<!-- -->
        return new SqlSessionTemplate(sqlSessionFactory);
    }

}

The screenshot above shows the reason for the error.

It was found that the global configuration of mybatis was not configured.

And it is found that the data is all default

Then I went to the Baidu multi-data source configuration and found that there was originally a GlobalConfig bean missing here, so it appeared that the sqlsession factory of the current class could not be obtained.

The modified configuration file is

@Configuration
//Specify the mapper storage directory, and change the mapper under the package to use this datasource
@MapperScan(basePackages = {<!-- -->"com.jx.cnhb.mapper", "com.jx.cnhb.hiddenDanger"},sqlSessionTemplateRef = "damengSqlSessionTemplate")
public class DMConfiguration {<!-- -->
    @Bean(name = "damengDataSource")
    //Required for multiple data sources
    @Primary
    public DataSource setDataSource(DMConfig dmConfig){<!-- -->
        DruidDataSource dds = new DruidDataSource();
        dds.setUrl(dmConfig.getUrl());
        dds.setDriverClassName(dmConfig.getDriverClassName());
        dds.setUsername(dmConfig.getUsername());
        dds.setPassword(dmConfig.getPassword());
        return dds;
    }

    @Bean(name = "damengSqlSessionFactory")
    @Primary
    public SqlSessionFactory setSqlSessionFactory(@Qualifier("damengDataSource") DataSource dataSource) throws Exception{<!-- -->
        MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        sqlSessionFactoryBean.setGlobalConfig(globalConfig());
        MybatisConfiguration configuration = new MybatisConfiguration();
        configuration.setDefaultScriptingLanguage(MybatisXMLLanguageDriver.class);
        configuration.setJdbcTypeForNull(JdbcType.NULL);
        sqlSessionFactoryBean.setConfiguration(configuration);
        return sqlSessionFactoryBean.getObject();
    }
    @Bean(name = "damengSqlSessionTemplate")
    @Primary
    public SqlSessionTemplate setSqlSessionTemplate(@Qualifier("damengSqlSessionFactory")SqlSessionFactory sqlSessionFactory){<!-- -->
        return new SqlSessionTemplate(sqlSessionFactory);
    }

    @Bean("globalConfig")
    public GlobalConfig globalConfig(){<!-- -->
        //Meta object field filling controller can also be configured here
        return new GlobalConfig();
    }

}

The problem is solved and it can be seen that the factory has been obtained.

Questions

Why can’t we do it in batches, but can we do it individually? ? ? ?
Because the save method is obtained from Basemapper
The batch method is obtained from the GlobalConfig factory.

Reference blog

Link: link

okokok, the time is perfect, have a nice weekend, come with you┏ (゜ω゜)=?