java读写分离实现 javadao读写分离
程序员文章站
2022-03-13 09:17:36
...
数据库配置为一个主库 多个从库 主库用于写操作 从库只读操作
读写分离实现即为配置两个数据源,一个用于读写 连接主库 假设为ds_wr,一个用于只读 连接从库 假设为ds_r。
对数据库读操作时,操作ds_r数据源。
对数据源写操作时,操作ds_wr数据源。
读写分离可以有两种实现方式
第一种为写两套mappper
mapper写两套 一套用于读写 一套用于只读
dao1包中mapper是读写方法 对应xml文件在mapping1文件夹中
dao2包中mapper是只读方法 对应xml文件在mapping2文件夹中
第二种为通过实现AbstractRoutingDataSource类来动态管理数据源,本篇博客主要讲这部分内容
利用面向切面思维,每一次进入service方法前,选择数据源
首先pom.xml中添加依赖
实现AbstractRoutingDataSource类 作为数据源
用ThreadLcoal管理当前数据源
用注解的形式实现AOP管理数据源
切面类
将注解放在service实现类的方法前,自动设置当前数据源为注解中数据源。
接下来配置aop以及数据源。
mybatis.xml
在service实现类中
至此 读写分离实现
读写分离实现即为配置两个数据源,一个用于读写 连接主库 假设为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); }
至此 读写分离实现
上一篇: 连接数据库实现增删改查
下一篇: WPF-004 控件 ToolTip