java 切换数据库用户_动态添加数据源,根据用户登录切换数据库.编程式Spring事务....

这篇博客介绍了如何在Java中实现根据用户登录动态添加和删除数据源,使用Spring Data Source Routing进行数据源路由。当用户登录时,系统会创建私有数据库并加入数据源,而在Session超时时则移除数据源。文章提到了这种方式的好处和坏处,并通过反射方法动态添加和删除数据源。同时,展示了如何使用注解和AOP在方法级别切换数据源,以及编程式Spring事务的使用来控制数据库连接和提高性能。
摘要由CSDN通过智能技术生成

根据用户注册,系统自动创建私有数据库,用户登录,动态添加数据源到Spring数据路由,Session超时删除数据源

好处:当数据量大的时候,类似水平切割效果,效率会高一些

坏处:数据源切换,Spring 事务处理比较繁琐,数据连接处理不好会有很大消耗,如果涉及后台系统管理数据,也比较繁琐.

使用Spring数据源路由,现在好像没有直接添加数据源的方法,无奈之下只能用反射.

用户登录成功时,在Spring Security UserDetailService.loadUserByUsername 里面添加用户数据源

/**

* 加入用户数据源*/routingDataSource.addDataSource(userid);

/**

* 根据用户创建数据源*/

public voidaddDataSource(String userid) {if(StringUtils.isBlank(userid))return;

DbInfo dbInfo=getDbInfoService().getDbInfoByUserId(userid);try{

Field targetDataSources= AbstractRoutingDataSource.class.getDeclaredField("targetDataSources");

Field resolvedDataSources= AbstractRoutingDataSource.class.getDeclaredField("resolvedDataSources");

targetDataSources.setAccessible(true);

resolvedDataSources.setAccessible(true);

Map dataSources = (Map) targetDataSources.get(this);if (dataSources.get(userInfo.getId().toString()) != null)return;

Map dataSources2 = (Map) resolvedDataSources.get(this);

DruidDataSource dds= newDruidDataSource();

dds.setUrl("jdbc:mysql://" + dbInfo.getDbaddr() +

":" + dbInfo.getDbport() + "/" + dbInfo.getDbname() + "?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&useSSL=true");

dds.setUsername(dbInfo.getUsername());

dds.setPassword(dbInfo.getPwd());

dataSources.put(userid, dds);

dataSources2.put(userid, dds);

}catch(NoSuchFieldException e) {

e.printStackTrace();

}catch(IllegalAccessException e) {

e.printStackTrace();

}

}

加入了数据源,当然需要删除,可以在Session监听器里面,销毁Session的时候删除

/*** 根据用户删除数据源*/

public voidremoveDataSource(String userid) {if(StringUtils.isBlank(userid))return;try{

Field targetDataSources= AbstractRoutingDataSource.class.getDeclaredField("targetDataSources");

Field resolvedDataSources= AbstractRoutingDataSource.class.getDeclaredField("resolvedDataSources");

targetDataSources.setAccessible(true);

resolvedDataSources.setAccessible(true);

Map dataSources = (Map) targetDataSources.get(this);if (dataSources.get(userInfo.getUsrno()) != null) {

Map dataSources2 = (Map) resolvedDataSources.get(this);

dataSources.remove(userid);

dataSources2.remove(userid);

}

}catch(NoSuchFieldException e) {

e.printStackTrace();

}catch(IllegalAccessException e) {

e.printStackTrace();

}

}

注解加Aop 切换数据源

注解

/*** Created by 为 .

* 根据当前用户切换数据源*/@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)public @interfaceSwitchDataSource {

}

Spring AOP,新版本的SpringAOP 可以很好切入监听器,因为监听器可以被Spring容器管理了,变相加强了SpringAop,这样就不需要使用原生Aspectj了

/*** Created by 为 on 2017-4-27.*/@Component

@Aspect

@Order(0)//配置Spring注解事务时,在事务之前切换数据源public classSwitchDataSourceAspectj {//定义切点

@Pointcut("@annotation(com.lzw.common.annotation.SwitchDataSource)")public voidswitchDataSource(){}

@Around("switchDataSource()")publicObject arounduserDataSource(ProceedingJoinPoint joinPoint){

DataSourceContextHolder.user();try{returnjoinPoint.proceed();

}catch(Throwable throwable) {

throwable.printStackTrace();

}finally{

DataSourceContextHolder.write();

}return null;

}

}

这样可以在方法上添加注解切换数据源(注意事务与切换数据源的注解顺序),不过如果在一个方法中需要多次切换到不同数据源查询数据,会消耗很多连接数,为了更好控制数据库连接数,需要使用Spring事务

编程式Spring事务

注入TransactionManager

@Resourceprivate PlatformTransactionManager platformTransactionManager;

开始事务处理,每个用户单独数据库,访问量不大,所以没有配置连接池,每次重新获取连接性能比较低,开启事务是为了数据库连接重用

//为了节省连接数,尽可能在一次切换里获取需要的数据

DataSourceContextHolder.user();//TransactionTemplate 必须每次new出来,不能使用Spring单例注入,设置的数据会一直存在.

TransactionTemplate transactionTemplate = newTransactionTemplate(platformTransactionManager);

transactionTemplate.setPropagationBehavior(Propagation.REQUIRES_NEW.value());

transactionTemplate.execute(newTransactionCallbackWithoutResult() {

@Overridepublic voiddoInTransactionWithoutResult(TransactionStatus status) {//数据库操作代码

}

});

DataSourceContextHolder.write();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值