ssm 在不同的数据库中进行切换(开启事物禁用)

注意: ------引用

1. AOP可以触发数据源字符串的切换
2. 数据源真正切换的关键是 AbstractRoutingDataSource 的 determineCurrentLookupKey() **被调用,此方法是在open connection**时触发
3. 事务是在connection层面管理的,启用事务后,一个事务内部的connection是复用的,所以就算AOP切了数据源字符串,但是数据源并不会被真正修改

综上所述:
如果要使用事务,还是别用determineCurrentLookupKey()这种方法切数据源了,得配置多个才行

在ssm 运用的过程中,有时我们需要在不同数据库中进行切换

进行数据的增删改查,此时我们需要运用spring 的aop 原理进行配置

总体来说过程分三步,1 必要类的建立(放在最后,复制即可) 2 db.properties修改 3  spring-dao.xml 的配置

2 db.properties修改

#数据库1
db.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
db.url=jdbc:sqlserver://127.0.0.1:1433;databaseName=sj1
db.user=js
db.password=js

#数据库2
db.driver2=com.microsoft.sqlserver.jdbc.SQLServerDriver
db.url2=jdbc:sqlserver://127.0.0.1:1433;databaseName=sj2
db.user2=js
db.password2=js

3  spring-dao.xml 的配置

 <context:property-placeholder location="classpath:db.properties"/>
    <!--连接数据库1-->
    <bean id="datasource1" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${db.driver}"/>
        <property name="jdbcUrl" value="${db.url}"/>
        <property name="user" value="${db.user}"/>
        <property name="password" value="${db.password}"/>
        <!-- 初始化连接池中的连接数,取值应在minPoolSize与maxPoolSize之间,默认为3-->
        <property name="initialPoolSize" value="3"/>
        <!--最大空闲时间,30秒内未使用则连接被丢弃。若为0则永不丢弃。默认值: 0-->
        <property name="maxIdleTime" value="30"/>
        <!--连接池中保留的最大连接数。默认值: 15 -->
        <property name="maxPoolSize" value="100"/>
        <!-- 连接池中保留的最小连接数,默认为:3-->
        <property name="minPoolSize" value="10"/>
    </bean>
 <!--  &lt;!&ndash;连接数据库2-->
    <bean id="datasource2" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${db.driver}"/>
        <property name="jdbcUrl" value="${db.url2}"/>
        <property name="user" value="${db.user2}"/>
        <property name="password" value="${db.password2}"/>
      <!--  &lt;!&ndash; 初始化连接池中的连接数,取值应在minPoolSize与maxPoolSize之间,默认为3&ndash;&gt;-->
        <property name="initialPoolSize" value="3"/>
       <!-- &lt;!&ndash;最大空闲时间,30秒内未使用则连接被丢弃。若为0则永不丢弃。默认值: 0&ndash;&gt;-->
        <property name="maxIdleTime" value="30"/>
       <!-- &lt;!&ndash;连接池中保留的最大连接数。默认值: 15 &ndash;&gt;-->
        <property name="maxPoolSize" value="100"/>
       <!-- &lt;!&ndash; 连接池中保留的最小连接数,默认为:3&ndash;&gt;-->
        <property name="minPoolSize" value="10"/>
    </bean>

   <!-- <&#45;&#45;;自定义数据源&ndash;&gt;-->
    <bean id="datasource" class="com.js.util.DynamicDataSource">//自己创建的类
        <!-- 默认使用sqlite数据库 1;-->
        <property name="defaultTargetDataSource" ref="datasource1"></property>
        <property name="targetDataSources">
            <map>
                <entry key="dataSource1" value-ref="datasource1"></entry>
                <entry key="dateSource2" value-ref="datasource2"></entry>
            </map>
        </property>
    </bean>

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="datasource"/>
        <property name="configLocation" value="classpath:mybatis/mybatis_config.xml"/>
        <property name="mapperLocations" value="classpath:com/js/*/dao/*.xml"/>
       
    </bean>

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.js.*.dao"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    </bean>


    <!-- 切面 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    <bean id="dataSourceAspect" class="com.js.util.DataSourceAspect">//自己创建的类
    </bean>
    <aop:config>
        <aop:aspect ref="dataSourceAspect">
            <!-- 拦截所有service方法,在dao层添加注解 -->
            <aop:pointcut expression="execution(* com.js..dao..*.*(..))" id="dataSourcePointcut"/>
            <aop:before method="intercept" pointcut-ref="dataSourcePointcut"/>
        </aop:aspect>
    </aop:config>

运用:

在dao 类上加(如果出问题了,你可以加在方法上试试)

@DataSource("dataSource1") 或者  @DataSource("dataSource2")
@Repository
@DataSource("dataSource1")
public interface JsDao{

}

1 必要类的建立(四个类哦)

/**
 * @deprecated   数据库连接切换类
 *
 */

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

public class DataSourceAspect {
    //    拦截目标方法,获取由@DataSource指定的数据源标识,设置到线程存储中以便切换数据源
    public void intercept(JoinPoint point) throws Exception {
        Class<?> target = point.getTarget().getClass();
        MethodSignature signature = (MethodSignature) point.getSignature();
        // 默认使用目标类型的注解,如果没有则使用其实现接口的注解

        for (Class<?> clazz : target.getInterfaces()) {
            resolveDataSource(clazz, signature.getMethod());
        }
        resolveDataSource(target, signature.getMethod());
    }

    /**
     * 提取目标对象方法注解和类型注解中的数据源标识
     */

    public void resolveDataSource(Class<?> clazz, Method method) {
        try {
            Class<?>[] types = method.getParameterTypes();
//            默认使用类型注解
            if (clazz.isAnnotationPresent(DataSource.class)) {
                DataSource source = clazz.getAnnotation(DataSource.class);
                DbContextHolder.setDataSource(source.value());
            }
//            方法注解可以覆盖类型注解
            Method m = clazz.getMethod(method.getName(), types);
            if (m != null && m.isAnnotationPresent(DataSource.class)) {
                DataSource source = m.getAnnotation(DataSource.class);
                DbContextHolder.setDataSource(source.value());
            }
        } catch (Exception e) {
            System.out.println(clazz + ":" + e.getMessage());
        }
    }
}

/**
 *
 * 切换数据源的工具类
 */
public class DbContextHolder {
    private static final ThreadLocal<String>THREAD_DATA_SOURCE =new ThreadLocal<>();
    /**
     * 设置当前数据库
     */
    public static void setDataSource(String dataSource) {
        THREAD_DATA_SOURCE.set(dataSource);
    }
    /**
     * 取得当前数据库
     */
    public static String getDataSource() {
        return THREAD_DATA_SOURCE.get();
    }

    /**
     * 清除上下文数据
     */
    public static void clearDataSource() {
        THREAD_DATA_SOURCE.remove();
    }
}

public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {

        return  DbContextHolder.getDataSource();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值