开发者学堂课程【MySQL 实战进阶:MySQL Java 开发实战】学习笔记,与课程紧密联系,让用户快速学习知识
课程地址:https://developer.aliyun.com/learning/course/83/detail/1307
MySQL Java 开发实战
内容介绍:
一、深入浅出 ORM 框架 MyBatis
二、连接池框架构剖析和最佳实践
三、Java应用性能问题诊断技巧
一、深入浅出 ORM 框架 MyBatis
1.为什么要选 MyBatis
下面我们进入第一部分深入浅出 ORM 框架 MyBatis,为什么要用 MyBatis,很久以前我们其实是直接用 JDBC 去进行跟数据库进行查询的,用直接用 JDBC 的话,它的好处就是比较简单直接,他的缺点的话就是开发效率比较低,因为你如果自己去用 JDBC 写程序的话,需要有大量的手工写代码的这个工作,而且会有很多的这个代码的重复,所以后来逐渐演化出了这个 ORM 的框架。
ORM 框架的话最早期的话有 Hibernate,然后以及 JPA 的这个规范,Hibernate 是一个比较完善的一个 ORM 的框架,能够屏蔽底层的数据库的差异,自动帮我们根据我们这个 HQ 语言去生成底下的对应的数据库的这个方言,它的缺点是对关联查询不友好,同时他的动态 SQL 的能力也不是很好,就很难去写出高效的 SQL。
在国内其实主要还是流行 Hibernate,因为它比较倾向轻量级,同时对动态 SQL 以及关联查询都会比较好,同时他在国内这个生态里面也是比较流行,缺点就是因为它绑定了的 ADV,你可能因为你要去手写 SQL来进行动态拼接,那你很难从一个DB 的切换,也不是很大的问题,因为平时我们很少去切换 DB。
2.MyBatis 基本概念介绍
MyBatis 我认为可以分为三层,第一层是接口层、第二层是核心层,第三层是基础层,接口层面主要是通过提供的API来对数据库进行增删改查 MyBatis API,然后核心层有 SQL 预处理、SQL 执行和结果集映射,SQL 预处理就是对代码里面的一些变量进行绑定,以及动态 SQL 的一个生成。
SQL 执行就是把 SQL生成好的接口,然后通过 JDBC 的驱动传到对应面执行负责,而且负责网络通信部分,结果集映射就是把数据库返回的结果从关系型数据转换成为 Java 里面的数据,基础层就是一部分日志,还有事务管理、缓存、连接池,动态代理、配置解析。
日志的部分的话,主要是做框架里面的日志输出,以及 SQL 的输出,输出管理的话主要是对 JDBC 的一些事务数据库的管理,MyBatis 一般不会去做这个事情,还有缓存,因为比如 Hibernate 和 MyBatis 都提供一级缓存和二级缓存,它能够把结果集缓存在 GVM 内存的内部,这样一个好处就是它比较快,但是缺点会占用内存,建议大家还是多使用分布式的方法,MyBatis 提供连接词功能,连接能够加速查询,能够提高性能,但很多时候我们还是会选择市面上更成熟更专业的一些连接词,动态代理到底是什么?
就是我们在用 MyBatis 编程的时候,我们有基于注解的方式,有基于现有配置的方式,但其实核心来说都是通过 map 接口去对去执行数据库查询,这个接口它本身没有实现,他的实现就是配置的 SQL 语句。动态代理在运行时就会帮我们生成代理,然后我们去调用接口的时候,它会转化成实际的 SQL 语句。MyBatis 有大量配置,也要配置一些模块,读取配置,并把它映射为配置属性。
3.MyBatis 从0开始搭建工程
下面我们讲一下怎么样去重新开始搭建一个 MyBatis 的工程,现在最主流的还是用框架结合,还有连接词要去做结合,技术选型就是最新的 spring-boot2,然后因为我们需要去开发一个工程,所以说可以选择 spring mvc 框架,持久层可以选用MyBatis框架。在连接词的话,可以选择其他的连接词,这里的话是用这个cp,因为 cp 是 spring-boot2的默认连接。
然后底下还有数据库,推荐大家使用 RDS MySQL。这也是国内比较流行的一个数据库,数据库已选之后,你可以在 spring 官网上面,就是下面这个链接http://spring.io/quickstart,通过链接填入相关信息,就可以生成一个项目的模板,这个模板下载下来之后,在你的 IDE 里面去打开导入项目,这样的话就有了你开始工作的一个项目模板。
下面有一部分肯定要一个 spring boot starter 这个依赖的作用,我们管理 Skype,开始做spring boot项目的时候,这个一些默认的依赖都已经在这个这个 start 里面,我们还用了 springweb mvc。用最新的2.1版本的,我们用了 MyBatis,所以还需要去依赖 MyBatis starter。
需要注意的是 MyBatis 并没有 spring 的官方的 starter,而是 MyBatis 社区提供了一个 MyBatis spring boot starter。我们还要学习 JDBC 的 MySQL 版的实现,就是 MySQL connector Java 标,因为 JDBC 其实是一套规范,一套 API,具体实现是各个数据库厂商去实现的,比如说 MYSQL 或者 Oracle 或 SQL server 都会有对应的实现。
我们依赖 spring boot 测试框架,除此之外的话,为了减少代码量用 MacBook。我们来看一下工程结构,这是一个最简单的一个项目,工程结构里面可以从下往上看这个控制器 controller,这有一个自己的控制器,一个层主要是数据库的增删改查的一个接口,一个 model 层里面主要是在Java里面的对象的类定义,还有service 层,Service 又有这个API层和 implementation层,API 层主要是接口定义,implementation 层主要是接口实现,在接口里面会调用 MYSQL 层或者去掉一些业务层的东西,实现业务逻辑的组装和编排。这是我们启动的入口,这次选择的话,还是用这个 x mile 的方式去配置 MyBatis ,所以说在这个过程里面,你需要去增加一个目录里面去放入你的这个 map 文件,底下的是 spring 的配置文件,还有配置 MyBatis 文件,MyBatis 文件可以通过这个编程的方式去实现。
当工程启动了之后,你可以去浏览器里面输入这个链接,这里的端口还有路径都是自己定的,可以验证工厂是否正常运作。
二、连接池框架构剖析和最佳实践
前面讲到的这个MyBatis的原理。组建框架和它的一个基本的项目搭建,我们再来讲这个连接词框架,druid HikariCP
1.为什么要用连接池
如果不用连接池,那么你每次查询都需要去建立连接,连接的话它有两层,第一层是 tcp 层,第二层是 mexico 协议里面的,这两个协议的话大概需要有多个tcp数据包,这些都需要时间的,除此之外内部还需要处理,所以建立连接是比较费时间的一个操作,第二的话就是对于当代的这个应用来说,应用服务器很多台,数据库服务器相比之下可能会少一些,应用服务器在业务高峰期的时候会存在很多DB的连接,DB 承载的连接数目是有限的,所以说如果不用连接池,连接的数量它就会受限制,可能会把这个导致 DB 的性能严重降低,除此之外的话,如果我们不用连接池,就意味着我们每次去执行这个 MYSQL 语句的时候,都需要创建 TCB 链接和关闭 TCB 链接,关闭动作一般来说是在这个应用端去完成,这样就会导致应用服务器上存在较多的 TCB 连接,而这些连接的状态,连接数达到一定数量之后,会有可能会引起问题,比如说端口不够用之类的问题。
用连接池的收益,第一个,因为他不用每次都去建立连接,而是直接从连接池里面去取连接,所以说它的这个性能会更好。
第二个就是因为连接池可以控制连接的数量,以及当连接出现问题的时候,能够去帮我们探测连接是否存活,如果连接中断的话,连接池会自动帮我们重建,比如说你用一个 RDS MySQL,那你有可能会需要对 MYSQL 的实例进行配置变更,比如说规格提高,磁盘空间,遇到一些奇怪问题,或者压力大的时候,希望能够重启MySQL 的时候,都会导致 MySQL 的连接中断。那如果有连接池就能够处理好这些问题,不会导致应用里面去拿到的这个连接不可用,就会导致业务问题。除此之外,连接池还能够对连接进行灵活的管理,能够连接池很多配置,能够连接池状态做一个监控,能够看到我连接里面的连接的数量和一些性能指标。
连接池的架构最顶层应该是接口层,它下面是核心层,最底下基础层,接口层的话主要其实就是比如说对于 MyBatis 来说,他需要从连接池里面拿获取连接,当连接用完需要直接关掉,它会调用连接的 close 连接的归还,核心层主要负责并发控制,连接控制,异常处理,并发控制就是连接池里的连接数量是有限的,但是我们应用里面的现场数量应该是会可能会多于连接池的连接数量,当这个连接池里的连接数量都处于活跃状态的时候,想要继续得到连接就要等待,因为数量有限的,就需要排队这种情况。
第二个的话就是同一个链接我们不能给他分配多个线层,因为对同一个连接进行多次开启事务,会引起混乱。
第二部分连接控制,就是我们需要能够动态的去调整连接时的大小,同时也要能够保证连接池里面连接数量在我们期望的这个范围内。第三部分是异常的处理,就是存在一些情况,比如说这个底下的数据库的重启,网络中断,或者说是这个连接里面发生一些协议层面的一些错误,连接已经不能使用了,那这个时候连接池就会自动帮我们去处理这些问题。把连接关掉。底下的是基础层,有配置管理,监控,定时任务,日志,字节码操纵。
下面分别简单说一下,配置管理的话,主要是连接池里面有很多的配置项,其实它的配置的点很多,那些东西需要一个解析和管理。第二个对连接池的运行,运行时需要做一个统计和监控,就能够去提供一个查看的页面。第三部分是定时任务,比如说连接池里面连接的数量超过一定的程度的时候,比如说这个空闲连接超过一定数量的时候,我们要对空闲连接做释放,这些通过定时任务完成。还有字节码操纵,其实Java框架里面存在大量的字节码操纵,会动态生成代理之类的,增加业务逻辑。
2.druid 最佳实践-参数配置
下面我们来讲一下druid最佳实践-参数配置,我这里整理了一些比较常用的参数配置,
第一个 max active,这个指的是连接词里面允许的最大的活跃连接数,连接数不会超过这个数量,这个的话需要根据应用的实际情况进行调整。
第二个 min-idle,就是如果我们这个应用里面有很多连接,连接现在都已经不使用了,这个时候你可以临时关掉多余,只保留必要的空闲连接,比如说保留十个,那这个时候你可以配置 min-idle 等于十,就会把剩下的多余的连接关闭,这样可以节省数据库的资源。
第三个是 max-wait,这个不是说是去建立连接时候的一个等待时间,而是我们应用层通过调用连接池 API 获取连接的等待时间,比如说连接池里的数据连接都已经被应用占用了,那这个时候并发连接想要获得连接的话就要等待。
max-wait就是指这个应用线程等待一个超时时间,这个的话一般可以在几秒钟,比如说一秒,三秒,四秒,五秒这样一个范围,根据你的应用实际情况来进行一个判定。
第四个 validation-query,这个的话就是连接词去探测当前连接是否健康的一个SQL语句。比如说druid对于最新版的JDBC驱动,它会去调用新的命令,如果你的这个JDBC用的比较新的话,就不会发SQL的一个命令。
第五个参数 validation-query-timeout,把这个就上面那个探测的一个超时时间,再往下是 test- on- borrow,这个的话是指你从连接池里面取出来的时候,连接池是否需要对连接进行一个健康探测。这个选项的话,以及下面的 test- on- return,我建议是关闭,因为如果打开这个选项的话,它会带来系统损失。还有个test -while- idle,这个的话建议打开,这个是控制当连接处于空闲状态的时候,是否需要去检测连接的健康状态。time -between- eviction -millis 指的是触发空闲连接健康探测的一个时间,这个的话需要跟上面的这个 test -while- idle 结合起来,你可以去配置这个超市,也可以不配置。
remove-abandoned 是是否需要开启泄漏连接的强制回收,这个默认是 false,如果说你的应用存在这个连接泄露的情况,这个时候可以选择去打开这个,但是不建议服务器长时间打开,因为打开以后,每次去获取连接的时候,他都需要去记录现场的执行对象,以便出现脸露泄露出现的时候能够去把堆栈打印出来排查问题。所以说现场不建议去开启这个,除非紧急情况下排查问题或者进行开发环境问题定位的。
remove-abandoned-timeout 是强制回收的触发时间阈值,比如说这个连接交给应用程序,它如果超过十秒钟还没给我,我就会触发对这个现场的一个强制回收。
你可以去配置,这个阈值配置太短,因为现场里面业务是需要有可能存在需要长时间使用连接,所以这个时间要比那个业务上实际合理的时间要高一些,值得注意的是这个 remove-abandoned-timeout 的单位是秒。log-abandoned 是当一个连接被探测为连接泄漏并且强制关闭的时候,是否要在日志里面输出获取连接的这个现场对账,这个跟 remove-abandoned 结合起来,如果你需要的时候,我建议你把这个 log-abandoned 打开为 true,这样就能看到具体的连接对账。下面来看一下,当你开启了空闲连接健康探测的时候,再登陆一个源码内部,它会出它会触发怎样的逻辑?
首先我们的入口是去,比如说 MyBatis 去找 druid 拿连接的时候给 connection。里面是一个循环,在循环里面他会去连接池里面取一个连接。
当这个探测空闲连接健康的开关开启的时候。那个 druid 就会检测你这个连接的空闲时间有没有超过你下面配置的预警,如果超过了,他就会去发起一个连接的健康探测,如果探测连接问题,就直接关闭连接,而且它就会回到最开头,他会去连接池里面再取一个连接,直到拿到一个可用的连接,或者说连接里面所有连接都有问题的时候,就会重新创建连接。





