专栏首页只喝牛奶的杀手浅谈Mybatis连接原理

浅谈Mybatis连接原理

众所周知数据库连接的过程,但是最近面试的人(菜面菜),都说用的SSM框架,但是我问了一下,mybatis是怎么连接上mysql的,基本上都会说:配置好的,直接用了,今天我来抛砖引玉一下,欢迎拍砖!

什么是JDBC?

Java语言访问数据库的一种规范,是一套API。JDBC (Java Database Connectivity) API,即Java数据库编程接口,是一组标准的Java语言中的接口和类,使用这些接口和类,Java客户端程序可以访问各种不同类型的数据库。JDBC规范采用接口和实现分离的思想设计了Java数据库编程的框架。接口包含在java.sql及javax.sql包中,其中java.sql属于JavaSE,javax.sql属于JavaEE。为了使客户端程序独立于特定的数据库驱动程序,JDBC规范建议开发者使用基于接口的编程方式,即尽量使应用仅依赖java.sql及javax.sql中的接口和类。

JAVA使用JDBC访问数据库的步骤:

1.得到数据库驱动程序

2.创建数据库连接

3.执行SQL语句

4.得到结果集

5.对结果集做相应的处理(增,删,改,查)

6.关闭资源:这里释放的是DB中的资源

mysql的驱动包提供了java.sql.Driver这个SPI的实现,实现类是com.mysql.jdbc.Driver,在mysql-connector-java-5.1.6.jar中,我们可以看到有一个META-INF/services目录,目录下有一个文件名为java.sql.Driver的文件,其中的内容是com.mysql.jdbc.Driver。 在运行DriverManager.getDriver并传入参数“com.mysql.jdbc.Driver”时,DriverManager会从mysql-connector-java-5.1.6.jar中找到com.mysql.jdbc.Driver并实例化返回一个com.mysql.jdbc.Driver的实例。而SPI(Service Provider Interface)是指一些提供给你继承、扩展,完成自定义功能的类、接口或者方法。

SPI是一种回调的思想,回调是指我们在使用api时,我们可以向API传入一个类或者方法,API在合适的时间调用类或者方法。SPI是在一些通用的标准中,为标准的实现产商提供的扩展点。标准在上层提供API,API内部使用了SPI,当API被客户使用时,会动态得从当前运行的classpath中寻找该SPI的实现,然后使用该SPI的实现来完成API的功能。

SPI的实现方式是:提供实现的实现类打包成Jar文件,这个Jar文件里面必须有META-INF目录,其下又有services目录,其下有一个文本文件,文件名即为SPI接口的全名,文件的内容该jar包中提供的SPI接口的实现类名。

大家看项目中Mybaits的jar包会发现:

private class SqlSessionInterceptor implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      SqlSession sqlSession = getSqlSession(
          SqlSessionTemplate.this.sqlSessionFactory,
          SqlSessionTemplate.this.executorType,
          SqlSessionTemplate.this.exceptionTranslator);
      try {
        Object result = method.invoke(sqlSession, args);
        if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
          // force commit even on non-dirty sessions because some databases require
          // a commit/rollback before calling close()
          sqlSession.commit(true);
        }
        return result;
      } catch (Throwable t) {
        Throwable unwrapped = unwrapThrowable(t);
        if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
          // release the connection to avoid a deadlock if the translator is no loaded. See issue #22
          closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
          sqlSession = null;
          Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
          if (translated != null) {
            unwrapped = translated;
          }
        }
        throw unwrapped;
      } finally {
        if (sqlSession != null) {
          closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
        }
      }
    }
  }

sqlSessionTemplate.SqlSessionInterceptor源码,有没有一种很熟悉的感觉?至于getConnection自己去看;用过ElasticSearch和Redis的童鞋,细心的童鞋会发现连接字符串都大同小异,连接都是类似的,标准的连接方式,提高效率,有效控制连接;

ElasticSearch的连接字符串:

protected SearchResponse getSearchResponse(String fieldName, String indexName) {
    client = null;
    SearchResponse response = null;
    try {
        getClient();
        MaxAggregationBuilder aggregation =
                AggregationBuilders
                        .max("agg")
                        .field(fieldName);
        SearchRequestBuilder request = client.prepareSearch(indexName).addAggregation(aggregation);
        response = request.execute().actionGet();
    } catch (Exception ex) {
        logger.error("getSearchResponse", ex);
    } finally {
        if (client != null) {
            client.close();
        }
        return response;
    }
}

Jedis连接字符串:

执行命令如下:
Jedis jedis = null;
try {
    jedis = jedisPool.getResource();
    //具体的命令
    jedis.executeCommand()
} catch (Exception e) {
    logger.error("op key {} error: " + e.getMessage(), key, e);
} finally {
    //注意这里不是关闭连接,在JedisPool模式下,Jedis会被归还给资源池。
    if (jedis != null)
        jedis.close();
}

拦截器的实现都是基于代理的设计模式实现的,简单的说就是要创造一个目标类的代理类,在代理类中执行目标类的方法并在方法之前执行拦截器代码,拦截器一般有登陆拦截器——验证会话信息,权限拦截器——验证权限信息,那么SqlSessionInterceptor是干什么的?

Mybatis拦截器设计的一个初衷就是为了供用户在某些时候可以实现自己的逻辑而不必去动Mybatis固有的逻辑。打个比方,对于Executor,Mybatis中有几种实现:BatchExecutor、ReuseExecutor、SimpleExecutor和CachingExecutor。 这个时候如果你觉得这几种实现对于Executor接口的query方法都不能满足你的要求,那怎么办呢?是要去改源码吗?当然不。我们可以建立一个Mybatis拦截器用于拦截Executor接口的query方法,在拦截之后实现自己的query方法逻辑,之后可以选择是否继续执行原来的query方法。允许你在已映射语句执行过程中的某一点进行拦截调用。有的用Mybatis拦截器统封装分页,有的用它实现读写分离等,如果读写分离还是建议配置多数据源;

spring整合mybatis之后,通过动态代理的方式,使用SqlSessionTemplate持有的sqlSessionProxy属性来代理执行sql操作,由spring管理的sqlSeesion在sql方法(增删改查等操作)执行完毕后就自行关闭了sqlSession,不需要我们对其进行手动关闭。

本文分享自微信公众号 - 只喝牛奶的杀手(killerhub),作者:只喝牛奶的杀手

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-11-09

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 外部配置存储模式

    将配置信息从应用程序部署包移出,移到一个集中的位置。 这可以提供用于简化管理和控制配置数据,以及用于在应用程序和应用程序实例之间共享配置数据的机会。

    只喝牛奶的杀手
  • 开发应该知道的Linux系统分析-网络篇

    说到网络,可以先在脑子里面有一个模型,就是你给你老家的父母视频聊天的时候,网络传输时间怎么算?当然你可能会感觉到时很快——毫秒级,但传播时间是存在的,这个跟光纤...

    只喝牛奶的杀手
  • 开发应该知道的Linux系统分析

    一谈到Linux系统分析,大多数开发觉得不了解也没有关系,但是了解了可以帮你走的更远。从开发的角度了解CPU,MEMORY,IO,NETWORK。在日常工作中我...

    只喝牛奶的杀手
  • 手把手教你在腾讯云上搭建hive3.1.2的方法

    所有操作开始前,先确定hadoop版本已经装好。具体可以看我的另一篇博客 搭建hadoop3.x

    砸漏
  • 【译】《Understanding ECMAScript6》- 第八章-Module

    目录 模块是什么 使用基础 接口标识符重命名 缺省接口 Re-exporting 非绑定import 总结 JavaScript令人困惑并且易引发错误的特性之一...

    寒月十八
  • 程序员的七夕,用30行代码让Python化身表白神器

    【导语】转眼又到了咱们中国传统的情人节七夕了,今天笔者就带大家来领略一下用 Python 表白的方式。让程序员的恋人们感受一下 IT 人的浪漫。

    AI科技大本营
  • Matlab 读写文件

    一、读取文本文件 思路: 1、用fopen来打开一个文件句柄 2、用fgetl来获得文件中的一行,如果文件已经结束,fgetl会返回-1 3、用fclo...

    week
  • 分布式监控系统Zabbix--完整安装记录(7)-使用percona监控MySQL

    前面已经介绍了分布式监控系统Zabbix-3.0.3-完整安装记录(2)-添加mysql监控,但是没有提供可以直接使用的Key,太过简陋,监控效果不佳。要想更加...

    洗尽了浮华
  • 【leetcode刷题】20T46-子集 II

    https://leetcode-cn.com/problems/subsets-ii

    木又AI帮
  • Redis 学习笔记6 - 管理Redis

    除了通过 redis.conf 文件对 Redis 进行配置外,我们还可以通过 config set 命令来个别值进行设置

    zhangyunfeiVir

扫码关注云+社区

领取腾讯云代金券