The Java Tutorials have been written for JDK 8.Java教程是为JDK 8编写的。Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available.本页中描述的示例和实践没有利用后续版本中引入的改进,并且可能使用不再可用的技术。See Java Language Changes for a summary of updated language features in Java SE 9 and subsequent releases.有关Java SE 9及其后续版本中更新的语言特性的摘要,请参阅Java语言更改。
See JDK Release Notes for information about new features, enhancements, and removed or deprecated options for all JDK releases.有关所有JDK版本的新功能、增强功能以及已删除或不推荐的选项的信息,请参阅JDK发行说明。
This section covers 本节介绍DataSource
objects, which are the preferred means of getting a connection to a data source.DataSource
对象,它们是获得数据源连接的首选方法。In addition to their other advantages, which will be explained later, 除了其他优势(稍后将解释)之外,DataSource
objects can provide connection pooling and distributed transactions.DataSource
对象还可以提供连接池和分布式事务。This functionality is essential for enterprise database computing.此功能对于企业数据库计算至关重要。In particular, it is integral to Enterprise JavaBeans (EJB) technology.特别是,它是企业JavaBeans(EJB)技术的组成部分。
This section shows you how to get a connection using the 本节介绍如何使用DataSource
interface and how to use distributed transactions and connection pooling.DataSource
接口获取连接,以及如何使用分布式事务和连接池。Both of these involve very few code changes in your JDBC application.这两种方法都很少涉及JDBC应用程序中的代码更改。
The work performed to deploy the classes that make these operations possible, which a system administrator usually does with a tool (such as Apache Tomcat or Oracle WebLogic Server), varies with the type of 为部署使这些操作成为可能的类而执行的工作(系统管理员通常使用工具(如Apache Tomcat或Oracle WebLogic Server)根据所部署的DataSource
object that is being deployed.DataSource
对象的类型而不同。As a result, most of this section is devoted to showing how a system administrator sets up the environment so that programmers can use a 因此,本节的大部分内容专门介绍系统管理员如何设置环境,以便程序员可以使用数据源对象获取连接。DataSource
object to get connections.
The following topics are covered:涵盖以下主题:
In Establishing a Connection, you learned how to get a connection using the 在建立连接时,您学习了如何使用DriverManager
class.DriverManager
类获取连接。This section shows you how to use a 本节将介绍如何使用DataSource
object to get a connection to your data source, which is the preferred way.DataSource
对象获得到数据源的连接,这是首选的方法。
Objects instantiated by classes that implement the 由实现DataSource
represent a particular DBMS or some other data source, such as a file. DataSource
的类实例化的对象表示特定的DBMS或某些其他数据源,如文件。A DataSource
object represents a particular DBMS or some other data source, such as a file. DataSource
对象表示特定DBMS或其他数据源,如文件。If a company uses more than one data source, it will deploy a separate 如果一家公司使用多个数据源,它将为每个数据源部署一个单独的DataSource
object for each of them. DataSource
对象。The DataSource
interface is implemented by a driver vendor. DataSource
接口由驱动程序供应商实现。It can be implemented in three different ways:它可以通过三种不同的方式实现:
DataSource
implementation produces standard Connection
objects that are not pooled or used in a distributed transaction.DataSource
实现生成标准Connection
对象,这些对象在分布式事务中不被池化或使用。DataSource
implementation that supports connection pooling produces Connection
objects that participate in connection pooling, that is, connections that can be recycled.DataSource
实现生成参与连接池的Connection
对象,即可以回收的连接。DataSource
implementation that supports distributed transactions produces Connection
objects that can be used in a distributed transaction, that is, a transaction that accesses two or more DBMS servers.DataSource
实现生成可在分布式事务中使用的Connection
对象,即访问两个或多个DBMS服务器的事务。A JDBC driver should include at least a basic JDBC驱动程序至少应该包括一个基本的DataSource
implementation. DataSource
实现。For example, the Java DB JDBC driver includes the implementation 例如,Java DB JDBC驱动程序包括org.apache.derby.jdbc.ClientDataSource
and for MySQL, com.mysql.jdbc.jdbc2.optional.MysqlDataSource
. org.apache.derby.jdbc.ClientDataSource
的实现,用于MySQL,包括com.mysql.jdbc.jdbc2.optional.MysqlDataSource
。If your client runs on Java 8 compact profile 2, then the Java DB JDBC driver is 如果您的客户机在Java 8 compact profile 2上运行,那么Java DB JDBC驱动程序是org.apache.derby.jdbc.BasicClientDataSource40
. org.apache.derby.jdbc.BasicClientDataSource40
。The sample for this tutorial requires compact profile 3 or greater.本教程的示例需要compact profile 3或更高版本。
A 支持分布式事务的DataSource
class that supports distributed transactions typically also implements support for connection pooling. DataSource
类通常还实现对连接池的支持。For example, a 例如,EJB供应商提供的DataSource
class provided by an EJB vendor almost always supports both connection pooling and distributed transactions.DataSource
类几乎总是支持连接池和分布式事务。
Suppose that the owner of the thriving chain of The Coffee Break shops, from the previous examples, has decided to expand further by selling coffee over the Internet.假设从前面的例子来看,这家咖啡休息店连锁店生意兴隆,店主决定通过互联网销售咖啡来进一步扩张。With the large amount of online business expected, the owner will definitely need connection pooling.由于预计会有大量在线业务,所有者肯定需要连接池。Opening and closing connections involves a great deal of overhead, and the owner anticipates that this online ordering system will necessitate a sizable number of queries and updates.打开和关闭连接涉及大量开销,所有者预计该在线订购系统将需要大量的查询和更新。With connection pooling, a pool of connections can be used over and over again, avoiding the expense of creating a new connection for every database access.通过连接池,可以反复使用连接池,从而避免为每次数据库访问创建新连接的开销。In addition, the owner now has a second DBMS that contains data for the recently acquired coffee roasting company.此外,所有者现在还有第二个数据库管理系统,其中包含最近收购的咖啡烘焙公司的数据。This means that the owner will want to be able to write distributed transactions that use both the old DBMS server and the new one.这意味着所有者希望能够编写同时使用旧DBMS服务器和新DBMS服务器的分布式事务。
The chain owner has reconfigured the computer system to serve the new, larger customer base.连锁店老板已经重新配置了计算机系统,以服务于新的、更大的客户群。The owner has purchased the most recent JDBC driver and an EJB application server that works with it to be able to use distributed transactions and get the increased performance that comes with connection pooling.所有者购买了最新的JDBC驱动程序和一个EJB应用程序服务器,它与之配合使用,以便能够使用分布式事务并获得连接池带来的更高性能。Many JDBC drivers are available that are compatible with the recently purchased EJB server.许多JDBC驱动程序都与最近购买的EJB服务器兼容。The owner now has a three-tier architecture, with a new EJB application server and JDBC driver in the middle tier and the two DBMS servers as the third tier.所有者现在拥有一个三层体系结构,中间层有一个新的EJB应用服务器和JDBC驱动程序,两个DBMS服务器作为第三层。Client computers making requests are the first tier.发出请求的客户端计算机是第一层。
The system administrator needs to deploy 系统管理员需要部署DataSource
objects so that The Coffee Break's programming team can start using them. DataSource
对象,以便咖啡休息的编程团队可以开始使用它们。Deploying a 部署DataSource
object consists of three tasks:DataSource
对象包括三项任务:
DataSource
classDataSource
类的实例First, consider the most basic case, which is to use a basic implementation of the 首先,考虑最基本的情况,即使用DataSource
interface, that is, one that does not support connection pooling or distributed transactions. DataSource
接口的基本实现,即不支持连接池或分布式事务的接口。In this case there is only one 在这种情况下,只需要部署一个DataSource
object that needs to be deployed. DataSource
对象。A basic implementation of DataSource
produces the same kind of connections that the DriverManager
class produces.DataSource
的基本实现产生的连接类型与DriverManager
类产生的连接类型相同。
Suppose a company that wants only a basic implementation of 假设一家只需要DataSource
has bought a driver from the JDBC vendor DB Access, Inc. DataSource
基本实现的公司从JDBC供应商DB Access,Inc.购买了一个驱动程序。This driver includes the class 此驱动程序包括实现com.dbaccess.BasicDataSource
that implements the DataSource
interface. DataSource
接口的com.dbaccess.BasicDataSource
类。The following code excerpt creates an instance of the class 下面的代码摘录创建类BasicDataSource
and sets its properties. BasicDataSource
的实例并设置其属性。After the instance of 部署BasicDataSource
is deployed, a programmer can call the method DataSource.getConnection
to get a connection to the company's database, CUSTOMER_ACCOUNTS
. BasicDataSource
实例后,程序员可以调用DataSource.getConnection
方法来获得到公司数据库CUSTOMER_ACCOUNTS
的连接。First, the system administrator creates the 首先,系统管理员使用默认构造函数创建BasicDataSource
object ds
using the default constructor. BasicDataSource
对象ds
。The system administrator then sets three properties. 然后,系统管理员设置三个属性。Note that the following code is typically be executed by a deployment tool:请注意,以下代码通常由部署工具执行:
com.dbaccess.BasicDataSource ds = new com.dbaccess.BasicDataSource(); ds.setServerName("grinder"); ds.setDatabaseName("CUSTOMER_ACCOUNTS"); ds.setDescription("Customer accounts database for billing");
The variable 变量ds
now represents the database CUSTOMER_ACCOUNTS
installed on the server. ds
现在表示服务器上安装的数据库CUSTOMER_ACCOUNTS
。Any connection produced by the BasicDataSource
object ds
will be a connection to the database CUSTOMER_ACCOUNTS
.BasicDataSource
对象ds
生成的任何连接都将是到数据库CUSTOMER_ACCOUNTS
的连接。
With the properties set, the system administrator can register the 通过设置属性,系统管理员可以使用JNDI(Java命名和目录接口)命名服务注册BasicDataSource
object with a JNDI (Java Naming and Directory Interface) naming service. BasicDataSource
对象。The particular naming service that is used is usually determined by a system property, which is not shown here. 所使用的特定命名服务通常由系统属性确定,此处未显示该属性。The following code excerpt registers the 以下代码摘录注册BasicDataSource
object and binds it with the logical name jdbc/billingDB
:BasicDataSource
对象,并将其与逻辑名称jdbc/billingDB
绑定:
Context ctx = new InitialContext(); ctx.bind("jdbc/billingDB", ds);
This code uses the JNDI API. 此代码使用JNDIAPI。The first line creates an 第一行创建一个InitialContext
object, which serves as the starting point for a name, similar to root directory in a file system. InitialContext
对象,作为名称的起点,类似于文件系统中的根目录。The second line associates, or binds, the 第二行将BasicDataSource
object ds
to the logical name jdbc/billingDB
. BasicDataSource
对象ds
关联或绑定到逻辑名称jdbc/billingDB
。In the next code excerpt, you give the naming service this logical name, and it returns the 在下一段代码摘录中,您为命名服务提供了这个逻辑名称,它将返回BasicDataSource
object. BasicDataSource
对象。The logical name can be any string. 逻辑名称可以是任何字符串。In this case, the company decided to use the name 在本例中,公司决定使用名称billingDB
as the logical name for the CUSTOMER_ACCOUNTS
database.billingDB
作为CUSTOMER_ACCOUNTS
数据库的逻辑名称。
In the previous example, 在前面的示例中,jdbc
is a subcontext under the initial context, just as a directory under the root directory is a subdirectory. jdbc
是初始上下文下的子上下文,就像根目录下的目录是子目录一样。The name 名称jdbc/billingDB
is like a path name, where the last item in the path is analogous to a file name. jdbc/billingDB
类似于路径名,路径中的最后一项类似于文件名。In this case, 在本例中,billingDB
is the logical name that is given to the BasicDataSource
object ds
. billingDB
是给定给BasicDataSource
对象ds
的逻辑名称。The subcontext 子文本jdbc
is reserved for logical names to be bound to DataSource
objects, so jdbc
will always be the first part of a logical name for a data source.jdbc
是为绑定到DataSource
对象的逻辑名称保留的,因此jdbc
将始终是数据源逻辑名称的第一部分。
After a basic 在系统管理员部署了基本的DataSource
implementation is deployed by a system administrator, it is ready for a programmer to use. DataSource
实现之后,就可以供程序员使用了。This means that a programmer can give the logical data source name that was bound to an instance of a 这意味着程序员可以给出绑定到DataSource
class, and the JNDI naming service will return an instance of that DataSource
class. DataSource
类实例的逻辑数据源名称,JNDI命名服务将返回该DataSource
类的实例。The method 然后可以对该getConnection
can then be called on that DataSource
object to get a connection to the data source it represents. DataSource
对象调用getConnection
方法,以获取到它所表示的数据源的连接。For example, a programmer might write the following two lines of code to get a 例如,程序员可能会编写以下两行代码来获取一个DataSource
object that produces a connection to the database CUSTOMER_ACCOUNTS
.DataSource
对象,该对象生成到数据库CUSTOMER_ACCOUNTS
的连接。
Context ctx = new InitialContext(); DataSource ds = (DataSource)ctx.lookup("jdbc/billingDB");
The first line of code gets an initial context as the starting point for retrieving a 第一行代码获取初始上下文作为检索DataSource
object. DataSource
对象的起点。When you supply the logical name 将逻辑名称jjdbc/billingDB
to the method lookup
, the method returns the DataSource
object that the system administrator bound to jdbc/billingDB
at deployment time. Because the return value of the method lookup
is a Java Object
, we must cast it to the more specific DataSource
type before assigning it to the variable ds
.dbc/billingDB
提供给方法lookup
时,该方法返回系统管理员在部署时绑定到jdbc/billingDB
的数据源对象。因为方法lookup
的返回值是一个JavaObject
,所以在将其分配给变量ds之前,必须将其转换为更具体的数据源类型。
The variable 变量ds
is an instance of the class com.dbaccess.BasicDataSource
that implements the DataSource
interface. ds
是实现DataSource
接口的类com.dbaccess.BasicDataSource
的实例。Calling the method 调用方法ds.getConnection
produces a connection to the CUSTOMER_ACCOUNTS
database.ds.getConnection
生成到CUSTOMER_ACCOUNTS
数据库的连接。
Connection con = ds.getConnection("fernanda","brewed");
The >getConnection方法只需要用户名和密码,因为变量getConnection
method requires only the user name and password because the variable ds
has the rest of the information necessary for establishing a connection with the CUSTOMER_ACCOUNTS
database, such as the database name and location, in its properties.ds
在其属性中包含与CUSTOMER_ACCOUNTS
数据库建立连接所需的其余信息,例如数据库名称和位置。
Because of its properties, a 由于其属性,DataSource
object is a better alternative than the DriverManager
class for getting a connection. DataSource
对象比DriverManager
类更适合获得连接。Programmers no longer have to hard code the driver name or JDBC URL in their applications, which makes them more portable. 程序员不再需要在他们的应用程序中硬编码驱动程序名或JDBCURL,这使它们更具可移植性。Also, 此外,DataSource
properties make maintaining code much simpler. DataSource
属性使维护代码更加简单。If there is a change, the system administrator can update data source properties and not be concerned about changing every application that makes a connection to the data source. 如果有更改,系统管理员可以更新数据源属性,而不必担心更改与数据源建立连接的每个应用程序。For example, if the data source were moved to a different server, all the system administrator would have to do is set the 例如,如果数据源被移动到另一台服务器,系统管理员只需将serverName
property to the new server name.serverName
属性设置为新的服务器名称。
Aside from portability and ease of maintenance, using a 除了可移植性和易于维护外,使用DataSource
object to get connections can offer other advantages. DataSource
对象获取连接还可以提供其他优势。When the 当实现DataSource
interface is implemented to work with a ConnectionPoolDataSource
implementation, all of the connections produced by instances of that DataSource
class will automatically be pooled connections. DataSource
接口以使用ConnectionPoolDataSource
实现时,该DataSource
类的实例生成的所有连接将自动成为池连接。Similarly, when the 类似地,当DataSource
implementation is implemented to work with an XADataSource
class, all of the connections it produces will automatically be connections that can be used in a distributed transaction. DataSource
实现实现为与XADataSource
类一起工作时,它生成的所有连接将自动成为可在分布式事务中使用的连接。The next section shows how to deploy these types of 下一节将展示如何部署这些类型的DataSource
implementations.DataSource
实现。
A system administrator or another person working in that capacity can deploy a 系统管理员或以该身份工作的其他人员可以部署DataSource
object so that the connections it produces are pooled connections. DataSource
对象,以便它生成的连接是池连接。To do this, he or she first deploys a 为此,他或她首先部署一个ConnectionPoolDataSource
object and then deploys a DataSource
object implemented to work with it. ConnectionPoolDataSource
对象,然后部署一个为使用它而实现的DataSource
对象。The properties of the ConnectionPoolDataSource
object are set so that it represents the data source to which connections will be produced. ConnectionPoolDataSource
对象的属性被设置为表示将生成连接的数据源。After the 在使用JNDI命名服务注册ConnectionPoolDataSource
object has been registered with a JNDI naming service, the DataSource
object is deployed. ConnectionPoolDataSource
对象之后,将部署DataSource
对象。Generally only two properties must be set for the 通常,只能为DataSource
object: description
and dataSourceName
. DataSource
对象设置两个属性:description
和dataSourceName
。The value given to the 给定给dataSourceName
property is the logical name identifying the ConnectionPoolDataSource
object previously deployed, which is the object containing the properties needed to make the connection.dataSourceName
属性的值是标识先前部署的ConnectionPoolDataSource
对象的逻辑名称,该对象包含建立连接所需的属性。
With the 部署ConnectionPoolDataSource
and DataSource
objects deployed, you can call the method DataSource.getConnection
on the DataSource
object and get a pooled connection. ConnectionPoolDataSource
和DataSource
对象后,可以调用DataSource
对象上的方法DataSource.getConnection
并获得池连接。This connection will be to the data source specified in the 此连接将连接到ConnectionPoolDataSource
object's properties.ConnectionPoolDataSource
对象属性中指定的数据源。
The following example describes how a system administrator for The Coffee Break would deploy a 下面的示例描述了咖啡休息时间的系统管理员如何部署实现的DataSource
object implemented to provide pooled connections. DataSource
对象以提供池连接。The system administrator would typically use a deployment tool, so the code fragments shown in this section are the code that a deployment tool would execute.系统管理员通常会使用部署工具,因此本节中显示的代码片段是部署工具将执行的代码。
To get better performance, The Coffee Break company has bought a JDBC driver from DB Access, Inc. that includes the class 为了获得更好的性能,Coffee Break公司从DB Access,Inc.购买了一个JDBC驱动程序,其中包括实现com.dbaccess.ConnectionPoolDS
, which implements the ConnectionPoolDataSource
interface. ConnectionPoolDataSource
接口的类com.dbaccess.ConnectionPoolDS
。The system administrator creates an instance of this class, sets its properties, and registers it with a JNDI naming service. 系统管理员创建该类的实例,设置其属性,并向JNDI命名服务注册它。The Coffee Break has bought its Coffee Break从其EJB服务器供应商Application Logic,Inc.处购买了其数据源类DataSource
class, com.applogic.PooledDataSource
, from its EJB server vendor, Application Logic, Inc. com.applogic.PooledDataSource
。The class 类com.applogic.PooledDataSource
implements connection pooling by using the underlying support provided by the ConnectionPoolDataSource
class com.dbaccess.ConnectionPoolDS
.com.applogic.PooledDataSource
通过使用ConnectionPoolDataSource
类com.dbaccess.ConnectionPoolDS
提供的底层支持来实现连接池。
The 必须首先部署ConnectionPoolDataSource
object must be deployed first. ConnectionPoolDataSource
对象。The following code creates an instance of 以下代码创建com.dbaccess.ConnectionPoolDS
and sets its properties:com.dbaccess.ConnectionPoolDS
的实例并设置其属性:
com.dbaccess.ConnectionPoolDS cpds = new com.dbaccess.ConnectionPoolDS(); cpds.setServerName("creamer"); cpds.setDatabaseName("COFFEEBREAK"); cpds.setPortNumber(9040); cpds.setDescription("Connection pooling for " + "COFFEEBREAK DBMS");
After the 部署ConnectionPoolDataSource
object has been deployed, the system administrator deploys the DataSource
object. ConnectionPoolDataSource
对象后,系统管理员将部署DataSource
对象。The following code registers the 以下代码使用JNDI命名服务注册com.dbaccess.ConnectionPoolDS
object cpds
with a JNDI naming service. com.dbaccess.ConnectionPoolDS
对象CPD
。Note that the logical name being associated with the 请注意,与cpds
variable has the subcontext pool
added under the subcontext jdbc
, which is similar to adding a subdirectory to another subdirectory in a hierarchical file system. cpds
变量关联的逻辑名称在子上下文jdbc
下添加了子上下文pool
,这类似于将子目录添加到分层文件系统中的另一个子目录。The logical name of any instance of the class 类com.dbaccess.ConnectionPoolDS
will always begin with jdbc/pool
. com.dbaccess.ConnectionPoolDS
的任何实例的逻辑名称始终以jdbc/pool
开头。Oracle recommends putting all Oracle建议将所有ConnectionPoolDataSource
objects under the subcontext jdbc/pool
:ConnectionPoolDataSource
对象放在子上下文jdbc/pool
下:
Context ctx = new InitialContext(); ctx.bind("jdbc/pool/fastCoffeeDB", cpds);
Next, the 接下来,将部署用于与DataSource
class that is implemented to interact with the cpds
variable and other instances of the com.dbaccess.ConnectionPoolDS
class is deployed. cpds
变量和com.dbaccess.ConnectionPoolDS
类的其他实例交互的DataSource
类。The following code creates an instance of this class and sets its properties. 下面的代码创建此类的实例并设置其属性。Note that only two properties are set for this instance of 请注意,此com.applogic.PooledDataSource
. com.applogic.PooledDataSource
实例只设置了两个属性。The 设置description
property is set because it is always required. description
属性是因为它始终是必需的。The other property that is set, 设置的另一个属性dataSourceName
, gives the logical JNDI name for cpds
, which is an instance of the com.dbaccess.ConnectionPoolDS
class. dataSourceName
为cpds
提供逻辑JNDI名称,它是com.dbaccess.ConnectionPoolDS
类的实例。In other words, 换句话说,cpds
represents the ConnectionPoolDataSource
object that will implement connection pooling for the DataSource
object.cpds
表示将为数据源对象实现连接池的ConnectionPoolDataSource
对象。
The following code, which would probably be executed by a deployment tool, creates a 以下代码(可能由部署工具执行)创建PooledDataSource
object, sets its properties, and binds it to the logical name jdbc/fastCoffeeDB
:PooledDataSource
对象,设置其属性,并将其绑定到逻辑名称jdbc/fastCoffeeDB
:
com.applogic.PooledDataSource ds = new com.applogic.PooledDataSource(); ds.setDescription("produces pooled connections to COFFEEBREAK"); ds.setDataSourceName("jdbc/pool/fastCoffeeDB"); Context ctx = new InitialContext(); ctx.bind("jdbc/fastCoffeeDB", ds);
At this point, a 此时,部署了一个DataSource
object is deployed from which an application can get pooled connections to the database COFFEEBREAK
.DataSource
对象,应用程序可以从中获得到数据库COFFEEBREAK
的池连接。
A connection pool is a cache of database connection objects. 连接池是数据库连接对象的缓存。The objects represent physical database connections that can be used by an application to connect to a database. 这些对象表示应用程序可以用来连接数据库的物理数据库连接。At run time, the application requests a connection from the pool. 在运行时,应用程序从池请求连接。If the pool contains a connection that can satisfy the request, it returns the connection to the application. 如果池包含一个可以满足请求的连接,它会将该连接返回给应用程序。If no connections are found, a new connection is created and returned to the application. 如果未找到任何连接,则会创建一个新连接并返回给应用程序。The application uses the connection to perform some work on the database and then returns the object back to the pool. 应用程序使用连接对数据库执行一些工作,然后将对象返回到池中。The connection is then available for the next connection request.然后,该连接可用于下一个连接请求。
Connection pools promote the reuse of connection objects and reduce the number of times that connection objects are created. 连接池促进了连接对象的重用,并减少了创建连接对象的次数。Connection pools significantly improve performance for database-intensive applications because creating connection objects is costly both in terms of time and resources.连接池显著提高了数据库密集型应用程序的性能,因为创建连接对象在时间和资源方面都很昂贵。
Now that these 现在已经部署了这些DataSource
and ConnectionPoolDataSource
objects are deployed, a programmer can use the DataSource
object to get a pooled connection. DataSource
和ConnectionPoolDataSource
对象,程序员可以使用DataSource
对象获得池连接。The code for getting a pooled connection is just like the code for getting a nonpooled connection, as shown in the following two lines:获取池连接的代码与获取非池连接的代码类似,如下两行所示:
ctx = new InitialContext(); ds = (DataSource)ctx.lookup("jdbc/fastCoffeeDB");
The variable 变量ds
represents a DataSource
object that produces pooled connections to the database COFFEEBREAK
. ds
表示一个数据源对象,该对象生成到数据库COFFEEBREAK
的池连接。You need to retrieve this 您只需要检索此DataSource
object only once because you can use it to produce as many pooled connections as needed. DataSource
对象一次,因为您可以根据需要使用它来生成尽可能多的池连接。Calling the method 对getConnection
on the ds
variable automatically produces a pooled connection because the DataSource
object that the ds
variable represents was configured to produce pooled connections.ds
变量调用getConnection
方法会自动生成池连接,因为ds
变量表示的DataSource
对象已配置为生成池连接。
Connection pooling is generally transparent to the programmer.连接池通常对程序员是透明的。There are only two things you need to do when you are using pooled connections:使用池连接时,只需做两件事:
Use a 使用DataSource
object rather than the DriverManager
class to get a connection. DataSource
对象而不是DriverManager
类来获取连接。In the following line of code, 在以下代码行中,ds
is a DataSource
object implemented and deployed so that it will create pooled connections and username
and password
are variables that represent the credentials of the user that has access to the database:ds
是一个实现和部署的DataSource
对象,它将创建池连接,username
和password
是代表有权访问数据库的用户凭据的变量:
Connection con = ds.getConnection(username, password);
Use a 使用finally
statement to close a pooled connection. finally
语句关闭池连接。The following 以下finally
block would appear after the try/catch
block that applies to the code in which the pooled connection was used:finally
块将出现在try/catch
块之后,该块应用于使用池连接的代码:
try { Connection con = ds.getConnection(username, password); // ... code to use the pooled // connection con } catch (Exception ex { // ... code to handle exceptions } finally { if (con != null) con.close(); }
Otherwise, an application using a pooled connection is identical to an application using a regular connection.否则,使用池连接的应用程序与使用常规连接的应用程序相同。The only other thing an application programmer might notice when connection pooling is being done is that performance is better.在进行连接池时,应用程序程序员可能会注意到的另一件事是性能更好。
The following sample code gets a 以下示例代码获取一个DataSource
object that produces connections to the database COFFEEBREAK
and uses it to update a price in the table COFFEES
:DataSource
对象,该对象生成到数据库COFFEEBREAK
的连接,并使用它更新COFFEES
表中的价格:
import java.sql.*; import javax.sql.*; import javax.ejb.*; import javax.naming.*; public class ConnectionPoolingBean implements SessionBean { // ... public void ejbCreate() throws CreateException { ctx = new InitialContext(); ds = (DataSource)ctx.lookup("jdbc/fastCoffeeDB"); } public void updatePrice(float price, String cofName, String username, String password) throws SQLException{ Connection con; PreparedStatement pstmt; try { con = ds.getConnection(username, password); con.setAutoCommit(false); pstmt = con.prepareStatement("UPDATE COFFEES " + "SET PRICE = ? " + "WHERE COF_NAME = ?"); pstmt.setFloat(1, price); pstmt.setString(2, cofName); pstmt.executeUpdate(); con.commit(); pstmt.close(); } finally { if (con != null) con.close(); } } private DataSource ds = null; private Context ctx = null; }
The connection in this code sample participates in connection pooling because the following are true:此代码示例中的连接参与连接池,原因如下:
ConnectionPoolDataSource
has been deployed.ConnectionPoolDataSource
的类的实例。DataSource
has been deployed, and the value set for its dataSourceName
property is the logical name that was bound to the previously deployed ConnectionPoolDataSource
object.DataSource
的类的实例,其dataSourceName
属性的值集是绑定到先前部署的ConnectionPoolDataSource
对象的逻辑名称。Note that although this code is very similar to code you have seen before, it is different in the following ways:请注意,尽管此代码与您以前看到的代码非常相似,但在以下方面有所不同:
It imports the 除了javax.sql
, javax.ejb
, and javax.naming
packages in addition to java.sql
.java.sql
之外,它还导入javax.sql
、javax.ejb
和javax.naming
包。
The DataSource
and ConnectionPoolDataSource
interfaces are in the javax.sql
package, and the JNDI constructor InitialContext
and method Context.lookup
are part of the javax.naming
package. DataSource
和ConnectionPoolDataSource
接口位于javax.sql
包中,JNDI构造函数InitialContext
和方法Context.lookup
是javax.naming
包的一部分。This particular example code is in the form of an EJB component that uses API from the 这个特定的示例代码以EJB组件的形式出现,该组件使用javax.ejb
package. javax.ejb
包中的API。The purpose of this example is to show that you use a pooled connection the same way you use a nonpooled connection, so you need not worry about understanding the EJB API.本示例的目的是展示使用池连接的方式与使用非池连接的方式相同,因此您不必担心理解EJB API。
It uses a 它使用DataSource
object to get a connection instead of using the DriverManager
facility.DataSource
对象来获取连接,而不是使用DriverManager
工具。
It uses a 它使用finally
block to ensure that the connection is closed.finally
块来确保连接已关闭。
Getting and using a pooled connection is similar to getting and using a regular connection. 获取和使用池连接类似于获取和使用常规连接。When someone acting as a system administrator has deployed a 当担任系统管理员的人正确部署了ConnectionPoolDataSource
object and a DataSource
object properly, an application uses that DataSource
object to get a pooled connection. ConnectionPoolDataSource
对象和DataSource
对象时,应用程序将使用该DataSource
对象来获得池连接。An application should, however, use a 然而,应用程序应该使用finally
block to close the pooled connection. finally
块来关闭池连接。For simplicity, the preceding example used a 为简单起见,前面的示例使用了finally
block but no catch
block. If an exception is thrown by a method in the try
block, it will be thrown by default, and the finally
clause will be executed in any case.finally
块,但没有catch
块。如果一个异常是由try
块中的一个方法引发的,那么默认情况下它将被引发,并且在任何情况下都将执行finally
子句。
可以部署DataSource
objects can be deployed to get connections that can be used in distributed transactions. DataSource
对象以获取可在分布式事务中使用的连接。As with connection pooling, two different class instances must be deployed: an 与连接池一样,必须部署两个不同的类实例:一个XADataSource
object and a DataSource
object that is implemented to work with it.XADataSource
对象和一个为使用它而实现的DataSource
对象。
Suppose that the EJB server that The Coffee Break entrepreneur bought includes the 假设咖啡休息企业家购买的EJB服务器包括DataSource
class com.applogic.TransactionalDS
, which works with an XADataSource
class such as com.dbaccess.XATransactionalDS
. DataSource
类com.applogic.TransactionalDS
,该类与诸如com.dbaccess.XATransactionalDS
之类的XADataSource
类一起工作。The fact that it works with any 它与任何XADataSource
class makes the EJB server portable across JDBC drivers. XADataSource
类一起工作的事实使得EJB服务器可以跨JDBC驱动程序进行移植。When the 部署DataSource
and XADataSource
objects are deployed, the connections produced will be able to participate in distributed transactions. DataSource
和XADataSource
对象时,生成的连接将能够参与分布式事务。In this case, the class 在本例中,类com.applogic.TransactionalDS
is implemented so that the connections produced are also pooled connections, which will usually be the case for DataSource
classes provided as part of an EJB server implementation.com.applogic.TransactionalDS
的实现使得生成的连接也是池连接,这通常是作为EJB服务器实现的一部分提供的数据源类的情况。
The 必须首先部署XADataSource
object must be deployed first. XADataSource
对象。The following code creates an instance of 以下代码创建com.dbaccess.XATransactionalDS
and sets its properties:com.dbaccess.XATransactionalDS
的实例并设置其属性:
com.dbaccess.XATransactionalDS xads = new com.dbaccess.XATransactionalDS(); xads.setServerName("creamer"); xads.setDatabaseName("COFFEEBREAK"); xads.setPortNumber(9040); xads.setDescription("Distributed transactions for COFFEEBREAK DBMS");
The following code registers the 以下代码向JNDI命名服务注册com.dbaccess.XATransactionalDS
object xads
with a JNDI naming service. com.dbaccess.XATransactionalDS
对象xads
。Note that the logical name being associated with 请注意,与xads
has the subcontext xa
added under jdbc
. xads
关联的逻辑名称在jdbc
下添加了子文本xa
。Oracle recommends that the logical name of any instance of the class Oracle建议类com.dbaccess.XATransactionalDS
always begin with jdbc/xa
.com.dbaccess.XATransactionalDS
的任何实例的逻辑名称始终以jdbc/xa
开头。
Context ctx = new InitialContext(); ctx.bind("jdbc/xa/distCoffeeDB", xads);
Next, the 接下来,将部署用于与DataSource
object that is implemented to interact with xads
and other XADataSource
objects is deployed. xads
和其他XADataSource
对象交互的DataSource
对象。Note that the 请注意,DataSource
class, com.applogic.TransactionalDS
, can work with an XADataSource
class from any JDBC driver vendor. DataSource
类com.applogic.TransactionalDS
可以与任何JDBC驱动程序供应商提供的XADataSource
类一起使用。Deploying the 部署DataSource
object involves creating an instance of the com.applogic.TransactionalDS
class and setting its properties. DataSource
对象涉及创建com.applogic.TransactionalDS
类的实例并设置其属性。The dataSourceName
property is set to jdbc/xa/distCoffeeDB
, the logical name associated with com.dbaccess.XATransactionalDS
. dataSourceName
属性设置为jdbc/xa/distCoffeeDB
,这是与com.dbaccess.XATransactionalDS
关联的逻辑名称。This is the 这是XADataSource
class that implements the distributed transaction capability for the DataSource
class. XADataSource
类,它实现了DataSource
类的分布式事务功能。The following code deploys an instance of the 以下代码部署DataSource
class:DataSource
类的实例:
com.applogic.TransactionalDS ds = new com.applogic.TransactionalDS(); ds.setDescription("Produces distributed transaction " + "connections to COFFEEBREAK"); ds.setDataSourceName("jdbc/xa/distCoffeeDB"); Context ctx = new InitialContext(); ctx.bind("jdbc/distCoffeeDB", ds);
Now that instances of the classes 现在已经部署了com.applogic.TransactionalDS
and com.dbaccess.XATransactionalDS
have been deployed, an application can call the method getConnection
on instances of the TransactionalDS
class to get a connection to the COFFEEBREAK
database that can be used in distributed transactions.com.applogic.TransactionalDS
和com.dbaccess.XATransactionalDS
类的实例,应用程序可以在TransactionalDS
类的实例上调用getConnection
方法,以获得到可用于分布式事务的COFFEEBREAK
数据库的连接。
To get a connection that can be used for distributed transactions, must use a 要获得可用于分布式事务的连接,必须使用已正确实现和部署的DataSource
object that has been properly implemented and deployed, as shown in the section Deploying Distributed Transactions. DataSource
对象,如部署分布式事务一节所示。With such a 对于这样的DataSource
object, call the method getConnection
on it. DataSource
对象,调用其上的getConnection
方法。After you have the connection, use it just as you would use any other connection. 建立连接后,请像使用任何其他连接一样使用它。Because 由于jdbc/distCoffeesDB
has been associated with an XADataSource
object in a JNDI naming service, the following code produces a Connection
object that can be used in distributed transactions:jdbc/distCoffeesDB
已与JNDI命名服务中的XADataSource
对象关联,因此以下代码生成了可在分布式事务中使用的Connection
对象:
Context ctx = new InitialContext(); DataSource ds = (DataSource)ctx.lookup("jdbc/distCoffeesDB"); Connection con = ds.getConnection();
There are some minor but important restrictions on how this connection is used while it is part of a distributed transaction.当此连接是分布式事务的一部分时,对于如何使用此连接存在一些次要但重要的限制。A transaction manager controls when a distributed transaction begins and when it is committed or rolled back; therefore, application code should never call the methods 事务管理器控制分布式事务何时开始以及何时提交或回滚;因此,应用程序代码不应调用Connection.commit
or Connection.rollback
. Connection.commit
或Connection.rollback
方法。An application should likewise never call 应用程序也不应该调用Connection.setAutoCommit(true)
, which enables the auto-commit mode, because that would also interfere with the transaction manager's control of the transaction boundaries. Connection.setAutoCommit(true)
,后者启用自动提交模式,因为这也会干扰事务管理器对事务边界的控制。This explains why a new connection that is created in the scope of a distributed transaction has its auto-commit mode disabled by default. 这解释了为什么在分布式事务范围内创建的新连接在默认情况下禁用其自动提交模式。Note that these restrictions apply only when a connection is participating in a distributed transaction; there are no restrictions while the connection is not part of a distributed transaction.请注意,这些限制仅在连接参与分布式事务时适用;当连接不是分布式事务的一部分时,没有任何限制。
For the following example, suppose that an order of coffee has been shipped, which triggers updates to two tables that reside on different DBMS servers. 对于下面的示例,假设已经发送了一份咖啡订单,这将触发对驻留在不同DBMS服务器上的两个表的更新。The first table is a new 第一个表是新的INVENTORY
table, and the second is the COFFEES
table. INVENTORY
表,第二个表是COFFEES
表。Because these tables are on different DBMS servers, a transaction that involves both of them will be a distributed transaction. 由于这些表位于不同的DBMS服务器上,因此涉及这两个表的事务将是分布式事务。The code in the following example, which obtains a connection, updates the 下面示例中的代码是分布式事务的第二部分,它获取连接、更新COFFEES
table, and closes the connection, is the second part of a distributed transaction.COFFEES
表并关闭连接。
Note that the code does not explicitly commit or roll back the updates because the scope of the distributed transaction is being controlled by the middle tier server's underlying system infrastructure.请注意,代码没有显式提交或回滚更新,因为分布式事务的范围由中间层服务器的底层系统基础结构控制。Also, assuming that the connection used for the distributed transaction is a pooled connection, the application uses a 另外,假设用于分布式事务的连接是池连接,应用程序使用finally
block to close the connection. finally
块关闭连接。This guarantees that a valid connection will be closed even if an exception is thrown, thereby ensuring that the connection is returned to the connection pool to be recycled.这保证了即使抛出异常,也会关闭有效的连接,从而确保连接返回到连接池进行回收。
The following code sample illustrates an enterprise Bean, which is a class that implements the methods that can be called by a client computer.下面的代码示例演示了一个企业Bean,它是一个实现客户机可以调用的方法的类。The purpose of this example is to demonstrate that application code for a distributed transaction is no different from other code except that it does not call the 本示例的目的是演示分布式事务的应用程序代码与其他代码没有什么不同,只是它不调用Connection
methods commit
, rollback
, or setAutoCommit(true)
. Connection
方法commit
、rollback
或setAutoCommit(true)
。Therefore, you do not need to worry about understanding the EJB API that is used.因此,您不必担心理解所使用的EJB API。
import java.sql.*; import javax.sql.*; import javax.ejb.*; import javax.naming.*; public class DistributedTransactionBean implements SessionBean { // ... public void ejbCreate() throws CreateException { ctx = new InitialContext(); ds = (DataSource)ctx.lookup("jdbc/distCoffeesDB"); } public void updateTotal(int incr, String cofName, String username, String password) throws SQLException { Connection con; PreparedStatement pstmt; try { con = ds.getConnection(username, password); pstmt = con.prepareStatement("UPDATE COFFEES " + "SET TOTAL = TOTAL + ? " + "WHERE COF_NAME = ?"); pstmt.setInt(1, incr); pstmt.setString(2, cofName); pstmt.executeUpdate(); stmt.close(); } finally { if (con != null) con.close(); } } private DataSource ds = null; private Context ctx = null; }