赞
踩
读完本篇文章你将学到:原生jdbc开发流程,datasource数据源层,多数据源组件原理。以及它们三者之间的关系架构
使用原生jdbc来访问数据库的流程为:
- Class.forName(“com.mysql.jdbc.Driver”);
- String url = “jdbc:mysql://hostip:3306/test?user=root&password=123456″;
- Connection con = DriverManager.getConnection(url);
- Statement statement = con.createStatement();
在原生的jdbc访问过程中,重要的领域对象包括:Driver ,DriverManager ,Connection ,Statement 等等。
其实主要与数据库交互的是connection对象,连接的创建会向操作系统申请网络连接资源并占用,直到conneciton对象销毁才还给操作系统,因为每次都要申请并释放操作系统资源,所以原生开发在业务繁忙的项目中资源的释放和申请就会非常频繁。
为了避免这种频繁资源申请和释放情况,DataSource层使用连接池方式解决了这个问题。
DataSource领域模型也是建立在这些原生领域对象之上建立的代理层。
原生jdbc访问过程包括:
- static {
- try {
- java.sql.DriverManager.registerDriver(new Driver());
- } catch (SQLException E) {
- throw new RuntimeException(“Can’t register driver!”);
- }
- }
- Connection con = aDriver.driver.connect(url, info);
- return (con);
分析:我们每次执行sql我们都需要去初始化connection,执行完后又释放连接,这个过程中包括锁的金证以及与远程数据库的交互过程,因此每次connection的建立和释放所需要的成本。因此为了降低连接的建立和释放的消耗,这里就需要datasource领域模型来实现。
原生jdbc提到的连接重复建立和释放的成本问题,在datasource领域模型中使用了池技术思想,实现了连接的重复使用,避免了每次使用时都重新建立与数据库之间的连接,会产生较大的系统开销。以空间换时间的方式来提高效率。
datasource的主要API如下
- DataSource只有两个方法(确切的说是一个方法的两个重载版本),用于建立与此 DataSource 对象所表示的数据源的连接。
-
- Connection getConnection()
- Connection getConnection(String username, String password)
在阿里的DruidDataSource实现类中,我们能看到类的connections连接对象容器。
- // store
- private volatile DruidConnectionHolder[] connections;
connections连接数组结合datasource的池技术机制实现来管理数据源的连接对象。我们也可以把datasource看作业务程序和DriverManager之间的中间层,这个中间层有管理connection对象功能以及实现事务机制。
看下图,清楚DataSource与原生jdbc的关系架构。
从关系图能看出:
3. 多数据源组件AbstractRoutingDataSource 多数据源按字面理解就是 DataSource有多个,用户程序可以自动选择不同的DataSource来为自己的业务服务。因此。
根据Java面向对象的思想,用户程序会觉得多数据源组件AbstractRoutingDataSource就是数据源对象,因为多数据源组件实现了DataSource接口,有数据源接口的两个api方法,如下所示:
- Connection getConnection() throws SQLException;
-
- Connection getConnection(String username, String password)
- throws SQLException;
因此,我们可以把多数据源组件看作维护多个数据源的代理层,它们之间的关系如下图所示:
从关系图可以看出:
根据多数据源的关系结构图,可以分析出:只要用户程序根据自己的业务,在执行某项业务时候指定Stringkey,就能做到切换数据源的目的。
因此在读写分离的应用场景中,客户端程序需要识别Mybatis的Dao层执行的方法是读还是写。
Mybatis框架提供了获取方法执行的sql类型的Api
SqlCommandType type = sqlSessionFactory.getConfiguration().getMappedStatement(key).getSqlCommandType();
key的值能通过切面的JoinPoint来获得,这里我不再赘述,大家可以结合项目的RwSeparateDataSourceAspect类代码来看。
这里涉及到Spring容器中的@Aspect切面编程,这里就不对切面开发进行剖析。
有的公司产品的后台管理项目,如果只是给运营使用的话,一般项目都是一个体量比较大的maven聚合项目,在这样的一个项目中,我们就需要去访问不同的产品的数据库,这里我们就要主动的去动态切换数据源。
这种聚合项目也是要进行切面开发的,不像读写分离场景需要在Dao层进行切面开发,这里是基于业务层面进行切面开发,因此我们切点会放在Controller层或者service层。
总而言之,从多数据源的原理和应用来看,多数据源结合了ThreadLcoal传参+切面编程+池技术等多种技术方案。读写分离场景还结合了Mybatis框架的API技术,来判断sql的类型。
因此多数据源分可以简单拆分成两个阶段:用户程序指定Datasource的key;用户程序根据Key来获取对应的connection对象。
执行业务时动态切换数据源
- create database myutilproject0;
- create database myutilproject1;
-
- create table user(
- id int(11) not null primary key,
- name varchar(100),
- gender varchar(10));
-
测试类执行完成后,两张表中有了数据,分别往两个库插入了数据。
分别插入两个不同库中的表,由下面两个方法完成,不同的业务使用@DBType注解来动态切换数据源
- @DBType(DataSourceType.MASTER)
- public void insert2Master(User user){
- userMapper.insertSelective(user);
- }
-
- @DBType(DataSourceType.SLAVE)
- public void insert2Slave(User user){
- userMapper.insertSelective(user);
- }
看UserService类的几个方法
执行DynamicDatasourceAnnoApplicationTests测试类,分别运行select1和select3。这两个方法调用了select2,打印结果如下
- select1
- MASTER:11--jackdking-master==male
-
- select2
- SLAVE:11--jackdking-master==male
-
- select3
- MASTER:11--jackdking-master==male
-
- select2
- SLAVE:11--jackdking-slave==male
-
你会发现: select1调用select2时候,select2切换数据源失败;但是select3调用select1时候,数据源切换生效了。 这个坑大家自己可以思考下,有疑问可来咨询我!
读写分离切换数据源
将RwSeparateDataSourceAspect类中的下的pointcut注释去掉。
- // @Pointcut("execution(* org.jackdking.core.dao.*.*(..))")
- public void declareJoinPoint(){
- }
读写方法执行后,你会发现select方法查出从库数据:11--jackdking-slave==male。而主库写入了一条数据。
至此,读写分离就实现了,注意在测试数据动态源切换的时候一定要把读写注掉,否则会影响动态切换测试。
到这里,文章就学完了,识别下面小程序码,进入本文的技术知识点做题页面,来看看你能掌握多少,满分10分。
架构方案系列文章
Spring Boot2.0 学习示例
介绍
SpringBoot2.0-Jackdking 使用的各种示例,整合流行的中间件,此开源项目中的每个示例都是站在初学者角度,细心剖析技术实现细节,帮助初学者快速掌握 Spring Boot2.0 各组件的使用。
文章
SpringBoot学习示例—整合Redis之StringRedisTemplate(附完整项目代码):SpringBoot2.0-Redis-StringRedisTemplate
SpringBoot学习示例—Redis多个实例简单的手动配置之整合Lettuce池(附完整项目代码):SpringBoot2.0-Redis-MultilDb
SpringBoot学习示例—全面解析RedisTemplate配置及序列化、与StringRedisTemplate序列化区别(附完整项目代码):SpringBoot2.0-Redis-RedisTemplate
还要配置状态转移信息以及事件处理器逻辑的开发。完整的demo项目,请关注公众号“前沿科技bot“并发送"数据源切换"获取。

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。