如何避免Mybatis为每个SqlSessionTemplate重复加载配置?
解决多分片场景下Mybatis重复加载配置导致初始化慢的问题
针对Spring 4.3 + Mybatis 3.4 + Mybatis-spring 1.3环境下,多分片每个SqlSessionTemplate重复加载配置和映射器导致初始化耗时过长的问题,可以通过预加载基础Configuration并克隆复用的方式解决,核心思路是先加载一次配置和映射器,再为每个分片克隆独立的Configuration并绑定对应数据源,避免重复加载。
实现步骤
1. 预加载基础Configuration(仅加载配置与映射器,不绑定业务数据源)
先创建一个基础的SqlSessionFactoryBean,仅加载Mybatis核心配置和映射器文件,设置临时数据源避免初始化报错,获取已加载完成的Configuration作为复用模板。
// 初始化基础SqlSessionFactoryBean,仅加载配置和映射器 SqlSessionFactoryBean baseFactoryBean = new SqlSessionFactoryBean(); baseFactoryBean.setConfigLocation(new ClassPathResource("mybatis-config.xml")); baseFactoryBean.setMapperLocations( new PathMatchingResourcePatternResolver().getResources("classpath:mappers/*.xml") ); // 设置临时内存数据源,仅用于完成Configuration初始化 baseFactoryBean.setDataSource(new DriverManagerDataSource("jdbc:h2:mem:tmp", "sa", "")); // 获取已加载完所有配置和映射器的基础Configuration Configuration baseConfig = baseFactoryBean.getObject().getConfiguration();
2. 为每个分片克隆Configuration并绑定对应数据源
针对每个分片的独立数据源,克隆基础Configuration,替换其Environment中的数据源,再创建专属的SqlSessionFactory和SqlSessionTemplate,无需重复加载配置与映射器。
方式一:手动复制核心配置(可控性强)
// 遍历所有分片数据源 for (DataSource shardDataSource : shardDataSources) { // 基于基础配置的环境模板,创建绑定当前分片数据源的新Environment Environment newEnv = new Environment( baseConfig.getEnvironment().getId(), baseConfig.getEnvironment().getTransactionFactory(), shardDataSource ); Configuration clonedConfig = new Configuration(newEnv); // 复制基础Configuration的核心配置项 clonedConfig.setCacheEnabled(baseConfig.isCacheEnabled()); clonedConfig.setLazyLoadingEnabled(baseConfig.isLazyLoadingEnabled()); clonedConfig.setAggressiveLazyLoading(baseConfig.isAggressiveLazyLoading()); // 按需复制其他配置项(如日志实现、类型处理器等) // 复用已加载的映射器,避免重新解析XML文件 for (Class<?> mapperInterface : baseConfig.getMapperRegistry().getMappers()) { clonedConfig.addMapper(mapperInterface); } // 创建当前分片的SqlSessionFactory与SqlSessionTemplate SqlSessionFactoryBean shardFactoryBean = new SqlSessionFactoryBean(); shardFactoryBean.setConfiguration(clonedConfig); // 无需重复设置configLocation和mapperLocations SqlSessionFactory shardSessionFactory = shardFactoryBean.getObject(); SqlSessionTemplate shardTemplate = new SqlSessionTemplate(shardSessionFactory); // 将分片SqlSessionTemplate注册到Spring容器或路由封装器中 }
方式二:使用BeanUtils快速复制(简化代码)
// 遍历所有分片数据源 for (DataSource shardDataSource : shardDataSources) { // 克隆基础Configuration实例 Configuration clonedConfig = new Configuration(); // 复制基础配置的所有属性(包括已加载的映射器、配置项) org.springframework.beans.BeanUtils.copyProperties(baseConfig, clonedConfig); // 替换Environment中的数据源为当前分片数据源 Environment newEnv = new Environment( baseConfig.getEnvironment().getId(), baseConfig.getEnvironment().getTransactionFactory(), shardDataSource ); clonedConfig.setEnvironment(newEnv); // 创建分片专属的SqlSessionFactory与SqlSessionTemplate SqlSessionFactoryBean shardFactoryBean = new SqlSessionFactoryBean(); shardFactoryBean.setConfiguration(clonedConfig); SqlSessionFactory shardSessionFactory = shardFactoryBean.getObject(); SqlSessionTemplate shardTemplate = new SqlSessionTemplate(shardSessionFactory); // 注册到容器或路由封装器 }
关键注意事项
- 必须使用独立Configuration实例:每个分片对应单独的Configuration,绝对不能共享实例,否则会出现数据源串用的问题。
- 复用已加载的映射器:基础Configuration已经完成了映射器的解析与注册,克隆后直接复用即可,彻底避免重复解析XML的耗时。
- 临时数据源不影响业务:预加载时使用的临时内存数据源仅用于完成Configuration初始化,不会参与任何业务数据库操作。
内容的提问来源于stack exchange,提问作者rooot
相关产品推荐
相关产品推荐

