ssm如何实现一次操作多数据库连接与数据同步?

在SSM(Spring+SpringMVC+MyBatis)框架中实现一次操作多数据库的需求,通常涉及多个数据源的配置、动态切换以及事务管理,以下从配置、代码实现、事务处理等方面详细说明具体步骤和注意事项。

多数据源配置

首先需要在Spring配置文件中定义多个数据源,每个数据源对应一个数据库,配置两个数据源dataSource1dataSource2,分别指向不同的数据库。

<!-- 数据源1 -->
<bean id="dataSource1" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="com.mysql.jdbc.Driver"/>
    <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/db1"/>
    <property name="user" value="root"/>
    <property name="password" value="123456"/>
</bean>
<!-- 数据源2 -->
<bean id="dataSource2" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="com.mysql.jdbc.Driver"/>
    <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/db2"/>
    <property name="user" value="root"/>
    <property name="password" value="123456"/>
</bean>

配置SqlSessionFactory和Mapper扫描

每个数据源需要独立的SqlSessionFactoryMapperScannerConfigurer,通过指定不同的sqlSessionFactoryBeanNamebasePackage来实现隔离。

<!-- SqlSessionFactory1 -->
<bean id="sqlSessionFactory1" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource1"/>
    <property name="mapperLocations" value="classpath:mapper/db1/*.xml"/>
</bean>
<!-- SqlSessionFactory2 -->
<bean id="sqlSessionFactory2" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource2"/>
    <property name="mapperLocations" value="classpath:mapper/db2/*.xml"/>
</bean>
<!-- Mapper扫描1 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.example.mapper.db1"/>
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory1"/>
</bean>
<!-- Mapper扫描2 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.example.mapper.db2"/>
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory2"/>
</bean>

动态数据源切换

通过继承AbstractRoutingDataSource实现动态数据源切换,在determineCurrentLookupKey()方法中返回当前线程对应的数据源标识。

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSourceType();
    }
}

定义线程安全的DataSourceContextHolder来存储当前数据源类型:

ssm怎么一次多数据库

public class DataSourceContextHolder {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
    public static void setDataSourceType(String type) {
        contextHolder.set(type);
    }
    public static String getDataSourceType() {
        return contextHolder.get();
    }
    public static void clearDataSourceType() {
        contextHolder.remove();
    }
}

在Spring配置中注册动态数据源:

<bean id="dynamicDataSource" class="com.example.config.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>

注解实现数据源切换

自定义注解@DataSource,结合AOP实现动态切换:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSource {
    String value() default "db1";
}

AOP切面实现:

@Aspect
@Component
public class DataSourceAspect {
    @Before("@annotation(dataSource)")
    public void setDataSource(DataSource dataSource) {
        DataSourceContextHolder.setDataSourceType(dataSource.value());
    }
    @After("@annotation(dataSource)")
    public void clearDataSource(DataSource dataSource) {
        DataSourceContextHolder.clearDataSourceType();
    }
}

在Service方法上使用注解:

ssm怎么一次多数据库

@Service
public class UserService {
    @DataSource("db1")
    public void insertUser(User user) {
        // 操作db1
    }
    @DataSource("db2")
    public void insertLog(Log log) {
        // 操作db2
    }
}

多数据源事务管理

多数据源事务需要使用JtaTransactionManager或编程式事务,以下是基于JtaTransactionManager的配置:

  1. 添加JTA依赖(如Atomikos或Bitronix):

    <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-jta-atomikos</artifactId>
    </dependency>
  2. 配置JTA事务管理器:

    <bean id="jtaTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"/>
  3. 在Service方法上添加@Transactional注解,确保多个数据源操作在同一个事务中:

    ssm怎么一次多数据库

    @Transactional
    public void transferData() {
     DataSourceContextHolder.setDataSourceType("db1");
     userMapper.insert(user); // db1操作
     DataSourceContextHolder.setDataSourceType("db2");
     logMapper.insert(log);  // db2操作
    }

注意事项

  1. 线程安全DataSourceContextHolder使用ThreadLocal确保线程隔离。
  2. 事务一致性:跨数据库事务需保证所有数据库支持XA协议,或采用最终一致性方案。
  3. 性能影响:频繁切换数据源可能影响性能,建议按模块划分数据源。
  4. Mapper隔离:不同数据源的Mapper接口和XML文件需严格分开,避免冲突。

相关问答FAQs

Q1: 如何在同一个Service方法中同时操作多个数据库?
A: 可以通过手动切换数据源实现,在Service方法中,先调用DataSourceContextHolder.setDataSourceType("db1")执行第一个数据库操作,再切换为"db2"执行第二个数据库操作,若需事务一致性,需结合JTA事务管理器,确保所有操作在同一个事务中提交或回滚。

Q2: 多数据源配置下,MyBatis的Mapper扫描如何避免冲突?
A: 为每个数据源配置独立的SqlSessionFactoryMapperScannerConfigurer,并通过basePackage指定不同的Mapper接口包路径。db1的Mapper放在com.example.mapper.db1db2的Mapper放在com.example.mapper.db2,确保XML文件和接口包路径一一对应,避免扫描混乱。

【版权声明】:本站所有内容均来自网络,若无意侵犯到您的权利,请及时与我们联系将尽快删除相关内容!

(0)
热舞的头像热舞
上一篇 2025-09-21 13:07
下一篇 2025-09-21 13:22

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们

QQ-14239236

在线咨询: QQ交谈

邮件:asy@cxas.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信