spring 多数据源切换
spring配置管理多数据源,方便服务访问不同数据库时,数据源切换。多少无意,直接上代码。
1.定义数据源key枚举值(可以直接使用字符串代替,为了代码的整洁及易读性,这里使用枚举)
public enum DataSourceEnum { anquan, publ, tlshow, }
2.定义数据源持有者,切换数据源使用
public final class DataSourceHolder { private static ThreadLocal<DataSourceEnum> currentDBName = new ThreadLocal<DataSourceEnum>(); private static DataSourceEnum DEFAULT_HASH = DataSourceEnum.anquan; public static DataSourceEnum determineDefault() { return determineDS(DEFAULT_HASH); } public static DataSourceEnum determineDS(DataSourceEnum key) { currentDBName.set(key); log.debug("determineDS:" + key); return key; } public static DataSourceEnum getCurrentDBName() { return currentDBName.get(); } }
3.实现数据源路由接口
public class DBRoutingDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DataSourceHolder.getCurrentDBName(); } @Override public void setTargetDataSources(Map targetDataSources) { super.setTargetDataSources(targetDataSources); } @Override public Object unwrap(Class iface) throws SQLException { return null; } @Override public boolean isWrapperFor(Class iface) throws SQLException { return false; } }
4.定义spring 切面,在执行service方法前,切换数据源。(首先要保证spring支持注解)
@Aspect @lombok.extern.log4j.Log4j public class DetermineAspect { @Pointcut("within(com.changyou.*.service.impl.*)") public void withController() {} @Before("withController()") public void beforeAdvice(JoinPoint jp) { if(log.isDebugEnabled()) { log.debug("Reset db router before " + jp.getSignature().getDeclaringType().getSimpleName() + "." + jp.getSignature().getName() + "()"); } DataSourceMethod datasourceMethod = ((MethodSignature)jp.getSignature()).getMethod().getAnnotation(DataSourceMethod.class); DataSourceFile datasourceFile = ((MethodSignature)jp.getSignature()).getMethod().getDeclaringClass().getAnnotation(DataSourceFile.class); if(datasourceMethod!=null){ DataSourceHolder.determineDS(datasourceMethod.value()); }else if(datasourceFile!=null){ DataSourceHolder.determineDS(datasourceFile.value()); }else{ DataSourceHolder.determineDefault(); } } }
5.spring配置数据源,使用自己实现的数据源路由类(DBRoutingDataSource )
<!-- 配置数据源 -->
<bean name="dataSource_0" parent="abstractProxoolDataSource">
<property name="url" value="${jdbc.0.url}" />
<property name="username" value="${jdbc.0.username}" />
<property name="password" value="${jdbc.0.password}" />
</bean>
<!-- 配置数据源tlshow-->
<bean name="dataSource_1" parent="abstractProxoolDataSource">
<property name="url" value="${jdbc.1.url}" />
<property name="username" value="${jdbc.1.username}" />
<property name="password" value="${jdbc.1.password}" />
</bean>
<!-- 配置数据源publicaccount-->
<bean name="dataSource_2" parent="abstractProxoolDataSource">
<property name="url" value="${jdbc.2.url}" />
<property name="username" value="${jdbc.2.username}" />
<property name="password" value="${jdbc.2.password}" />
</bean>
<bean id="dataSource" class="com.changyou.common.util.dbaccess.DBRoutingDataSource">
<property name="defaultTargetDataSource" ref="dataSource_0"/>
<property name="targetDataSources">
<map key-type="com.changyou.common.enums.DataSourceEnum"><!-- 数据源枚举 -->
<entry key="anquan" value-ref="dataSource_0" />
<entry key="tlshow" value-ref="dataSource_1" />
<entry key="publ" value-ref="dataSource_2" />
</map>
</property>
</bean>
6.基础工作完成,下面开始使用,需要在server类或方法上添加注解。(上面的切面会查看是否有指定注解的存在)。
定义自己的注解:
@Target(value={ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface DataSourceRouter { public DataSourceEnum value() default DataSourceEnum.anquan; }
7.开始愉快的使用吧,方法上的注解权限高于整个类上的注解,这取决于切面的处理方式。
@Service @DataSourceRouter(DataSourceEnum.publ) public class CyjUserServiceImpl{ @Autowired private UserMapper userMapper; public void saveOrUpdateBlock(CyjUserBlock cyjUserBlock) { userMapper.saveOrUpdateBlock(cyjUserBlock); } @DataSourceRouter(DataSourceEnum.anquan) public void deleteBlockById(int blockId) { userMapper.deleteBlockById(blockId); } }
ok,后期补上demo。。。。。。。