先回答下

1.为啥要读写分离?  

大家都知道最初开始,一个项目对应一个数据库,基本是一对一的,但是由于后来用户及数据还有访问的急剧增多,

系统在数据的读写上出现了瓶颈,为了让提高效率,想读和写不相互影响,读写分离就诞生了......

2.什么样的项目需要读写分离?

并不是所有项目都适合读写分离,如果我把我自己的博客网站也搞成读写分离的,菜鸟觉得哇好高大上;砖家就会说 SB

读写分离仅适合用在读写尤其频繁的项目,如淘宝这类访问量多,读写都很频繁的情况下,

一般来说想中小型企业的erp,网站啥的都不需要,用了反而影响性能,因为读写时的切换也是要耗费资源的

3.读写分离的前提条件是什么?

如2所说,如果确定了项目需要用到读写分离,那就得配置数据库同步了,数据不同步读写有啥意思,

同步方式很多种,最简单的主从同步可以参考我的博客另一篇文章  http://www.cnblogs.com/xiaochangwei/p/4824355.html

当然还有很多同步方式,抛砖引玉  请自由发挥

大家别急,不要说我写了半天还不如正题, 我文学功底差,语文老师死得早,想到啥说啥,毕竟语文考试很少及格,你们要理解下

下面我讲的j2ee主从同步,用到的是技术框架: 基于注解的SpringMVC + Mybatis + Mysql,

Spring mvc就很熟悉了,自己搭个框架一边玩吧,讲讲整合mybatis时候怎么读写分离的,

直接贴代码:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd"> <context:component-scan base-package="com.xiao" />
<aop:aspectj-autoproxy/> <!-- 引入属性文件 -->
<context:property-placeholder location="classpath:application.properties" /> <!-- 数据源配置,使用应用内的proxool数据库连接池 -->
<bean id="business_write" class="org.logicalcobwebs.proxool.ProxoolDataSource">
<!-- Connection Info destroy-method="close" -->
<property name="driver" value="${jdbc.driver}" />
<property name="driverUrl" value="${business.write.url}" />
<property name="user" value="${business.write.username}" />
<property name="password" value="${business.write.password}" />
<property name="alias" value="master_db" /> <!-- 测试的SQL执行语句 -->
<property name="houseKeepingTestSql" value="select count(*) from dual" />
<!-- 最少保持的空闲连接数 (默认2个) -->
<property name="prototypeCount" value="${jdbc.prototypeCount}" />
<!-- proxool自动侦察各个连接状态的时间间隔(毫秒),侦察到空闲的连接就马上回收,超时的销毁 默认30秒) -->
<property name="houseKeepingSleepTime" value="${jdbc.hourseKeepingSleepTime}" />
<!-- 最大活动时间(毫秒)(超过此时间线程将被kill,默认为5分钟) -->
<property name="maximumActiveTime" value="${jdbc.maximumActiveTime}" />
<!-- 连接最长时间(毫秒)(默认为4个小时) -->
<property name="maximumConnectionLifetime" value="${jdbc.maximumConnectionLifetime}" />
<!-- 最小连接数 (默认2个) -->
<property name="minimumConnectionCount" value="${jdbc.minimumConnectionCount}" />
<!-- 最大连接数 (默认5个) -->
<property name="maximumConnectionCount" value="${jdbc.maximumConnectionCount}" />
</bean> <bean id="business_read" class="org.logicalcobwebs.proxool.ProxoolDataSource">
<!-- Connection Info destroy-method="close" -->
<property name="driver" value="${jdbc.driver}" />
<property name="driverUrl" value="${business.read.url}" />
<property name="user" value="${business.read.username}" />
<property name="password" value="${business.read.password}" />
<property name="alias" value="slave_db" />
<!-- 测试的SQL执行语句 -->
<property name="houseKeepingTestSql" value="select count(*) from dual" />
<!-- 最少保持的空闲连接数 (默认2个) -->
<property name="prototypeCount" value="${jdbc.prototypeCount}" />
<!-- proxool自动侦察各个连接状态的时间间隔(毫秒),侦察到空闲的连接就马上回收,超时的销毁 默认30秒) -->
<property name="houseKeepingSleepTime" value="${jdbc.hourseKeepingSleepTime}" />
<!-- 最大活动时间(毫秒)(超过此时间线程将被kill,默认为5分钟) -->
<property name="maximumActiveTime" value="${jdbc.maximumActiveTime}" />
<!-- 连接最长时间(毫秒)(默认为4个小时) -->
<property name="maximumConnectionLifetime" value="${jdbc.maximumConnectionLifetime}" />
<!-- 最小连接数 (默认2个) -->
<property name="minimumConnectionCount" value="${jdbc.minimumConnectionCount}" />
<!-- 最大连接数 (默认5个) -->
<property name="maximumConnectionCount" value="${jdbc.maximumConnectionCount}" />
</bean> <bean id="dataSource" class="com.xiao.weixin.common.jdbc.DynamicDataSource">
<property name="targetDataSources">
<map>
<entry key="business_write" value-ref="business_write" />
<entry key="business_read" value-ref="business_read" />
</map>
</property>
<property name="defaultTargetDataSource" ref="business_write" />
</bean> <!-- 线程池配置 -->
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<!-- 线程池活跃的线程数 -->
<property name="corePoolSize" value="5" />
<!-- 线程池最大活跃的线程数 -->
<property name="maxPoolSize" value="10" />
<!-- 队列的最大容量 -->
<property name="queueCapacity" value="25" />
</bean> <!-- myBatis文件 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 自动扫描entity目录, 省掉Configuration.xml里的手工配置 -->
<property name="mapperLocations" value="classpath:com/xiao/**/*Mapper.xml" /> <!-- <property name="configLocation" value="classpath:mybatisMapConfig.xml" />-->
</bean> <!-- myBatis Mapper文件 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.xiao.**.dao" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
</bean> <!-- 事务管理器配置 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean> <!-- 使用annotation定义事务 -->
<tx:annotation-driven transaction-manager="transactionManager" order="2"/> <!-- Spring jdbcTemplate配置 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean> <bean id="xiaoFilter" class="com.xiao.weixin.common.filter.XiaoFilter" /> <import resource="spring-mybatis_quartz.xml"/>
<!-- 引入shiro 缓存配置 -->
<import resource="applicationContext-shiro.xml"/>
<!-- 引入国际化 配置-->
<import resource="spring-i18n.xml"/>
</beans>

首先你得有配置好了的 读数据库和写数据库  不会的戳这里哈 http://www.cnblogs.com/xiaochangwei/p/4824355.html

配置好了读和写的数据源了后,仔细看

<bean id="dataSource" class="com.xiao.weixin.common.jdbc.DynamicDataSource">
<property name="targetDataSources">
<map>
<entry key="business_write" value-ref="business_write" />
<entry key="business_read" value-ref="business_read" />
</map>
</property>
<property name="defaultTargetDataSource" ref="business_write" />
</bean>

这里指定了两个数据源,并且默认是用的写数据库,
数据源之所以能切换是因为Spring提供了 org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource接口

默认不是写么

package com.xiao.weixin.common.jdbc;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; /**
* 设置数据源
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface DataSource {
String value() default "business_read";
}

如果我们在serviceimpl中,某个方法上加上 @DataSource 如下:

@Override
@DataSource
public String getAccessToken() {
String access_token = null;
try {
AccessToken token = weixinApiMapper.findToken();// 数据库查找没过期的token并返回
if (token != null) {
access_token = token.getAccessToken();
}
} catch (Exception e) {
log.error("获取accessToken出错");
e.printStackTrace();
}
log.debug("获取到的accessToken是:" + access_token);
return access_token;
}

就会连接到读数据库,不写则用默认的读数据库

不过 只是上面的代码是不行的 ,具体切换还得看Spring提供的接口

配置中关联的实现类代码如下

package com.xiao.weixin.common.jdbc;

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

public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
protected Object determineCurrentLookupKey() {
return JdbcContextHolder.getJdbcType();
}
}

JdbcContextHolder 又是下面这样实现滴

package com.xiao.weixin.common.jdbc;

/**
* 连接哪个数据源的环境变量
*/
public class JdbcContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(); public static void setJdbcType(String jdbcType) {
contextHolder.set(jdbcType);
} /**
* 在选用business_write数据源前,执行此方法
*/
public static void setBusinessWrite(){
setJdbcType("business_write");
}
/**
* 在选用business_read数据源前,执行此方法
*/
public static void setBusinessRead(){
setJdbcType("business_read");
}
public static String getJdbcType(){
return (String) contextHolder.get();
}
/**
* 恢复成默认的数据源,即defaultTargetDataSource,执行此方法
*/
public static void clearJdbcType() {
contextHolder.remove();
}
}

就这样就能轻松搞定读写分离了,搞不定的朋友请和我交流

不要问我为啥知道这些,都是面试的时候不懂回来自己研究的,

正如我股灾期间我告诉大家一定要坚持到16号,16号有大量资金入场,大家回复我这么牛逼,知道啥子内幕么,我呵呵一笑  因为我们公司15号发工资  o(^▽^)o

每天进步一点点  仅此而已

J2EE 项目读写分离的更多相关文章

  1. SpringBoot Mybatis 读写分离配置(山东数漫江湖)

    为什么需要读写分离 当项目越来越大和并发越来大的情况下,单个数据库服务器的压力肯定也是越来越大,最终演变成数据库成为性能的瓶颈,而且当数据越来越多时,查询也更加耗费时间,当然数据库数据过大时,可以采用 ...

  2. mybatis plugins实现项目【全局】读写分离

    在之前的文章中讲述过数据库主从同步和通过注解来为部分方法切换数据源实现读写分离 注解实现读写分离: http://www.cnblogs.com/xiaochangwei/p/4961807.html ...

  3. web 项目 连接mycat 读写分离失效问题,

    问题描述:mycat 读写分离已配好,在sql工具上查询操作是可以的,但是在项目中,读数据就走write 数据库, 解决      :环境spring +mvc +ibaites,在java中自己写j ...

  4. spring项目配置双数据源读写分离

    我们最早做新项目的时候一直想做数据库的读写分离与主从同步,由于一些原因一直没有去做这个事情,这次我们需要配置双数据源的起因是因为我们做了一个新项目用了另一个数据库,需要把这个数据库的数据显示到原来的后 ...

  5. 在项目中部署redis的读写分离架构(包含节点间认证口令)

    #### 在项目中部署redis的读写分离架构(包含节点间认证口令) ##### 1.配置过程 ---  1.此前就是已经将redis在系统中已经安装好了,redis utils目录下,有个redis ...

  6. Spring + Mybatis项目实现数据库读写分离

    主要思路:通过实现AbstractRoutingDataSource类来动态管理数据源,利用面向切面思维,每一次进入service方法前,选择数据源. 1.首先pom.xml中添加aspect依赖 & ...

  7. Maven构建真正的J2EE项目

    今天同事问起我眼下用Maven构建的多模块项目架构和曾经用Eclipse创建的Web项目的问题.以下将讲一下使用maven搭建多模块的J2ee项目,以及採用这样的方式搭建项目对日后项目的水平拆分和垂直 ...

  8. java 读写分离

    源码地址:http://git.oschina.net/xiaochangwei 先回答下 1.为啥要读写分离? 大家都知道最初开始,一个项目对应一个数据库,基本是一对一的,但是由于后来用户及数据还有 ...

  9. Spring aop应用之实现数据库读写分离

    Spring加Mybatis实现MySQL数据库主从读写分离 ,实现的原理是配置了多套数据源,相应的sqlsessionfactory,transactionmanager和事务代理各配置了一套,如果 ...

随机推荐

  1. KV存储系统

    现在的KV存储系统都是分布式的,首先介绍Zookeeper——针对大型分布式系统的高可靠的协调系统. 开发分布式系统是件很困难的事情,其中的困难主要体现在分布式系统的“部分失败”.“部分失败”是指信息 ...

  2. 算法与数据结构(十三) 冒泡排序、插入排序、希尔排序、选择排序(Swift3.0版)

    本篇博客中的代码实现依然采用Swift3.0来实现.在前几篇博客连续的介绍了关于查找的相关内容, 大约包括线性数据结构的顺序查找.折半查找.插值查找.Fibonacci查找,还包括数结构的二叉排序树以 ...

  3. 简约之美Jodd-http--深入源码理解http协议

    Jodd 是一个开源的 Java 工具集, 包含一些实用的工具类和小型框架.简单,却很强大! jodd-http是一个轻巧的HTTP客户端.现在我们以一个简单的示例从源码层看看是如何实现的? Http ...

  4. JS继承之借用构造函数继承和组合继承

    根据少一点套路,多一点真诚这个原则,继续学习. 借用构造函数继承 在解决原型中包含引用类型值所带来问题的过程中,开发人员开始使用一种叫做借用构造函数(constructor stealing)的技术( ...

  5. 云瓣影音网站&&微信端(已开源)

    随着该项目的发布到线上(小打小闹),即将又要开启另一段崭新的旅程.强迫自己停下来写写所学所得,个人认为总结和分享是一种很棒的学习方式.那让我们先来瞧瞧项目长的什么样.如果着急要源码的朋友,可以下拉到最 ...

  6. 使用蓝灯后,IE浏览器以及内置IE浏览器的程序不能使用的解决方案

    使用完蓝灯后,每次使用IE浏览器都不能正常使用,于是有了下面的这个方案 1.通过Win+R 打开注册表编辑器(regedit) 进入目录 HKEY_CURRENT_USER \ Software \ ...

  7. [笔记]kubernetes 无法启动问题

    在启动kubernetes的时候报错误. ERROR: timed out for http://localhost:4001/v2/keys/ 原因是无法启动etcd, etcd 监听4001本地端 ...

  8. HIVE教程

    完整PDF下载:<HIVE简明教程> 前言 Hive是对于数据仓库进行管理和分析的工具.但是不要被“数据仓库”这个词所吓倒,数据仓库是很复杂的东西,但是如果你会SQL,就会发现Hive是那 ...

  9. Impress.js上手 - 抛开PPT、制作Web 3D幻灯片放映

    前言: 如果你已经厌倦了使用PPT设置路径.设置时间.设置动画方式来制作动画特效.那么Impress.js将是你一个非常好的选择. 用它制作的PPT将更加直观.效果也是嗷嗷美观的. 当然,如果用它来装 ...

  10. MSSQL 事务,视图,索引,存储过程,触发器

    事务 事务是一种机制.是一种操作序列,它包含了一组数据库操作命令,这组命令要么全部执行,要么全部不执行. 在数据库系统上执行并发操作时事务是作为最小的控制单元来使用的.这特别适用于多用户同时操作的数据 ...