您的位置:首页 > 编程语言 > Java开发

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

2015-09-16 10:27 337 查看
实现数据库读写分离步骤

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 效果

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: