8

我们有一个在 websphere 7 中使用 hibernate、spring 和 DB2 的应用程序。我们有审计触发器,我们需要设置触发器可以知道登录的用户(我们使用通用登录到数据库)。我们提出了一个新方案,用于在新应用程序中设置它,以便它可以自动加入新交易。我们覆盖了事务管理器并在 doBegin 中完成了工作。

这些方案在一个应用程序中运行良好,并且似乎在第二个应用程序中运行良好,但是现在,几周后,并且不一致(行为是间歇性的,不会在本地开发中发生),我们得到了这个 Pre-bound JDBC Connection found错误。在线查看大多数帖子都说这是当您对一个数据源使用两个事务管理器时。这就是我们现在正在做的事情。

我还阅读了一篇文章,想知道是不是因为他混合了注释和基于 AOP 的事务。这个应用程序做了一些。我并不真正相信这个理论,但我想我会提到它。

例外:

Caused by: 
org.springframework.transaction.IllegalTransactionStateException: Pre-bound JDBC Connection found! HibernateTransactionManager does not support running within DataSourceTransactionManager if told to manage the DataSource itself. It is recommended to use a single HibernateTransactionManager for all transactions on a single DataSource, no matter whether Hibernate or JDBC access.
at java.lang.Throwable.<init>(Throwable.java:67)
at org.springframework.core.NestedRuntimeException.<init>(NestedRuntimeException.java:54)
at org.springframework.transaction.TransactionException.<init>(TransactionException.java:34)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:475)
at gov.usdoj.afms.umc.utils.hibernate.AfmsHibernateTransactionManager.doBegin(AfmsHibernateTransactionManager.java:28)

代码(注意异常来自super.doBegin()):

protected void doBegin(Object arg0, TransactionDefinition arg1) {
    super.doBegin(arg0, arg1);
    if (!Db2ClientInfo.exists()) {
        clearDBProperty();
    } else {
        setDBProperty(Db2ClientInfo.getClientUserId(), Db2ClientInfo.getClientApplicationId());
    }
}
private void setDBProperty(String uId, String appName) {
    Session session = getSessionFactory().getCurrentSession();

    Properties props = new Properties();
    props.setProperty(WSConnection.CLIENT_ID, uId);
    props.setProperty(WSConnection.CLIENT_APPLICATION_NAME, appName);
    try {
        Connection nativeConn = new SimpleNativeJdbcExtractor().getNativeConnection(session.connection());
        if (nativeConn instanceof WSConnection) {
            WSConnection wconn = (WSConnection) nativeConn;
            wconn.setClientInformation(props);
        } else {
            logger.error("Connection was NOT an instance of WSConnection so client ID and app could not be set");
        }
    } catch (Exception e) {
        throw new RuntimeException("Cannot set DB parameters!", e);
    }
}
4

3 回答 3

6

我才意识到我从来没有回答过这个问题。事实证明,异常与我们的 Tx 管理器无关。事实上,这个特定的 EAR 中有两个应用程序,每个应用程序都指向同一个数据源。显然这会混淆hibernate。我们计划有一天将应用程序分开,但创建一个相同的(名称除外)数据源并将应用程序分别指向它们现在可以解决这个问题。

于 2014-05-22T16:56:27.033 回答
1

DelegatingDataSource与其修改事务管理器,不如在数据源周围创建一个包装器(从 spring 扩展)并覆盖 2 个 getConnection 方法可能更容易(更好?) 。对于清理,您可以将连接包装在代理中并拦截 close 方法。

这应该是一种更安全(我猜也更容易)的方法,然后尝试使用事务管理器,只要您使用包装的数据源,它就适用于每种技术(JDBC、Hibernate、JPA 等)。(注册可以通过BeanPostProcessor检测DataSource实例并将它们简单地包装在委托中来完成)。

如果那是激进的(因为这意味着更改您当前的应用程序而不是更新库)。这可能是一个配置问题,请确保您只加载一次配置(因此 DataSource 和 TransactionManager),复制 bean 实例可能会导致类似的行为。

于 2013-08-24T09:02:47.877 回答
0

对于后代,我刚刚遇到了这个问题,这里的答案并不是很有帮助。我们通过删除包含 AOP 事务管理器定义的核心 XML 文件的双重导入来解决该问题:

<tx:annotation-driven transaction-manager="..."
    proxy-target-class="true" />

我认为这会导致有 2 个事务管理器重叠相同的命名空间。为了解决这个问题,我们移动了导入,所以它们只完成了一次。

希望这对其他人有帮助。

于 2016-01-19T19:05:26.843 回答