java实现数据库读写分离[ AOP实例]

阅读: 评论:0

java实现数据库读写分离[ AOP实例]

java实现数据库读写分离[ AOP实例]

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

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

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

第一种为写两套mappper 
mapper写两套 一套用于读写 一套用于只读 **

    <bean id="sqlSessionFactory_wr" class=&#batis.spring.SqlSessionFactoryBean">  <property name="dataSource" ref="dataSource_wr"/>  <!-- 自动扫描l文件-->  <!--  <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=&#batis.spring.SqlSessionFactoryBean">  <property name="dataSource" ref="dataSource_r"/>  <!-- 自动扫描l文件-->  <!--  <property name="mapperLocations" value="classpath:com/ifeng/auto/we_provider/mapping2/*.xml" />  -->  <property name="mapperLocations" value="classpath:mapping/*.xml"/>  </bean>  <bean class=&#batis.spring.mapper.MapperScannerConfigurer">  <property name="basePackage" value="com.ifeng.auto.we_provider.dao1"/>  <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory_wr"/>  </bean>  <bean class=&#batis.spring.mapper.MapperScannerConfigurer">  <property name="basePackage" value="com.ifeng.auto.we_provider.dao2"/>  <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory_r"/>  </bean>  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

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

    User user = (1);  user.setName("Susan")  userMapper1.update(user);  
  • 1
  • 2
  • 3

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

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

首先l中添加依赖

    <!-- .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>  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

实现AbstractRoutingDataSource类 作为数据源

    package com.ifeng.auto.we_providermon.db;  import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;  /** * Created by Terry on 2016/7/23. */  public class DynamicDataSource extends AbstractRoutingDataSource {  @Override  protected Object determineCurrentLookupKey() {  DataSouce();  }  }  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

用ThreadLcoal管理当前数据源

    package com.ifeng.auto.we_providermon.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() {  ();  }  }  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

用注解的形式实现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();  }  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

切面类

    package com.ifeng.auto.we_providermon.proxy;  import com.ifeng.auto.we_provider.annotation.DataSource;  import com.ifeng.auto.we_providermon.db.DynamicDataSourceHolder;  import org.aspectj.lang.JoinPoint;  import org.flect.MethodSignature;  import flect.Method;  /** * Created by Terry on 2016/7/23. */  public class DataSourceAspect {  public void before(JoinPoint point)  {  Object target = Target();  System.out.String());  String method = Signature().getName();  System.out.println(method);  Class<?> classz = Class();  Class<?>[] parameterTypes = ((MethodSignature) Signature())  .getMethod().getParameterTypes();  try {  Method m = Method(method, parameterTypes);  System.out.Name());  if (m != null && m.isAnnotationPresent(DataSource.class)) {  DataSource data = m.getAnnotation(DataSource.class);  DynamicDataSourceHolder.putDataSource(data.value());  }  } catch (Exception e) {  e.printStackTrace();  }  }  }  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

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

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

l

    <?xml version="1.0" encoding="UTF-8"?>  <beans xmlns=""  xmlns:xsi=""  xmlns:context=""  xmlns:aop=""  xsi:schemaLocation="  .1.xsd      .1.xsd    .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_providermon.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=&#batis.spring.SqlSessionFactoryBean">  <property name="dataSource" ref="dataSource"/>  <!-- 自动扫描l文件-->  <!--  <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_providermon.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=&#batis.spring.mapper.MapperScannerConfigurer">  <property name="basePackage" value="com.ifeng.auto.we_provider.dao"/>  <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>  </bean>  </beans>  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110

在service实现类中

    @DataSource("write")  public void savetag(UserTag userTag) {  userTagMapper.addUserTag(userTag);  }  
  • 1
  • 2
  • 3
  • 4
    @DataSource("read")  public UserTag getUserTagByUUID(String uuid) {  UserTagByUUID(uuid);  }  
  • 1
  • 2
  • 3
  • 4

至此 读写分离实现

本文发布于:2024-02-04 23:33:05,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170718901960764.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:实例   数据库   java   AOP
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23