美国上市公司,专注Java培训21年

Java教程:一个不安分的JDBC驱动解析


连接, 连接, 总是连接!

生活中肯定有比数据库连接更有趣的事情。

1数据库连接

又到了数据库连接的时间!

那些码农把数据库参数送过来, Oracle , Db2, Sybase, SQL Server这些JDBC Driver 懒洋洋起来去干活赚钱。

小东也是其中之一, 每天的工作就是连接Mysql 数据库, 发出SQL查询, 获取结果集。

工作稳定, 收入不菲, 只是日复一日,年复一年, 枯燥的工作实在是太令人厌烦了。

有时候小东会和其他JDBC Driver 聊天, 谈起有些不着调的码农, 创建一个Connection, 发出一个查询, 处理完ResultSet后 , 立刻就把Connection给关掉了。

“他们简直不知道我们建立一个数据连接有多么辛苦, 先通过Socket 建立TCP连接, 然后还要有应用层的握手协议, 唉, 不知道要干多少脏活累活, 这帮码农用完就关, 真是浪费啊。 ”

“还有更可气的, 有些家伙使用了PreparedStatement , 我通知数据库做了预编译, 制定了查询计划, 为此我还花费了不菲的小费。 但是只执行了一次查询, Connection就关掉了, PreparedStatement 也就不可用了, 现在数据库都懒的给我做预编译了 !”

“你们这都是好的, 有些极品根本就不关闭Connection, 最后让这个Connection 进入了不可控状态。 ”

“我们啊, 都把宝贵的生命都献给了数据库连接事业...... ”

抱怨归抱怨, 大部分人都安于现状,逆来顺受了。

2、向Tomcat取经

但是不安分的小东决心改变, 他四处拜访取经, 但是一无所获。

这一天在Tomcat村遇到了Tomcat 村长, 看到了村长处理Http请求的方式, 突然间看到了曙光。

村长说: 我们本来是一个线程处理一个Http请求 , 一个Http请求来到我们这里以后, 我并不会新建一个线程来处理, 而是从一个小黑屋叫来一个线程直接干活, 干完活以后再回到小黑屋待着。

小东问: 小黑屋是什么?

(码农翻身注: 参见文章《我是一个线程》)

村长说: “学名是线程池, 为了充分利用资源, 我在启动时就建立了一批线程, 放到线程池里, 需要线程时直接去取就可以了。 ”

“那要是线程池里的线程都被派出去了怎么办 ? ”

"要么新创建线程, 要么新来的Http请求就要等待了。 实际上,线程也不是无限可用的资源, 也得复用。"

小东心想, 我们JDBC也可以这么搞啊, 把数据库连接给缓存下来, 随用随取, 一来正好可以控制码农们无限制的连接数据库; 二来可以减少数据库连接时间; 第三还可以复用Connection上的PreparedStatement, 不用老是找数据库预编译了。

3、数据库连接池

建立数据库连接池不是那么一帆风顺的, 小东的第一次尝试是创建了一个ConnectionPool这个接口:

【一个不安分的JDBC驱动解析】

里边有两个重要的方法, getConnection(), 用于从池中取出一个让用户使用;

releaseConnection() 把数据库连接放回池中去。

小东想, 只要我写一个ConnectionPool的实现类, 里边可以维护一个管理数据库连接的数据结构就行了, 码农们用起来也很方便, 他们肯定会喜欢的。

可是事与愿违, 几乎没有人用这样的接口。

小东经过多方打探才明白, 码农们要么是用DriverManager来获得Connection, 要么是使用DataSource来得到Connection;关闭的时候,只需要调用Connection.close() 就可以了。

这样的代码已经有很多了, 而小东的新方案相当于新的接口, 需要改代码才能用, 话说回来, 谁愿意没事改代码玩? 尤其是正在运行的系统。

再做一次改进吧, 小东 去找Java 这个设计高手求教。

Java 说:“虽然ConnectionPool概念不错, 但是具体的实现最好隐藏起来, 对码农来说,还是通过DataSource 来获取Connection, 至于这个Connection 是新建的还是从连接池中来的, 码农不应该关心, 所以应该加一个代理Proxy,把物理的Connection给封装起来, 然后把这个Proxy返回给码农。”

“那这个Proxy是不是得和您定义的接口Connection 接口保持一致? 要不然码农还得面对新东西。”

“是的, 这个Proxy 应该也实现JDBC的Connection 接口, 像这样: ”

【一个不安分的JDBC驱动解析】

小东说: ”奥, 我明白了, 当码农从DataSource中获得Connection的时候, 我返回的其实是一个ConnectionProxy , 其中封装了一个从ConnectionPool来的Connection , 然后把各种调用转发到这个实际的physicalConn的方法去, 关键点在close, 并不会真的关闭Connection, 而是放回到ConnectionPool “

“哈哈, 看来你已经get了, 这就是面向接口编程的好处啊, 你给码农返回了一个ConnectionProxy, 但是码农们一无所知, 仍然以为是在使用Connection , 这是一次成功的‘欺骗’啊”

“但是你定义的Connection 接口中的方法实在是太多了, 足足有50多个, 我这个Proxy类实际上只关注那么几个, 例如close方法, 其他的都是转发而已,这么多无聊的转发代码是在是太烦人了”

Java说: “还有一种办法,可以用动态代理啊”

小东问:“什么是动态代理?”

"刚才我们提供的那个Proxy可以称为静态代理, 我的动态代理不用你写一个类去实现Connection, 完全可以在运行期来做, 还是先来看代码吧"

【一个不安分的JDBC驱动解析】

“代码有点难懂, 你看,这里没有声明一个实际的类来实现Connection 接口 , 而是用动态代理在运行时创建了一个类Proxy.newProxyInstance(....) , 重点部分就是InvocationHandler, 在他的invoke方法中, 我们判断下被调用的方法是不是close, 如果是, 就把Connection 放回连接池, 如果不是,就调用实际Connection的方法。” Java 解释了一通。

小东惊叹到:“代码虽然难懂, 但是精简了好多,我对Java 反射不太熟, 回头我再仔细研究下。”

(码农翻身注: 不熟悉Java动态代理的也可以研究下, 这是一项重要的技术)

经过一番折腾, 数据库连接池终于隐藏起来了, 码农们可以使用原有的方式去获取Connection, 只是不知道背后其实发生了巨变。

当然也不可能让码农完全意识不到连接池, 毕竟他们还得去设置一些参数, 小东定义了一些:

【一个不安分的JDBC驱动解析】

数据库连接池获得了巨大的成功, 几乎成了每一个Java Web 项目的标配, 不一样的JDBC驱动小东也获得了极高的荣誉, 后面等着他的还会有哪些挑战呢?


【免责声明】本文部分系转载,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,如涉及作品内容、版权和其它问题,请在30日内与我们联系,我们会予以重改或删除相关文章,以保证您的权益!

Java开发高端课程免费试学

大咖讲师+项目实战全面提升你的职场竞争力

  • 海量实战教程
  • 1V1答疑解惑
  • 行业动态分析
  • 大神学习路径图

相关推荐

更多
  • 一文搞懂为啥你的应用内存泄漏?
    一文搞懂为啥你的应用内存泄漏?
    最近在项目中偶尔会发现内存泄漏现象。一开始还是一脸懵逼的查来查去:这怎么就泄漏了?这样竟然没泄漏?一直没有个清晰地思路。这几天闲下来,打算认真整理学习一下 详情>>

    2017-10-20

  • Java教程:一个不安分的JDBC驱动解析
    Java教程:一个不安分的JDBC驱动解析
    连接, 连接, 总是连接!生活中肯定有比数据库连接更有趣的事情。每天的工作就是连接Mysql 数据库, 发出SQL查询, 获取结果集。 详情>>

    2017-02-21

  • Java开班时间

    收起