`
tmj_159
  • 浏览: 699592 次
  • 性别: Icon_minigender_1
  • 来自: 永州
社区版块
存档分类
最新评论

Spring Mybatis 配置Mysql主从库

阅读更多

之前有写过在linux上搭建多个mysql实例,然后又写了一篇多个mysql之间如何配置主从,现在终于到了如何使用的时候了,这篇文章就说明了,如何在程序中,而且是在通常的项目结构(基于Spring构建的项目中)中如何使用。

 

一、说说原理

简单的不能再简单了,配置多个datasource ,不同的方法使用不同的datasource。比如说,来自主库的datasource1,来自从库的datasource2 ,方法method1有数据更改操作(insert, update,delete), 使用datasource1, 方法method2有查询操作(select),使用datasource2。

 

为什么这么设计呢,因为对于一个项目来时候,绝大部分的数据库操作是查询,而不是更改,而且更改和查询的机制和方式不一样,更改涉及到的是对单表的修改,所的机制,事务的处理,而查询更多的是索引,主键的关联方面。

 

如果对mysql了解多一点的可能会有新的问题,如果我把主库的存储引擎弄成InnoDB来支持事务,从库用不支持事务的存储引擎来加快查询速度,这不是很好吗?的确很不错,但是有一个问题,如果主库挂了之后,从库需要立即来担任主库的责任的时候,这时候从库不支持事务,部分操作可能会引起问题。所以要视情况来说了,也可以通过多个从库来弥补一下这个问题。

 

二、Spring如何使用主从

在Spring使用主从主要利用了切面(AOP)和AbstractRoutingDataSource这个抽象类, 流程是这样的,在某一个或者某一类型的类的上加一个切面,当此类方法被调用时,会进入切面,根据方法之前设置的类型,被指向某个切面的datasource实例,这样,当调用mapper的时候就会使用这个datasource来操作数据库了。

 

做PPT的时候画了个草图,大家凑合看吧。



 

 

代码如下

    有自定义注解如下

 

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

@Retention(RetentionPolicy.RUNTIME)
@Target(value = ElementType.METHOD)
public @interface DataSource {
	String value();
}
    实现类方法如下

 

 

@Override
@DataSource(value="slave")
public List<Map<String, Object>> getMaterials(String name, String code, String type, String state) {

	try {
		List<Map<String, Object>> materials = this.materialMapper.getMaterials(null, name, code, type, state);
		return materials;
	} catch (Exception e) {
		e.printStackTrace();
	}
	return null;
}
   Spring 相关配置如下

 

 

<bean id="basic" class="org.apache.commons.dbcp2.BasicDataSource"
		destroy-method="close" abstract="true">
		<!-- Connection Info -->
		<property name="driverClassName" value="${jdbc.driver}" />
		<property name="username" value="${jdbc.username}" />
		<property name="password" value="${jdbc.password}" />

		<!-- Connection Pooling Info -->
		<property name="maxTotal" value="${jdbc.pool.maxActive}" />
		<property name="maxIdle" value="${jdbc.pool.maxIdle}" />
		<property name="minIdle" value="0" />
		<property name="defaultAutoCommit" value="false" />
	</bean>
	<!-- 从库 -->
	<bean id="slaveDataSource" parent="basic">
		<property name="url" value="${jdbc.url.second}" />
	</bean>
	<!-- 主库 -->
	<bean id='masterDataSource' parent="basic">
		<property name="url" value="${jdbc.url.main}" />
	</bean>
	<!-- 数据源 -->
	<bean id="dataSource" class="com.fantong.common.datasource.DataSourceSwitcher">
		<property name="targetDataSources">
			<map key-type="java.lang.String">
				<entry key="master" value-ref="masterDataSource" />
				<entry key="slave" value-ref="slaveDataSource" />
			</map>
		</property>
		<property name="defaultTargetDataSource" ref="masterDataSource">
		</property>
	</bean>
	<!-- 配置切面 用于分库 -->
	<aop:aspectj-autoproxy />
	<bean id="dataSourceAspect" class="com.fantong.common.datasource.DataSourceAspect" />
	<aop:config>
		<aop:aspect id="c" ref="dataSourceAspect">
			<aop:pointcut id="tx" expression="execution(* *..service.impl.*.*(..))" />
			<aop:before pointcut-ref="tx" method="before" />
		</aop:aspect>
	</aop:config>
相关自定义类

 

    DataSourceAspect

 

import java.lang.reflect.Method;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
public class DataSourceAspect {
	public void before(JoinPoint point) {

		Object target = point.getTarget();
		String method = point.getSignature().getName();
		Class<? extends Object> classz = target.getClass();

		Class<?>[] parameterTypes = ((MethodSignature) point.getSignature()).getMethod().getParameterTypes();
		try {
			Method m = classz.getMethod(method, parameterTypes);
			if (m != null && m.isAnnotationPresent(DataSource.class)) {
				DataSource data = m.getAnnotation(DataSource.class);
				DataSourceSwitcherToken.putToken(data.value());
				System.out.println(data.value());
			}

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

}
   DataSourceSwitcher

 

 

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

public class DataSourceSwitcher extends AbstractRoutingDataSource {

	@Override
	protected Object determineCurrentLookupKey() {
		return DataSourceSwitcherToken.getToken();
	}

}
    DataSourceSwitcherToken

 

public class DataSourceSwitcherToken {
	public static final ThreadLocal<String> token = new ThreadLocal<String>();

	public static void putToken(String name) {
		token.set(name);
	}

	public static String getToken() {
		return token.get();
	}

	public static void relaxToken() {
		token.remove();
	}

}

 

 

  • 大小: 24.8 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics