spring+spring mvc +mybatis+druid 实现数据库主从分离

注:在博客上看到这个主从分离的文章,亲自试了一下可行,所以就转载了

本文是基于:spring+spring mvc +mybatis+druid为基础框架, 实现MySQL数据库主从分离.

mysql 主从配置(超简单)http://369369.blog.51cto.com/319630/790921/

第一步:基于Java annotation(注解)并通过spring aop 实现动态数据源动态选择

package com.wlsq.util;  

import java.lang.annotation.ElementType;  
import java.lang.annotation.Target;  
import java.lang.annotation.Retention;  
import java.lang.annotation.RetentionPolicy;  
/**  
 * RUNTIME  
 * 编译器将把注释记录在类文件中,在运行时 VM 将保留注释,因此可以反射性地读取。  
 * @author yangGuang  
 *  
 */  
@Retention(RetentionPolicy.RUNTIME)  
@Target(ElementType.METHOD)  
public @interface DataSource {  
    String value();  
}  

第二步: 实现spring 提供 AbstractRoutingDataSource 类 实现数据源设置

spring AbstractRoutingDataSource类介绍:http://www.cnblogs.com/surge/p/3582248.html

package com.wlsq.util;  

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

public class ChooseDataSource extends AbstractRoutingDataSource  {  
    /**  
     * 获取与数据源相关的key  
     * 此key是Map resolvedDataSources 中与数据源绑定的key值  
     * 在通过determineTargetDataSource获取目标数据源时使用  
     */  
    @Override  
    protected Object determineCurrentLookupKey() {  
        // TODO Auto-generated method stub  
        return HandleDataSource.getDataSource();  
    }  

}  

第三步:利用ThreadLocal 解决数据源设置 线程安全性问题

package com.wlsq.util;  

/**  
 * 保存当前线程数据源的key  
 * @author   
 * @version 1.0  
 *  
 */  
public class HandleDataSource {  
    public static final ThreadLocal holder = new ThreadLocal();  

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

    /**  
     * 获取当前线程的数据源路由的key  
     * @return  
     */  
    public static String getDataSource() {  
        return holder.get();  
    }      
}  

第四步: 定义一个数据源切面类,通过aop 实现访问,在spring 文件中进行相关的配置工作。

package com.wlsq.util;  


import java.lang.reflect.Method;  
import org.aspectj.lang.JoinPoint;  

import org.aspectj.lang.reflect.MethodSignature;  


/**  
 * 执行dao方法之前的切面  
 * 获取datasource对象之前往HandleDataSource中指定当前线程数据源路由的key  
 * @author Administrator  
 *  
 */  
public class DataSourceAspect {  


    /**  
     * 在dao层方法之前获取datasource对象之前在切面中指定当前线程数据源路由的key  
     */  
     public void before(JoinPoint point)  
        {         


             Object target = point.getTarget();  
             System.out.println(target.toString());  
             String method = point.getSignature().getName();  
             System.out.println(method);  
             Class[] classz = target.getClass().getInterfaces();  
             Class[] parameterTypes = ((MethodSignature) point.getSignature())  
                     .getMethod().getParameterTypes();  
             try {  
                 Method m = classz[0].getMethod(method, parameterTypes);  
                 System.out.println(m.getName());  
                 if (m != null && m.isAnnotationPresent(DataSource.class)) {  
                     DataSource data = m.getAnnotation(DataSource.class);  
                     System.out.println("用户选择数据库库类型:"+data.value());  
                     HandleDataSource.putDataSource(data.value());  
                 }  

             } catch (Exception e) {  
                 e.printStackTrace();  
             }  
        }  
}  

第五步:配置spring-mybatis.xml 配置文件

  
  


       
      

      
          
      

      
      
          
      



         
      
        
        
        

        
        
         
        

        
        

        
        

        
        

        
        
        
        

        
        
        

        
         
      

        
      
        
        
        

        
        
         
        

        
        

        
        

        
        

        
        
        
        

        
        
        

        
         
      

      
              
                
                  
                   
                 
                   
                         
           
              

      




      
      
          
          
          
      

      
      
          
          
      

      
      
          
      


        
        
        
            
                
                            
            
      








  

第六步:使用@DataSource 标签,动态选择读写数据库

package com.wlsq.service;  

import java.util.List;  
import java.util.Map;  

import org.apache.ibatis.annotations.Param;  

import com.wlsq.model.News;  
import com.wlsq.model.User;  
import com.wlsq.util.DataSource;  

public interface IUserMapperService {  


    int deleteByPrimaryKey(Integer userid);  

    int insert(User record);  

    int insertSelective(User record);  

    User selectByPrimaryKey(Integer userid);  

    int updateByPrimaryKeySelective(User record);  

    int updateByPrimaryKey(User record);  

    List selectByObject (User record);  

    @DataSource("read")  
    public List selectObject (User record);  

    @DataSource("write")  
    public List selectAllUsers(@Param("maps") Map maps);  

    @DataSource("write")  
    public int selectCountUsers();  
}  

学习总结:

第一个错误:Could not open JDBC Connection for transaction; nested exception is java.lang.IllegalStateException: Cannot determine target DataSource for lookup key [null] 找不到数据源错误

解决办法:事务管理配置一定要配置在,往HandlerDataSource中注入数据源key之前.

第二个错误:spring aop 实现动态数据源选择,但有时存在数据源切换不及时,导致数据查询错误。

解决办法:调整aop 执行排序级别
[html] view plain copy 在CODE上查看代码片派生到我的代码片

原文链接 http://blog.csdn.net/zhouzhiwengang/article/details/51087920

你可能感兴趣的:(学习笔记)