动态添加数据源,根据用户登录切换数据库.编程式Spring事务.
根据用户注册,系统自动创建私有数据库,用户登录,动态添加数据源到Spring数据路由,Session超时删除数据源
好处:当数据量大的时候,类似水平切割效果,效率会高一些
坏处:数据源切换,Spring 事务处理比较繁琐,数据连接处理不好会有很大消耗,如果涉及后台系统管理数据,也比较繁琐.
使用Spring数据源路由,现在好像没有直接添加数据源的方法,无奈之下只能用反射.
用户登录成功时,在Spring Security UserDetailService.loadUserByUsername 里面添加用户数据源
/**
* 加入用户数据源
*/
routingDataSource.addDataSource(userid);
/**
* 根据用户创建数据源
*/
public void addDataSource(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<Object, Object> dataSources = (Map<Object, Object>) targetDataSources.get(this);
if (dataSources.get(userInfo.getId().toString()) != null)
return;
Map<Object, DataSource> dataSources2 = (Map<Object, DataSource>) resolvedDataSources.get(this);
DruidDataSource dds = new DruidDataSource();
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 void removeDataSource(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<Object, Object> dataSources = (Map<Object, Object>) targetDataSources.get(this);
if (dataSources.get(userInfo.getUsrno()) != null) {
Map<Object, DataSource> dataSources2 = (Map<Object, DataSource>) 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 @interface SwitchDataSource {
}
Spring AOP,新版本的SpringAOP 可以很好切入监听器,因为监听器可以被Spring容器管理了,变相加强了SpringAop,这样就不需要使用原生Aspectj了
/**
* Created by 为 on 2017-4-27.
*/
@Component
@Aspect
@Order(0)//配置Spring注解事务时,在事务之前切换数据源
public class SwitchDataSourceAspectj { //定义切点
@Pointcut("@annotation(com.lzw.common.annotation.SwitchDataSource)")
public void switchDataSource(){} @Around("switchDataSource()")
public Object arounduserDataSource(ProceedingJoinPoint joinPoint){
DataSourceContextHolder.user();
try {
return joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}finally {
DataSourceContextHolder.write();
}
return null;
}
}
这样可以在方法上添加注解切换数据源(注意事务与切换数据源的注解顺序),不过如果在一个方法中需要多次切换到不同数据源查询数据,会消耗很多连接数,为了更好控制数据库连接数,需要使用Spring事务
编程式Spring事务
注入TransactionManager
@Resource
private PlatformTransactionManager platformTransactionManager;
开始事务处理,每个用户单独数据库,访问量不大,所以没有配置连接池,每次重新获取连接性能比较低,开启事务是为了数据库连接重用
//为了节省连接数,尽可能在一次切换里获取需要的数据
DataSourceContextHolder.user();
//TransactionTemplate 必须每次new出来,不能使用Spring单例注入,设置的数据会一直存在.
TransactionTemplate transactionTemplate = new TransactionTemplate(platformTransactionManager);
transactionTemplate.setPropagationBehavior(Propagation.REQUIRES_NEW.value());
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
public void doInTransactionWithoutResult(TransactionStatus status) {
//数据库操作代码
}
});
DataSourceContextHolder.write();
动态添加数据源,根据用户登录切换数据库.编程式Spring事务.的更多相关文章
- SpringBoot运行时动态添加数据源
此方案适用于解决springboot项目运行时动态添加数据源,非静态切换多数据源!!! 一.多数据源应用场景: 1.配置文件配置多数据源,如默认数据源:master,数据源1:salve1...,运行 ...
- springboot添加多数据源 以及 动态添加数据源动态切换数据源
<!-- Druid 数据连接池依赖 --> <dependency> <groupId>com.alibaba</groupId> <artif ...
- ubuntu使用root用户登录/切换root权限
ubuntu系统默认root用户是不能登录的,密码也是空的. 如果要使用root用户登录,必须先为root用户设置密码 打开终端,输入:sudo passwd root 然后按回车 此时会提示你输入密 ...
- asp.net 动态添加多个用户控件
动态添加多个相同用户控件,并使每个用户控件获取不同的内容. 用户控件代码: 代码WebControls using System; using System.Collections.Generic; ...
- Django学习路13_创建用户登录,判断数据库中账号名密码是否正确
在 models.py 中设置数据库表的信息 from django.db import models # Create your models here. class User(models.Mod ...
- springboot动态多数据源
参考文章:https://www.cnblogs.com/hehehaha/p/6147096.html 前言 目标是springboot工程支持多个MySQL数据源,在代码层面上,同一个SQL(Ma ...
- 【SSH学习笔记】用Struts2实现简单的用户登录
准备阶段 在使用学习Struts2的时候首先要下载相应的架包 Struts2资源下载 这里建议下载第一个,在struts-2.5.14.1-all.zip里有很多实用的东西,不仅有架包还有官方为开发者 ...
- mysql 切换数据库方案
业务场景 在SAAS模式下,不同的租户需要切换数据库,我们可以使用动态数据源,动态数据源有个问题,就是需要对每一个数据库创建一个连接池,在初始化的时候初始化这些连接池, 如果多台应用服务器的情况,每一 ...
- 用redis和cookie做单用户登录
因为公司的项目需要用到单用户登录,于是今天用redis和cookie给系统添加了单用户登录功能,再次简单记录一下. 单用户登录是为了防止同一账户在不同电脑和不同浏览器里面同时登录.所以我这边的思路是: ...
随机推荐
- php curl模拟登陆抓取数据
http://www.cnblogs.com/zengguowang/p/6814474.html
- 用 chrome 调试 node.js 代码
1.全局安装 node-inspector cnpm install -g node-inspector 2.启动node项目入口文件,如 node --inspect index.js 3.控制台 ...
- JavaScript数据结构 (手打代码)
array: 数组创建: ); //创建一个长度为6的数组 ,,,,,); 数组方法: var str="I love javascript"; var single=str.sp ...
- redis发布与订阅
发布与订阅 除了实现任务队列外, Redis还提供了一组命令可以让开发者实现"发布/订阅"(publish/subscribe)模式. "发布/订阅"模式同样可 ...
- oracle case when及decode的用法
case ... when 语句 1) CASE column_name WHEN value1 THEN resutl1,... [ ELSE result ] END select name , ...
- 基于 React + Webpack 的音乐相册项目(上)
笔记仓库:https://github.com/nnngu/LearningNotes 上一篇文章用爬虫自动下载了一些图片,这一篇就用这些图片做一个音乐相册吧! 效果预览 点击图片,切换到背面: 演示 ...
- JavaScript 基本语法 -- 数据类型 & 变量
JavaScript都有哪些数据类型呢? 在JavaScript里面,数据类型分为两类:原始类型(primitive type)和对象类型(object type) 1. 原始类型(我的理解,不可分割 ...
- Nutch2.2.1在MyEclipse中的安装(window7环境)
在https://svn.apache.org/repos/asf/nutch/branches/branch-2.2.1/网址里面可以找到Nutch2.2.1版本的资源文件. 1. 在MyEclip ...
- How to fix “HTTP Status Code 505 – HTTP Version Not Supported” error?--转
http://dotnetstock.com/technical/http-status-code-505-http-version-not-supported/ The reason for the ...
- CTP期货期权交易开发
CTP交易部分接口说明 综合交易平台(Comprehensive Transaction Platform,CTP)是专门为期货公司开发的一套期货经纪业务管理系统,由交易.风险控制和结算三大系统组成. ...