问题描述
JDBC 教程 建议使用 DataSource
对象来获取数据库连接而不是使用 DriverManager
类.引用连接数据源对象 页面:
The JDBC Tutorial recommends using a DataSource
object to obtain database connections rather than using the DriverManager
class. To quote the Connecting with DataSource Objects page:
DataSource
对象……是获取数据源连接的首选方法.
如何为 JDBC 连接到 Postgres 获取这样的对象?我有一个 JDBC 驱动程序.
How do I get such an object for a JDBC connection to Postgres? I have a JDBC driver in place.
Right now, I do not want to fiddle around with JNDI like this or this.
我可以在我的 Java 应用程序中以编程方式实例化 DataSource
吗?还是我必须自己实现那个 DataSource
接口?
Can I instantiate a DataSource
programmatically within my Java app? Or must I implement that DataSource
interface myself?
推荐答案
tl;dr
PGSimpleDataSource
与来自 jdbc.postgresql.org 的 JDBC 驱动程序捆绑在一起的类实现了 DataSource
接口.在 PGSimpleDataSource
对象中配置您的数据库连接详细信息,并作为 DataSource
对象传递.
tl;dr
The PGSimpleDataSource
class bundled with the JDBC driver from jdbc.postgresql.org implements DataSource
interface. Configure your database connection details in a PGSimpleDataSource
object, and pass around as a DataSource
object.
PGSimpleDataSource ds = new PGSimpleDataSource() ;
ds.setServerName( "localhost" );
ds.setDatabaseName( "your_db_name_here" );
ds.setUser( "scott" );
ds.setPassword( "tiger" );
根据需要使用该对象与数据库建立连接.使用方便的try-with-resources 语法.
Use that object to make a connection to the database as needed. Use convenient try-with-resources syntax.
try
(
Connection conn = ds.getConnection() ;
)
{ … }
JDBC驱动的实现
您的JDBC 驱动程序可能会为您提供DataSource
接口.
JDBC driver’s implementation
Your JDBC driver may provide for you an implementation of the DataSource
interface.
此实现的对象包含建立和配置到数据库的连接所需的信息,例如:
An object of this implementation contains the information needed to make and configure a connection to the database, such as:
- 名称和数据库用户密码
- IP 地址和数据库服务器端口号
最多提供三种实现方式:
Up to three kinds of implementation provided may be available:
- 通常这样的实现是围绕
DriverManager
.每次调用DataSource 时::getConnection
在这样一个实现的对象上,你会得到一个新的数据库连接. - 或者,一个实现可以使用下面的连接池来提供已经存在的连接.这些连接会分发并重新签入,就像图书馆中的书籍一样,可以回收以重复使用.
- 一个实现可能支持 Java 事务 API,支持 X/Open XA,用于复杂的需求,例如协调跨多个资源(如数据库和消息队列)的事务.不常用,所以我在这里忽略这种类型.
- Often such an implementation is a thin wrapper around the
DriverManager
. Each time you callDataSource::getConnection
on the object of such an implementation, you get a fresh database connection. - Alternatively, an implementation may be using a connection pool underneath to supply already-existing connections. These connections are handed out and checked back in, like books in a library, to be recycled for repeated use.
- An implementation may support the Java Transaction API, supporting X/Open XA, for sophisticated needs like coordinating the transactions across multiple resources such as databases and message queues. Not as commonly used, so I ignore this type here.
来自 jdbc.postgresql.org 的开源免费驱动程序提供了所有三种类型的实现.但是作者不建议实际使用他们的连接池类型 生产中;如果您想要池,请使用第三方连接池库.我们忽略了XA 类型.
The open-source free-of-cost driver from jdbc.postgresql.org provides all three types of DataSource
implementation. But the authors do not recommend actually using their connection pool type in production; if you want pooling, use a third-party connection pooling library. And we are ignoring the XA type.
那么让我们看一下 DataSource
的简单的每次新鲜连接的实现:org.postgresql.ds.PGSimpleDataSource
So let's look at the simple fresh-connection-each-time implementation of DataSource
: org.postgresql.ds.PGSimpleDataSource
实例化一个空对象,然后调用一系列setter 方法来配置您的特定数据库设想.setter 方法继承自 org.postgresql.ds.common.BaseDataSource
.
Instantiate an empty object, then call a series of setter methods to configure for your particular database scenario. The setter methods are inherited from org.postgresql.ds.common.BaseDataSource
.
我们还没有向上转换到接口DataSource
,所以我们可以调用各种设置方法.请参阅数据源和 JNDI 页面上的示例代码和讨论.
We are not yet upcasting to the interface DataSource
, so that we can call the various setter methods. See example code and discussion on the Data Sources and JNDI page.
PGSimpleDataSource ds = new PGSimpleDataSource() ; // Empty instance.
ds.setServerName( "localhost" ); // The value `localhost` means the Postgres cluster running locally on the same machine.
ds.setDatabaseName( "testdb" ); // A connection to Postgres must be made to a specific database rather than to the server as a whole. You likely have an initial database created named `public`.
ds.setUser( "testuser" ); // Or use the super-user 'postgres' for user name if you installed Postgres with defaults and have not yet created user(s) for your application.
ds.setPassword( "password" ); // You would not really use 'password' as a password, would you?
通常我会使用这些单独的 setter 方法.或者,您可以构造一个字符串,一个 URL,将各种信息一次性设置在 DataSource
上.如果你想走那条路,请调用 setUrl
.
Generally I would use these separate setter methods. Alternatively, you construct a String, a URL, with the various pieces of info to be set on the DataSource
in one stroke. If you want to go that route, call setUrl
.
这涵盖了基础知识.但是你可能想要或需要一些其他的二传手.其中大部分是在服务器上设置 Postgres property 值.这些属性都有智能默认值,但您可能希望在特殊情况下覆盖.
That covers the basics. But you might want or need some of the other setters. Most of these are setting Postgres property values on the server. The properties all have smart defaults, but you may wish to override for special situations.
ds.setPortNumber( 6787 ) ; // If not using the default '5432'.
ds.setApplicationName( "whatever" ) ; // Identify the application making this connection to the database. Also a clever way to back-door some information to the Postgres server, as you can encode small values into this string for later parsing.
ds.setConnectTimeout( … ) ; // The timeout value used for socket connect operations, in whole seconds. If connecting to the server takes longer than this value, the connection is broken.
ds.setSocketTimeout( … ) ; // The timeout value used for socket read operations. If reading from the server takes longer than this value, the connection is closed. This can be used as both a brute force global query timeout and a method of detecting network problems.
ds.setReadOnly( boolean ) ; // Puts this connection in read-only mode.
如果使用 TLS(以前称为 SSL)来加密数据库连接以防止窃听或恶意操作,为此使用多个 setter.
If using TLS (formerly known as SSL) to encrypt the database connection to protect against eavesdropping or malevolent manipulation, use several setters for that.
对于没有特定 setter 方法的任何 Postgres 属性,您可以调用 setProperty(PGProperty 属性,字符串值)
.
For any Postgres property without a specific setter method, you may call setProperty( PGProperty property, String value )
.
您可以通过调用许多 getter 方法中的任何一个来检查或验证此数据源的设置.
You can inspect or verify settings on this data source by calling any of the many getter methods.
在配置您的 PGSimpleDataSource
之后,您可以将代码库的其余部分作为简单的 DataSource
对象.这使您的代码库免受更改为另一个 DataSource
实现或更改为 另一个 JDBC 的冲击司机.
After configuring your PGSimpleDataSource
, you can pass off to the rest of your codebase as simply a DataSource
object. This insulates your codebase from the shock of changing to another DataSource
implementation or changing to another JDBC driver.
DataSource dataSource = ds ; // Upcasting from concrete class to interface.
return dataSource ;
使用数据源
使用 DataSource
非常简单,因为它只提供两种方法,getConnection
获取Connection
对象用于您的数据库工作.
Using the data source
Using a DataSource
is utterly simple as it provides for only two methods, a pair of variations on getConnection
to get a Connection
object for your database work.
Connection conn = dataSource.getConnection() ;
完成Connection
后,最佳做法是确保关闭它.要么使用 try-with-resources 语法 来自动关闭连接,或明确关闭它.
When finished with your Connection
, best practice is to be sure to close it. Either use a try-with-resources syntax to automatically close the connection, or explicitly close it.
conn.close() ;
请记住,DataSource
实际上并不是数据源.DataSource
实际上是生成/访问数据库连接的源.在我看来,这是用词不当,因为我认为它是 ConnectionSource
.DataSource
与您的数据库对话的时间仅足以使用用户名和密码登录.登录后,您可以使用 Connection
对象与数据库交互.
Keep clear in your mind that a DataSource
is not actually a data source. A DataSource
is really a source for generating/accessing connections to the database. To my mind, this is a misnomer, as I think of it as ConnectionSource
. The DataSource
talks to your database only long enough to sign-in with user name and password. After that sign-in, you use the Connection
object to interact with the database.
配置后,您希望保留该 DataSource
对象并缓存.无需重复重新配置.实现应该是线程安全的.您可以随时随地调用 getConnection
.
Once configured, you want to keep that DataSource
object around, cached. No need to re-configure repeatedly. The implementation should be written to be thread-safe. You may call getConnection
at anytime from anywhere.
对于一个简单的小型 Java 应用程序,您可能希望将其作为字段存储在单例或静态全局变量中.
For a simple little Java app, you may want to store it as a field on a singleton or in a static global variable.
对于基于 Servlet 的应用,例如 Vaadin 应用程序,您将创建一个实现 ServletContextListener
接口的类.在该类中,您将在您的网络应用程序启动时建立您的 DataSource
对象.从那里你可以将对象存储在 ServletContext
对象通过传递给 setAttribute
.Context
是网络应用"的技术术语.通过调用 getAttribute
并转换为 DataSource
进行检索.
For a Servlet-based app such as a Vaadin app, you would create a class implementing ServletContextListener
interface. In that class your would establish your DataSource
object when your web app is launching. From there you would store the object in the ServletContext
object by passing to setAttribute
. Context
is the technical term for 'web app'. Retrieve by calling getAttribute
and casting to DataSource
.
在企业场景中,DataSource
可能存储在 JNDIa> 兼容的实现.一些 Servlet 容器,例如 Apache Tomcat 可以提供 JNDI 实现.某些组织使用服务器,例如 LDAP 服务器.注册&使用 JNDI 检索您的 DataSource
对象在许多其他问题中都有涉及.Stack Overflow 上的答案.
In an enterprise scenario, the DataSource
may be stored in a JNDI-compliant implementation. Some Servlet containers such as Apache Tomcat may provide a JNDI implementation. Some organizations use a server such as an LDAP server. Registering & retrieving your DataSource
object with JNDI is covered in many other Questions & Answers on Stack Overflow.
这篇关于以编程方式为 Postgres JDBC 生成一个 `DataSource` 对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!