第九章 连接(Connection)

Connection对象表示通过启用JDBC技术的驱动程序与数据源的连接。 数据源可以是DBMS,传统文件系统或其他具有相应JDBC驱动程序的其他数据源。 使用JDBC API的单个应用程序可能会维护多个连接。 这些连接可以访问多个数据源,或者它们都可以访问单个数据源

从JDBC驱动程序的角度来看,Connection对象表示客户端会话。 它具有关联的状态信息,例如用户ID,在该会话中使用的一组SQL语句和结果集,以及什么事务语义有效

要获得连接,应用程序可能与之相互作用:

  • DriverManager类与一个或多个驱动程序实现或DataSource实现

使用DataSource对象是首选方法,因为它增强了应用程序的可移植性,使得代码维护更加容易,并且使得应用程序可以透明地利用连接池和分布式事务。 建立与数据源连接的所有Java EE组件都使用DataSource对象来获取连接

本章介绍了各种类型的JDBC驱动程序以及Driver接口的使用,DriverManager类和基本的DataSource接口。 第11章“连接池”和第12章“分布式事务”中讨论了支持连接池和分布式事务的DataSource实现。

9.1 驱动类型(Types of Drivers)

JDBC驱动程序有许多可能的实现。 这些实现分类如下:

  • 类型1:实现JDBC API作为映射到另一个数据访问API(如ODBC)的驱动程序。 这种类型的驱动程序通常取决于本机库,这限制了其可移植性。 JDBC-ODBC Bridge驱动程序是Type 1驱动程序的示例
  • 类型2:部分以Java编程语言编写的驱动程序,以本地代码编写。 这些驱动程序使用特定于其连接的数据源的本地客户端库。 再次,由于本地代码,它们的可移植性是有限的
  • 类型3:使用纯Java客户端并使用独立于数据库的协议与中间件服务器通信的驱动程序。 然后中间件服务器将客户端的请求传达给数据源
  • 类型4:纯Java的驱动程序通常使用网络协议或文件I / O来与特定数据源进行通信。 客户端直接连接到数据源

9.2 Driver 接口(The Driver Interface)

JDBC驱动程序必须实现驱动程序接口,并且实现必须包含一个静态的初始化程序,当加载驱动程序时它将被调用。 该初始化程序使用DriverManager注册了一个新的实例

public class AcmeJdbcDriver implements java.sql.Driver {
static {
java.sql.DriverManager.registerDriver(new AcmeJdbcDriver());
}
...
}

当加载驱动程序实现时,静态初始化程序将自动注册驱动程序的实例

为了确保使用这种机制可以加载驱动程序,驱动程序需要提供一个无参数的构造函数

当DriverManager类希望与注册的驱动程序进行交互时,调用Driver方法。 驱动程序接口还包括方法acceptURL。 DriverManager可以使用此方法来确定哪个注册的驱动程序应该用于给定的URL

当DriverManager尝试建立连接时,它会调用该驱动程序的connect方法并传递该驱动程序的URL。
如果驱动程序实现了解URL,它将返回一个Connection对象,或者一个连接不能到达数据库,它将返回一个Connection对象或抛出一个SQLException,如果Driver实现不了解URL,它将返回null

9.3 加载实现java.sql.Driver的驱动程序

作为其初始化的一部分,DriverManager类将尝试加载在系统属性“jdbc.drivers”中引用的任何JDBC驱动程序类

jdbc.drivers=com.acme.jdbc.AcmeJdbcDriver

DriverManager.getConnection方法已得到增强,以支持Java Standard Edition服务提供者机制。 JDBC 4.0驱动程序必须包含文件META-INF / services / java.sql.Driver。 该文件包含JDBC驱动程序的java.sql.Driver实现的名称。 代码示例9-3显示了META-INF / services / java.sql.Driver文件的内容,以加载my.sql.driver类

备注:当前使用Class.forName()加载JDBC驱动程序的现有应用程序将继续工作,无需修改

9.4 DriverAction 接口

当驱动程序想要被DriverManager方法deregisterDriver通知时,JDBC驱动程序可以实现DriverAction接口

DriverAction实现不是直接由应用程序使用。 JDBC驱动程序可以选择在私有类中创建其DriverAction实现,以避免直接调用它
JDBC驱动程序的静态初始化块必须调用DriverManager.registerDriver(java.sql.Driver,java.sql.DriverAction)才能通知DriverManager当JDBC驱动程序被注册时调用那个DriverAction实现

public class AcmeJdbcDriver implements java.sql.Driver {
static DriverAction da;
static {
java.sql.DriverManager.registerDriver(new AcmeJdbcDriver(), da);
}
...
}

9.5 DriverManager 类

DriverManager类与Driver接口一起使用来管理JDBC客户端可用的驱动程序集。 当客户端请求连接并提供URL时,DriverManager负责查找识别URL的驱动程序,并使用该驱动程序连接到相应的数据源

DriverManager 方法包括:

  • registerDriver :该方法将驱动程序添加到可用驱动程序集中,并在加载驱动程序时隐式调用。 registerDriver方法通常由每个驱动程序提供的静态初始化程序调用
  • getConnection :JDBC客户端调用以建立连接的方法。 调用包括一个JDBC URL,DriverManager传递给列表中的每个驱动程序,直到找到一个Driver.connect方法识别URL的URL。 该驱动程序将一个Connection对象返回给DriverManager,DriverManager又将其传递给应用程序

Connection con = DriverManager.getConnection(url, user, passwd);

9.6 SQLPermission 类

SQLPermission类表示可以授予代码库的一组权限
目前唯一定义的权限是setLog。 当Applet调用其中一个DriverManager方法setLogWriter和setLogStream时,SecurityManager将检查setLog权限。 如果代码库没有setLog权限,将抛出java.lang.SecurityException异常

9.7 DataSource 接口

JDBC 2.0可选包中引入的DataSource接口是获取数据源连接的首选方法。 实现Datasource接口的JDBC驱动程序返回实现与DriverManager使用Driver接口返回的连接相同的接口Connection的连接。 使用Datasource对象可以通过使应用程序使用数据源的逻辑名称而不是提供特定于特定驱动程序的信息来提高应用程序的可移植性。 逻辑名称通过使用Java命名和目录接口(JNDI)的命名服务映射到DataSource对象。 DataSource对象表示物理数据源,并提供与该数据源的连接。 如果数据源或其相关信息发生变化,则可以简单地修改DataSource对象的属性以反映更改; 应用代码不需要更改

可以实现DataSource接口,以便透明地提供以下内容

  • 通过连接池提高性能和可扩展性
  • 通过XADataSource接口支持分布式事务

备注:DataSource实现必须包含无参数的构造函数

接下来的三个部分讨论(1)基本的DataSource属性,(2)使用JNDI API的逻辑命名如何提高应用程序的可移植性并使其更容易维护,(3)如何获取连接

9.7.1 DataSource Properties

JDBC API定义了一组属性来标识和描述DataSource实现。 特定实现所需的实际集合取决于DataSource对象的类型,即它是基本的DataSource对象,ConnectionPoolDataSource对象还是XADataSource对象。 所有DataSource实现所需的唯一属性是描述
下表描述了标准DataSource属性:

属性名称 类型 描述
databaseNam String 服务器上特定数据库的名称
dataSourceName String 数据源名称; 用于在连接池进行时命名底层的XADataSource对象或ConnectionPoolDataSource对象
description String data source描述
networkProtoco String 用于与服务器通信的网络协议
password String 密码
portNumber int 服务器正在侦听请求的端口号
roleName String 角色名
serverName int 数据库服务名称
user String 账户名

DataSource属性遵循JavaBeans 1.01规范中为JavaBeansTM组件的属性指定的约定。 DataSource实现可以使用实现特定的属性来扩充该集合。 如果添加了新的属性,它们必须被赋予与标准属性名称不冲突的名称

DataSource实现必须为其支持的每个属性提供“getter”和“setter”方法。 这些属性通常在部署DataSource对象时初始化,如CODE示例9-6中,VendorDataSource对象实现DataSource接口。

VendorDataSource vds = new VendorDataSource();
vds.setServerName("my_database_server");
String name = vds.getServerName();

DataSource属性不能直接由JDBC客户端访问。 通过在实现类上定义访问方法而不是应用程序使用的公共DataSource接口来加强此设计。 此外,客户端操作的对象可以是仅实现DataSource接口的包装器。 属性的setter和getter方法不需要暴露给客户端

9.7.2 JNDI API和应用程序可移植性

Java命名和目录接口(JNDI)API为应用程序通过网络访问远程服务提供了一种统一的方式。 本节介绍如何用于注册和访问JDBC DataSource对象。 有关此接口的完整说明,请参阅JNDI规范

使用JNDI API,应用程序可以通过指定其逻辑名称来访问DataSource对象。 使用JNDI API的命名服务将此逻辑名称映射到相应的数据源。 该方案大大增强了可移植性,因为可以更改任何DataSource属性(如portNumber或serverName),而不影响JDBC客户端代码。 事实上,应用程序可以以完全透明的方式重新定向到不同的底层数据源。 这在三层环境中特别有用,其中应用服务器隐藏访问不同数据源的细节

VendorDataSource vds = new VendorDataSource();
vds.setServerName("my_database_server");
vds.setDatabaseName("my_database");
vds.setDescription("data source for inventory and personnel");
Context ctx = new InitialContext();
ctx.bind("jdbc/AcmeDB", vds);

备注:Java EE组件使用特殊约定来命名其数据源 - 有关更多详细信息,请参阅Java EE平台规范中的第5章“命名”

9.7.3 获取一个连接来自DataSource对象

Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("jdbc/AcmeDB");
Connection con = ds.getConnection("user", "pwd");

9.7.4 关闭Connection 对象

Connection.close(),Connection.isclosed()和Connection.isValid()可能用于关闭Connection并确定Connection是否已关闭或仍然有效
一旦连接已经关闭,除了close(),isClosed()或isValid()方法之外,任何访问其任何方法的尝试将导致抛出SQLException

9.7.4.1 Connection.isClosed

Connection.isClosed()方法指示应用程序是否调用了Connection.close()方法。 该方法通常不能用于确定与数据库的连接是否有效

9.7.4.2 Connection.isValid

Connection.isValid()方法指示Connection是否仍然有效。 如果Connection.isValid()返回true,则Connection仍然有效。 如果返回值为false,则连接无效,除了close(),isClosed()或isValid()方法之外,任何访问其任何方法的尝试将导致抛出SQLException。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,194评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,058评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,780评论 0 346
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,388评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,430评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,764评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,907评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,679评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,122评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,459评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,605评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,270评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,867评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,734评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,961评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,297评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,472评论 2 348

推荐阅读更多精彩内容