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),而今天我们就是来简化 ...
随机推荐
- Angular 选项卡
<div ng-init="now=0;" class="nav"> <h4>选项卡</h4> <div > & ...
- 关于Swing窗体有时候要放大缩小边框才能显示问题?
有时候会出现编写swing窗体后添加的组件在run之后显示不出来的问题.如图: 搜了下解决办法.此时如果是程序里面有panel组件的话,应该这样: labels[i] = new Label(lett ...
- Android回顾系列——之HttpUrlConnect的使用
写在前面: 最近准备一个关于Android的比赛.由于赛项要求,不得使用第三方工具.框架:故最近来温习一下Google官方提供的原始API的使用. 说实话,用惯了第三方的库,再回过头来用原生的api的 ...
- block的修饰词为什么选用copy
想必很多开发人员知道一般用copy修饰block,接下来就讲解为什么需要用copy,甚至会讲到其实用strong修饰block也是可以的 在 Objective-C 语言中,一共有 3 种类型的 bl ...
- Centos系统下Lamp环境的快速搭建(超详细)
lamp的搭建对于初学者是一件很头疼的事情,所以借此机会把自己当初快速搭建linux+apche+mysql+php的方法分享大家希望能到你. 工具/原料 虚拟机及Centos操作系统 Linux基本 ...
- 正则API
正则表达式:规定字符串中字符出现规律的公式 如果备选字符列表中个别字符之间是连续的,可用-省略中间的字符.比如: 匹配1位数字: [0-9]匹配1位小写字母 : [a-z] 匹配1位大写字母 : ...
- 如何看apache的版本号
在服务器上输入httpd -v就可以看到 在服务器上运行apachectl -v命令即可 Server version: Apache/2.2.3 Server built: Feb 25 2012 ...
- 修真院java后端工程师学习课程--任务1(day one)
这是我从学习资料-线下报名-北京报名截取的报名截图,从图中我们可以看出我们的报名对象应该有姓名,qq,修真类型,预计入学时间,毕业院校,线上学号,日报链接,立愿,辅导师兄等属性,其中线上学号是主码. ...
- ajax和跨域
一.简介 ajax是什么? AJAX(Asynchronous JavaScript and XML) 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术. AJAX, (异步的JavaSc ...
- VM安装Ubuntu问题合集(无法联网、中文界面设置、中文输入法etc)
经常使用VM安装Ubuntu,安装系统的步骤跟着系统提示一步步下来就行,但总是遇到一些问题,这里记录一下常遇到的问题,以及自己解决的办法: 1.无法联网: 状况:Ubuntu不能联网,联网地方一直在闪 ...