mybatis的多数据源配置
mybatis是一种比较常用的持久化框架,广泛被开发人员所使用。但在开发中,常常会遇到一个项目要访问多个数据源的情况,如何解决这种问题呢?网上的解决思路大概两种,第一种就是动态切换数据源(需要配合自定义注解和切面拦截实现),第二种就是对不同数据源所涉及到的映射文件和接口进行分包。今天要介绍的第二种实现方式,实现起来也较为简单。
1. 数据源配置
server.port=8099
oracle.datasource.url=jdbc:oracle:thin:@127.0.0.1:1521:orcl
oracle.datasource.username=cs_info
oracle.datasource.password=123456
oracle.datasource.driver=oracle.jdbc.driver.OracleDriver
all.datasource.maxActive=20
mysql.datasource.url=jdbc:mysql://localhost:3306/seckill?useUnicode=true&characterEncoding=utf-8
mysql.datasource.username=root
mysql.datasource.password=123456
mysql.datasource.driver=com.mysql.jdbc.Driver
配置文件中存在两个数据源,为了方便区分,我们将其称为 mysql数据源和Oracle数据源。
2.Springboot配置类整合mybatis
利用spring来管理mybatis,所配置的内容通过配置类去编写,为了区分不同的数据源,我分为了两个配置类,分别管理不同的数据源。
1.数据源读取
@Component
public class DbPropertiesByAuto {
@Value("${mysql.datasource.url}")
public String mysqlurl;
@Value("${mysql.datasource.username}")
public String mysqlusername;
@Value("${mysql.datasource.password}")
public String mysqlpwd;
@Value("${mysql.datasource.driver}")
public String mysqldirver;
@Value("${all.datasource.maxActive}")
public int maxActive;
@Value("${oracle.datasource.url}")
public String oracleurl;
@Value("${oracle.datasource.username}")
public String oracleusername;
@Value("${oracle.datasource.password}")
public String oraclepwd;
@Value("${oracle.datasource.driver}")
public String oracledirver;
}
2.mysql数据源
@Configuration
@MapperScan(basePackages="com.wang.dao.mysql",sqlSessionFactoryRef="mysql_sqlSessionFactory")
public class MysqlDbConfig {
@Autowired
DbPropertiesByAuto dbPropertiesByAuto;
@Bean("mysqlDataSource")
public DataSource mysqlDataSource() {
DruidDataSource mysqlDataSource=new DruidDataSource();
mysqlDataSource.setDriverClassName(dbPropertiesByAuto.mysqldirver);
mysqlDataSource.setUrl(dbPropertiesByAuto.mysqlurl);
mysqlDataSource.setUsername(dbPropertiesByAuto.mysqlusername);
mysqlDataSource.setPassword(dbPropertiesByAuto.mysqlpwd);
mysqlDataSource.setMaxActive(dbPropertiesByAuto.maxActive);
return mysqlDataSource;
}
@Bean("mysql_sqlSessionFactory")
public SqlSessionFactory mysql_sqlSessionFactory(@Qualifier("mysqlDataSource")DataSource mysqlDataSource) throws Exception {
SqlSessionFactoryBean mysql_sqlSession=new SqlSessionFactoryBean();
mysql_sqlSession.setDataSource(mysqlDataSource);
Resource configLocation = new ClassPathResource("mybatis-mysql-config.xml");
mysql_sqlSession.setConfigLocation(configLocation);
mysql_sqlSession.setTypeAliasesPackage("com.wang.bean");
PathMatchingResourcePatternResolver resolver=new PathMatchingResourcePatternResolver();
Resource[] mapperLocations=resolver.getResources("classpath:com/wang/mapper/mysql/*.xml");
mysql_sqlSession.setMapperLocations(mapperLocations);
return mysql_sqlSession.getObject();
}
@Bean("mysqlTransactionManager")
public PlatformTransactionManager mysqlTransactionManager(@Qualifier("mysqlDataSource")DataSource mysqlDataSource) {
DataSourceTransactionManager mysqlTransactionManager=new DataSourceTransactionManager() ;
mysqlTransactionManager.setDataSource(mysqlDataSource);
return mysqlTransactionManager;
}
}
整合mybatis,需要配置SqlSessionFactory ,这是管理sqlSession的工厂,非常重要。以上代码可以看出,sqlsessionfactory设置了 datasource 、mybatis的配置文件位置、Mapper映射文件的存放位置等。
除此之外 ,该配置类引用了@MapperScan 注解,这是指定要扫描的Mapper类的包的路径,值得注意的是,还有个sqlSessionFactoryRef属性,通常只有一个sqlsessionfactory(一个数据源)时,可以不用指定,现在是多数据源,必须指定。如果不想使用@MapperScan,还可以用下面这种方式实现
@Bean("mysqlMapperScannerConfigurer")
public MapperScannerConfigurer mysqlMapperScannerConfigurer() {
MapperScannerConfigurer scannerConfigurer=new MapperScannerConfigurer();
scannerConfigurer.setSqlSessionFactoryBeanName("mysql_sqlSessionFactory");
scannerConfigurer.setBasePackage("com.wang.dao.mysql");
return scannerConfigurer;
}
3.oracle数据源
@Configuration
@MapperScan(basePackages="com.wang.dao.oracle",sqlSessionFactoryRef="oracle_sqlSessionFactory")
public class OracleDbConfig {
@Autowired
DbPropertiesByAuto dbPropertiesByAuto;
@Bean("oracleSource")
@Primary
public DataSource oracleSource() {
DruidDataSource oracleDataSource=new DruidDataSource();
oracleDataSource.setDriverClassName(dbPropertiesByAuto.oracledirver);
oracleDataSource.setUrl(dbPropertiesByAuto.oracleurl);
oracleDataSource.setUsername(dbPropertiesByAuto.oracleusername);
oracleDataSource.setPassword(dbPropertiesByAuto.oraclepwd);
oracleDataSource.setMaxActive(dbPropertiesByAuto.maxActive);
return oracleDataSource;
}
@Bean("oracle_sqlSessionFactory")
@Primary
public SqlSessionFactory oracle_sqlSessionFactory(@Qualifier("oracleSource")DataSource oracleSource) throws Exception {
SqlSessionFactoryBean oracle_sqlSession=new SqlSessionFactoryBean();
oracle_sqlSession.setDataSource(oracleSource);
Resource configLocation = new ClassPathResource("mybatis-oracle-config.xml");
oracle_sqlSession.setConfigLocation(configLocation);
oracle_sqlSession.setTypeAliasesPackage("com.wang.bean");
PathMatchingResourcePatternResolver resolver=new PathMatchingResourcePatternResolver();
Resource[] mapperLocations=resolver.getResources("classpath:com/wang/mapper/oracle/*.xml");
oracle_sqlSession.setMapperLocations(mapperLocations);
return oracle_sqlSession.getObject();
}
@Bean("oracleTransactionManager")
public PlatformTransactionManager oracleTransactionManager(@Qualifier("oracleSource")DataSource oracleSource ) {
DataSourceTransactionManager oracleTransactionManager=new DataSourceTransactionManager() ;
oracleTransactionManager.setDataSource(oracleSource);
return oracleTransactionManager;
}
}
原理与mysql数据源配置相同,不再赘述。
4.mybatis配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--配置全局属性 -->
<settings>
<!--使用列别名替换列名 默认值为true(可以不用写出来,这里写出来只是为了讲解该配置的作用)
select name as title(实体中的属性名是title) form table;
开启后mybatis会自动帮我们把表中name的值赋到对应实体的title属性中 -->
<setting name="useColumnLabel" value="true" />
<!--开启驼峰命名转换Table:create_time到 Entity(createTime) -->
<setting name="mapUnderscoreToCamelCase" value="true" />
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
</configuration>
3.编写xml映射文件和Mapper接口
配置完mybatis之后,其实就可以正常开发了,需要注意的是,不同的数据源指定了对应的映射文件和Mapper类位置,映射文件和mapper接口要放在对应的包中。下面贴出mysql数据源的代码
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace:指定为哪个接口提供配置 -->
<mapper namespace="com.wang.dao.mysql.SeckillDao">
<!--目的:为dao接口方法提供sql语句配置, 即针对dao接口中的方法编写我们的sql语句 -->
<!-- parameterType:使用到的参数类型
正常情况java表示一个类型的包名+类名,这直接写类名,因为后面有一个配置可以简化写包名的过程 -->
<select id="queryById" resultType="Seckill" parameterType="long">
<!-- 可以通过别名的方式列明到java名的转换,如果开启了驼峰命名法就可以不用这么写了
select seckill_id as seckillId
-->
SELECT seckill_id,name,number,create_time,start_time,end_time
FROM seckill
WHERE seckill_id= #{seckillId}
</select>
<select id="queryAll" resultType="Seckill">
SELECT *
FROM seckill
ORDER BY create_time DESC
</select>
<insert id="insertSeckill" parameterType="Seckill">
INSERT INTO seckill
(
seckill_id
, name
, number
, create_time
, start_time
, end_time
)
VALUES
(
#{seckillId}
, #{name}
, #{number}
, #{createTime}
, #{startTime}
, #{endTime}
)
</insert>
<update id="updateSeckill" parameterType="Seckill">
update seckill set number=#{number}
<if test="name!=null">
, name=#{name}
</if>
where seckill_id=#{seckillId}
</update>
</mapper>
package com.wang.dao.mysql;
import java.util.List;
import com.wang.bean.Seckill;
public interface SeckillDao {
/**
* 根据id查询秒杀商品
*
* @param seckillId
* @return
*/
Seckill queryById(long seckillId);
/**
* 查询全部
* @return
*/
List<Seckill>queryAll();
void insertSeckill(Seckill seckill);
void updateSeckill(Seckill seckill);
}
4.测试
@Resource
private SeckillDao seckillDao;
public List<Seckill> queryAll(){
List<Seckill>seckills= seckillDao.queryAll();
return seckills;
}
@Transactional(value="mysqlTransactionManager" ,propagation=Propagation.REQUIRED)
public void dbOperateWithShiwu() {
update();
insert();
}
public void insert() {
Seckill seckill=new Seckill();
setValue(seckill);
seckillDao.insertSeckill(seckill);
}
public void update() {
Seckill seckill=seckillDao.queryById(1008L);
seckill.setName(seckill.getName()+"--修改");
seckillDao.updateSeckill(seckill);
}
通过测试,发现使用不同包下的mapper接口,可以操作不同的数据源。以上代码中,我们可以看到使用了事务,不同的数据源定义不同的事务,在业务层指定事务就可以使用了。
源代码地址