`
天堂飘过
  • 浏览: 19747 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

java读写分离实现

阅读更多
数据库配置为一个主库 多个从库 主库用于写操作 从库只读操作
读写分离实现即为配置两个数据源,一个用于读写 连接主库 假设为ds_wr,一个用于只读 连接从库 假设为ds_r。

对数据库读操作时,操作ds_r数据源。
对数据源写操作时,操作ds_wr数据源。

读写分离可以有两种实现方式

第一种为写两套mappper
mapper写两套 一套用于读写 一套用于只读
    <bean id="sqlSessionFactory_wr" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource_wr"/>
        <!-- 自动扫描mapping.xml文件-->
        <!--
        <property name="mapperLocations" value="classpath:com/ifeng/auto/we_provider/mapping/*.xml" />
         -->
        <property name="mapperLocations" value="classpath:mapping1/*.xml"/>
    </bean>
    <bean id="sqlSessionFactory_r" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource_r"/>
        <!-- 自动扫描mapping.xml文件-->
        <!--
        <property name="mapperLocations" value="classpath:com/ifeng/auto/we_provider/mapping2/*.xml" />
         -->
        <property name="mapperLocations" value="classpath:mapping/*.xml"/>
    </bean>
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.ifeng.auto.we_provider.dao1"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory_wr"/>
    </bean>
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.ifeng.auto.we_provider.dao2"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory_r"/>
    </bean>


dao1包中mapper是读写方法 对应xml文件在mapping1文件夹中
dao2包中mapper是只读方法 对应xml文件在mapping2文件夹中

User user = userMapper2.get(1);
user.setName("Susan")
userMapper1.update(user);




第二种为通过实现AbstractRoutingDataSource类来动态管理数据源,本篇博客主要讲这部分内容

利用面向切面思维,每一次进入service方法前,选择数据源

首先pom.xml中添加依赖
		<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>1.7.4</version>
		</dependency>
				<dependency>
					<groupId>org.aspectj</groupId>
					<artifactId>aspectjweaver</artifactId>
					<version>1.7.4</version>
				</dependency>


实现AbstractRoutingDataSource类 作为数据源
package com.ifeng.auto.we_provider.common.db;

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

/**
 * Created by Terry on 2016/7/23.
 */
public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceHolder.getDataSouce();
    }

}


用ThreadLcoal管理当前数据源
package com.ifeng.auto.we_provider.common.db;

public class DynamicDataSourceHolder {
    public static final ThreadLocal<String> holder = new ThreadLocal<String>();

    public static void putDataSource(String name) {
        holder.set(name);
    }

    public static String getDataSouce() {
        return holder.get();
    }
}



用注解的形式实现AOP管理数据源
package com.ifeng.auto.we_provider.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DataSource {
    String value();
}


切面类
package com.ifeng.auto.we_provider.common.proxy;


import com.ifeng.auto.we_provider.annotation.DataSource;
import com.ifeng.auto.we_provider.common.db.DynamicDataSourceHolder;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;

import java.lang.reflect.Method;

/**
 * Created by Terry on 2016/7/23.
 */
public class DataSourceAspect {
    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();
        Class<?>[] parameterTypes = ((MethodSignature) point.getSignature())
                .getMethod().getParameterTypes();
        try {
            Method m = classz.getMethod(method, parameterTypes);
            System.out.println(m.getName());
            if (m != null && m.isAnnotationPresent(DataSource.class)) {
                DataSource data = m.getAnnotation(DataSource.class);
                DynamicDataSourceHolder.putDataSource(data.value());
            }

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


将注解放在service实现类的方法前,自动设置当前数据源为注解中数据源。

接下来配置aop以及数据源。

mybatis.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
					  http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
					  http://www.springframework.org/schema/context  
					  http://www.springframework.org/schema/context/spring-context-4.1.xsd
					  http://www.springframework.org/schema/aop
	                  http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
    <!-- 引入配置文件 -->
    <context:property-placeholder location="classpath:db.properties" ignore-unresolvable="true"/>

    <!-- 数据源配置 -->
    <bean id="dataSource_wr" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <property name="url" value="${db.url}"/>
        <property name="username" value="${db.username}"/>
        <property name="password" value="${db.password}"/>
        <property name="connectionProperties" value="${db.driver}"></property>

        <!-- 配置初始化大小、最小、最大 -->
        <property name="initialSize" value="1"/>
        <property name="minIdle" value="1"/>
        <property name="maxActive" value="20"/>

        <!-- 配置获取连接等待超时的时间 -->
        <property name="maxWait" value="60000"/>

        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="60000"/>

        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="300000"/>

        <property name="validationQuery" value="SELECT 'x'"/>
        <property name="testWhileIdle" value="true"/>
        <property name="testOnBorrow" value="true"/>
        <property name="testOnReturn" value="false"/>
    </bean>
    <bean id="dataSource_r" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <property name="url" value="${db1.url}"/>
        <property name="username" value="${db1.username}"/>
        <property name="password" value="${db1.password}"/>
        <property name="connectionProperties" value="${db.driver}"></property>

        <!-- 配置初始化大小、最小、最大 -->
        <property name="initialSize" value="1"/>
        <property name="minIdle" value="1"/>
        <property name="maxActive" value="20"/>

        <!-- 配置获取连接等待超时的时间 -->
        <property name="maxWait" value="60000"/>

        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="60000"/>

        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="300000"/>

        <property name="validationQuery" value="SELECT 'x'"/>
        <property name="testWhileIdle" value="true"/>
        <property name="testOnBorrow" value="true"/>
        <property name="testOnReturn" value="false"/>
    </bean>

    <bean id="dataSource" class="com.ifeng.auto.we_provider.common.db.DynamicDataSource">
        <property name="targetDataSources">
            <map key-type="java.lang.String">
                <!-- write -->
                <entry key="write" value-ref="dataSource_wr"/>
                <!-- read -->
                <entry key="read" value-ref="dataSource_r"/>
            </map>

        </property>
        <property name="defaultTargetDataSource" ref="dataSource_wr"/>
    </bean>

    <!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!-- 自动扫描mapping.xml文件-->
        <!--
        <property name="mapperLocations" value="classpath:com/ifeng/auto/we_provider/mapping/*.xml" />
         -->
        <property name="mapperLocations" value="classpath:mapping/*.xml"/>
    </bean>

    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <aop:aspectj-autoproxy proxy-target-class="true"/>
    <bean id="dataSourceAspect" class="com.ifeng.auto.we_provider.common.proxy.DataSourceAspect"/>
    <aop:config>
    <aop:aspect id="c" ref="dataSourceAspect">
    <aop:pointcut id="tx" expression="execution(* com.ifeng.auto.we_provider.service..*.*(..))"/>
    <aop:before pointcut-ref="tx" method="before"/>
    </aop:aspect>
    </aop:config>

    <!-- DAO接口所在包名,Spring会自动查找其下的类 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.ifeng.auto.we_provider.dao"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    </bean>

</beans>


在service实现类中
    @DataSource("write")
    public void savetag(UserTag userTag) {
        userTagMapper.addUserTag(userTag);
    }


    @DataSource("read")
    public UserTag getUserTagByUUID(String uuid) {
        return userTagMapper.getUserTagByUUID(uuid);
    }


至此 读写分离实现
分享到:
评论

相关推荐

    springboot实现mysql的读写分离的案例源码

    一般来说,读写分离有两种实现方式。第一种是依靠中间件MyCat,也就是说应用程序连接到中间件,中间件帮我们做SQL分离,去选择指定的数据源;第二种是应用程序自己去做分离。这里我用程序自己来做,主要是利用Spring...

    JAVA数据库读写分离项目源码(MYSQL)

    在Java开发领域,数据库读写分离是一种常见的优化策略,它能显著提高系统性能,尤其是在高并发环境下。本项目源码是基于MySQL数据库实现的,利用SSM(Spring、SpringMVC、MyBatis)框架进行开发,旨在帮助开发者快速...

    使用Spring实现读写分离(MySQL实现主从复制)

    ## 使用Spring实现读写分离(MySQL实现主从复制) ### 概述 随着业务量的增长和技术的发展,单一数据库往往无法满足日益增长的数据处理需求。对于读多写少的应用场景,采用数据库集群的方式进行读写分离是一种常见...

    oracle读写分离(中间键Mycat)

    Oracle数据库的读写分离是一种优化策略,用于提升大型系统中数据处理能力,通过将读操作与写操作分离到不同的数据库实例上,实现高并发场景下的性能优化。在本配置文档中,我们将关注如何利用Mycat中间键实现Oracle ...

    spring mysql 读写分离

    Spring作为一个灵活的Java应用程序框架,提供了多种方式来支持数据库的读写分离。通过配置数据源、事务管理器以及AOP(面向切面编程)等机制,Spring可以帮助我们透明地处理读写操作的路由。 **3. 主从复制** MySQL...

    使用mysql-proxy实现mysql读写分离

    ### 使用mysql-proxy实现MySQL读写分离 随着业务规模的不断扩大,数据库系统往往成为整个系统中的瓶颈之一。为了提高系统的响应速度以及数据处理能力,一种常用的技术手段就是采用**读写分离**的方式。读写分离的...

    使用sharding-jdbc快速实现自动读写分离-demo源码

    Sharding-JDBC是阿里巴巴开源的一款轻量级Java框架,它可以在不改变业务代码的前提下,帮助我们快速实现数据库的读写分离。在这个“使用sharding-jdbc快速实现自动读写分离-demo源码”中,我们将探讨如何利用...

    突破Java面试(50)-MySQL读写分离及主从同步延时解决方案.docx

    - **如何实现MySQL的读写分离?** - **MySQL主从复制的工作原理是什么?** - **如何解决MySQL主从同步的延时问题?** **答案解析:** 1. **是否接触过MySQL读写分离?** 这是一个常见的面试问题,旨在考察候选人...

    数据库主从->读写分离

    在**读写分离**的实现中,我们需要将写操作路由到主库,而读操作则分散到从库。SpringBoot+MyBatis可以通过AOP(面向切面编程)实现这一目标。创建一个自定义的`RoutingDataSource`,根据操作类型动态选择数据源: ...

    redis读写分离demo

    简单的redis读写分离demo 用的是依赖注入的方式,redis用的是主从复制

    基于Mycat实现Mysql读写分离以及分库分表.doc

    基于Mycat实现Mysql读写分离以及分库分表详解 本文档详细介绍了基于Mycat实现Mysql读写分离以及分库分表的技术,涵盖了Mycat安装、配置、读写分离、分库分表等多方面的知识点。 一、读写分离 Mycat读写分离是指将...

    springBoot+mybatis读写分离(AOP)

    在Spring Boot项目中,我们可以通过AOP来实现读写分离。首先,我们需要定义两个数据源,一个作为主数据源(写库),另一个作为从数据源(读库)。这可以通过配置Spring Boot的数据源切换功能实现,例如在`...

    mysql5.7 双主互备、高可用、读写分离 + keepalived 实战演练

    3. 配置读写分离:在应用程序中或通过中间件(如 ProxySQL、HAProxy)实现读写请求的路由。 4. 安装并配置 keepalived:根据官方文档或教程,设置 keepalived 监控 MySQL 服务,并配置虚拟 IP。 5. 测试和监控:进行...

    数据库读写分离(aop方式完整实现)

    最近项目要支持读写分离, 网上找了很多,但都是不太完整,我自己整理了下供大家参考。 我的项目使用的框架: springMvc+spring+hibernate+springJPA+maven, 数据库连接池用阿里的druid。

    AOP动态实现MYSQL数据库读写分离

    本示例通过Java的面向切面编程(AOP)技术来实现实现MySQL数据库的读写分离,旨在帮助开发者理解如何在实际项目中应用这一技术。 首先,我们要理解什么是AOP(Aspect-Oriented Programming)。AOP是面向切面编程的...

    达梦数据库DM8读写分离集群部署

    达梦数据库DM8读写分离集群部署是指在达梦数据库DM8中实现读写分离和集群部署,以提高数据库的性能和可用性。在本文中,我们将详细介绍达梦数据库DM8读写分离集群部署的步骤和配置。 一、安装准备 在开始部署达梦...

    数据库读写分离:Java中的实现策略与代码示例

    数据库读写分离是提高Java服务端应用性能的有效策略。通过合理配置主从复制、实现读写分离逻辑,并进行充分测试和监控,可以确保数据库的高性能和稳定性。随着技术的发展,读写分离将继续在提升数据库性能和扩展性...

    ssm读写分离

    3. **读写分离实现**: - **数据库配置**:需要至少两台数据库服务器,一台作为主数据库,负责所有的写操作;一台或多台作为从数据库,处理读操作。主从同步可以通过MySQL的复制机制实现,确保数据一致性。 - **...

    数据库读写分离demo

    本示例是基于Java和MySQL,利用MyBatis作为数据库访问层来实现读写分离的解决方案。 首先,我们需要理解MyBatis是如何工作的。MyBatis是一个优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。它避免了...

Global site tag (gtag.js) - Google Analytics