winter4666 / datasource-router

基于spring的AbstractRoutingDataSource,封装了一些工具类和注解,使多数据源的切换变得更加简单自然

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

datasource-router

基于spring的AbstractRoutingDataSource,封装了一些工具类和注解,使多数据源的切换变得更加简单自然

简介

代码基本实现思路来源于文章Dynamic DataSource Routing,在此基础之上,利用spring的aop特性,简化了切换多数据源的方式。

使用方法

  1. 修改spring配置,启用@AspectJ支持
<aop:aspectj-autoproxy/>
  1. 使用RoutingDataSource作为数据源
<bean id="dataSource" class="com.github.winter4666.datasourcerouter.RoutingDataSource">
    <property name="targetDataSources">
        <map key-type="java.lang.String">
            <entry key="db0" value-ref="db0DataSource"/>
            <entry key="db1" value-ref="db1DataSource"/>
        </map>
    </property>
    <property name="defaultTargetDataSource" ref="db0"/>
</bean>
  1. DSRAspect注入spring
<bean id="dataSourceRouter" class="com.github.winter4666.datasourcerouter.DataSourceRouter"/>
    
<bean id="sharedTransactionTemplate" class="com.github.winter4666.datasourcerouter.DSRTransactionTemplate">
    <property name="transactionManager" ref="txManager"/>
    <property name="dataSourceRouter" ref="dataSourceRouter"/>
</bean>
   
<bean class="com.github.winter4666.datasourcerouter.DSRAspect">
    <property name="dataSourceRouter" ref="dataSourceRouter"/>
    <property name="dsrTransactionTemplate" ref="sharedTransactionTemplate"/>
</bean>
  1. 使用注解切换数据源

在dao层的类或方法上,加上@DataSource注解,方法执行访问数据库时,将使用@DataSource注解所指定的数据源。

@DataSource("db1")
@Repository
public class UserDao {
	
	public User getUserById(Long id) {
		//通过用户id查找用户
	}

}
@Repository
public class UserDao {
	
	@DataSource("db1")
	public User getUserById(Long id) {
		//通过用户id查找用户
	}

}

在service层的类或方法上,加上@DSRTransactional注解,使用多数据源版本的声明式事务

@DSRTransactional("db1")
@Service
public class UserServiceImpl implements UserService{
	
	public void transfer(long fromUserId,long toUserId,int amount) {
		//转账
	}

}
@Service
public class UserServiceImpl implements UserService{
	
	@DSRTransactional("db1")
	public void transfer(long fromUserId,long toUserId,int amount) {
		//转账
	}

}
  1. 也可以直接使用DataSourceRouter类和DSRTransactionTemplate类,通过编码的方式切换数据源,在某些场景下,这样比使用注解灵活。
@Repository
public class UserDao {
	
	@Autowired
	private DataSourceRouter dataSourceRouter;
	
	public User getUserById(Long id) {
		return dataSourceRouter.accessDb("db1", new DataSourceCallback<User>() {
		
			public User doWithDataSource() {
				//通过用户id查找用户
			}
			
		});
	}

}
@Service
public class UserServiceImpl implements UserService{
	
	private DSRTransactionTemplate transactionTemplate;
	
	public void transfer(long fromUserId,long toUserId,int amount) {
		transactionTemplate.execute("db1", new TransactionCallbackWithoutResult() {
			
			@Override
			protected void doInTransactionWithoutResult(TransactionStatus status) {
				//转账
			}
		});
	}

}
  1. 在一些场景下,数据源的确定是动态的。譬如,对用户id取模2,值为0的用户记录在db0,值为1的用户记录在db1。这种情况下,可以利用LookupKeyBuilder接口和SpEL实现数据源的动态确定。
public class UserDbLookupKeyBuilder implements LookupKeyBuilder {
	
	private static final int USER_ID_MOD = 2;

	@Override
	public String getLookupKey(Object param) {
		long userId;
		if(param instanceof Long) {
			userId = (Long)param;
		} else {
			userId = Long.valueOf(param.toString());
		}
		return "db" + userId%USER_ID_MOD;
	}

	@Override
	public List<String> getAllLookupKeys() {
    	List<String> list = new ArrayList<>();
    	for(int i = 0;i < USER_ID_MOD;i++) {
    		list.add("db" + i);
    	}
    	return list;
	}

}
@Repository
public class UserDao {
	
	@DataSource(param="#a0",builderClass = UserDbLookupKeyBuilder.class)
	public User getUserById(Long id) {
		//通过用户id查找用户
	}

}

About

基于spring的AbstractRoutingDataSource,封装了一些工具类和注解,使多数据源的切换变得更加简单自然


Languages

Language:Java 100.0%