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┏ (゜ω゜)=?