前言
一、大部分情况下我们的数据库可能不止一个,比如sqlserver或者mysql等等,或者不在同一个服务器中,不在同一个端口等等,但是我们的一个项目又需要获取所有的数据库信息做后台,所以就用到了mybatis多数据源的配置
一、整体逻辑
二、配置
2.1、在application.yml中配置数据源(多个数据库的连接地址),列子如下:
spring:
datasource:
dspublicdbuat:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc
:mysql
://91.150.232.255
:3306/public_db_uat
?useUnicode=true
&characterEncoding=utf
-8
&useSSL=false
username: ioplj
password: jhjhujhj
dsyygj:
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
url: jdbc
:sqlserver
://59.160.284.185
:1433;DatabaseName=YYGJ
username: dty
password: disdusad
2.2、配置对应的数据源映射bean
package cn
.gxm
.test
.config
;
import org
.springframework
.beans
.factory
.annotation
.Qualifier
;
import org
.springframework
.boot
.autoconfigure
.jdbc
.DataSourceProperties
;
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 javax
.sql
.DataSource
;
@Configuration
public class DataSourceConfig {
@Primary
@Bean(name
= "dsyygjDataSourceProperties")
@ConfigurationProperties(prefix
= "spring.datasource.dsyygj")
public DataSourceProperties
dsyygjDataSourceProperties() {
return new DataSourceProperties();
}
@Primary
@Bean(name
= "dsyygjDataSource")
public DataSource
dsyygjDataSource(
@Qualifier("dsyygjDataSourceProperties") DataSourceProperties dataSourceProperties
) {
return dataSourceProperties
.initializeDataSourceBuilder().build();
}
@Bean(name
= "dspublicdbuatDataSourceProperties")
@ConfigurationProperties(prefix
= "spring.datasource.dspublicdbuat")
public DataSourceProperties
dspublicdbuatDataSourceProperties() {
return new DataSourceProperties();
}
@Bean(name
= "dspublicdbuatDataSource")
public DataSource
dspublicdbuatDataSource(
@Qualifier("dspublicdbuatDataSourceProperties") DataSourceProperties dataSourceProperties
) {
return dataSourceProperties
.initializeDataSourceBuilder().build();
}
}
2.3、配置每一个数据源对应的注解(代替mybatis原生的@mapper注解)
每一个不同的注解都表明这个mapper使用那个数据源 连接YYGJ数据是mapper使用的注解
@Target(ElementType
.TYPE
)
@Retention(RetentionPolicy
.RUNTIME
)
public @
interface YYGJAnno {
String
value() default "";
}
连接PublicDbUat数据是mapper使用的注解
@Target(ElementType
.TYPE
)
@Retention(RetentionPolicy
.RUNTIME
)
public @
interface PublicDbUatAnno {
String
value() default "";
}
2.4、为每一个数据源配置一整套 manager,factory,template
2.4.1、配置 YYGJ数据库的manager,factory,template
package cn
.gxm
.test
.config
;
import cn
.gxm
.test
.annotation
.YYGJAnno
;
import org
.apache
.ibatis
.io
.VFS
;
import org
.apache
.ibatis
.plugin
.Interceptor
;
import org
.apache
.ibatis
.session
.SqlSessionFactory
;
import org
.mybatis
.spring
.SqlSessionFactoryBean
;
import org
.mybatis
.spring
.SqlSessionTemplate
;
import org
.mybatis
.spring
.annotation
.MapperScan
;
import org
.mybatis
.spring
.boot
.autoconfigure
.SpringBootVFS
;
import org
.springframework
.beans
.factory
.annotation
.Qualifier
;
import org
.springframework
.beans
.factory
.annotation
.Value
;
import org
.springframework
.context
.annotation
.Bean
;
import org
.springframework
.context
.annotation
.Configuration
;
import org
.springframework
.context
.annotation
.Primary
;
import org
.springframework
.core
.io
.support
.PathMatchingResourcePatternResolver
;
import org
.springframework
.jdbc
.datasource
.DataSourceTransactionManager
;
import javax
.sql
.DataSource
;
@Configuration
@MapperScan(basePackages
= {
"cn.gxm.test.mapper" }, annotationClass
= YYGJAnno
.class, sqlSessionTemplateRef
= "dsyygjSqlSessionTemplate")
public class MybatisDSYYGJConfig {
@Primary
@Bean("dsyygjSqlSessionFactory")
public SqlSessionFactory
dsyygjSqlSessionFactory(@Qualifier("dsyygjDataSource") DataSource dataSource
)
throws Exception
{
SqlSessionFactoryBean sqlSessionFactory
= new SqlSessionFactoryBean();
sqlSessionFactory
.setDataSource(dataSource
);
sqlSessionFactory
.setMapperLocations(
new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/yygj/*Mapper.xml"));
sqlSessionFactory
.setConfigLocation(
new PathMatchingResourcePatternResolver().getResource("classpath:mapper/mybatis-config.xml"));
sqlSessionFactory
.setVfs(SpringBootVFS
.class);
VFS
.addImplClass(SpringBootVFS
.class);
sqlSessionFactory
.setPlugins(new Interceptor[] { MybatisCommon
.getPageHelper() });
// 扫描别名
// sqlSessionFactory
.setTypeAliasesPackage(String
.join(",", MybatisCommon
.getPackages(typeAliasesPackage
)));
return sqlSessionFactory
.getObject();
}
@Primary
@Bean(name
= "dsyygjTransactionManager")
public DataSourceTransactionManager
dsyygjTransactionManager(@Qualifier("dsyygjDataSource") DataSource dataSource
) {
return new DataSourceTransactionManager(dataSource
);
}
@Primary
@Bean(name
= "dsyygjSqlSessionTemplate")
public SqlSessionTemplate
dsyygjSqlSessionTemplate(
@Qualifier("dsyygjSqlSessionFactory") SqlSessionFactory sqlSessionFactory
) {
return new SqlSessionTemplate(sqlSessionFactory
);
}
}
2.4.2、配置 publicdbuat数据库的manager,factory,template
package cn
.gxm
.test
.config
;
import cn
.gxm
.test
.annotation
.PublicDbUatAnno
;
import org
.apache
.ibatis
.io
.VFS
;
import org
.apache
.ibatis
.plugin
.Interceptor
;
import org
.apache
.ibatis
.session
.SqlSessionFactory
;
import org
.mybatis
.spring
.SqlSessionFactoryBean
;
import org
.mybatis
.spring
.SqlSessionTemplate
;
import org
.mybatis
.spring
.annotation
.MapperScan
;
import org
.mybatis
.spring
.boot
.autoconfigure
.SpringBootVFS
;
import org
.springframework
.beans
.factory
.annotation
.Qualifier
;
import org
.springframework
.context
.annotation
.Bean
;
import org
.springframework
.context
.annotation
.Configuration
;
import org
.springframework
.core
.io
.support
.PathMatchingResourcePatternResolver
;
import org
.springframework
.jdbc
.datasource
.DataSourceTransactionManager
;
import javax
.sql
.DataSource
;
@Configuration
@MapperScan(basePackages
= {
"cn.gxm.test.mapper" }, annotationClass
= PublicDbUatAnno
.class, sqlSessionTemplateRef
= "dspublicdbuatSqlSessionTemplate")
public class MybatisPublicDBUatConfig {
@Bean("dspublicdbuatSqlSessionFactory")
public SqlSessionFactory
dspublicdbuatSqlSessionFactory(@Qualifier("dspublicdbuatDataSource") DataSource dataSource
)
throws Exception
{
SqlSessionFactoryBean sqlSessionFactory
= new SqlSessionFactoryBean();
sqlSessionFactory
.setDataSource(dataSource
);
sqlSessionFactory
.setMapperLocations(
new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/public_db_uat/*Mapper.xml"));
sqlSessionFactory
.setConfigLocation(
new PathMatchingResourcePatternResolver().getResource("classpath:mapper/mybatis-config.xml"));
sqlSessionFactory
.setVfs(SpringBootVFS
.class);
VFS
.addImplClass(SpringBootVFS
.class);
sqlSessionFactory
.setPlugins(new Interceptor[] { MybatisCommon
.getPageHelper() });
return sqlSessionFactory
.getObject();
}
@Bean(name
= "dspublicdbuatTransactionManager")
public DataSourceTransactionManager
dspublicdbuatTransactionManager(@Qualifier("dspublicdbuatDataSource") DataSource dataSource
) {
return new DataSourceTransactionManager(dataSource
);
}
@Bean(name
= "dspublicdbuatSqlSessionTemplate")
public SqlSessionTemplate
dspublicdbuatSqlSessionTemplate(
@Qualifier("dspublicdbuatSqlSessionFactory") SqlSessionFactory sqlSessionFactory
) {
return new SqlSessionTemplate(sqlSessionFactory
);
}
}
2.5、为每一个数据源配置对应的放置mapper接口的包名
需要与MybatisDSYYGJConfig中的basePackages配置一致 YYGJ数据库的mapper(注意各个接口上的注解不再是@mapper而是对应的数据源的自定义注解)
@Component
@YYGJAnno
public interface BaseConfigMapper {
BaseConfig
selectOne();
int createTable(String tableName
);
BaseConfig
selectByTempTable(String tableName
);
}
PublicDBUat数据库的mapper
@Component
@PublicDbUatAnno
public interface DBConfigMapper {
DbConfig
selectOne();
}
2.6、为每一个数据源配置对应的防止mapperms.xml文件的包名
对应的xml文件的位置需要与之前java代码配置中写明的一致
new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/yygj/*Mapper.xml"));
new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/public_db_uat/*Mapper.xml"));
DBConfigMapper.xml
<?xml version
="1.0" encoding
="UTF-8"?>
<!DOCTYPE mapper PUBLIC
"-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace
="cn.gxm.test.mapper.DBConfigMapper">
<select id
="selectOne" resultType
="DbConfig">
select
* from db_config where id
= 1
</select
>
</mapper
>
BaseConfigMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.gxm.test.mapper.BaseConfigMapper">
<select id="selectOne" resultType="BaseConfig">
select * from BaseConfig where ID = 1
</select>
<update id="createTable" parameterType="string">
select * into ##TB from BaseConfig;
</update>
<select id="selectByTempTable" parameterType="string" resultType="BaseConfig">
select * from ##TB where id = 1
</select>
</mapper>
全局的mybatis的config配置如下(mybatis-config.xml)
<?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>
<setting name="cacheEnabled" value="true" />
<setting name="lazyLoadingEnabled" value="true" />
<setting name="multipleResultSetsEnabled" value="true" />
<setting name="useColumnLabel" value="true" />
<setting name="useGeneratedKeys" value="false" />
<setting name="autoMappingBehavior" value="PARTIAL" />
<setting name="defaultExecutorType" value="SIMPLE" />
<setting name="defaultStatementTimeout" value="250" />
<setting name="safeRowBoundsEnabled" value="false" />
<setting name="mapUnderscoreToCamelCase" value="false" />
<setting name="localCacheScope" value="SESSION" />
<setting name="jdbcTypeForNull" value="OTHER" />
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString" />
<setting name="logImpl" value="SLF4J"/>
</settings>
<typeAliases>
<package name="cn.gxm.test.model" />
</typeAliases>
</configuration>
最后整体的目录如下
三、多事务配置
本身springboot如果加入了数据库的连接查询,那么springboot就会默认会开启和当前数据库一致的事务处理,以前直接在类上放上注解就可以了,如下
@Transactional()
@LogAnno(module
= "公有模块-基础配置", operate
= "添加")
@PostMapping("/add")
public CommonResult
add(@RequestBody BaseConfig model
) {
但是现在我们有多个数据源,如果还是这样写,它就会提示,不知道使用哪一个数据源的事务处理器,如下
org
.springframework
.beans
.factory
.NoUniqueBeanDefinitionException
: No qualifying bean of type
'org.springframework.transaction.PlatformTransactionManager' available
: more than one
'primary' bean found among candidates
: [dspublicdbuatTransactionManager
, dsyygjTransactionManager
]
错误信息告诉我们我们有很多数据源以及事务,所以我们在使用的时候需要指定哪一个事务管理器,如下
@Transactional(value
= "dsyygjTransactionManager")
@LogAnno(module
= "公有模块-基础配置", operate
= "添加")
@PostMapping("/add")
public CommonResult
add(@RequestBody BaseConfig model
) {
那么就ok了
3.1、解释说明: 数据库事务隔离级别-- 脏读、幻读、不可重复读(清晰解释) 3.2、详细配置事务(设置隔离级别等等) 简单使用,直接在注解上表明要是的隔离级别以及事务传播类型
@Transactional(readOnly
= false, propagation
= Propagation
.REQUIRES_NEW
)
public void updateFoo(Foo foo
) {
具体可以参考: SpringBoot设置事务隔离等级 3.3、 分布式事务 参考文章 【分布式事务】使用atomikos+jta解决分布式事务问题