J2EE 项目读写分离
先回答下
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 项目读写分离的更多相关文章
- SpringBoot Mybatis 读写分离配置(山东数漫江湖)
为什么需要读写分离 当项目越来越大和并发越来大的情况下,单个数据库服务器的压力肯定也是越来越大,最终演变成数据库成为性能的瓶颈,而且当数据越来越多时,查询也更加耗费时间,当然数据库数据过大时,可以采用 ...
- mybatis plugins实现项目【全局】读写分离
在之前的文章中讲述过数据库主从同步和通过注解来为部分方法切换数据源实现读写分离 注解实现读写分离: http://www.cnblogs.com/xiaochangwei/p/4961807.html ...
- web 项目 连接mycat 读写分离失效问题,
问题描述:mycat 读写分离已配好,在sql工具上查询操作是可以的,但是在项目中,读数据就走write 数据库, 解决 :环境spring +mvc +ibaites,在java中自己写j ...
- spring项目配置双数据源读写分离
我们最早做新项目的时候一直想做数据库的读写分离与主从同步,由于一些原因一直没有去做这个事情,这次我们需要配置双数据源的起因是因为我们做了一个新项目用了另一个数据库,需要把这个数据库的数据显示到原来的后 ...
- 在项目中部署redis的读写分离架构(包含节点间认证口令)
#### 在项目中部署redis的读写分离架构(包含节点间认证口令) ##### 1.配置过程 --- 1.此前就是已经将redis在系统中已经安装好了,redis utils目录下,有个redis ...
- Spring + Mybatis项目实现数据库读写分离
主要思路:通过实现AbstractRoutingDataSource类来动态管理数据源,利用面向切面思维,每一次进入service方法前,选择数据源. 1.首先pom.xml中添加aspect依赖 & ...
- Maven构建真正的J2EE项目
今天同事问起我眼下用Maven构建的多模块项目架构和曾经用Eclipse创建的Web项目的问题.以下将讲一下使用maven搭建多模块的J2ee项目,以及採用这样的方式搭建项目对日后项目的水平拆分和垂直 ...
- java 读写分离
源码地址:http://git.oschina.net/xiaochangwei 先回答下 1.为啥要读写分离? 大家都知道最初开始,一个项目对应一个数据库,基本是一对一的,但是由于后来用户及数据还有 ...
- Spring aop应用之实现数据库读写分离
Spring加Mybatis实现MySQL数据库主从读写分离 ,实现的原理是配置了多套数据源,相应的sqlsessionfactory,transactionmanager和事务代理各配置了一套,如果 ...
随机推荐
- App开发:模拟服务器数据接口 - MockApi
为了方便app开发过程中,不受服务器接口的限制,便于客户端功能的快速测试,可以在客户端实现一个模拟服务器数据接口的MockApi模块.本篇文章就尝试为使用gradle的android项目设计实现Moc ...
- C# DateTime与时间戳转换
C# DateTime与时间戳的相互转换,包括JavaScript时间戳和Unix的时间戳. 1. 什么是时间戳 首先要清楚JavaScript与Unix的时间戳的区别: JavaScript时间戳: ...
- 说说Makefile那些事儿
说说Makefile那些事儿 |扬说|透过现象看本质 工作至今,一直对Makefile半知半解.突然某天幡然醒悟,觉得此举极为不妥,只得洗心革面从头学来,以前许多不明觉厉之处顿时茅塞顿开,想想好记性不 ...
- nodejs进阶(6)—连接MySQL数据库
1. 建库连库 连接MySQL数据库需要安装支持 npm install mysql 我们需要提前安装按mysql sever端 建一个数据库mydb1 mysql> CREATE DATABA ...
- Android指纹解锁
Android6.0及以上系统支持指纹识别解锁功能:项目中用到,特此抽离出来,备忘. 功能是这样的:在用户将app切换到后台运行(超过一定的时长,比方说30秒),再进入程序中的时候就会弹出指纹识别的界 ...
- SQLSERVER走起微信公众帐号全新改版 全新首页
SQLSERVER走起微信公众帐号全新改版 全新首页 今天,SQLSERVER走起微信公众帐号增加了首页功能 虽然还是订阅号,不过已经对版面做了比较大的修改,希望各位亲用得放心.用得安心O(∩_∩)O ...
- C++ std::set
std::set template < class T, // set::key_type/value_type class Compare = less<T>, // set::k ...
- 【翻译】MongoDB指南/CRUD操作(三)
[原文地址]https://docs.mongodb.com/manual/ CRUD操作(三) 主要内容: 原子性和事务(Atomicity and Transactions),读隔离.一致性和新近 ...
- 认识 Azure
本文为官网摘录总结
- css3线条围绕跑马+jquery打字机效果
原文地址:css3线条围绕跑马+jquery打字机效果 有图有真相,今天偶然看到了一种效果,仔细看了下,发现它是用css的clip+css3的动画实现的,简直叼.于是自己拿来了前一阵子写的打字机效果, ...