php mysql jdbc_再说JDBC

上篇文章《再说Java EE》说明了一下什么是规范,有什么作用,这篇文章来细说一下JDBC。 JDBC JDBC(Java Database Connection)也是Java EE中的一个规范,所谓规范是一组接口,如JDBC接口包含在java.sql及javax.sql包中,其中java.sql属于JavaSE,javax.sql

上篇文章《再说Java EE》说明了一下什么是规范,有什么作用,这篇文章来细说一下JDBC。

JDBC

JDBC(Java Database Connection)也是Java EE中的一个规范,所谓规范是一组接口,如JDBC接口包含在java.sql及javax.sql包中,其中java.sql属于JavaSE,javax.sql属于JavaEE,部分如下图:

f4f8be48ed467520250b71da6cfefcc7.png

以上来自jdk中的src/java/sql。

因为提倡面向接口编程,所以建议仅使用JDBC规范中的类,规范与实现的关系如下:

86302d3018ff56e824610029d4506dd3.png

使用

核心API

JDBC中核心的API有: DriverManager:工厂类,用来生产Driver对象Driver:驱动程序对象的接口Connection:数据库连接对象Statement:执行静态的SQL语句的接口Resultset:结果集对象的接口

操作流程

加载数据库驱动创建数据库连接执行SQL语句,得到结果集对结果集进行CRUD处理释放资源

如图:

65de984efec7acc8f5f4ace994511f73.png

源码分析

java.sql下有48个类,javax.sql下有45个类,展开分析不太现实,本文仅分析两个类,DriverManager和Driver。不知大家注意过这个问题没有,JDBC是接口,数据库驱动是实现,那么你编写的项目是如何找到实现的呢?

控制台输出

为了可以看到驱动加载过程中输出的日志,在加载驱动Class.forName("com.mysql.jdbc.Driver")之前,加上一句:

DriverManager.setLogWriter(new java.io.PrintWriter(System.out));

即可在控制台中看到输出。

加载驱动

驱动使用很简单,将数据库驱动放到项目的lib中,在代码中写入:

Class.forName("com.mysql.jdbc.Driver");

如果使用框架,如Hebernate配置文件中写入:

com.mysql.jdbc.Driver

很明显,这两种方式都是使用反射加载驱动程序,我们来看一下驱动程序Driver的源代码,以mysql-connector-java-3.1.13为例:

package com.mysql.jdbc;

import java.sql.SQLException;

public class Driver extends NonRegisteringDriver implements java.sql.Driver {

//

// Register ourselves with the DriverManager

//

static {

try {

java.sql.DriverManager.registerDriver(new Driver());

} catch (SQLException E) {

throw new RuntimeException("Can't register driver!");

}

}

/**

* Construct a new driver and register it with DriverManager

* @throws SQLException

* if a database error occurs.

*/

public Driver() throws SQLException {

// Required for Class.forName().newInstance()

}

}

核心代码就是那段静态代码块(static{}的意思是在类加载时执行一次,并且仅此一次),可以看到静态代码断的意思是将此Driver类实例化后注册到JDBC的java.sql.DriverManager类中,所以再来看一下JDBC的DriverManager.registerDriver:

/**

* Registers the given driver with the DriverManager.

* A newly-loaded driver class should call

* the method registerDriver to make itself

* known to the DriverManager.

*

* @param driver the new JDBC Driver that is to be registered with the

* DriverManager

* @exception SQLException if a database access error occurs

*/

public static synchronized void registerDriver(java.sql.Driver driver)

throws SQLException {

if (!initialized) {

initialize();

}

DriverInfo di = new DriverInfo();

di.driver = driver;

di.driverClass = driver.getClass();

di.driverClassName = di.driverClass.getName();

// Not Required -- drivers.addElement(di);

writeDrivers.addElement(di);

println("registerDriver: " + di);

/* update the read copy of drivers vector */

readDrivers = (java.util.Vector) writeDrivers.clone();

}

即可将com.mysql.jdbc.Driver添加到DriverManager的成员变量readDrivers中,以后获取数据库连接需要这个变量的帮助。

看上面的代码发现,还调用了initialize(),查看initialize()的源码看到它调用loadInitialDrivers(),这个函数的主要作用是加载JDBC默认驱动,registerDriver执行完,控制台的输出语句为:

JdbcOdbcDriver class loaded

registerDriver: driver[className=sun.jdbc.odbc.JdbcOdbcDriver,sun.jdbc.odbc.JdbcOdbcDriver@134e4fb]

DriverManager.initialize: jdbc.drivers = null

JDBC DriverManager initialized

registerDriver: driver[className=com.mysql.jdbc.Driver,com.mysql.jdbc.Driver@157c2bd]

可以看到先加载JdbcOdbcDriver,再加载我们加入的MySQL的driver。

获取链接

加载驱动完毕后,如何获取连接,继续看DriverManager的getConnection():

// Worker method called by the public getConnection() methods.

private static Connection getConnection(

String url, java.util.Properties info, ClassLoader callerCL) throws SQLException {

java.util.Vector drivers = null;

/*

* When callerCl is null, we should check the application's

* (which is invoking this class indirectly)

* classloader, so that the JDBC driver class outside rt.jar

* can be loaded from here.

*/

synchronized(DriverManager.class) {

// synchronize loading of the correct classloader.

if(callerCL == null) {

callerCL = Thread.currentThread().getContextClassLoader();

}

}

if(url == null) {

throw new SQLException("The url cannot be null", "08001");

}

println("DriverManager.getConnection(\"" + url + "\")");

if (!initialized) {

initialize();

}

synchronized (DriverManager.class){

// use the readcopy of drivers

drivers = readDrivers;

}

// Walk through the loaded drivers attempting to make a connection.

// Remember the first exception that gets raised so we can reraise it.

SQLException reason = null;

for (int i = 0; i < drivers.size(); i++) {

DriverInfo di = (DriverInfo)drivers.elementAt(i);

// If the caller does not have permission to load the driver then

// skip it.

if ( getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) {

println(" skipping: " + di);

continue;

}

try {

println(" trying " + di);

Connection result = di.driver.connect(url, info);

if (result != null) {

// Success!

println("getConnection returning " + di);

return (result);

}

} catch (SQLException ex) {

if (reason == null) {

reason = ex;

}

}

}

// if we got here nobody could connect.

if (reason != null) {

println("getConnection failed: " + reason);

throw reason;

}

println("getConnection: no suitable driver found for "+ url);

throw new SQLException("No suitable driver found for "+ url, "08001");

}

这个函数代码比较多,但是我们关注的核心代码就一句:

Connection result = di.driver.connect(url, info);

其中di就是我们前面加载驱动后DriverManager的成员变量readDrivers包含的一个对象,也就是调用com.mysql.jdbc.driver的connect函数,但是从上面该类代码可知,它只包含一个构造函数和静态代码段,connect函数从何而来?

别忘了com.mysql.jdbc.driver继承自NonRegisteringDriver,这也是MySQL驱动下的一个类,进入该类,找到connect函数:

package com.mysql.jdbc;

/***省略引用和注释***/

public class NonRegisteringDriver implements java.sql.Driver {

/***省略其他函数和注释***/

public java.sql.Connection connect(String url, Properties info)

throws SQLException {

Properties props = null;

if ((props = parseURL(url, info)) == null) {

return null;

}

try {

Connection newConn = new com.mysql.jdbc.Connection(host(props),

port(props), props, database(props), url, this);

return newConn;

} catch (SQLException sqlEx) {

// Don't wrap SQLExceptions, throw

// them un-changed.

throw sqlEx;

} catch (Exception ex) {

throw new SQLException(Messages

.getString("NonRegisteringDriver.17") //$NON-NLS-1$

+ ex.toString()

+ Messages.getString("NonRegisteringDriver.18"), //$NON-NLS-1$

SQLError.SQL_STATE_UNABLE_TO_CONNECT_TO_DATASOURCE);

}

}

}

因为NonRegisteringDriver也是java.sql.Driver的实现,返回的也是JDBC中Connection的实现,所以如上面向接口编程,即可从DriverManager中得到MySQL的Connection。

总结

JDBC的分析介绍到此结束,如果有兴趣大家可以看一下其他数据库驱动的源码,因为都是根据JDBC而来,所以大都大同小异。

本文原创发布php中文网,转载请注明出处,感谢您的尊重!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值