1.功能介绍
在实际的开发中,同一个项目中使用多个数据源是很常见的场景。最近在学习的过程中使用注解的方式实现了一个Springboot项目多数据源的功能。具体实现方式如下。
2.在application.properties中添加多数据源配置
添加多个数据源和mapper文件路径配置,此配置用于基于java的配置数据源中使用。
#数据库配置spring.datasource.demo.user.url=jdbc:mysql://xxx.xx.xx.xx:3306/demo-userspring.datasource.demo.user.username=xxxx spring.datasource.demo.user.password=xxxx spring.datasource.demo.user.driver-class-name=com.mysql.jdbc.Driver spring.datasource.demo.server.url=jdbc:mysql://xxx.xx.xx.xx:3306/springbootdemospring.datasource.demo.server.username=xxxx spring.datasource.demo.server.password=xxxx spring.datasource.demo.server.driver-class-name=com.mysql.jdbc.Driver#mapper文件的路径mybatis.demo.server.mapper-location=classpath*:mapper/demo-server/*.xml mybatis.demo.user.mapper-location=classpath*:mapper/demo-user/*.xml
3.基于java的方式实现数据库配置
配置类图如下:
其中DemoUserDbConfig类源代码如下:
其中Configuration注解表识此类为Spring的配置类。
MapperScan注解中的basePackages、annotationClass、sqlSessionTemplateRef用于配置此数据库链接扫描com.example包中所有注解为DemoUserMapper的接口。
@Configuration@MapperScan(basePackages = {"com.example"},annotationClass = DemoUserMapper.class, sqlSessionTemplateRef = "demoUserTemplate") public class DemoUserDbConfig extends AbstractDbConfig { @Value("${spring.datasource.demo.user.url}") private String url; @Value("${spring.datasource.demo.user.username}") private String userName; @Value("${spring.datasource.demo.user.password}") private String password; @Value("${spring.datasource.demo.user.driver-class-name}") private String driveClassName; @Value(value = "${mybatis.demo.user.mapper-location}") private String mapperLocation; @Bean(name = "demoUser") public DataSource secondaryDataSource() { return dataSourceFactory(driveClassName, url, userName, password); } @Bean(name = "demoUserTemplate") public SqlSessionTemplate demoUserSqlTemplate() throws Exception { return new SqlSessionTemplate((sqlSessionFactory(secondaryDataSource(), mapperLocation))); } @Bean @Qualifier("demoUserTransaction") public PlatformTransactionManager demoUserTransaction() { return new DataSourceTransactionManager(secondaryDataSource()); } }
其中AbstractDatasource设置了通用的方法,源代码如下:
public abstract class AbstractDbConfig { protected SqlSessionFactory sqlSessionFactory(DataSource dataSource, String mapperLocation) throws Exception { SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(dataSource); ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver(); Resource[] resource= resourceResolver.getResources(mapperLocation); factoryBean.setMapperLocations(resource); return factoryBean.getObject(); } protected DataSource dataSourceFactory(String driveClassName, String url, String userName, String password){ DruidDataSource datasource = new DruidDataSource(); datasource.setDriverClassName(driveClassName); datasource.setUrl(url); datasource.setUsername(userName); datasource.setPassword(password); datasource.setMaxActive(20); datasource.setInitialSize(20); return datasource; } }
使用相同的方法定义其他数据源。
4.定义接口和mapper文件
分别定义连接demo-user数据库和springbootdemo数据库的mapper文件。连接demo-user数据库的接口如下,使用DemoUserMapper注解表识。
@DemoUserMapperpublic interface UserDao { /** * 返回所有的dictionary列表 * * @return 所有的dictionary列表 */ List<String> list(); }
mapper文件如下:
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" ><mapper namespace="com.example.multidatasource.business.user.UserDao"> <select id="list" resultType="string"> SELECT `name` FROM `user` </select></mapper>
定义读取springbootdemo数据库的接口,代码如下。使用DemoServerMapper注解表识
@DemoServerMapperpublic interface DictionaryDao { /** * 返回所有的dictionary列表 * * @return 所有的dictionary列表 */ List<Dictionary> list(); /** * 查询此key下的所有子节点 * * @param key 数据字典key * @return 返回key所有的子节点列表 */ List<Dictionary> listChildrenByKey(String key); /** * 插入数据到数据库 * * @param dictionary */ void insert(Dictionary dictionary); }
mapper文件代码如下:
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" ><mapper namespace="com.example.multidatasource.business.dictionary.dao.DictionaryDao"> <resultMap id="DictionaryResultMap" type="com.example.multidatasource.business.dictionary.Dictionary"> <result property="id" column="id"></result> <result property="dictKey" column="dict_key"></result> <result property="dictValue" column="dict_value"></result> <result property="parentId" column="parent_id"></result> <result property="description" column="description"></result> </resultMap> <select id="list" resultMap="DictionaryResultMap"> SELECT * FROM `dictionary` </select> <select id="listChildrenByKey" resultMap="DictionaryResultMap"> SELECT * FROM dictionary where parent_id= (select id from dictionary where dict_key= #{key}) </select> <delete id="delete" parameterType="int"> delete from dictionary where id = #{id} </delete> <insert id="insert" parameterType="com.example.multidatasource.business.dictionary.Dictionary"> INSERT INTO `dictionary`(`dict_key`,`dict_value`,`parent_id`,`description`) VALUES(#{dictKey}, #{dictValue}, #{parentId}, #{description}) </insert></mapper>
5.定义注解
定义DemoUserMapper和DemoServerMapper注解,分别作为使用demo-user和springbootdemo数据库的表识。
定义代码如下:
@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Component@Mapperpublic @interface DemoServerMapper { /** * The value may indicate a suggestion for a logical component name, * to be turned into a Spring bean in case of an autodetected component. * @return the suggested component name, if any (or empty String otherwise) */ String value() default ""; }@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Component@Mapperpublic @interface DemoUserMapper { /** * The value may indicate a suggestion for a logical component name, * to be turned into a Spring bean in case of an autodetected component. * @return the suggested component name, if any (or empty String otherwise) */ String value() default ""; }
6.使用单元测试验证配置
编写单元测试代码如下:
@RunWith(SpringRunner.class)@SpringBootTestpublic class MultiDatasourceApplicationTests { @Autowired private DictionaryDao dictionaryDao; @Autowired private UserDao userDao; @Test public void contextLoads() { System.out.println(dictionaryDao.list()); System.out.println("==================="); System.out.println(userDao.list()); } }