springmvc4.2.1+mybatis3.3.0+maven3.3+mysql读写分离

来源:互联网 发布:信息系统网络架构图 编辑:程序博客网 时间:2024/06/16 03:38


实现数据库读写分离步骤

    1  mysql数据库 设置 主从  日志同步

    2  spring配置文件配置 2个数据源  然后放到一个datasource, 其他的txmanager和sessionfactory直接使用datasource

   3  新建一个类 继承 AbstractRoutingDataSource 重写determineCurrentLookupKey方法

   4  写一个 dbhelper类, 用来 设置 和获取 数据源

   5 在controller层 需要使用数据库的地方 手工设置 数据源 DBContextHolder.setDbType(DBContextHolder.DB_RW 或者 DB_R);

      读写分离最好不要用注解的方案, 应该在CONTROLLER层 手动  切换
       
       因为 比如更新信息, 更新到主库,更新完后 为了防止数据延迟,读到旧数据,所以应该接着读主库, 而不是去读从库。



     1  MAVEN 配置文件

     <properties>


<!-- spring版本号 -->
<spring.version>4.2.1.RELEASE</spring.version>

<!-- mybatis版本号  -->
<mybatis.version>3.3.0</mybatis.version>

<!-- spring mybatis融合包 版本号  -->
<mybatis_spring.version>1.2.3 </mybatis_spring.version>

<!-- log4j日志文件管理包版本 -->
<slf.version>1.7.10</slf.version>


</properties>


<dependencies>

      <!-- mybatis逆向工程 需要使用的包 -->
       <dependency>
 <groupId>org.mybatis.generator</groupId>
 <artifactId>mybatis-generator-core</artifactId>
<version>1.3.2</version> </dependency>
 
 


<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<!--test 表示开发的时候引入,发布的时候不会加载此包 -->
<scope>compile</scope>
</dependency>




<!-- spring核心包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>


<!-- <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> 
<version>${spring.version}</version> </dependency> -->




<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>


<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>


<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>






<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>

<!-- AOP需要的 切面包 -->
 
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.7</version>
</dependency>

<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.7</version>
</dependency>




<!-- spring上传组件 依赖的 上传组件包 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>


<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>


<!-- jackson包, springmvc 用他来为@ ResponseBody 注解的方法 , 返回 json -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.6.1</version>
</dependency>




<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.6.1</version>
</dependency>


<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.6.1</version>
</dependency>


<!-- mybatis和 spring的整合包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>${mybatis_spring.version}</version>
</dependency>






<!-- mybatis核心包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>

 







<!-- 导入Mysql数据库链接jar包 -->


<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.35</version>
</dependency>




<!-- dbcp2 连接池 下面的pool2也一起需要 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.1</version>
</dependency>


<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.3</version>
</dependency>






<!-- 日志文件管理包 -->


<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf.version}</version>
</dependency>


<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf.version}</version>
</dependency>


<!-- log end -->






<!-- web 相关包 tomcat 7 servlet 3.0 jsp 2.2 jdk1.7 javaee最低1.6 -->


<!-- <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> 
<version>3.1.0</version> </dependency> -->


<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>




<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>




<!-- google提供的json解析包 spring4.x需要它 -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.3.1</version>
</dependency>








<!--     图片验证码  使用 kaptcha  -->


<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>




</dependencies>


2  spring配置文件

     <!--主数据源   支持读写  -->
<bean id="dbSourceRW"  class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
         <property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<!--初始化连接大小-->
<property name="initialSize" value="10"></property>
<!--连接池最大数量-->
<property name="maxTotal" value="30"></property>
<!--连接池最大空闲-->
<property name="maxIdle" value="10"></property>
<!--连接池最小空闲-->
<property name="minIdle" value="1"></property>
<!--获取连接最大等待时间-->
<property name="maxWaitMillis" value="60000"></property>
</bean>

  <!--附属数据源  只用来读-->
    <bean id="dbSourceR"  class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
         <property name="driverClassName" value="${jdbc.driver2}" />
<property name="url" value="${jdbc.url2}" />
<property name="username" value="${jdbc.username2}" />
<property name="password" value="${jdbc.password2}" />
<!--初始化连接大小-->
<property name="initialSize" value="10"></property>
<!--连接池最大数量-->
<property name="maxTotal" value="30"></property>
<!--连接池最大空闲-->
<property name="maxIdle" value="10"></property>
<!--连接池最小空闲-->
<property name="minIdle" value="1"></property>
<!--获取连接最大等待时间-->
<property name="maxWaitMillis" value="60000"></property>
    </bean>
    
    <!-- 动态数据源 -->
    <bean id="dynamicDataSource"    class="com.zms.dbhelper.DynamicDataSource">
        <!-- 通过key-value关联数据源 -->
        <property name="targetDataSources">
            <map>
                <entry value-ref="dbSourceRW"    key="readwritedb"></entry>
                <entry value-ref="dbSourceR"    key="readdb"></entry>
            </map>
        </property>
        <property name="defaultTargetDataSource"  ref="dbSourceRW" />    
    </bean>
 
       <!--  会话工厂    完美整合 mybatis, 不需要mybatis配置文件-->
<bean  name="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--  加载mybatis配置文件  已经不需要 mybatis配置文件了-->
        <!-- <property name="configLocation"  value="classpath:mybatis.xml"></property>    -->
             <property name="dataSource"  ref="dynamicDataSource" ></property>
             
             <!-- 自动扫描mapping.xml文件  支持通配符 com/zms/hengjinsuo/*/mapping/*.xml -->
<property name="mapperLocations"    value="classpath:com/zms/hengjinsuo/mapping/*.xml"></property>
 
</bean>



3     自定义 数据库切换类

package com.zms.dbhelper;


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


/**
 * 
 * 功能说明:自己写一个spring 数据库动态路由 实现类
 * 创建人:@author 330140511@qq.com  
 * 创建时间:2015年9月15日/下午2:51:20
 */
public class DynamicDataSource  extends AbstractRoutingDataSource {





@Override
protected Object determineCurrentLookupKey() {
 
return DBContextHolder.getDbType();
}


}


4   DBHELPER类


package com.zms.dbhelper;


import org.apache.log4j.Logger;


import com.zms.hengjinsuo.user.controller.UserController;






/**
 * 
 * 功能说明: 
 * 创建人:@author 330140511@qq.com  
 * 创建时间:2015年9月15日/下午2:52:49
 */
public class DBContextHolder {


 /**
  * 把 数据库类型放到threadLocal中 确保数据源对线程独立
  */
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();


private static Logger log = Logger.getLogger(DBContextHolder.class);



public  static  String  DB_RW="readwritedb";
public  static  String  DB_R="readdb";


    public static String getDbType() {
        
   
    String db = contextHolder.get();
   
        if (db == null) {
            db = DB_RW;// 默认是读写库
        }
        
        log.debug("动态选定的数据库是:"+db);
        return db; 
   
    //return contextHolder.get();
    }


    /**
     * 
     * 功能说明:设置本次操作的 数据源 (由dao)来调用
     * 创建人:@author 330140511@qq.com   
     * 创建时间:2015年9月15日/下午2:59:23 
     * @param str
     */
    public static void setDbType(String str) {
     log.debug("动态设定的数据库为:"+str);
        contextHolder.set(str);
    }


    /**
     * clearDBType
     * 
     * @Title: clearDBType
     * @Description: 清理连接类型
     */
    public static void clearDBType() {
        contextHolder.remove();
    }
}


5  controller层调用


/**

* 功能说明:处理增加用户 创建人:@author 330140511@qq.com 创建时间:2015年9月10日/上午11:07:04

* @param user
* @return
*/
 
@RequestMapping("/adduser")
public String adduser(User user, MultipartFile picFile, Model model)
throws ControllerException {


log.debug("需要增加的用户信息:" + user.getUsername() + "生日:"
+ user.getBirthday());

DBContextHolder.setDbType(DBContextHolder.DB_RW);

// 判断 文件控件是否传了文件 一般情况下 字符串长度肯定大于4
if (picFile != null & (picFile.getOriginalFilename().length() > 4)) {


String pic_path = "D:\\tomcat-7.0.63\\webapps\\pic\\";
// 获取图片后缀名
// 获取原始文件名称
String sourceFilename = picFile.getOriginalFilename();
// 取扩展名
String subFixName = sourceFilename.substring(sourceFilename
.lastIndexOf("."));
// 新图片名称
String newFileName = UUID.randomUUID() + subFixName;


// 创建新图片


File newPicFile = new File(pic_path + newFileName);


// 将接收到的图片 写入 硬盘
try {


picFile.transferTo(newPicFile);


// 为用户 图片 属性赋值
user.setPic(newPicFile.getName());


} catch (IllegalStateException e) {


throw new ControllerException(e, "图片上传失败" + e.getMessage());


} catch (IOException e) {
// TODO Auto-generated catch block
throw new ControllerException(e, "图片上传失败" + e.getMessage());
}


}


// 如果没有上传图片也能 保存
userService.insertUser(user);


// return "userlist";
return "redirect:userlist.html ";


}

 

6 效果  



0 2
原创粉丝点击