在JPA连接中设置上下文 - 这样安全吗?

时间:2012-12-26 19:24:57

标签: oracle hibernate java-ee jpa jboss7.x

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

我编写了一个Java EE拦截器,拦截了对@Stateless bean的调用。它调用Oracle函数来设置一些会话上下文(查看这个问题以获取一些示例代码How to tell if a transaction is active in a Java EE 6 interceptor)。

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

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

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

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

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

2 个答案:

答案 0 :(得分:2)

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

另一方面,因为您正在使用Oracle,所以您可能希望查看EclipseLink。它实现了JPA2并且得到了Oracle的大量资助,因此它支持所有奇怪的功能。您可能希望使用'Isolated Client Sessions'。它看起来支持需要单独会话设置的虚拟专用数据库。如果您需要来更改会话上下文,那么这将是一个解决方案。

答案 1 :(得分: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会话中的一些数据,因为知道连接不能被重用其他客户只要您使用交易业务方法。

更新:似乎可以使用与连接器和/或自定义数据源相关的某些应用服务器特定设置来执行我想要的操作(不确定这里的最佳答案是什么:{{3 }})