今天接触了下mybatis的数据库分库问题,于是就查了下各种资料,说说今天的收获,当然可能别人也写过了,但还是把自己的感受及经历写下,以后方便回顾。知识这个东西很多时候都是一点点积累的结果。可能多记录些并没有坏处。手懒的结果很多人也都吃亏过相信。
关于数据库的分库曾经听过些,但自己却没接触过,于是google下,照着代码走了一遍,代码如下
application-context.xml
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driverClassName}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="minPoolSize" value="${jdbc.min}" />
<property name="maxPoolSize" value="${jdbc.max}" />
<property name="maxIdleTime" value="${jdbc.maxIdleTime}" />
<property name="idleConnectionTestPeriod" value="${jdbc.idleConnectionTestPeriod}" />
</bean>
<!-- mybatis 配置 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSources" />
<property name="configLocation" value="classpath:config/mybatis-config.xml" />
<!-- 当Mapper文件跟对应的Mapper接口处于同一位置的时候可以不用指定该属性的值: -->
<!-- <property name="mapperLocations" value="classpath:org/user/persistence/*.xml" /> -->
</bean>
<!-- Mapper接口扫描 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="org.*.persistence;" />
<property name="annotationClass" value="org.springframework.stereotype.Repository" />
</bean>
<!-- add by xiao -->
<bean id="dataSource2" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driverClassName}" />
<property name="jdbcUrl" value="${jdbc.url2}" />
<property name="user" value="${jdbc.username2}" />
<property name="password" value="${jdbc.password2}" />
<property name="minPoolSize" value="${jdbc.min2}" />
<property name="maxPoolSize" value="${jdbc.max2}" />
<property name="maxIdleTime" value="${jdbc.maxIdleTime2}" />
<property name="idleConnectionTestPeriod" value="${jdbc.idleConnectionTestPeriod2}" />
</bean>
<bean id="dataSources" class="org.mutidatasource.test.CustomerRoutingDataSource">
<property name="targetDataSources">
<map key-type="org.mutidatasource.test.CustomerType">
<entry key="FIRST" value-ref="dataSource"/>
<entry key="SECOND" value-ref="dataSource2"/>
</map>
</property>
<property name="defaultTargetDataSource" ref="dataSource2"/>
</bean>
<bean id="choose" class="org.mutidatasource.test.ChooseDataSource"/>
<aop:config>
<aop:aspect ref="choose">
<aop:pointcut expression="execution(* org.mutidatasource.test.TestMutiDataSource.printRest(..))" id="point"/>
<aop:before method="chooseDataSource" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
java代码部分如下:
public class CustomerContextHolder {
private static final ThreadLocal<CustomerType> contextHolder =
new ThreadLocal<CustomerType>();
public static void setCustomerType(CustomerType customerType) {
Assert.notNull(customerType, "customerType cannot be null");
contextHolder.set(customerType);
}
public static CustomerType getCustomerType() {
return (CustomerType) contextHolder.get();
}
public static void clearCustomerType() {
contextHolder.remove();
}
}
public class CustomerRoutingDataSource extends AbstractRoutingDataSource{
@Override
protected Object determineCurrentLookupKey() {
return CustomerContextHolder.getCustomerType();
}
}
public class CustomerContextHolder {
private static final ThreadLocal<CustomerType> contextHolder =
new ThreadLocal<CustomerType>();
public static void setCustomerType(CustomerType customerType) {
Assert.notNull(customerType, "customerType cannot be null");
contextHolder.set(customerType);
}
public static CustomerType getCustomerType() {
return (CustomerType) contextHolder.get();
}
public static void clearCustomerType() {
contextHolder.remove();
}
}
public enum CustomerType {
FIRST,SECOND
}
测试类如下:
@Service(value="muti")
public class TestMutiDataSource implements TestMutiDataSourceIntf{
@Resource
MutiDataSourceMapper mutiDataSourceMapper;
public void printRest(int agencyId){
CustomerContextHolder.setCustomerType(CustomerType.FIRST);
List<String> list = mutiDataSourceMapper.selectMutiNames();
for(String tmp:list){
System.err.println(tmp);
}
CustomerContextHolder.setCustomerType(CustomerType.SECOND);
List<String> lists = mutiDataSourceMapper.selectMutiNames();
for(String tmp:lists){
System.err.println(tmp);
}
}
}
运行即可。
其中在xml中有一段aop的配置,我是打算配置成自动路由的方式来选数据源
public class ChooseDataSource {
public void chooseDataSource(JoinPoint joinPoint){
LocalVariableTableParameterNameDiscoverer parameterNameDiscovere =
new LocalVariableTableParameterNameDiscoverer();
Method method = getMethod(joinPoint);
String[] names = parameterNameDiscovere.getParameterNames(method);
System.out.println("names:"+names[0]);
System.err.println("Method Name :" + joinPoint.getSignature().toShortString() + "| Args => " + Arrays.asList(joinPoint.getArgs()));
}
private Method getMethod(JoinPoint joinPoint) {
//String methodLongName = joinPoint.getSignature().toLongString();
String methodLongName = joinPoint.getSignature().toShortString();
String[] tmp = methodLongName.split("\\.");
methodLongName = tmp[tmp.length-1];
Method[] methods = joinPoint.getTarget().getClass().getMethods();
Method method = null;
for(int i=0, len=methods.length; i<len; i++) {
if(methods[i].toString().contains(methodLongName)) {
method = methods[i];
break;
}
}
return method;
}
}
这边在获取参数名称的时候出现了些问题,我本来打算用
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
String[] parameterNames = signature.getParameterNames();
System.out.println(parameterNames);
这样的方法来获取参数名称,但得到的却是null,查了很多资料,说是要aspectJ专用的编译器可以,或者是在java编译的时候用
javac -g这样的命令可以使编译的结果之中有方法参数的名字,否则是得不到参数的名称的。上面还有个方法得到了参数的名称,就
是用LocalVariableTableParameterNameDiscoverer 这个类来获取,据说它是在java编译的时候生成的,具体我也不大了解。以后再补充
今天就到这里吧