4

我需要在每次数据库操作之前设置一些上下文(我曾尝试使用 Oracle 的包级变量,但由于包重新编译的一些问题,我将尝试使用DBMS_SESSION和/或DBMS_APPLICATION_INFO),以便我们可以在任何地方获取特定的用户信息我们需要它(过程、触发器等),而不是将数十个数据库连接标识为“JBoss”。

我编写了一个 Java EE 拦截器来拦截对 @Stateless bean 的调用。它调用一个 Oracle 函数来设置一些会话上下文(查看这个问题以获取一些示例代码如何判断事务是否在 Java EE 6 拦截器中处于活动状态)。

我首先担心的是连接池。起初我认为 Java EE 提供的默认 @PersistenceContext 传播足以保证一切都在同一个连接/事务/EntityManager 中运行,而我只需要在拦截器结束时取消设置所有内容(在一个finally块中)之前连接返回到池中。它似乎有点脆弱,但我认为它可以工作。

然后我发现 Hibernate 有一个名为 hibernate.connection.release_mode 的属性关于 hibernate.connection.release_mode 的 Hibernate 文档关于 org.hibernate.ConnectionReleaseMode 的 Red Hat 文档)并且使用 JTA 事务时的默认和推荐行为是释放每个语句之后的连接(尽管文档说了一些关于重新获取相同的底层连接,这让我很困惑)。

现在我什至不确定我是否可以在拦截器中可靠地设置一些内容,这些内容只对这个用户/操作可见,而不会有其他人在我的业务方法中间抓住相同的连接并弄乱我的用户上下文的风险. 据我了解,Oracle 数据库会话变量是为连接保留的,而不是为事务或 @PersistenceContext (数据库毕竟对持久性上下文一无所知,并且一个连接可用于多个事务)。

我即将放弃,因为随着我对所涉及的所有技术的实现细节的了解越来越多,这看起来越来越脆弱。可以使这个用户上下文的想法起作用还是我应该尝试一种完全不同的方法?我如何测试/调试我的实现以确保没有任何并发​​问题?我还没有找到任何有用的事件监听器来监视框架行为,并且构建一个程序来对服务器进行压力测试是太多的工作,无法投资于我不确定是否应该工作的东西。

我正在使用 JBoss AS 7.1、EJB 3.1、Oracle 10g 数据库和 JPA 2.0(由 Hibernate 支持,尽管我们不使用任何特定于 Hibernate 的 API)。

4

2 回答 2

2

所以我会用我最近发现的所有东西来回答我自己的问题。

为了了解服务器行为,我将 JBoss 配置更改为使用只有 1 个连接的池,这样我就可以检测到其他人何时被阻塞等待。

如果当前操作在事务内部(例如@TransactionAttribute(REQUIRED)),则在事务完成之前,连接不会用于其他任何事情(其他客户端将不得不等待)。但是,如果您在没有事务的情况下读取数据库,则其他客户端可能会在您不使用它时获取相同的连接,甚至在您的业务方法完成之前(我不知道这种行为有多少是标准的,有多少是实现细节)。

默认情况下,Hibernate 在每个语句之后都会释放连接,这就是为什么可以在非事务方法中重用连接的原因。另一方面,如果您仍在同一个事务中,JDBC 和 JEE 具有重新获取相同连接所需的功能。

但是为什么 Hibernate 会释放一个稍后会重新获取的连接呢?如果 Hibernate 没有释放它,一些 JEE 服务器可能会认为 Hibernate 在嵌套 EJB 调用中打开一个连接并使其保持打开状态以供调用者重用时正在泄漏连接。这篇文章对此进行了解释:

http://www.mail-archive.com/hibernate-dev@lists.jboss.org/msg00612.html

为了安全起见,我们需要保存的所有数据(以及稍后呈现给用户)都作为参数显式传递,但出于日志记录的目的,我们确实使用了存储在 Oracle 会话中的一些数据,因为我们知道该连接不能被其他客户端重用,因为只要您使用交易业务方法。

更新:似乎可以使用与连接器和/或自定义数据源相关的一些应用服务器特定设置来做我想做的事情(不确定这里的最佳答案是什么:https ://developer.jboss.org/thread/250132 )

于 2013-12-06T13:00:54.967 回答
2

我个人会避免尝试在池中的 JDBC 连接上设置单个参数。毕竟,池的想法是所有连接都是相同的。因此,尽管您的拦截器想法可行,但我也担心它会变得多么脆弱。该实现中的任何错误都将是最恶劣的竞争条件。

另一方面,由于您使用的是 Oracle,您可能希望查看 EclipseLink。它实现了 JPA2,并得到了 Oracle 的大力资助,因此它支持他们所有的奇异特性。您可能想考虑使用'Isolated Client Sessions'。它看起来支持需要单独会话设置的虚拟专用数据库。因此,如果您需要更改会话上下文,这将是一个解决方案。

于 2013-01-05T05:53:28.337 回答