根据用户注册,系统自动创建私有数据库,用户登录,动态添加数据源到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事务.的更多相关文章

  1. SpringBoot运行时动态添加数据源

    此方案适用于解决springboot项目运行时动态添加数据源,非静态切换多数据源!!! 一.多数据源应用场景: 1.配置文件配置多数据源,如默认数据源:master,数据源1:salve1...,运行 ...

  2. springboot添加多数据源 以及 动态添加数据源动态切换数据源

    <!-- Druid 数据连接池依赖 --> <dependency> <groupId>com.alibaba</groupId> <artif ...

  3. ubuntu使用root用户登录/切换root权限

    ubuntu系统默认root用户是不能登录的,密码也是空的. 如果要使用root用户登录,必须先为root用户设置密码 打开终端,输入:sudo passwd root 然后按回车 此时会提示你输入密 ...

  4. asp.net 动态添加多个用户控件

    动态添加多个相同用户控件,并使每个用户控件获取不同的内容. 用户控件代码: 代码WebControls using System; using System.Collections.Generic;  ...

  5. Django学习路13_创建用户登录,判断数据库中账号名密码是否正确

    在 models.py 中设置数据库表的信息 from django.db import models # Create your models here. class User(models.Mod ...

  6. springboot动态多数据源

    参考文章:https://www.cnblogs.com/hehehaha/p/6147096.html 前言 目标是springboot工程支持多个MySQL数据源,在代码层面上,同一个SQL(Ma ...

  7. 【SSH学习笔记】用Struts2实现简单的用户登录

    准备阶段 在使用学习Struts2的时候首先要下载相应的架包 Struts2资源下载 这里建议下载第一个,在struts-2.5.14.1-all.zip里有很多实用的东西,不仅有架包还有官方为开发者 ...

  8. mysql 切换数据库方案

    业务场景 在SAAS模式下,不同的租户需要切换数据库,我们可以使用动态数据源,动态数据源有个问题,就是需要对每一个数据库创建一个连接池,在初始化的时候初始化这些连接池, 如果多台应用服务器的情况,每一 ...

  9. 用redis和cookie做单用户登录

    因为公司的项目需要用到单用户登录,于是今天用redis和cookie给系统添加了单用户登录功能,再次简单记录一下. 单用户登录是为了防止同一账户在不同电脑和不同浏览器里面同时登录.所以我这边的思路是: ...

随机推荐

  1. 判断具有某个属性js、jQuery

    if(!rr.classList.contains('invalid')){ updateCount(i,-1);//更新tab数量 } /*if(!$(rr).hasClass('invalid') ...

  2. Linux指令--grep

    原文地址:http://www.cnblogs.com/peida/archive/2012/12/17/2821195.html.感谢作者的无私分享. Linux系统中grep命令是一种强大的文本搜 ...

  3. IDEA新建Maven项目

    Maven是什么? 当我们在开发一个项目的时候,不可避免地会使用到第三方的类库,而它们又可能依赖着另外的Jar包,又得引入其他Jar包,而且我们很容易就会引漏掉~然后就会报错,有时候报的错会让我们花掉 ...

  4. awk处理重复行错误分析

    [root@localhost ~]#cat 0712 YRSD2-1-11 YRSD2-2-18 YRSD1-1-8 YRSD1-1-18 YRSD1-1-20 YRSD1-1-25 YRSD1-2 ...

  5. 【转】GPS网平差

    进行GPS网平差的目的主要有三个: (1)消除由观测量和已知条件中存在的误差所引起的GPS网在几何上的不一致.包括闭合环闭合差不为0:复测基线较差不为0:通过由基线向量所形成的导线,将坐标由一个已知点 ...

  6. VS 2017 发布:由于构建错误,发布失败

    用17写AspNetCore 也一年了,最近出现了这个问题 : 在点击发布的时候 报错了,构建失败的问题,刚开始还排查日子,删除以往的发布遗留痕迹,后来发现不行, 但是项目在本地运行的时候是好使的,生 ...

  7. Core Animation 文档翻译 (第五篇)

      构建Layer层次结构 在APP中大多数情况下,将Layer和View对象结合使用是Layer最好的使用方式.然而,很多时候我们可能需要通过添加单独的Layer对象,以便增加视图继承层次:当为了提 ...

  8. [DeeplearningAI笔记]改善深层神经网络_优化算法2.1_2.2_mini-batch梯度下降法

    觉得有用的话,欢迎一起讨论相互学习~Follow Me 2.1 mini-batch gradient descent mini-batch梯度下降法 我们将训练数据组合到一个大的矩阵中 \(X=\b ...

  9. Linux下php+imagemagick支持webp格式的图片

    摘要 ImageMagick是一款功能强大的图片处理工具包,很多互联网应用中都会涉及到图片处理工作,比如切割.缩放.水印.格式转换等.ImageMagick就是一个理想的工具包. 安装基础依赖 先检查 ...

  10. spring boot + vue + element-ui全栈开发入门——开篇

    最近经常看到很多java程序员朋友还在使用Spring 3.x,Spring MVC(struts),JSP.jQuery等这样传统技术.其实,我并不认为这些传统技术不好,而我想表达的是,技术的新旧程 ...