前言:Spring Boot提供了简单而强大的多数据源支持,使得在应用程序中轻松使用和管理多个数据库变得非常容易。使用多数据源可以解决一些复杂的业务场景,比如在一个应用中同时访问多个数据库,或者在微服务架构中需要每个微服务连接自己的数据库。
在Spring Boot和MyBatis中实现多数据源可以通过配置多个数据源和事务管理器来实现。以下是一个简单的步骤:
1、添加依赖:确保在
pom.xml
文件中添加Spring Boot和MyBatis的相关依赖。例如:
<dependencies><!-- Spring Boot Starter Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Spring Boot Starter Data JPA --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><!-- MyBatis --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId></dependency><!-- MySQL Connector --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency> </dependencies>
2、配置数据源:
在
application.properties
(或application.yml
)文件中配置多个数据源信息。例如:
# 第一个数据源 spring.datasource.first.url=jdbc:mysql://localhost:3306/first_db spring.datasource.first.username=username1 spring.datasource.first.password=password1 spring.datasource.first.driver-class-name=com.mysql.cj.jdbc.Driver# 第二个数据源 spring.datasource.second.url=jdbc:mysql://localhost:3306/second_db spring.datasource.second.username=username2 spring.datasource.second.password=password2 spring.datasource.second.driver-class-name=com.mysql.cj.jdbc.Driver
3、配置数据源Bean:
import com.baomidou.mybatisplus.spring.boot.starter.SpringBootVFS; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.annotation.MapperScan; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternUtils; import org.springframework.jdbc.datasource.DataSourceTransactionManager;import javax.sql.DataSource;/*** 配置连接*/ @Configuration @MapperScan(basePackages = "com.smoky.dao" ,sqlSessionTemplateRef = "sqlSessionTemplateA" ) public class MyBatisConfig {private Logger logger = LoggerFactory.getLogger(MyBatisConfig.class);@Value("${spring.datasource.datasourceA.driver-class-name}")private String driverClassNameA;@Bean(name = "dataSourceA")@Primary@ConfigurationProperties(prefix = "spring.datasource.datasourceA")public DataSource dataSourceA() {return DataSourceBuilder.create().build();}@Primary@Bean(name = "sqlSessionFactoryA")public SqlSessionFactory testSqlSessionFactoryA(@Qualifier("dataSourceA") DataSource dataSource) throws Exception {ResourcePatternResolver patternResolver = ResourcePatternUtils.getResourcePatternResolver(new DefaultResourceLoader());SqlSessionFactoryBean sqlSession = new CDBSqlSessionFactoryBean();sqlSession.setDataSource(dataSource);String classPath;if ("com.mysql.cj.jdbc.Driver".equals(driverClassNameA)) {classPath = "classpath*:mysql_mapper/*.xml";} else if ("oracle.jdbc.driver.OracleDriver".equals(driverClassNameA)) {classPath = "classpath*:oracel_mapper/*.xml";} else if ("com.ibm.db2.jcc.DB2Driver".equals(driverClassNameA)) {classPath = "classpath*:db2_mapper/*.xml";} else {throw new SystemException(SystemErrorEnum.SYSTEM_ERROR.getCode(), "不支持的数据库类型");}//根据实际情况添加,视情况删除sqlSession.setVfs(SpringBootVFS.class);org.apache.ibatis.session.Configuration conf = new org.apache.ibatis.session.Configuration();// 查询结果为map时不忽略空值conf.setCallSettersOnNulls(true);// 开启驼峰命名转换 conf.setMapUnderscoreToCamelCase(true);sqlSession.setConfiguration(conf);try {sqlSession.setMapperLocations(patternResolver.getResources(classPath));} catch (Exception e) {logger.error(e.getMessage());}return sqlSession.getObject();}@Primary@Bean(name = "transactionManagerA")public DataSourceTransactionManager testTransactionManagerA(@Qualifier("dataSourceA") DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}@Primary@Bean(name = "sqlSessionTemplateA")public SqlSessionTemplate testSqlSessionTemplateA(@Qualifier("sqlSessionFactoryA") SqlSessionFactory sqlSessionFactory) throws Exception {return new SqlSessionTemplate(sqlSessionFactory);}}
import com.baomidou.mybatisplus.spring.boot.starter.SpringBootVFS; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.annotation.MapperScan; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternUtils; import org.springframework.jdbc.datasource.DataSourceTransactionManager;import javax.sql.DataSource;/*** 配置连接*/ @Configuration @MapperScan(basePackages = "com.smoky.skdao" ,sqlSessionTemplateRef = "sqlSessionTemplateB" )public class SKMybatisConfig {private Logger logger = LoggerFactory.getLogger(SKMybatisConfig.class);@Value("${spring.datasource.datasourceB.driver-class-name}")private String driverClassNameB;@Bean(name = "dataSourceB")@ConfigurationProperties(prefix = "spring.datasource.datasourceB")public DataSource dataSourceB() {return DataSourceBuilder.create().build();}@Bean(name = "sqlSessionFactoryB")public SqlSessionFactory testSqlSessionFactoryB(@Qualifier("dataSourceB") DataSource dataSource) throws Exception {ResourcePatternResolver patternResolver = ResourcePatternUtils.getResourcePatternResolver(new DefaultResourceLoader());SqlSessionFactoryBean sqlSession = new CDBSqlSessionFactoryBean();sqlSession.setDataSource(dataSource);String classPath;if ("com.mysql.cj.jdbc.Driver".equals(driverClassNameB)) {classPath = "classpath*:sk_mysql_mapper/*.xml";} else if ("oracle.jdbc.driver.OracleDriver".equals(driverClassNameB)) {classPath = "classpath*:oracel_mapper/*.xml";} else if ("com.ibm.db2.jcc.DB2Driver".equals(driverClassNameB)) {classPath = "classpath*:db2_mapper/*.xml";} else {throw new SystemException(SystemErrorEnum.SYSTEM_ERROR.getCode(), "不支持的数据库类型");}//根据实际情况添加,视情况删除sqlSession.setVfs(SpringBootVFS.class);org.apache.ibatis.session.Configuration conf = new org.apache.ibatis.session.Configuration();// 查询结果为map时不忽略空值conf.setCallSettersOnNulls(true);// 开启驼峰命名转换 seckill_id====>seckillIdconf.setMapUnderscoreToCamelCase(true);sqlSession.setConfiguration(conf);try {sqlSession.setMapperLocations(patternResolver.getResources(classPath));} catch (Exception e) {logger.error(e.getMessage());}return sqlSession.getObject();}@Bean(name = "transactionManagerB")public DataSourceTransactionManager testTransactionManagerB(@Qualifier("dataSourceB") DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}@Bean(name = "sqlSessionTemplateB")public SqlSessionTemplate testSqlSessionTemplateB(@Qualifier("sqlSessionFactoryB") SqlSessionFactory sqlSessionFactory) throws Exception {return new SqlSessionTemplate(sqlSessionFactory);}}
4、使用多数据源,首先,创建主数据源的
UserMapper
接口:package com.example.mapper.primary;import com.example.model.User;import java.util.List;public interface UserMapper {User getUserById(Long id);List<User> getAllUsers();void insertUser(User user);void updateUser(User user);void deleteUser(Long id); }
主数据源Mapper XML文件
在
src/main/resources/mapper/primary
目录下,创建主数据源的UserMapper.xml
文件:<!-- src/main/resources/mapper/primary/UserMapper.xml --><mapper namespace="com.example.mapper.primary.UserMapper"><!-- 根据ID查询用户 --><select id="getUserById" resultType="com.example.model.User">SELECT * FROM users_primary WHERE id = #{id}</select><!-- 查询所有用户 --><select id="getAllUsers" resultType="com.example.model.User">SELECT * FROM users_primary</select><!-- 插入用户 --><insert id="insertUser" parameterType="com.example.model.User">INSERT INTO users_primary (username, email) VALUES (#{username}, #{email})</insert><!-- 更新用户 --><update id="updateUser" parameterType="com.example.model.User">UPDATE users_primary SET username = #{username}, email = #{email} WHERE id = #{id}</update><!-- 根据ID删除用户 --><delete id="deleteUser">DELETE FROM users_primary WHERE id = #{id}</delete></mapper>
第二数据源Mapper接口:接着,创建第二数据源的
UserMapper
接口:package com.example.mapper.secondary;import com.example.model.User;import java.util.List;public interface UserMapper {User getUserById(Long id);List<User> getAllUsers();void insertUser(User user);void updateUser(User user);void deleteUser(Long id); }
第二数据源Mapper XML文件:在
src/main/resources/mapper/secondary
目录下,创建第二数据源的UserMapper.xml
文件:<!-- src/main/resources/mapper/secondary/UserMapper.xml --><mapper namespace="com.example.mapper.secondary.UserMapper"><!-- 根据ID查询用户 --><select id="getUserById" resultType="com.example.model.User">SELECT * FROM users_secondary WHERE id = #{id}</select><!-- 查询所有用户 --><select id="getAllUsers" resultType="com.example.model.User">SELECT * FROM users_secondary</select><!-- 插入用户 --><insert id="insertUser" parameterType="com.example.model.User">INSERT INTO users_secondary (username, email) VALUES (#{username}, #{email})</insert><!-- 更新用户 --><update id="updateUser" parameterType="com.example.model.User">UPDATE users_secondary SET username = #{username}, email = #{email} WHERE id = #{id}</update><!-- 根据ID删除用户 --><delete id="deleteUser">DELETE FROM users_secondary WHERE id = #{id}</delete></mapper>
使用Mapper接口:在需要使用数据访问的地方,注入对应的
UserMapper
接口,然后调用接口中定义的方法:@Service public class UserService {private final UserMapper primaryUserMapper;private final UserMapper secondaryUserMapper;@Autowiredpublic UserService(@Qualifier("primaryUserMapper") UserMapper primaryUserMapper,@Qualifier("secondaryUserMapper") UserMapper secondaryUserMapper) {this.primaryUserMapper = primaryUserMapper;this.secondaryUserMapper = secondaryUserMapper;}public User getPrimaryUserById(Long id) {return primaryUserMapper.getUserById(id);}public User getSecondaryUserById(Long id) {return secondaryUserMapper.getUserById(id);}// 其他业务方法... }
在这个示例中,
UserMapper
接口和XML文件分别针对主数据源和第二数据源进行了定义和配置。在UserService
中,通过@Qualifier
注解分别注入了主数据源和第二数据源的UserMapper
,使得在业务层可以方便地调用对应数据源的方法。需要确保主数据源和第二数据源的配置和连接信息都正确,以便MyBatis能够正确地访问数据库。
总结:
在Spring Boot应用程序中利用MyBatis实现多数据源的配置。这一技术的重要性在于,对于复杂的应用场景,如微服务架构或需要同时连接多个数据库的系统,多数据源的支持成为了必备的功能。通过以下几个关键步骤,我们成功地搭建了一个支持多数据源的Spring Boot应用:
首先,我们在
pom.xml
文件中引入了Spring Boot、MyBatis以及相应的数据库驱动依赖,确保项目能够充分利用这些强大的框架。其次,通过在
application.properties
中配置多个数据源的连接信息,我们为每个数据库建立了必要的基础设置。这包括数据库的URL、用户名、密码等信息。接下来,我们创建了
DataSourceConfig
类,通过该类配置了每个数据源的DataSource
Bean。这一步骤对于确保数据源的正确配置至关重要。在MyBatis的配置方面,我们使用了
SqlSessionFactory
和SqlSessionTemplate
,并通过@MapperScan
注解指定了Mapper接口的扫描路径。这样,MyBatis能够正确地找到和关联到各个数据源的Mapper接口和XML文件。最后,为了实现事务管理,我们创建了
TransactionManagerConfig
类,为每个数据源配置了对应的事务管理器。这确保了在多数据源的环境下,事务能够得到正确的管理和隔离。通过以上步骤的完成,我们不仅成功实现了多数据源的配置,而且在MyBatis的Mapper接口和XML文件中清晰地定义了数据库操作。这种模块化的数据访问层设计使得代码更易维护、更具可读性。总的来说,本文提供了一个全面而实用的指南,帮助开发者们在Spring Boot应用中优雅地处理多数据源的场景,充分发挥了Spring Boot和MyBatis的优势,提高了应用的灵活性和可扩展性。