我们有一个在websphere 7中使用hibernate,spring和DB2的应用程序。我们有审计触发器,我们需要设置,以便触发器可以知道登录用户(我们使用通用登录到数据库)。我们想出了一个新的方案,用于在新的应用程序中设置它,以便它可以自动加入新的交易。我们覆盖了事务管理器并在doBegin中完成了工作。
这些方案在一个应用程序中运行良好,并且似乎在第二个应用程序中运行良好,但现在,几周后,并且不一致(行为是间歇性的,并且在本地开发中不会发生),我们正在获得此预先绑定JDBC Connection发现错误。在线查看大多数帖子都说这是针对一个数据源使用两个事务管理器的时候。现在就是我们正在做的事情。
我还读了一篇文章,想知道是不是因为他混合了注释和基于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);
}
}
答案 0 :(得分:5)
我刚才意识到我从未回答过这个问题。事实证明,这个例外与我们的Tx经理无关。事实上,这个特定的EAR中有两个应用程序,每个应用程序指向相同的数据源。显然这会混淆休眠。我们计划有一天将这些应用程序分开,但创建一个相同的(名称除外)数据源并将应用程序分别指向它们可以解决此问题。
答案 1 :(得分:1)
而不是修改事务管理器可能更容易(更好?)在数据源周围创建一个包装器(从spring扩展DelegatingDataSource
)并覆盖2个getConnection方法。对于清理,您可以将连接包装在代理中并拦截close方法。
这应该是一种更安全(更容易猜测)的方式,然后尝试摆弄事务管理器,只要您使用包装的数据源,它就适用于每种技术(JDBC,Hibernate,JPA等)。 (可以使用BeanPostProcessor
进行注册,该DataSource
检测{{1}}个实例,并将它们简单地包装在代理中。)
如果这是激进的(因为这意味着更改当前的应用程序而不是更新库)。这可能是一个配置问题,请确保您只加载配置(以及DataSource和TransactionManager)一次,复制bean实例可能会导致类似行为。
答案 2 :(得分:0)
对于后人,我刚遇到这个问题,这里的答案不是很有帮助。我们通过删除具有AOP事务管理器定义的核心XML文件的双重导入来解决该问题:
<tx:annotation-driven transaction-manager="..."
proxy-target-class="true" />
我认为它会导致2个事务管理器重叠相同的命名空间。为了解决这个问题,我们将进口转移到了一次。
希望这有助于其他人。