Spring Boot 集成 Mybatis 实现双数据源
这里用到了Spring Boot + Mybatis + DynamicDataSource配置动态双数据源,可以动态切换数据源实现数据库的读写分离。
添加依赖
加入Mybatis启动器,这里添加了Druid连接池、Oracle数据库驱动为例。
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
</dependency>
添加启动类
@EnableMybatis
@EnableTransactionManagement
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class Application {
public static void main(String[] args) {
SpringApplication.run(ServiceApplication.class, args);
}
}
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }):
这里用到了双数据源,需要排除数据源的自动配置,如果只有一个数据源用Spring Boot的自动配置就行。
@EnableTransactionManagement:开启事务支持。
@EnableMybatis:开启Mybatis功能
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(MybatisConfig.class)
public @interface EnableMybatis {
}
Mybatis配置类
@Configuration
@MapperScan(basePackages = DSConfig.BASE_PACKAGES)
public class MybatisConfig implements DSConfig {
@Primary
@Bean
public DynamicDataSource dynamicDataSource(@Qualifier(DB_MASTER) DataSource master,
@Qualifier(DB_SLAVE) DataSource slave) {
Map<Object, Object> dsMap = new HashMap<>();
dsMap.put(DB_MASTER, master);
dsMap.put(DB_MASTER, slave);
DynamicDataSource dynamicDataSource = new DynamicDataSource();
dynamicDataSource.setDefaultTargetDataSource(master);
dynamicDataSource.setTargetDataSources(dsMap);
return dynamicDataSource;
}
@Bean
public PlatformTransactionManager transactionManager(DynamicDataSource dynamicDataSource) {
return new DataSourceTransactionManager(dynamicDataSource);
}
@Bean
public SqlSessionFactory sqlSessionFactory(DynamicDataSource dynamicDataSource)
throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dynamicDataSource);
sessionFactory.setMapperLocations(
((ResourcePatternResolver) new PathMatchingResourcePatternResolver())
.getResources(DSConfig.MAPPER_LOCATIONS));
return sessionFactory.getObject();
}
}
DSConfig常量类:
public interface DSConfig {
String DS_PREFIX = "spring.datasource";
String DS_ACTIVE = "active";
String DB_MASTER = "db-master";
String DB_SLAVE = "db-slave";
String DRUID = "druid";
String DRUID_MONITOR_USERNAME = "spring.druid.username";
String DRUID_MONITOR_PASSWORD = "spring.druid.password";
String DRUID_MONITOR_URL = "/druid/*";
String DRUID_FILTER_EXCLUSIONS = "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*";
String DRUID_FILTER_URL = "/*";
String BASE_PACKAGES = "com.example.**.mapper";
String MAPPER_LOCATIONS = "mapper/**/*.xml";
}
连接池配置类
Druid连接池的自动配置类:
@Configuration
@Import({ PropertiesConfig.class })
@ConditionalOnClass(DruidDataSource.class)
@ConditionalOnProperty(prefix = DSConfig.DS_PREFIX, value = DSConfig.DS_ACTIVE, havingValue = DSConfig.DRUID)
public class DruidAutoConfig implements DSConfig {
private Logger logger = LoggerUtils.getLogger(this);
@Bean(name = DB_MASTER, initMethod = "init", destroyMethod = "close")
public DataSource dataSourceMaster(DruidMasterProperties masterProperties) throws SQLException {
logger.debug("master properties: {}", masterProperties.toString());
DruidDataSource dds = new DruidDataSource();
dds.setDriverClassName(masterProperties.getDriverClassName());
dds.setUrl(masterProperties.getUrl());
dds.setUsername(masterProperties.getUsername());
dds.setPassword(masterProperties.getPassword());
dds.setInitialSize(masterProperties.getInitialSize());
dds.setMinIdle(masterProperties.getMinIdle());
dds.setMaxActive(masterProperties.getMaxActive());
dds.setMaxWait(masterProperties.getMaxWait());
dds.setTimeBetweenEvictionRunsMillis(masterProperties.getTimeBetweenEvictionRunsMillis());
dds.setMinEvictableIdleTimeMillis(masterProperties.getMinEvictableIdleTimeMillis());
dds.setValidationQuery(masterProperties.getValidationQuery());
dds.setTestOnBorrow(masterProperties.isTestOnBorrow());
dds.setTestWhileIdle(masterProperties.isTestWhileIdle());
dds.setTestOnReturn(masterProperties.isTestOnReturn());
dds.setPoolPreparedStatements(masterProperties.isPoolPreparedStatements());
dds.setMaxPoolPreparedStatementPerConnectionSize(
masterProperties.getMaxPoolPreparedStatementPerConnectionSize());
dds.setFilters(masterProperties.getFilters());
return dds;
}
@Bean(name = DB_SLAVE, initMethod = "init", destroyMethod = "close")
public DataSource dataSourceSlave(DruidSlaveProperties slaveProperties) throws SQLException {
logger.debug("slave properties: {}", slaveProperties.toString());
DruidDataSource dds = new DruidDataSource();
dds.setDriverClassName(slaveProperties.getDriverClassName());
dds.setUrl(slaveProperties.getUrl());
dds.setUsername(slaveProperties.getUsername());
dds.setPassword(slaveProperties.getPassword());
dds.setInitialSize(slaveProperties.getInitialSize());
dds.setMinIdle(slaveProperties.getMinIdle());
dds.setMaxActive(slaveProperties.getMaxActive());
dds.setMaxWait(slaveProperties.getMaxWait());
dds.setTimeBetweenEvictionRunsMillis(slaveProperties.getTimeBetweenEvictionRunsMillis());
dds.setMinEvictableIdleTimeMillis(slaveProperties.getMinEvictableIdleTimeMillis());
dds.setValidationQuery(slaveProperties.getValidationQuery());
dds.setTestOnBorrow(slaveProperties.isTestOnBorrow());
dds.setTestWhileIdle(slaveProperties.isTestWhileIdle());
dds.setTestOnReturn(slaveProperties.isTestOnReturn());
dds.setPoolPreparedStatements(slaveProperties.isPoolPreparedStatements());
dds.setMaxPoolPreparedStatementPerConnectionSize(
slaveProperties.getMaxPoolPreparedStatementPerConnectionSize());
dds.setFilters(slaveProperties.getFilters());
return dds;
}
@Bean
public ServletRegistrationBean druidServletRegistrationBean(EnvConfig env) {
String username = env.getStringValue(DSConfig.DRUID_MONITOR_USERNAME);
String password = env.getStringValue(DSConfig.DRUID_MONITOR_PASSWORD);
return new ServletRegistrationBean(new DruidStatViewServlet(username, password),
DSConfig.DRUID_MONITOR_URL);
}
@Bean
public FilterRegistrationBean druidFilterRegistrationBean() {
WebStatFilter wsf = new WebStatFilter();
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(wsf);
filterRegistrationBean.setUrlPatterns(Arrays.asList(DSConfig.DRUID_FILTER_URL));
filterRegistrationBean.setInitParameters(
Collections.singletonMap("exclusions", DSConfig.DRUID_FILTER_EXCLUSIONS));
return filterRegistrationBean;
}
}
根据类路径下有DruidDataSource这个类即有Druid这个jar包和配置文件中spring.datasource.active=druid才开启对Druid连接池的自动配置。
导入的配置文件:
@Configuration
@ComponentScan(basePackages = "com.example.common.config.properties")
public class PropertiesConfig {
}
DruidMasterProperties、DruidSlaveProperties属性文件读取的配置省略。
连接池监控配置类:
public class DruidStatViewServlet extends StatViewServlet {
private static final long serialVersionUID = 1L;
private String username;
private String password;
@Override
public String getInitParameter(String name) {
if ("loginUsername".equals(name)) {
return username;
}
if ("loginPassword".equals(name)) {
return password;
}
return super.getInitParameter(name);
}
public DruidStatViewServlet(String username, String password) {
super();
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
}
在META-INF/spring.factories中加入Druid自动配置映射:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.common.config.ds.DruidAutoConfig
切换数据源
切换数据源注解:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DS {
String value() default DSConfig.DB_MASTER;
}
动态数据源类:
public class DynamicDataSource extends AbstractRoutingDataSource {
private final Logger logger = LoggerUtils.getLogger(this);
@Override
protected Object determineCurrentLookupKey() {
logger.debug("当前数据源为{}", DataSourceContextHolder.getDS());
return DataSourceContextHolder.getDS();
}
}
动态数据源AOP实现类:
@Aspect
@Component
public class DynamicDataSourceAspect {
@Before("@annotation(DS)")
public void beforeSwitchDS(JoinPoint point) {
Class<?> className = point.getTarget().getClass();
String methodName = point.getSignature().getName();
Class<?>[] argClass = ((MethodSignature) point.getSignature()).getParameterTypes();
String dataSource = DataSourceContextHolder.DEFAULT_DS;
try {
Method method = className.getMethod(methodName, argClass);
if (method.isAnnotationPresent(DS.class)) {
DS annotation = method.getAnnotation(DS.class);
dataSource = annotation.value();
}
} catch (Exception e) {
e.printStackTrace();
}
DataSourceContextHolder.setDS(dataSource);
}
@After("@annotation(DS)")
public void afterSwitchDS(JoinPoint point) {
DataSourceContextHolder.clearDS();
}
}
绑定当前线程数据源类:
public class DataSourceContextHolder {
public static final String DEFAULT_DS = DSConfig.DB_MASTER;
private static final ThreadLocal<String> DS_HOLDER = new ThreadLocal<>();
public static void setDS(String dbType) {
DS_HOLDER.set(dbType);
}
public static String getDS() {
return (DS_HOLDER.get());
}
public static void clearDS() {
DS_HOLDER.remove();
}
}
Spring Boot 集成 Mybatis 实现双数据源的更多相关文章
- Spring Boot 集成Mybatis实现多数据源
静态的方式 我们以两套配置方式为例,在项目中有两套配置文件,两套mapper,两套SqlSessionFactory,各自处理各自的业务,这个两套mapper都可以进行增删改查的操作,在这两个主MYS ...
- Spring Boot集成MyBatis开发Web项目
1.Maven构建Spring Boot 创建Maven Web工程,引入spring-boot-starter-parent依赖 <project xmlns="http://mav ...
- 详解Spring Boot集成MyBatis的开发流程
MyBatis是支持定制化SQL.存储过程以及高级映射的优秀的持久层框架,避免了几乎所有的JDBC代码和手动设置参数以及获取结果集. spring Boot是能支持快速创建Spring应用的Java框 ...
- 【spring boot】14.spring boot集成mybatis,注解方式OR映射文件方式AND pagehelper分页插件【Mybatis】pagehelper分页插件分页查询无效解决方法
spring boot集成mybatis,集成使用mybatis拖沓了好久,今天终于可以补起来了. 本篇源码中,同时使用了Spring data JPA 和 Mybatis两种方式. 在使用的过程中一 ...
- spring boot + druid + mybatis + atomikos 多数据源配置 并支持分布式事务
文章目录 一.综述 1.1 项目说明 1.2 项目结构 二.配置多数据源并支持分布式事务 2.1 导入基本依赖 2.2 在yml中配置多数据源信息 2.3 进行多数据源的配置 三.整合结果测试 3.1 ...
- spring boot集成mybatis(1)
Spring Boot 集成教程 Spring Boot 介绍 Spring Boot 开发环境搭建(Eclipse) Spring Boot Hello World (restful接口)例子 sp ...
- spring boot集成mybatis(2) - 使用pagehelper实现分页
Spring Boot 集成教程 Spring Boot 介绍 Spring Boot 开发环境搭建(Eclipse) Spring Boot Hello World (restful接口)例子 sp ...
- spring boot集成mybatis(3) - mybatis generator 配置
Spring Boot 集成教程 Spring Boot 介绍 Spring Boot 开发环境搭建(Eclipse) Spring Boot Hello World (restful接口)例子 sp ...
- spring boot集成MyBatis 通用Mapper 使用总结
spring boot集成MyBatis 通用Mapper 使用总结 2019年 参考资料: Spring boot集成 MyBatis 通用Mapper SpringBoot框架之通用mapper插 ...
随机推荐
- 转:Loadrunner添加服务器监控
一.监控windows系统:1.监视连接前的准备 1)进入被监视windows系统,开启以下二个服务Remote Procedure Call(RPC) 和Remote Registry ...
- jsonarray根据id排序
List<JSONObject> jsonValue=new ArrayList<JSONObject>(); JSONArray sortJsonarr=new JSONAr ...
- XPath简介及节点
XPath是一门在XML文档中查找信息的语言. XPath可用来在XML文档中对元素和属性进行遍历. XPath使用路径表达式在XML文档中进行导航. XPath路径表达式:XPath使用路径表达式来 ...
- pythone函数基础(10)MD5加密
导入hashlib模块import hashlibs='yulin123456's.encode()#把数字转换成bytes类型m=hashlib.md5(s.encode())print(m.hex ...
- jdbcTemplate的简单介绍
Spring JDBC抽象框架core包提供了JDBC模板类,其中JdbcTemplate是core包的核心类,所以其他模板类都是基于它封装完成的,JDBC模板类是第一种工作模式. JdbcTempl ...
- 跑python用ThinkPad好还是MacBook好?
跑Python,那肯定是服务器操作系统最好,找个方便安装Linux的本子. 我想题主的意图应该是做Python开发吧,如果是Python开发,还要看一下开发方向,如果是网络爬虫.服务器后端编程类的,那 ...
- redis使用规范文档 20170522版
运维redis很久了,一直是口头给rd说各种要求,尝试把这些规范总结成文档 摘选一些可能比较通用的规则如下: 强制:所有的key设置过期时间(最长可设置过期时间10天,如有特殊要求,联系dba说明原因 ...
- python_day12_css
目录: 简介 选择器(selecttor) 常用属性 页面布局 一.简介 1.CSS 定义 CSS是Cascading Style Sheets的简称,中文称为层叠样式表. CSS 规则由两个主要的部 ...
- mysql---select的五种子句学习(where、group by、having、order by、limit)
mysql---select的五种子句学习(where.group by.having.order by.limit) 分类: Mysql学习2012-09-27 16:14 1533人阅读 评论 ...
- W7500P硬件TCP/IP+硬件物理层PHY+Cortex-M0处理器(48MHZ)
W7500P 硬件TCP/IP+硬件物理层PHY+Cortex-M0处理器(48MHZ) 硬件TCP/IP+硬件物理层PHY+Cortex-M0处理器(48MHZ) 如果您发现商品信息不准确,欢迎纠错 ...