Documentation

The Java™ Tutorials
Hide TOC
Connecting with DataSource Objects连接数据源对象
Trail: JDBC Database Access
Lesson: JDBC Basics

Connecting with DataSource Objects连接数据源对象

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 DataSource object that is being deployed.为部署使这些操作成为可能的类而执行的工作(系统管理员通常使用工具(如Apache Tomcat或Oracle WebLogic Server)根据所部署的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:涵盖以下主题:

Using DataSource Objects to Get a Connection使用数据源对象获取连接

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:它可以通过三种不同的方式实现:

A JDBC driver should include at least a basic DataSource implementation. JDBC驱动程序至少应该包括一个基本的DataSource实现。For example, the Java DB JDBC driver includes the implementation org.apache.derby.jdbc.ClientDataSource and for MySQL, com.mysql.jdbc.jdbc2.optional.MysqlDataSource. 例如,Java DB JDBC驱动程序包括org.apache.derby.jdbc.ClientDataSource的实现,用于MySQL,包括com.mysql.jdbc.jdbc2.optional.MysqlDataSourceIf your client runs on Java 8 compact profile 2, then the Java DB JDBC driver is org.apache.derby.jdbc.BasicClientDataSource40. 如果您的客户机在Java 8 compact profile 2上运行,那么Java DB JDBC驱动程序是org.apache.derby.jdbc.BasicClientDataSource40The 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 DataSource class provided by an EJB vendor almost always supports both connection pooling and distributed transactions.例如,EJB供应商提供的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.发出请求的客户端计算机是第一层。

Deploying Basic DataSource Objects部署基本数据源对象

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对象包括三项任务:

  1. Creating an instance of the DataSource class创建DataSource类的实例
  2. Setting its properties设置其属性
  3. Registering it with a naming service that uses the Java Naming and Directory Interface (JNDI) API向使用Java命名和目录接口(JNDI)API的命名服务注册它

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类产生的连接类型相同。

Creating Instance of DataSource Class and Setting its Properties创建DataSource类的实例并设置其属性

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对象dsThe 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_ACCOUNTSAny connection produced by the BasicDataSource object ds will be a connection to the database CUSTOMER_ACCOUNTS.BasicDataSource对象ds生成的任何连接都将是到数据库CUSTOMER_ACCOUNTS的连接。

Registering DataSource Object with Naming Service That Uses JNDI API向使用JNDIAPI的命名服务注册数据源对象

With the properties set, the system administrator can register the BasicDataSource object with a JNDI (Java Naming and Directory Interface) naming service. 通过设置属性,系统管理员可以使用JNDI(Java命名和目录接口)命名服务注册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/billingDBIn 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将始终是数据源逻辑名称的第一部分。

Using Deployed DataSource Object使用已部署的数据源对象

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 jdbc/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.将逻辑名称jdbc/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 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.>getConnection方法只需要用户名和密码,因为变量ds在其属性中包含与CUSTOMER_ACCOUNTS数据库建立连接所需的其余信息,例如数据库名称和位置。

Advantages of DataSource Objects数据源对象的优点

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实现。

Deploying Other DataSource Implementations部署其他数据源实现

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 ConnectionPoolDataSource object has been registered with a JNDI naming service, the DataSource object is deployed. 在使用JNDI命名服务注册ConnectionPoolDataSource对象之后,将部署DataSource对象。Generally only two properties must be set for the DataSource object: description and dataSourceName. 通常,只能为DataSource对象设置两个属性:descriptiondataSourceNameThe 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. 部署ConnectionPoolDataSourceDataSource对象后,可以调用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 com.dbaccess.ConnectionPoolDS, which implements the ConnectionPoolDataSource interface. 为了获得更好的性能,Coffee Break公司从DB Access,Inc.购买了一个JDBC驱动程序,其中包括实现ConnectionPoolDataSource接口的类com.dbaccess.ConnectionPoolDSThe 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 DataSource class, com.applogic.PooledDataSource, from its EJB server vendor, Application Logic, Inc. Coffee Break从其EJB服务器供应商Application Logic,Inc.处购买了其数据源类com.applogic.PooledDataSourceThe class com.applogic.PooledDataSource implements connection pooling by using the underlying support provided by the ConnectionPoolDataSource class com.dbaccess.ConnectionPoolDS.com.applogic.PooledDataSource通过使用ConnectionPoolDataSourcecom.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 com.dbaccess.ConnectionPoolDS object cpds with a JNDI naming service. 以下代码使用JNDI命名服务注册com.dbaccess.ConnectionPoolDS对象CPDNote 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 ConnectionPoolDataSource objects under the subcontext jdbc/pool:Oracle建议将所有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. 设置的另一个属性dataSourceNamecpds提供逻辑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的池连接。

Getting and Using Pooled Connections获取和使用池连接

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. 现在已经部署了这些DataSourceConnectionPoolDataSource对象,程序员可以使用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:使用池连接时,只需做两件事:

  1. 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对象,它将创建池连接,usernamepassword是代表有权访问数据库的用户凭据的变量:

    Connection con = ds.getConnection(username, password);
  2. 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:此代码示例中的连接参与连接池,原因如下:

Note that although this code is very similar to code you have seen before, it is different in the following ways:请注意,尽管此代码与您以前看到的代码非常相似,但在以下方面有所不同:

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子句。

Deploying Distributed Transactions部署分布式事务

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 DataSource class com.applogic.TransactionalDS, which works with an XADataSource class such as com.dbaccess.XATransactionalDS. 假设咖啡休息企业家购买的EJB服务器包括DataSourcecom.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. 部署DataSourceXADataSource对象时,生成的连接将能够参与分布式事务。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 com.dbaccess.XATransactionalDS object xads with a JNDI naming service. 以下代码向JNDI命名服务注册com.dbaccess.XATransactionalDS对象xadsNote that the logical name being associated with xads has the subcontext xa added under jdbc. 请注意,与xads关联的逻辑名称在jdbc下添加了子文本xaOracle recommends that the logical name of any instance of the class com.dbaccess.XATransactionalDS always begin with jdbc/xa.Oracle建议类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. 请注意,DataSourcecom.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.TransactionalDScom.dbaccess.XATransactionalDS类的实例,应用程序可以在TransactionalDS类的实例上调用getConnection方法,以获得到可用于分布式事务的COFFEEBREAK数据库的连接。

Using Connections for Distributed Transactions为分布式事务使用连接

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.commitConnection.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方法commitrollbacksetAutoCommit(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;
}

Previous page: Establishing a Connection
Next page: Handling SQLExceptions