有时候我们会配置多个数据源来减轻数据库的压力,以便服务能正常运行。在此就不介绍数据库读写分离的具体实现
只是在代码方面实现数据库的动态切换,如有感兴趣的小伙伴可以看看数据库中间件mycat来实现数据库的读写分离

首先我们需要新建这几个类,用来实现数据库的动态切换,我们需要创建四个类,如下:

分别用来处理不同的业务需求。

DataSource.java

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Ret

<!--more-->

有时候我们会配置多个数据源来减轻数据库的压力,以便服务能正常运行。在此就不介绍数据库读写分离的具体实现
只是在代码方面实现数据库的动态切换,如有感兴趣的小伙伴可以看看数据库中间件mycat来实现数据库的读写分离
上次参考别的文章进行写的,出现了很对问题,大致就是在有事务的方法上就会出现数据源切换错误,我们的从库,只允许读操作,因此,就会导致操作不成功,写操作也会自己切换到读库上,最后发现是用完数据源没有清空引起的。
首先我们需要新建这几个类,用来实现数据库的动态切换,我们需要创建四个类,如下:

分别用来处理不同的业务需求。

`DataSource.java`

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**

  • RUNTIME
  • 编译器将把注释记录在类文件中,在运行时 VM 将保留注释,因此可以反射性地读取。
  • */

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


`DataSourceAspect.java`

import java.lang.reflect.Method;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;

import com.gainet.controller.admin.IndexController;

public class DataSourceAspect

{

/**
 * 在dao层方法获取datasource对象之前,在切面中指定当前线程数据源
 */
private static final Logger logger = Logger
        .getLogger(DataSourceAspect.class);
public void before(JoinPoint point)
{

    Object target = point.getTarget();
    String method = point.getSignature().getName();
    Class[] classz = target.getClass().getInterfaces();                        // 获取目标类的接口, 所以@DataSource需要写在接口上
    Class[] parameterTypes = ((MethodSignature) point.getSignature())
            .getMethod().getParameterTypes();
    try
    {
        Method m = classz[0].getMethod(method, parameterTypes);
        if (m != null && m.isAnnotationPresent(DataSource.class))
        {
            DataSource data = m.getAnnotation(DataSource.class);
            logger.info("数据库库类型:" + data.value());
            HandleDataSource.putDataSource(data.value());    // 数据源放到当前线程中
            if(null==data.value() || "".equals(data.value())){
                HandleDataSource.putDataSource("master");                        // 数据源放到当前线程中
            }
        }else{
            HandleDataSource.putDataSource("master");                        // 数据源放到当前线程中
            logger.info("数据库库类型:master" );
        }

    } catch (Exception e)
    {
        e.printStackTrace();
    }
}
//执行完切面后,将线程共享中的数据源名称清空
public void after(JoinPoint joinPoint){
    logger.info("执行完切面,将线程共享中的数据源名称清空");
    HandleDataSource.removeDataSource();
}
}
`DynamicDataSource.java`

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

public class DynamicDataSource extends AbstractRoutingDataSource
{

/**
 * 获取与数据源相关的key 此key是Map resolvedDataSources 中与数据源绑定的key值
 * 在通过determineTargetDataSource获取目标数据源时使用
 */
@Override
protected Object determineCurrentLookupKey()
{
    return HandleDataSource.getDataSource();
}

}

`HandleDataSource.java`

public class HandleDataSource
{

public static final ThreadLocal holder = new ThreadLocal();

/**
 * 绑定当前线程数据源
 * 
 * @param key
 */
public static void putDataSource(String datasource)
{
    holder.set(datasource);
}

/**
 * 获取当前线程的数据源
 * 
 * @return
 */
public static String getDataSource()
{
    return holder.get();
}
/**
 * 移除数据源
 */
public static void removeDataSource() {
    holder.remove();
}

}

`db.properties`

main database 主库

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc\:mysql\://192.168.103.23\:3306/hotel-proof?useUnicode\=true&characterEncoding\=utf-8&useSSL\=false jdbc.username=root
jdbc.password=123456
jdbc.initialSize=1
jdbc.minIdle=1
jdbc.maxActive=20
jdbc.maxWait=60000
jdbc.removeAbandoned=true
jdbc.removeAbandonedTimeout=180
jdbc.timeBetweenEvictionRunsMillis=60000
jdbc.minEvictableIdleTimeMillis=300000
jdbc.validationQuery=SELECT 1
jdbc.testWhileIdle=true
jdbc.testOnBorrow=false
jdbc.testOnReturn=false

slave database 从库

slave.jdbc.driverClassName=com.mysql.jdbc.Driver
slave.jdbc.url=jdbc\:mysql\://ip\:端口/数据库?useUnicode\=true&characterEncoding\=utf-8&useSSL\=false
slave.jdbc.username=root
slave.jdbc.password=123456
slave.jdbc.initialSize=1
slave.jdbc.minIdle=1
slave.jdbc.maxActive=20
slave.jdbc.maxWait=60000
slave.jdbc.removeAbandoned=true
slave.jdbc.removeAbandonedTimeout=180
slave.jdbc.timeBetweenEvictionRunsMillis=60000
slave.jdbc.minEvictableIdleTimeMillis=300000
slave.jdbc.validationQuery=SELECT 1
slave.jdbc.testWhileIdle=true
slave.jdbc.testOnBorrow=false
slave.jdbc.testOnReturn=false

`applicationContext-dao.xml`
 
 

    
        
            classpath:mybatis/db.properties
            classpath:alipayinfo.properties
            classpath:wxpayinfo.properties
        
    



      
      
      
      
      
      
       
      
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    




      
      
      
      
      
       
      
    
    
    
    
    
    
    
    
    



  
          
        
        
             
              
               
               
               
                     
       
          
  




     
    
    
    



    
    




    




   
    
    
        
            
        
        
        

怎样使用呢?
我们只需要把注解 @DataSource("slave") 打在接口上即可,一定要在接口上,不然不起作用。

标签: SSM

添加新评论