先大概介绍一下主从数据库是什么?
其实就是两个或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进行主从数据库的动态切换,以及一些数据库层面和分布式事物的解决方案的更多相关文章

  1. mybatis源码学习(四)--springboot整合mybatis原理

    我们接下来说:springboot是如何和mybatis进行整合的 1.首先,springboot中使用mybatis需要用到mybatis-spring-boot-start,可以理解为mybati ...

  2. SpringBoot学习- 3、整合MyBatis

    SpringBoot学习足迹 1.下载安装一个Mysql数据库及管理工具,同类工具很多,随便找一个都可以,我在windows下做测试项目习惯使用的是haosql 它内部集成了MySql-Front管理 ...

  3. spring学习07(整合MyBatis)

    10.整合MyBatis 10.1 相关jar包 junit <dependency> <groupId>junit</groupId> <artifactI ...

  4. Spring Boot入门系列(十九)整合mybatis,使用注解实现动态Sql、参数传递等常用操作!

    前面介绍了Spring Boot 整合mybatis 使用注解的方式实现数据库操作,介绍了如何自动生成注解版的mapper 和pojo类. 接下来介绍使用mybatis 常用注解以及如何传参数等数据库 ...

  5. Java学习笔记-spring整合mybatis

    这个项目就是一个例子,只有添加图书的功能: 项目架构: resource: 整合流程: 1.pom文件节点,这两个是整合用的,其他节点不再赘述: <!-- https://mvnreposito ...

  6. SpirngBoot整合Mybatis Plus多数据源

    导读 有一个这样子的需求,线上正在跑的业务,由于业务发展需要,需重新开发一套新系统,等新系统开发完成后,需要无缝对接切换,当初具体设计见草图. 添加依赖 <!--lombok--> < ...

  7. springboot学习四:整合mybatis

    在application.properties加入配置 ## Mybatis 配置 mybatis.typeAliasesPackage=org.spring.springboot.domain my ...

  8. Spring Boot学习笔记(五)整合mybatis

    pom文件里添加依赖 <!-- 数据库需要的依赖 --> <dependency> <groupId>org.mybatis.spring.boot</gro ...

  9. spring boot整合mybatis基于注解开发以及动态sql的使用

    让我们回忆一下上篇博客中mybatis是怎样发挥它的作用的,主要是三类文件,第一mapper接口,第二xml文件,第三全局配置文件(application.properties),而今天我们就是来简化 ...

随机推荐

  1. 面试(2)-java-se-HashSet和TreeSet12

    Set是java中一个不包含重复元素的collection.更正式地说,set 不包含满足 e1.equals(e2) 的元素对 e1 和 e2,并且最多包含一个 null 元素.正如其名称所暗示的, ...

  2. nginx 防火墙、权限问题

      1.nginx安装,配置完成之后,尝试访问没有响应,主机可以ping通,/var/log/nginx/access.log日志没有查到任何记录 解决方法:查看linux防火墙,关闭 命令:ipta ...

  3. mysql 批量更新与批量更新多条记录的不同值实现方法

    作者: 字体:[增加 减小] 类型:转载 时间:2013-10-02 我要评论 在mysql中批量更新我们可能使用update,replace into来操作,下面小编来给各位同学详细介绍mysql ...

  4. 深入理解:Linear Regression及其正则方法

    这是最近看到的一个平时一直忽略但深入研究后发现这里面的门道还是很多,Linear Regression及其正则方法(主要是Lasso,Ridge, Elastic Net)这一套理论的建立花了很长一段 ...

  5. CPU频率

    CPU频率 CPU频率,就是CPU的时钟频率,简单说是CPU运算时的工作的频率(1秒内发生的同步脉冲数)的简称. 概念 CPU频率,就是CPU的时钟频率,简单说是CPU运算时的工作的频率(1秒内发生的 ...

  6. HTML学习(一)

    文本输出/超链接 <!--/* * @<h1></h1>到<h6></h6>六个h标签,分别表示不同大小的字体.h1最大,h6最小 * @< ...

  7. Git: 本地创建版本库用于多处同步

    问题背景 目前有一个 Android 和 一个 iOS 项目,两个项目底层使用相同的 C++ 代码.由于在开发迭代中代码时常更新,而且往往是今天 Android 部分修改一小部分,明天 iOS 部分修 ...

  8. sqlserver存储过程及mybatis调用——待续

    创建带输入参数存储过程 use yanantestgoif exists (select * from sys.objects where name='yanan')drop procedure ya ...

  9. junit4X系列--Assert与Hamcrest

    原文出处:http://www.blogjava.net/DLevin/archive/2012/05/12/377960.html.感谢作者无私分享 到目前,JUnit4所有的核心源码都已经讲解过了 ...

  10. linkin大话设计模式--单例模式

    linkin大话设计模式 开文前先弱弱的问一句:什么是设计模式?我在研究java2ee的时候有研究过,在学js的时候也有看到.设计模式的概念最早源于建筑设计大师<建筑的永恒算法>一书,它表 ...