为啥同时使用 C3PO 和 JNDI 会产生问题?
Posted
技术标签:
【中文标题】为啥同时使用 C3PO 和 JNDI 会产生问题?【英文标题】:Why does using C3PO and JNDI at the same time create an issue?为什么同时使用 C3PO 和 JNDI 会产生问题? 【发布时间】:2016-12-25 23:09:46 【问题描述】:我正在从 Tomcat 8 服务器运行一个使用 Hibernate 的应用程序。我想使用与 Hibernate 不同的连接池,因为它们很明显它不适合在生产环境中使用。
此外,他们提到:
为了在应用服务器内部使用,您几乎总是应该配置 Hibernate 以从 JNDI 中注册的应用服务器 javax.sql.Datasource 获取连接。
看来我需要做两件事:
-
配置 Hibernate 以使用第三方连接池 -- Hibernate 推荐 C3PO
配置 Hibernate 以从注册在 JNDI 中的
javax.sql.Datasource
对象获取连接
我一直在研究如何进行这些更改,并且遇到了this SO 问题。发帖人已经在使用 C3PO,并询问如何通过 JNDI Datasource
对象连接到他们的数据库。但是,他们遇到了问题,因为他们在按照回答者的步骤使用 JNDI 数据源时已经在使用 C3PO。发帖人在接受答案的 cmets 部分这样说:
是的,我一直在使用 c3p0 和 JNDI 做一些非常愚蠢的事情。我删除了所有 c3p0 配置,现在可以正常工作了。
Hibernate 建议使用第三方连接池,即 C3PO,并使用 JNDI 数据源来接收连接,然而,这似乎给这个用户带来了问题;他们甚至谈论同时使用它们,好像这是一个明显的错误。
那么我不能同时使用它们吗,还是应该按照 Hibernate 的建议?我要做的就是将 Hibernate 的默认连接池替换为用于生产环境的池,并将 Hibernate 配置为从 JNDI 中注册的javax.sql.Datasource
对象获取连接,正如他们所建议的那样。
【问题讨论】:
【参考方案1】:我会尽量消除混乱。
我认为它始于令人惊讶的简单 DataSource 接口:https://docs.oracle.com/javase/7/docs/api/javax/sql/DataSource.html
DataSource 接口由驱动程序供应商实现。有 三种实现方式:
基本实现 -- 生成标准 Connection 对象 连接池实现——生成一个将自动参与连接池的连接对象。这 实现与中间层连接池管理器配合使用。 分布式事务实现 -- 生成一个 Connection 对象,该对象可用于分布式事务并且几乎总是 参与连接池。此实现适用于 中间层事务管理器,几乎总是有连接 池管理器。
Hibernate 需要一个 DataSource 才能使用,并建议它使用连接池。
C3PO 包装一个现有的 DataSource 并对其应用连接池,并创建一个类型 2 的新 DataSource。C3PO 假定它获得的 DataSource 是类型 1,但它不能确定。
在其他应用服务器中,如果你声明一个在 JNDI 中注册的数据源,它几乎总是使用容器中已经存在的连接池。对于 Tomcat 8,它在内部使用 C3PO。
所以在 Hibernate 中实现连接池有两种方法:要么创建一个类型 1 的数据源并在代码中将其嵌入到连接池中,要么在容器中声明您的数据源(带有连接池),然后在 hibernate 中从JNDI。
如果您同时这样做,就像您的情况一样,您的应用程序中的 C3PO 从 JNDI 获取数据源,该数据源本身就是由 tomcat 管理的 C3PO 数据源。当应用程序尝试获取连接时,应用程序 C3PO 将调用容器 C3PO,该容器将创建实际连接,但连接将在两个连接池中进行池化。当 hibernate 释放连接时,应用程序 C3PO 将保留它以供重用,但其他连接池也会继续等待连接被释放。
根据配置,底层连接池可能会在某个超时后终止连接。
因此在彼此之上配置两个连接池是危险的,完全没有必要。
回答悬赏问题:在生产环境中,在生产容器中声明数据源并通过 JNDI 将其连接到 Hibernate,而无需在 Hibernate 中配置任何额外的连接池。
【讨论】:
【参考方案2】:在参考 SO 帖子中,海报以 Hibernate 已配置的 C3PO 开头。当发帖人开始获取对已配置 C3PO 连接池的 JNDI 引用时,他/她认为 Hibernate 在启动期间正在处理该配置。解决方案是将 C3PO 配置移动到容器 (Tomcat) 并从 Hibernate 设置中删除配置。
这是应用程序启动的简化大纲:
容器执行其启动操作 创建连接并开始监听连接 创建和配置 JNDI 资源,例如 DataStore、邮件会话等 部署 Web 应用程序 扫描网络应用程序 配置网络应用程序 提供配置期间指定的任何 JNDI 资源 完成部署在 Web 应用程序部署阶段读取 Hibernate 配置并发出对 JNDI 资源的请求。由于已经配置了 C3PO,因此看不到在 Hibernate 中完成的任何配置。
【讨论】:
以上是关于为啥同时使用 C3PO 和 JNDI 会产生问题?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我对 QueueConnectionFactory 的 JNDI 查找返回 null?