告别数据孤岛:MyBatis 3多数据源整合实战指南

告别数据孤岛:MyBatis 3多数据源整合实战指南

【免费下载链接】mybatis-3 MyBatis SQL mapper framework for Java 【免费下载链接】mybatis-3 项目地址: https://gitcode.com/gh_mirrors/my/mybatis-3

在企业级应用开发中,你是否经常面临需要同时操作多个数据库的困境?订单数据存在MySQL、用户信息存储在PostgreSQL、商品库存又放在Oracle——这种数据分散存储的场景正在成为常态。本文将通过3个实战方案,手把手教你用MyBatis 3实现多数据源无缝整合,解决跨库事务、连接管理和动态路由难题,让数据流动像水一样自然。

多数据源整合的核心挑战

多数据源架构下,应用需要解决三个关键问题:如何管理不同数据库的连接配置、如何动态选择目标数据源、以及如何保证跨库操作的数据一致性。MyBatis作为优秀的ORM框架,通过灵活的数据源接口设计为这些问题提供了基础解决方案。

MyBatis定义了标准的数据源工厂接口DataSourceFactory.java,所有数据源实现都必须遵循这个规范:

public interface DataSourceFactory {
  void setProperties(Properties props);
  DataSource getDataSource();
}

框架默认提供了三种实现:

方案一:静态多数据源配置

最简单直接的实现方式是为每个数据源创建独立的SqlSessionFactory实例。这种方式适合数据源数量固定且不会频繁变化的场景,实现步骤如下:

  1. 配置多个数据源属性

在MyBatis配置文件中定义多个数据源环境:

<environments default="db1">
  <!-- 主数据库 -->
  <environment id="db1">
    <transactionManager type="JDBC"/>
    <dataSource type="POOLED">
      <property name="driver" value="${db1.driver}"/>
      <property name="url" value="${db1.url}"/>
      <property name="username" value="${db1.username}"/>
      <property name="password" value="${db1.password}"/>
    </dataSource>
  </environment>
  
  <!-- 从数据库 -->
  <environment id="db2">
    <transactionManager type="JDBC"/>
    <dataSource type="POOLED">
      <property name="driver" value="${db2.driver}"/>
      <property name="url" value="${db2.url}"/>
      <property name="username" value="${db2.username}"/>
      <property name="password" value="${db2.password}"/>
    </dataSource>
  </environment>
</environments>
  1. 创建多个SqlSessionFactory

通过指定环境ID构建不同的SqlSessionFactory:

// 主库SqlSessionFactory
SqlSessionFactory db1SessionFactory = new SqlSessionFactoryBuilder()
  .build(reader, "db1");
  
// 从库SqlSessionFactory  
SqlSessionFactory db2SessionFactory = new SqlSessionFactoryBuilder()
  .build(reader, "db2");
  1. 使用对应SqlSession操作数据
// 操作主库
try (SqlSession session = db1SessionFactory.openSession()) {
  UserMapper userMapper = session.getMapper(UserMapper.class);
  userMapper.insert(user);
}

// 操作从库
try (SqlSession session = db2SessionFactory.openSession()) {
  OrderMapper orderMapper = session.getMapper(OrderMapper.class);
  orderMapper.selectById(orderId);
}

这种方式的优势是实现简单、易于理解,缺点是当数据源数量增加时,配置和维护成本会线性增长。MyBatis的DefaultSqlSessionFactory.java会根据环境配置创建对应的Executor实例,从而实现对不同数据源的操作隔离。

方案二:动态数据源路由

当需要在运行时根据业务逻辑动态选择数据源时,可以实现自定义的动态数据源路由。这种方式通过AOP和ThreadLocal技术实现数据源上下文切换,核心思路是:

  1. 实现动态数据源类

创建一个继承AbstractRoutingDataSource的类,重写determineCurrentLookupKey方法:

public class DynamicDataSource extends AbstractRoutingDataSource {
  @Override
  protected Object determineCurrentLookupKey() {
    return DataSourceContextHolder.getDataSourceKey();
  }
}
  1. 创建数据源上下文持有者
public class DataSourceContextHolder {
  private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
  
  public static void setDataSourceKey(String key) {
    CONTEXT_HOLDER.set(key);
  }
  
  public static String getDataSourceKey() {
    return CONTEXT_HOLDER.get();
  }
  
  public static void clearDataSourceKey() {
    CONTEXT_HOLDER.remove();
  }
}
  1. 配置数据源路由
<bean id="dynamicDataSource" class="com.example.DynamicDataSource">
  <property name="targetDataSources">
    <map key-type="java.lang.String">
      <entry key="db1" value-ref="dataSource1"/>
      <entry key="db2" value-ref="dataSource2"/>
    </map>
  </property>
  <property name="defaultTargetDataSource" ref="dataSource1"/>
</bean>
  1. 使用AOP实现自动切换
@Aspect
@Component
public class DataSourceAspect {
  @Before("@annotation(dataSource)")
  public void beforeSwitchDataSource(DataSource dataSource) {
    DataSourceContextHolder.setDataSourceKey(dataSource.value());
  }
  
  @After("@annotation(dataSource)")
  public void afterSwitchDataSource(DataSource dataSource) {
    DataSourceContextHolder.clearDataSourceKey();
  }
}

这种方案的核心在于通过MyBatis的SqlSessionFactory.java接口实现对数据源的统一管理,再结合Spring的事务管理机制,可以有效解决大多数动态数据源场景需求。SqlSessionManager.java提供了对SqlSession的线程安全管理,可以作为实现动态数据源路由的参考。

方案三:分布式事务处理

在多数据源环境下保证事务一致性是一个复杂问题。MyBatis本身不提供分布式事务支持,但可以与第三方事务管理器集成,如Atomikos、Bitronix等JTA实现。

集成JTA事务的基本步骤:

  1. 添加JTA依赖
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>
  1. 配置分布式数据源
@Bean
public DataSource dataSource1() {
  AtomikosDataSourceBean ds = new AtomikosDataSourceBean();
  ds.setUniqueResourceName("db1");
  ds.setXaDataSourceClassName("com.mysql.cj.jdbc.MysqlXADataSource");
  
  Properties props = new Properties();
  props.setProperty("url", "jdbc:mysql://localhost:3306/db1");
  props.setProperty("user", "root");
  props.setProperty("password", "password");
  
  ds.setXaProperties(props);
  return ds;
}
  1. 配置JTA事务管理器
@Bean
public JtaTransactionManager transactionManager() {
  return new JtaTransactionManager();
}
  1. 使用@Transactional注解
@Service
public class OrderService {
  @Transactional
  public void createOrder(Order order) {
    // 操作多个数据源的代码
    orderMapper.insert(order);
    inventoryMapper.decrease(order.getProductId(), order.getQuantity());
  }
}

MyBatis的Transaction.java接口定义了事务操作的标准,而JdbcTransaction.java实现了基于JDBC的事务管理。在分布式场景下,这些本地事务会被JTA事务管理器协调,实现两阶段提交协议。

性能优化与最佳实践

无论采用哪种多数据源方案,都需要注意以下性能优化点:

  1. 合理配置连接池参数

对于PooledDataSourceFactory.java,关键参数包括:

  • poolMaximumActiveConnections:最大活动连接数
  • poolMaximumIdleConnections:最大空闲连接数
  • poolMaximumCheckoutTime:连接检出超时时间
  1. 使用读写分离策略

将查询操作路由到从库,写操作路由到主库:

@DataSource("master")
void insertUser(User user);

@DataSource("slave")
User selectUserById(Long id);
  1. 缓存策略设计

多数据源环境下,二级缓存需要按数据源隔离:

<cache type="org.apache.ibatis.cache.impl.PerpetualCache" />
<cache-ref namespace="com.example.db1.UserMapper"/>
  1. 监控与日志

通过MyBatis的日志插件记录数据源切换过程:

<setting name="logImpl" value="STDOUT_LOGGING"/>

MyBatis的LoggingPlugin.java提供了详细的SQL执行日志,可以帮助追踪数据源使用情况。

总结与选型建议

三种多数据源方案各有适用场景:

方案类型实现复杂度适用场景优势劣势
静态多数据源★☆☆☆☆数据源数量固定简单直观,易于调试配置冗余,不支持动态切换
动态数据源路由★★★☆☆需要按条件动态切换灵活度高,使用方便实现复杂,需处理线程安全
分布式事务★★★★★强一致性要求的跨库操作保证数据一致性性能开销大,配置复杂

在实际项目中,可以根据业务复杂度和一致性要求选择合适的方案。大多数业务场景下,动态数据源路由能够满足需求,而对于金融交易等核心业务,则需要引入分布式事务机制。

MyBatis通过SqlSessionManager.java提供了线程安全的SqlSession管理,结合本文介绍的多数据源方案,可以构建强大而灵活的数据访问层。随着微服务架构的普及,多数据源整合能力将成为后端开发工程师的必备技能。

最后,建议通过官方文档configuration.md深入了解MyBatis的配置选项,以及通过SqlSessionFactoryBuilder.java的源码学习MyBatis的初始化流程,这将帮助你更好地理解数据源配置的底层实现。

【免费下载链接】mybatis-3 MyBatis SQL mapper framework for Java 【免费下载链接】mybatis-3 项目地址: https://gitcode.com/gh_mirrors/my/mybatis-3

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值