gpt4 book ai didi

Spring:@Transactional with readonly=true 不调用 conn.setReadOnly(true)

转载 作者:行者123 更新时间:2023-12-01 04:04:36 25 4
gpt4 key购买 nike

我用 @Transactional 注释了我的服务方法readonly=true .

因为那个 spring/hibernate 没有调用 jdbc 连接驱动程序的 setReadonly 方法。我能做些什么?

因为我将使用主从复制,并且 jdbc 池使用连接上的只读标志将查询路由到主服务器或从服务器。

最佳答案

首先,当您的 PU 事务模式为 RESOURCE_LOCAL 时,您应该只为 JDBC 连接设置 readOnly 标志。如果它是 JTA,那么您不能更改该设置,因为您不会为事务中的每个 jdbc 调用获得相同的 jdbc 连接实例(JTA - 而不是 Hibernate - 将确保事务行为)。当它是 LOCAL 时,Hibernate 在第一次需要它时打开一个 jdbc 连接,并在事务期间保留它。

1. JPA

如果您将 JPA 与 Hibernate 作为提供程序一起使用,则可以通过以下方式添加此额外行为
为 EMF 定义提供您自己的 JpaDialect 实现。使用 Hibernate 时,通常会注入(inject)一个 HibernateJpaDialect。

JpaDialect 接口(interface)有一个 getJdbcConnection(em, readOnly)返回实际 JDBC 连接的句柄的方法。此方法在事务开始时由 JpaTransactionManager 调用。默认情况下,由于这种 JTA/RESOURCE_LOCAL 对偶性,HibernateJpaDialect 不会更改返回连接上的只读设置,但如果您只运行本地事务,则可以这样做。

这是实现您的目标的此类 JpaDialect 的实现:

ResourceLocalReadOnlyAwareHibernateJpaDialect

public class ResourceLocalReadOnlyAwareHibernateJpaDialect extends HibernateJpaDialect {
public ConnectionHandle getJdbcConnection(EntityManager entityManager, boolean readOnly) throws PersistenceException, SQLException {
Session session = getSession(entityManager);
return new HibernateReadOnlyAwareConnectionHandle(session, readOnly);
}

// this is similar to spring's HibernateJpaDialect own internal class,
// except for the readonly flags.
private static class HibernateReadOnlyAwareConnectionHandleimplements ConnectionHandle {
private final Session session;
private final boolean readOnly;
private static volatile Method connectionMethod;

public HibernateConnectionHandle(Session session, boolean readOnly) {
this.session = session;
this.readOnly = readOnly;
}

public Connection getConnection() {
try {
if (connectionMethod == null) {
// reflective lookup to bridge between Hibernate 3.x and 4.x
connectionMethod = this.session.getClass().getMethod("connection");
}
Connection con = (Connection) ReflectionUtils.invokeMethod(connectionMethod, this.session);
con.setReadOnly(this.readOnly);
return con;
} catch (NoSuchMethodException ex) {
throw new IllegalStateException("Cannot find connection() method on Hibernate session", ex);
}
}

public void releaseConnection(Connection con) { // #1
con.setReadOnly(false);
JdbcUtils.closeConnection(con);
}
}

}

注意 #1:在关闭连接之前将 readOnly 标志重置为 false(实际上不是真正的 connection.close() 调用,只是释放与池的连接)。不太确定是什么触发了此方法调用,但在与更改位置相同的类中重置 readOnly 标志看起来是合法的。

2.纯 hibernate

一、确保 HibernateTransactionManager.prepareConnection保持真实。

然后,我不知道该怎么办。您必须调试到 Spring 的 HibernateTransactionManager.isSameConnectionForEntireSession() :如果方法返回true,将调用connection.setReadOnly(),因此一切正常。

如果没有,您可以将 Hibernate 的 connectionReleaseMode 设置更改为 ON_CLOSE( hibernate 属性 hibernate.transaction.auto_close_session=true,这是 Hibernate 3.1 之前的默认值),或者覆盖 HibernateTransactionManager.isSameConnectionForEntireSession()为了始终返回 true (这在 HibernateTransactionManager 注释方面被认为是安全的)。两者都是“高级调整”,但应该是安全的 AFAIK。实际上,我认为 HibernateTransactionManager.isSameConnectionForEntireSession() ON_CLOSE 都应更改为返回 true和 AFTER_TRANSACTION Release模式:关于 HibernateTransactionManager,在事务完成后无论如何都会进行清理,因此不会改变 Hibernate 行为。

关于Spring:@Transactional with readonly=true 不调用 conn.setReadOnly(true),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10271624/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com