免费的查企业的网站,seo优化培训,上海工程建设信息网站,网站建设合同的内容与结构在复杂业务系统中#xff0c;多数据源切换已成为必备技能。本文将深入剖析三种主流实现方案#xff0c;带你从入门到精通#xff01;
一、多数据源应用场景 读写分离#xff1a;主库负责写操作#xff0c;从库处理读请求 多租户系统#xff1a;不同租户使用独立数据库 …在复杂业务系统中多数据源切换已成为必备技能。本文将深入剖析三种主流实现方案带你从入门到精通
一、多数据源应用场景 读写分离主库负责写操作从库处理读请求 多租户系统不同租户使用独立数据库 分库分表业务数据按规则分散存储 多数据库类型同时使用MySQL、Oracle等异构数据库
二、3种实现方案对比
方案实现复杂度侵入性维护成本适用场景AbstractRoutingDataSource中等高高简单读写分离多SqlSessionFactory高高高异构数据库dynamic-datasource低低低复杂多数据源
三、方案一AbstractRoutingDataSource
实现原理
通过继承Spring的AbstractRoutingDataSource类动态路由数据源
实现步骤
1. 添加依赖
dependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-jdbc/artifactId/dependencydependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion8.0.27/version/dependency
/dependencies 2. 配置多数据源 # application.yml
spring:datasource:master:driver-class-name: com.mysql.cj.jdbc.Driverjdbc-url: jdbc:mysql://localhost:3306/master_dbusername: rootpassword: root123slave:driver-class-name: com.mysql.cj.jdbc.Driverjdbc-url: jdbc:mysql://localhost:3306/slave_dbusername: rootpassword: root123
3. 动态数据源配置类
Configuration
public class DataSourceConfig {BeanConfigurationProperties(spring.datasource.master)public DataSource masterDataSource() {return DataSourceBuilder.create().build();}BeanConfigurationProperties(spring.datasource.slave)public DataSource slaveDataSource() {return DataSourceBuilder.create().build();}Beanpublic DataSource dynamicDataSource() {MapObject, Object targetDataSources new HashMap();targetDataSources.put(master, masterDataSource());targetDataSources.put(slave, slaveDataSource());DynamicDataSource dynamicDataSource new DynamicDataSource();dynamicDataSource.setTargetDataSources(targetDataSources);dynamicDataSource.setDefaultTargetDataSource(masterDataSource());return dynamicDataSource;}
}
4. 自定义动态数据源
public class DynamicDataSource extends AbstractRoutingDataSource {Overrideprotected Object determineCurrentLookupKey() {return DataSourceContextHolder.getDataSourceKey();}public static class DataSourceContextHolder {private static final ThreadLocalString contextHolder new ThreadLocal();public static void setDataSourceKey(String key) {contextHolder.set(key);}public static String getDataSourceKey() {return contextHolder.get();}public static void clearDataSourceKey() {contextHolder.remove();}}
}
5. 自定义注解切换数据源
Target({ElementType.METHOD, ElementType.TYPE})
Retention(RetentionPolicy.RUNTIME)
Documented
public interface DataSource {String value() default master;
}
6. AOP切面实现动态切换
Aspect
Component
public class DataSourceAspect {Before(annotation(dataSource))public void beforeSwitchDataSource(JoinPoint point, DataSource dataSource) {String dataSourceKey dataSource.value();DynamicDataSource.DataSourceContextHolder.setDataSourceKey(dataSourceKey);}After(annotation(dataSource))public void afterSwitchDataSource(JoinPoint point, DataSource dataSource) {DynamicDataSource.DataSourceContextHolder.clearDataSourceKey();}
}
7. 业务层使用示例
Service
public class UserService {Autowiredprivate JdbcTemplate jdbcTemplate;// 使用主库DataSource(master)public void createUser(User user) {String sql INSERT INTO users(name, email) VALUES(?, ?);jdbcTemplate.update(sql, user.getName(), user.getEmail());}// 使用从库DataSource(slave)public ListUser getAllUsers() {String sql SELECT * FROM users;return jdbcTemplate.query(sql, new BeanPropertyRowMapper(User.class));}
}
方案优缺点
优点 纯Spring实现无第三方依赖 灵活控制数据源切换
缺点 事务管理复杂 需手动处理连接池 切换逻辑侵入业务代码
四、方案二多SqlSessionFactory
实现原理
为每个数据源创建独立的MyBatis SqlSessionFactory
实现步骤
1. 主数据源配置
Configuration
MapperScan(basePackages com.example.mapper.master, sqlSessionFactoryRef masterSqlSessionFactory)
public class MasterDataSourceConfig {BeanConfigurationProperties(spring.datasource.master)public DataSource masterDataSource() {return DataSourceBuilder.create().build();}Beanpublic SqlSessionFactory masterSqlSessionFactory(Qualifier(masterDataSource) DataSource dataSource) throws Exception {SqlSessionFactoryBean bean new SqlSessionFactoryBean();bean.setDataSource(dataSource);bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(classpath:mapper/master/*.xml));return bean.getObject();}Beanpublic DataSourceTransactionManager masterTransactionManager(Qualifier(masterDataSource) DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}
}
2. 从数据源配置
Configuration
MapperScan(basePackages com.example.mapper.slave, sqlSessionFactoryRef slaveSqlSessionFactory)
public class SlaveDataSourceConfig {BeanConfigurationProperties(spring.datasource.slave)public DataSource slaveDataSource() {return DataSourceBuilder.create().build();}Beanpublic SqlSessionFactory slaveSqlSessionFactory(Qualifier(slaveDataSource) DataSource dataSource) throws Exception {SqlSessionFactoryBean bean new SqlSessionFactoryBean();bean.setDataSource(dataSource);bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(classpath:mapper/slave/*.xml));return bean.getObject();}Beanpublic DataSourceTransactionManager slaveTransactionManager(Qualifier(slaveDataSource) DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}
}
3. 业务层使用
Service
public class OrderService {// 注入主库MapperAutowiredQualifier(masterOrderMapper)private OrderMapper masterOrderMapper;// 注入从库MapperAutowiredQualifier(slaveOrderMapper)private OrderMapper slaveOrderMapper;Transactional(transactionManager masterTransactionManager)public void createOrder(Order order) {masterOrderMapper.insert(order);}Transactional(transactionManager slaveTransactionManager)public Order getOrder(Long id) {return slaveOrderMapper.selectById(id);}
}
方案优缺点
优点 各数据源完全隔离 事务管理清晰 支持异构数据库
缺点 配置复杂冗余代码多 Mapper需按数据源分包 动态切换不灵活
五、方案三dynamic-datasource框架
框架优势 零侵入通过注解实现数据源切换 功能丰富支持读写分离、分库分表等 简单易用简化多数据源配置
实现步骤
1. 添加依赖
dependencygroupIdcom.baomidou/groupIdartifactIddynamic-datasource-spring-boot-starter/artifactIdversion3.5.0/version
/dependency
2. 配置数据源
spring:datasource:dynamic:primary: master # 默认数据源strict: false # 是否严格匹配数据源datasource:master:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/master_dbusername: rootpassword: root123slave1:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/slave_db1username: rootpassword: root123slave2:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/slave_db2username: rootpassword: root123oracle_db:driver-class-name: oracle.jdbc.OracleDriverurl: jdbc:oracle:thin:localhost:1521:orclusername: systempassword: oracle123
3. 使用DS注解切换数据源
Service
public class ProductService {// 默认使用主库Autowiredprivate JdbcTemplate jdbcTemplate;// 使用主库DS(master)public void createProduct(Product product) {jdbcTemplate.update(INSERT INTO product(...) VALUES(...));}// 随机使用从库DS(slave)public Product getProduct(Long id) {return jdbcTemplate.queryForObject(SELECT * FROM product WHERE id ?, new BeanPropertyRowMapper(Product.class), id);}// 指定特定从库DS(slave1)public ListProduct getHotProducts() {return jdbcTemplate.query(SELECT * FROM product WHERE hot 1, new BeanPropertyRowMapper(Product.class));}// 使用Oracle数据库DS(oracle_db)public ListCategory getOracleCategories() {return jdbcTemplate.query(SELECT * FROM categories, new BeanPropertyRowMapper(Category.class));}
}
4. 高级功能读写分离
spring:datasource:dynamic:primary: masterdatasource:master:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://master-host:3306/dbusername: rootpassword: root123slave_1:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://slave1-host:3306/dbusername: rootpassword: root123slave_2:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://slave2-host:3306/dbusername: rootpassword: root123strategy: # 读写分离配置load-balance: # 负载均衡策略slave: round_robin # 从库轮询策略
5. 事务管理
DS(master)
Transactional
public void placeOrder(Order order) {// 1. 扣减库存productService.reduceStock(order.getProductId(), order.getQuantity());// 2. 创建订单orderMapper.insert(order);// 3. 记录日志logService.logOrder(order);// 所有操作都在主库事务中执行
}
最佳实践技巧 数据源分组管理 spring:datasource:dynamic:datasource:master_1: # 配置...master_2:# 配置...slave_1:# 配置...slave_2:# 配置...group:masters: master_1, master_2slaves: slave_1, slave_2 多租户数据源动态注册 Autowired
private DynamicRoutingDataSource routingDataSource;public void addTenantDataSource(String tenantId, DataSourceProperty property) {DataSource dataSource dataSourceCreator.createDataSource(property);routingDataSource.addDataSource(tenantId, dataSource);
} 自定义负载均衡策略 public class RandomStrategy implements LoadBalanceStrategy {Overridepublic String determineDataSource(ListString dataSourceNames) {Random random new Random();return dataSourceNames.get(random.nextInt(dataSourceNames.size()));}
}
六、性能优化建议 连接池配置优化 spring:datasource:dynamic:datasource:master:# ...hikari:maximum-pool-size: 20minimum-idle: 5connection-timeout: 30000idle-timeout: 600000max-lifetime: 1800000 避免频繁切换数据源 将同一数据源操作集中处理 使用DSTransactional管理跨库事务 监控数据源状态 RestController
public class DataSourceMonitor {Autowiredprivate DynamicRoutingDataSource routingDataSource;GetMapping(/datasources)public MapString, DataSource listDataSources() {return routingDataSource.getDataSources();}GetMapping(/datasources/stats)public MapString, Object getDataSourceStats() {MapString, Object stats new HashMap();routingDataSource.getDataSources().forEach((key, ds) - {if(ds instanceof HikariDataSource) {HikariDataSource hikari (HikariDataSource) ds;HikariPoolMXBean pool hikari.getHikariPoolMXBean();stats.put(key, Map.of(active, pool.getActiveConnections(),idle, pool.getIdleConnections(),total, pool.getTotalConnections()));}});return stats;}
}
七、方案选型建议 中小型项目优先选用dynamic-datasource开发效率高 异构数据库系统选择多SqlSessionFactory方案隔离性好 需要高度定制AbstractRoutingDataSource提供最大灵活性 云原生环境dynamic-datasource Seata分布式事务
八、常见问题解决方案 数据源切换失效 检查方法是否被AOP代理 确保DS注解在public方法上 避免类内部方法调用 跨库事务问题 // 使用分布式事务
DS(order)
GlobalTransactional
public void createOrder(Order order) {// 操作订单库orderMapper.insert(order);// 操作库存库stockService.reduce(order.getProductId(), order.getQuantity());
} 连接泄露检测 Bean
public DataSource dataSource(DataSourceProperties properties) {HikariDataSource dataSource properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();dataSource.setLeakDetectionThreshold(5000); // 5秒泄露检测return dataSource;
}
九、结语
多数据源管理是现代应用开发的必备技能。通过本文介绍的三种方案 AbstractRoutingDataSourceSpring原生方案适合定制化场景 多SqlSessionFactory适合异构数据库系统 dynamic-datasource生产环境首选功能强大易用 最佳实践提示对于大多数Java项目推荐使用dynamic-datasource框架它提供了一站式的解决方案大大降低了多数据源管理的复杂度。同时结合Spring Cloud Alibaba Seata可轻松实现分布式事务管理。 扩展阅读 Spring官方文档数据访问 dynamic-datasource高级用法 MyBatis多数据源最佳实践
掌握多数据源切换技术让你的应用从容应对复杂数据场景 文章转载自: http://www.morning.rwbx.cn.gov.cn.rwbx.cn http://www.morning.ykshx.cn.gov.cn.ykshx.cn http://www.morning.nchsz.cn.gov.cn.nchsz.cn http://www.morning.rgwz.cn.gov.cn.rgwz.cn http://www.morning.dblfl.cn.gov.cn.dblfl.cn http://www.morning.krjrb.cn.gov.cn.krjrb.cn http://www.morning.qglqb.cn.gov.cn.qglqb.cn http://www.morning.jxwhr.cn.gov.cn.jxwhr.cn http://www.morning.wyrkp.cn.gov.cn.wyrkp.cn http://www.morning.sogou66.cn.gov.cn.sogou66.cn http://www.morning.mqss.cn.gov.cn.mqss.cn http://www.morning.zwdrz.cn.gov.cn.zwdrz.cn http://www.morning.tdzxy.cn.gov.cn.tdzxy.cn http://www.morning.tmfhx.cn.gov.cn.tmfhx.cn http://www.morning.dfygx.cn.gov.cn.dfygx.cn http://www.morning.ncqzb.cn.gov.cn.ncqzb.cn http://www.morning.rwzqn.cn.gov.cn.rwzqn.cn http://www.morning.ydwnc.cn.gov.cn.ydwnc.cn http://www.morning.zwzwn.cn.gov.cn.zwzwn.cn http://www.morning.pbwcq.cn.gov.cn.pbwcq.cn http://www.morning.ybmp.cn.gov.cn.ybmp.cn http://www.morning.hxftm.cn.gov.cn.hxftm.cn http://www.morning.htsrm.cn.gov.cn.htsrm.cn http://www.morning.rnnq.cn.gov.cn.rnnq.cn http://www.morning.pbzgj.cn.gov.cn.pbzgj.cn http://www.morning.rfycj.cn.gov.cn.rfycj.cn http://www.morning.tztgq.cn.gov.cn.tztgq.cn http://www.morning.monstercide.com.gov.cn.monstercide.com http://www.morning.ndpwg.cn.gov.cn.ndpwg.cn http://www.morning.ljwyc.cn.gov.cn.ljwyc.cn http://www.morning.lwwnq.cn.gov.cn.lwwnq.cn http://www.morning.pjxlg.cn.gov.cn.pjxlg.cn http://www.morning.lyzwdt.com.gov.cn.lyzwdt.com http://www.morning.yrddl.cn.gov.cn.yrddl.cn http://www.morning.mkczm.cn.gov.cn.mkczm.cn http://www.morning.fndmk.cn.gov.cn.fndmk.cn http://www.morning.rxdsq.cn.gov.cn.rxdsq.cn http://www.morning.tralution.cn.gov.cn.tralution.cn http://www.morning.kzrbn.cn.gov.cn.kzrbn.cn http://www.morning.owenzhi.com.gov.cn.owenzhi.com http://www.morning.ryyjw.cn.gov.cn.ryyjw.cn http://www.morning.wbxrl.cn.gov.cn.wbxrl.cn http://www.morning.ylljn.cn.gov.cn.ylljn.cn http://www.morning.ndyrb.com.gov.cn.ndyrb.com http://www.morning.qnhcx.cn.gov.cn.qnhcx.cn http://www.morning.wzwpz.cn.gov.cn.wzwpz.cn http://www.morning.llxqj.cn.gov.cn.llxqj.cn http://www.morning.kspfq.cn.gov.cn.kspfq.cn http://www.morning.wtbzt.cn.gov.cn.wtbzt.cn http://www.morning.mxlmn.cn.gov.cn.mxlmn.cn http://www.morning.pmtky.cn.gov.cn.pmtky.cn http://www.morning.nqlx.cn.gov.cn.nqlx.cn http://www.morning.tfgkq.cn.gov.cn.tfgkq.cn http://www.morning.rwfj.cn.gov.cn.rwfj.cn http://www.morning.pzss.cn.gov.cn.pzss.cn http://www.morning.knmp.cn.gov.cn.knmp.cn http://www.morning.mwlxk.cn.gov.cn.mwlxk.cn http://www.morning.rfdqr.cn.gov.cn.rfdqr.cn http://www.morning.xpfwr.cn.gov.cn.xpfwr.cn http://www.morning.ylsxk.cn.gov.cn.ylsxk.cn http://www.morning.krnzm.cn.gov.cn.krnzm.cn http://www.morning.hhboyus.cn.gov.cn.hhboyus.cn http://www.morning.nsyzm.cn.gov.cn.nsyzm.cn http://www.morning.jxtbr.cn.gov.cn.jxtbr.cn http://www.morning.lwwnq.cn.gov.cn.lwwnq.cn http://www.morning.pbxkk.cn.gov.cn.pbxkk.cn http://www.morning.dpjtn.cn.gov.cn.dpjtn.cn http://www.morning.qbmpb.cn.gov.cn.qbmpb.cn http://www.morning.qpsft.cn.gov.cn.qpsft.cn http://www.morning.rxxdk.cn.gov.cn.rxxdk.cn http://www.morning.ftntr.cn.gov.cn.ftntr.cn http://www.morning.dtmjn.cn.gov.cn.dtmjn.cn http://www.morning.lyzwdt.com.gov.cn.lyzwdt.com http://www.morning.pbknh.cn.gov.cn.pbknh.cn http://www.morning.rlbg.cn.gov.cn.rlbg.cn http://www.morning.nyplp.cn.gov.cn.nyplp.cn http://www.morning.tdnbw.cn.gov.cn.tdnbw.cn http://www.morning.pqfbk.cn.gov.cn.pqfbk.cn http://www.morning.qprtm.cn.gov.cn.qprtm.cn http://www.morning.jfnbh.cn.gov.cn.jfnbh.cn