2018-01-08 学习随笔 SpirngBoot整合Mybatis进行主从数据库的动态切换,以及一些数据库层面和分布式事物的解决方案
先大概介绍一下主从数据库是什么?
其实就是两个或N个数据库,一个或几个主负责写(当然也可以读),另一个或几个从只负责读.从数据库要记录主数据库的具体url以及BigLOG(二进制日志文件)的参数.原理就是在
定时的从主数据库的BigLOG文件中获取相应的日志记录,并转换成相应的sql语句进行同步.
SpringBoot整合Mybatis怎么自动化的区分主从数据库进行读写,并且保证其线程安全性;
创建一个DataBaseContextHolder类,在类里定义一个成员变量ThreadLocal(一个可以绑定线程的Map,自动会以当前线程为Key,并将传入的值做浅克隆保存),
定义一个枚举,创建两个枚举常量(Master,Slave),并写上get,set方法,以及clean方法(getDataBaseType(),setDataBaseType());
public class DataBaseContextHolder {
public enum DataBaseType {
Master, Slave;
}
private static final ThreadLocal<DataBaseType> CONTEXTHOLDER = new ThreadLocal<>();
public static void setDataBaseType(DataBaseType dst) {
if (dst == null)
throw new NullPointerException();
CONTEXTHOLDER.set(dst);
}
public static DataBaseType getDataBaseType() {
return CONTEXTHOLDER.get() == null ? DataBaseType.Master : CONTEXTHOLDER.get();
}
public static void clearDataSource() {
CONTEXTHOLDER.remove();
}
之后创建一个Mybatis配置类,继承MyBatisAutoConfiguration(这是SpringBoot对Mybatis的默认配置类,所以我们可以继承它进行一个扩展),
注入主数据源和从数据源,并复写SqlSessionFactory()方法,在方法里调用父类的SqlSessionFactory方法,参数需要传入一个AbstractRoutingDataSource对象,
这个我们需要写一个自定义类,并且继承这个类,实现它的一个抽象方法determineCurrentLookupKey(),在方法中,直接调用DataBaseContextHolder.getDataBaseType(),
并返回它的返回值.
之后我们需要创建我们自定义类的对象,并通过ClassLoaderRepository对象的SoftHashMap方法获得一个SoftHashMap对象(一个线程安全,并且排序也就是存取有序的Map集合,也不知道它很LinklistHashMap有神马区别),
将我们的枚举,DataBaseContextHolder.DataBaseType.Master和DataBaseContextHolder.DataBaseType.Slave作为键,两个主从数据源作为值传入,我们自定义的AbstractRoutingDataSource子类对象调用setTargetDataSource(SoftHashMap)方法(记录指向数据源),
再指定一个默认数据源setDefaultDataSource(master),这个肯定指定主数据源,可读可写啊.
@Configuration
@AutoConfigureAfter({ DataBaseConfiguration.class })
public class MybatisConfiguration extends MybatisAutoConfiguration {
@Resource(name = "masterDataSource")
private DataSource masterDataSource;
@Resource(name = "slaveDataSource")
private DataSource slaveDataSource;
@Bean(name = "sqlSessionFactory")
public SqlSessionFactory SqlSessionFactory() throws Exception {
return super.sqlSessionFactory(roundrobinDataSource());
}
public AbstractRoutingDataSource roundrobinDataSource() {
ReadWriterSplitRoutingDataSource rsd = new ReadWriterSplitRoutingDataSource();
SoftHashMap shm = new ClassLoaderRepository.SoftHashMap();
shm.put(DataBaseContextHolder.DataBaseType.Master, masterDataSource);
shm.put(DataBaseContextHolder.DataBaseType.Slave, slaveDataSource);
rsd.setDefaultTargetDataSource(masterDataSource);
rsd.setTargetDataSources(shm);
return rsd;
}
}
public class ReadWriterSplitRoutingDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataBaseContextHolder.getDataBaseType();
}
}
当然做完这一切也仅仅是指定了配置而已,我们并没有在我们想切换数据源时就可以指定数据源的函数.这个我们可以通过注解加Aop的方式来实现;
创建一个注解,不用添加属性,只要指定其可以在方法和类上生效,生命周期的话需要指定为运行时.
之后创建一个Aop类,并拦截带有此注解的方法,在其运行之前更换当前ThreadLocal中保存的DataBaseType为Slave,并在方法执行完后清除ThreadLocal.
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface ReadOnlyConnection {
}
@Aspect
@Component
public class ReadOnlyConnectionInterceptor implements Ordered {
private static final Logger log = LoggerFactory.getLogger(ReadOnlyConnectionInterceptor.class);
@Around("@annotation(readOnlyConnection)")
public Object connetionProceed(ProceedingJoinPoint proceedingJoinPoint, ReadOnlyConnection readOnlyConnection)
throws Throwable {
try {
log.info("set database connection to readonly");
DataBaseContextHolder.setDataBaseType(DataBaseContextHolder.DataBaseType.Slave);
return proceedingJoinPoint.proceed();
} finally {
DataBaseContextHolder.clearDataSource();
log.info("restore database connection");
}
}
@Override
public int getOrder() {
return 0;
}
}
这个Order的话只是一个可以指定执行顺序(执行优先级)的接口,其实用@Order注解也可以指定,实现不实现都无所谓,不用管它.
普通视图,物化视图
普通视图的话只是定义,不是一个物理上的实表,并且不能做增删改操作,当我们查找普通视图上保存的数据的时候,是由数据库根据定义来生成sql在基表上进行查询的.
而物化视图则是一个实实在在的物理意义上的实表,和普通表一样可以创建索引,做增删改操作,并可以指定两种更新方式(就是讲基表上更新过的数据同步到物化视图上),OnDemand和OnCommit.
OnDemand的话也有两种一种是手动刷新,也就是需要我们代码调用存储函数,而自动刷新则可以在创建物化视图的时候直接指定时间,具体操作请百度.
OnCommit则是见其名知其义了,就是在基表发生commit事件的时候(任何事件完成后都会触发),就将基表数据同步更新到物化视图上.
个人观点:视图的创建除非是安全必要,否则没有必要且浪费性能,很多时候一个冗余字段就可以解决的事情就不必做跨表或者跨库(Oracle专属)的视图了;
分表,分库
水平拆分:按行拆分,id若为int自增可以直接利用取膜再查表.为UUID类字符型,则需要先计算出其HASH值再取膜查找是那个表;
垂直拆分:根据字段关联性拆分;
当每日增长新数据很大的时候,可以利用存储过程加定时任务,进行一个周期性的建表;
分布式事物要解决的就是两个不同数据源之间保存的数据的最终一致性,实现方式只能通过合理的代码设计(例如:加版本号字段实现乐观锁)
2018-01-08 学习随笔 SpirngBoot整合Mybatis进行主从数据库的动态切换,以及一些数据库层面和分布式事物的解决方案的更多相关文章
- mybatis源码学习(四)--springboot整合mybatis原理
我们接下来说:springboot是如何和mybatis进行整合的 1.首先,springboot中使用mybatis需要用到mybatis-spring-boot-start,可以理解为mybati ...
- SpringBoot学习- 3、整合MyBatis
SpringBoot学习足迹 1.下载安装一个Mysql数据库及管理工具,同类工具很多,随便找一个都可以,我在windows下做测试项目习惯使用的是haosql 它内部集成了MySql-Front管理 ...
- spring学习07(整合MyBatis)
10.整合MyBatis 10.1 相关jar包 junit <dependency> <groupId>junit</groupId> <artifactI ...
- Spring Boot入门系列(十九)整合mybatis,使用注解实现动态Sql、参数传递等常用操作!
前面介绍了Spring Boot 整合mybatis 使用注解的方式实现数据库操作,介绍了如何自动生成注解版的mapper 和pojo类. 接下来介绍使用mybatis 常用注解以及如何传参数等数据库 ...
- Java学习笔记-spring整合mybatis
这个项目就是一个例子,只有添加图书的功能: 项目架构: resource: 整合流程: 1.pom文件节点,这两个是整合用的,其他节点不再赘述: <!-- https://mvnreposito ...
- SpirngBoot整合Mybatis Plus多数据源
导读 有一个这样子的需求,线上正在跑的业务,由于业务发展需要,需重新开发一套新系统,等新系统开发完成后,需要无缝对接切换,当初具体设计见草图. 添加依赖 <!--lombok--> < ...
- springboot学习四:整合mybatis
在application.properties加入配置 ## Mybatis 配置 mybatis.typeAliasesPackage=org.spring.springboot.domain my ...
- Spring Boot学习笔记(五)整合mybatis
pom文件里添加依赖 <!-- 数据库需要的依赖 --> <dependency> <groupId>org.mybatis.spring.boot</gro ...
- spring boot整合mybatis基于注解开发以及动态sql的使用
让我们回忆一下上篇博客中mybatis是怎样发挥它的作用的,主要是三类文件,第一mapper接口,第二xml文件,第三全局配置文件(application.properties),而今天我们就是来简化 ...
随机推荐
- HDU 2682 Tree
题目: There are N (2<=N<=600) cities,each has a value of happiness,we consider two cities A and ...
- nodejs学习笔记 —— 异步编程解决方案
在js或者node编程中,由于异步的频繁和广度使用,使得回调和嵌套的深度导致编程的体验遇到一些挑战,如果写出优雅和好看的代码,本文主要针对异步编程的主流方案做一些总结 1.事件发布/订阅模式 事件监听 ...
- Oracle_SQL92_连接查询
Oracle_SQL92_连接查询 笛卡儿积 --笛卡尔积 select * from emp;----14 select * from dept;----4 select * from emp, ...
- YUM常用命令介绍
http://www.cnblogs.com/lostyue/archive/2012/05/06/2485653.html 1.列出所有可更新的软件清单 命令:yum check-update 2. ...
- 人人都是CEO
在这个互联网崛起的时代有些流行说法,比如:人人都是产品经理,人人都是程序员以突显行业繁荣的特点,但从更基本的出发点,难道人人不都是 CEO 么?个人的 CEO. 从这个名字套路出发,我沿着想了下去,作 ...
- Redis集群方案怎么做?大牛给你介绍五种方案!
Redis集群方案 Redis数据量日益增大,而且使用的公司越来越多,不仅用于做缓存,同时趋向于存储这块,这样必促使集群的发展,各个公司也在收集适合自己的集群方案,目前行业用的比较多的是下面几种集群架 ...
- .net Core学习笔记3 编辑列表并绑定下拉列
本次主要实现列表的编辑及下拉列表的绑定 先看效果图: 主要用DropDownList绑定下拉列后端代码: 1:定义一个存下拉数据类 public class SelectItem { public s ...
- [Git] git log命令
这是git的新系列,不常用的命令和其参数比较容易记不住,干脆将常用的记录下来,日后查查方便也是好的,一篇文章一个git命令,长短根据命令有所不同. git log命令主要用于查看提交历史,同时根据添加 ...
- 转-Determining whether a Computer Needs to be Rebooted
1 如何检查机器是否因为装了Windows更新而需要重新启动 2 Determining whether a Computer Needs to be Rebooted 3 How can I tel ...
- 流API--使用并行流
这篇博客一起来研究下使用并行流.借组多核处理器并行执行代码可以显著提高性能,但是并行编程可能十分复杂且容易出错,流API提供的好处之一是能够轻松可靠的并行执行一些操作.请求并行处理流,首先要获得一个并 ...