为什么我们使用DataSource而不是DriverManager?

107
我正在阅读Java JDBC规范(版本4),遇到了这个声明:
DataSource-该接口在JDBC 2.0可选包API中引入。它比DriverManager更受欢迎,因为它允许应用程序透明地处理底层数据源的细节。
我试图理解的是ConnectionDataSource之间的区别以及存在的原因。我的意思是,上面的块说数据源的详细信息对于应用程序是透明的,但是将数据库属性(如用户名、密码、URL等)外部化到属性文件中,然后使用DriverManager是否可以以同样的方式工作?

DataSource 接口是用于创建一种常见的返回可以被池化等连接的方式吗?在Java EE中,应用服务器是否实现此接口,并且部署的应用程序具有对数据源的引用,而不是连接?

6个回答

79
更好的可伸缩性和维护性
对于DriverManager,您需要知道所有详细信息(主机、端口、用户名、密码、驱动程序类)才能连接到数据库并获取连接。将其外部化到属性文件中并不会改变您需要了解这些信息的事实。
使用DataSource,您只需要知道JNDI名称。应用服务器关心细节,而不是由客户端应用程序供应商配置,而是由托管应用程序的管理员配置。
可伸缩性:
假设您需要自己创建连接,如何处理不断变化的负载?有时您有10个用户,有时您有1000个用户,您不能随时获得连接,然后“释放”它,以使数据库服务器不会出现连接问题,这导致您需要使用连接池。 DriverManager不提供它,DataSource提供它。
如果要自己编写连接池,则必须使用DriverManager,否则请使用DataSource。

5
数据源实现由驱动程序提供商(比如MySQL)提供。应用服务器需要知道驱动程序才能创建数据源。之后,它会负责将其绑定到已配置的JNDI名称(逻辑名称)。请注意,在此配置步骤中,所有详细信息(驱动程序类、URL、用户名、密码等)都必须已知。但这仍然比让客户端应用程序了解这些信息要好。 - A4L
4
"如果你打算编写连接池,那么你必须使用DriverManager,否则就使用Datasource。" - 你是否颠倒了名称? - arun
3
我认为,DriverManager是比DataSource更低层次的API。 - A4L
10
我理解他的意思是,如果你想自己实现一个连接池,那么就没有什么需要翻转的了。 - Koray Tugay
2
数据源提供连接池技术。最后一句话中说,如果你想要编写连接池程序,可以使用DataManager。这可能会有点误导。正确的是,如果你想在你的应用程序中使用连接池技术,应该使用数据源。 - Aniket Thakur
显示剩余7条评论

44

DriverManager

  • 在Java类中创建/关闭连接会影响应用程序的性能。
  • 不支持连接池。

DataSource

  • 提高了应用程序的性能,因为连接不是在类内部创建/关闭的,而是由应用服务器管理,并且可以在运行时获取。
  • 它提供了创建连接池的功能。
  • 对企业应用程序有帮助。

但是,如果您创建了自己的类,例如MyConnectionPool,并在其中使用DriverManager进行了一些魔法操作,那么这是否与使用实现DataSource接口的类相同? DataSource接口仅用于具有公共接口以获取连接吗? - LuckyLuke
1
并不完全一样,诸如Spring这样的框架展示了dataSource的能力和性能。 - NaveenKumar1410

5

简而言之

  • DataSource 是一种将连接数据库所需的信息外部化的方式:服务器名称或地址、用户名、用户密码、特定于您的特定数据库引擎的设置等。
  • DriverManager 在你初学时使用很好。但是在部署到生产环境时,您不希望在代码库中硬编码连接信息。在实际工作中,使用 DataSource 而不是 DriverManager 来访问外部化的配置信息(地址、名称、密码等)。
  • Connection 是你与数据库的实时连接。一个 DataSource 对象将利用 DriverManager 为您获取一个 Connection 对象,以便您在查询数据库时使用它。

详细信息

让我们来看看您的问题的具体内容。

我试图了解的是 ConnectionDataSource 之间的区别是什么

一个Connection对象表示与数据库服务器的实时会话,来回进行查询并获取结果。
一个DataSource对象保存了连接到数据库所需的凭据。通常,DataSource保存了被数据库服务器识别的用户名、该用户的密码以及各种设置,以自定义与数据库的任何未来会话。一个DataSource不是“打开”或“关闭”的;它仅仅保存了创建一个已经打开或关闭的Connection所需的信息。

为什么它存在

Connection作为与数据库服务器交流的管道而存在。
“DataSource”存在的目的是为了避免在应用程序代码中硬编码连接信息(用户名、密码、选项)。在实际工作中,当您部署应用程序后,您不希望因为DBA更改密码而不得不编辑代码、重新编译和重新部署。
作为一个程序员,您不希望受到部署问题的影响,例如数据库服务器的机器网络地址、用户名、用户密码等。您希望将这些信息外部化到代码库之外。
“externalizing database properties such as username, password, url etc in a property file and then use DriverManager work in the same way?” 不是的。您的代码仍然会被硬编码为寻找该属性文件。但是,DBA和SysAdmins还有其他方法来配置和传达连接信息(用户名、密码、服务器地址等)。Java程序员不应该对部署期间做出的选择和更改做出假设。
主要将信息外部化的方法是将信息放置在目录服务器中。有许多目录服务器实现。这些通常可以通过标准化接口(例如LDAP接口)进行访问。
Java提供了一种机制,使您的基于Java的应用程序能够通过标准化接口与目录服务交互。这个机制被称为Java命名和目录接口(JNDI)
通过JNDI,您的应用程序可以请求目录服务提供一个带有必要连接信息的DataSource对象。通过使用JNDI,您的应用程序不需要对DBA/SysAdmin选择如何向应用程序提供此连接信息做出假设。事实上,作为程序员,您无需了解他们的部署选择和更改方面的任何信息。

DataSource接口是否只是为了创建一种通用的返回连接的方式,以便可以对其进行池化等操作?

一个调用 DataSource#getConnection 返回的连接可能是连接池的一部分,也可能不是。作为Java程序员,您通常不需要关心这个。在部署时,DBA/SysAdmins 可能最初使用非连接池连接进行部署。然后稍后他们可能改用连接池连接。同样,您无需关心,也没有必要编辑您的代码,重新编译和重新部署。DBA可以在不涉及您的情况下更改连接池设置。

在Java EE中,应用服务器是否实现此接口并且部署的应用程序具有对数据源的引用而不是连接?

FYI,Java EE现在被称为 Jakarta EE,在 Oracle Corp 将责任转移给 Eclipse Foundation 后更名。
您可以在任何类型的Java应用程序中使用JDBCDataSource对象:控制台, 桌面 (JavaFX/Swing/SWT), Web应用程序, 微服务等。
如果您所说的“此接口”是指DataSource接口……不,像TomcatJettyGlassfishPayaraWildFlyJBossOpen Liberty这样的Jakarta EE实现并没有实现DataSource。通常JDBC驱动程序提供了一个实现,或者您的连接池实现提供了一个实现。
同样,在部署时由DBA/SysAdmin配置,而不是在开发期间由程序员配置。您不应该将JDBC驱动程序与您的Jakarta EE应用程序捆绑在一起。相反,应该配置您的依赖管理器(如Maven、Gradle等)使驱动程序在开发期间可用,但在最终部署文件(.war文件等)中不可用。
该 Jakarta EE 实现会处理获取应用程序的 DataSource 对象。实现本身可能充当目录服务;例如,Tomcat 可以在其自己的配置文件中保存连接信息,然后将该信息作为 DataSource 对象传递给您的应用程序。或者,DBA/SysAdmin 可以配置 Jakarta EE 实现以连接到单独的目录服务器实现,例如 Microsoft Active DirectoryOpenLDAP。再次强调,这些细节都不是 Java 程序员需要关心的。
在 Jakarta EE 部署中,Jakarta EE 实现向您的应用程序提供一个 DataSource 对象。然后,您的应用程序代码在需要与数据库服务器通信时调用 getConnection。您的应用程序代码在完成与数据库服务器通信后关闭生成的 Connection 对象。
提示:使用try-with-resources语法自动关闭连接、语句和其他JDBC资源。如上所述,DataSource对象不是这种意义上的资源,它本身不会被打开或关闭。

5

DataSource对象可以提供连接池和分布式事务,因此如果您需要这些功能中的一个或两个,就必须使用DataSource


点赞。其他答案中缺少“分布式事务”的要点。 - 卢声远 Shengyuan Lu

4
以下代码展示了两种获取连接的方式。
对于mySqlDataSource,不需要知道URL,因为这一行已经被注释掉了。
public class MySqlDataSourceTest {

public static void main(String[] args) throws SQLException, ClassNotFoundException {


    /************** using MysqlDataSource starts **************/
    MysqlDataSource d = new MysqlDataSource();
    d.setUser("root");
    d.setPassword("root");
//  d.setUrl("jdbc:mysql://localhost:3306/manavrachna");
    d.setDatabaseName("manavrachna");
    Connection c =  (Connection) d.getConnection();
    /************** using MysqlDataSource ends**************/


    /************** using DriverManager start **************/
    Class.forName("com.mysql.jdbc.Driver");
    Connection c=(Connection) DriverManager.getConnection("jdbc:mysql://localhost:3306/manavrachna","root","root");
    /************** using DriverManager ends **************/

    Statement st=(Statement) c.createStatement();
    ResultSet rs=st.executeQuery("select id from employee");
    while(rs.next())
    {
        System.out.println(rs.getInt(1));
    }

}

}

0
我们可以使用数据源来获取连接,如下所示。使用连接执行任何数据库查询。
DataSource datasource = (DataSource) new InitialContext().lookup(dataSourceName);
Connection connection = datasource.getConnection();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接