数据库-切数据源的一个简单例子

切数据源

当数据库需要使用读写分离的时候,需要根据读或者写方法切不同的数据源进行操作。
使用的框架:Spring+mybatis
数据源管理:DruidDataSource

基础配置文件

spring配置

数据源配置

数据源管理的数据库的连接,主要作用需要获取数据库连接,配置数据库的地址,用户名,密码等

<bean id="abstractDataSource" abstract="true" class="com.alibaba.druid.pool.DruidDataSource">
   <!-- <bean id="abstractDataSource" abstract="true" class="com.datasource.dbPool.MyDataSourcePool">-->
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <!--最大连接池数量-->
        <property name="maxActive" value="15"/>
        <!-- 	最小连接池数量-->
        <property name="minIdle" value="2"/>
        <!--连接池初始化数量 add-->
        <property name="initialSize" value="2"/>
        <!--获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,需手动置为非公平锁-->
        <property name="maxWait" value="60000"/>
        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="60000"/>
        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="180000"/>

        <property name="validationQuery" value="SELECT 'x'"/>
        <!--建议配置为true,不影响性能,并且保证安全性。
        申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,
        执行validationQuery检测连接是否有效。-->
        <property name="testWhileIdle" value="true"/>
        <!--申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。-->
        <property name="testOnBorrow" value="false"/>
        <!-- 	归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能-->
        <property name="testOnReturn" value="false"/>
        <!--是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。-->
        <property name="poolPreparedStatements" value="false"/>
        <!--要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true>-->
        <property name="maxPoolPreparedStatementPerConnectionSize" value="-1"/>

        <!-- 配置监控统计拦截的filters -->
        <property name="proxyFilters">
            <list>
                <bean class="com.alibaba.druid.filter.stat.StatFilter">
                    <property name="slowSqlMillis" value="500"/>
                    <property name="logSlowSql" value="true"/>
                </bean>
            </list>
        </property>

        <!--配置了maxWait druid默认使用公平锁,手动设置使用非公平锁-->
        <property name="useUnfairLock" value="true"/>
        <!--可以看到未关闭连接的具体堆栈信息,方便查看链接泄露-->
        <property name="removeAbandoned" value="true"/>
    </bean>

    <!-- 主库数据源 -->
    <bean id="masterDataSource" parent="abstractDataSource">
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/test?characterEncoding=UTF-8"/>
        <property name="username" value="admin"/>
        <property name="password" value="passw"/>
        <!--数据源名字-->
        <property name="name" value="master"/>
    </bean>


    <!-- 从库数据源 -->
    <bean id="slaveDataSource" parent="abstractDataSource">
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/test?characterEncoding=UTF-8"/>
        <property name="username" value="admin"/>
        <property name="password" value="passw"/>
        <!--数据源名字-->
        <property name="name" value="slave"/>
    </bean>

数据源路由

数据源配置了多个,选择数据源 1 是可以使用模版写死 使用哪个数据源,还有一种就是进行路由,Spring提供了一个路由基础类:org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource

public class MultipleDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        // 这个方法里可以用注解动态解析吗  如果是null 返回默认的数据源
       // return  String.valueOf(DataSourceType.MASTER);
        return  String.valueOf(DataSourceTypeManager.getDataSourceType());
    }
}

DataSourceTypeManager 是管理数据源的一个类,选择数据源的时候,会向DataSourceTypeManager 中设置数据源

mybatis配置

mybatis 需要配置扫描的包,sqlSessionFactory需要设置数据源

      <!-- 该包下的类支持注解,表示会被当作{@code mybatis mapper}处理 配置了之后表示可以自动引入mapper类-->
       <mybatis:scan base-package="com.jd.sep.dao" />

       <!-- mybatis配置 -->
       <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
              <property name="dataSource" ref="dataSource" />
              <property name="configLocation" value="classpath:mybatis-configure.xml" />
       </bean>

dao 层编写

数据源切换

选择使用方法上的注解,根据不同的注解解析选择出不同的数据源

加上数据源的注解


@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface DB {
    String name() default "master";
}

注解解析,设置数据源

这块的逻辑直接写在了拦截器里边,若优化,可以将逻辑提出

@Aspect
@Component
public class DBInterceptor {
    public void setDb(JoinPoint jp){
//        System.out.println("-["+jp.getTarget().getClass().getName() + "]设置数据源:" + DataSourceType.MASTER);
        MethodSignature methodSignature = (MethodSignature) jp.getSignature();
        Method method = methodSignature.getMethod();
        //如果有使用Db的注解
        if(Stream.of(method.getDeclaredAnnotations()).anyMatch(e->e.annotationType().equals(DB.class))){
            //获取注解参数
            DB db = method.getAnnotation(DB.class);
            String dbName = db.name();
//            System.out.println(method.getName()+"---->设置数据源:"+ JSON.toJSONString(DataSourceType.valueOf(dbName)));
            // 设置数据源
            DataSourceTypeManager.setDataSourceType(DataSourceType.valueOf(dbName));
        }
    }
}

DataSourceTypeManager:

public class DataSourceTypeManager {

   private static final ThreadLocal<DataSourceType> dataSourceHolder = new NamedThreadLocal("dataSourceType") {
       @Override
       protected DataSourceType initialValue() {
           return DataSourceType.MASTER;
       }
   };


   public static DataSourceType getDataSourceType() {
       return dataSourceHolder.get();
   }

   public static void setDataSourceType(DataSourceType dataSourceType) {
       dataSourceHolder.set(dataSourceType);
   }

   public static void remove() {
       dataSourceHolder.remove();
   }
}

aop拦截器配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="
              http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

       <!-- To enable @AspectJ support with XML based configuration -->
       <aop:aspectj-autoproxy  />

       <bean id="dataSourceInterceptor" class="com.datasource.interceptor.DBInterceptor" />

       <aop:config>
              <aop:pointcut id="managerLayer" expression="execution(* com.manager.impl.*.*(..))" />
              <aop:aspect id="dataSourceAspect" ref="dataSourceInterceptor">
                     <aop:before method="setDb" pointcut-ref="managerLayer" />
              </aop:aspect>
       </aop:config>
    
</beans>

使用

public interface TTableManager {

    @DB(name = "SLAVE")
    List<TTable> getTList(TTable tTable);
    
    @DB(name = "MASTER")
    int addT(TTable tTable);
}

遗留问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值