JBoss TreeCache 作为二级 Hibernate 缓存的并发策略配置

发布于 2024-10-17 12:37:01 字数 1039 浏览 6 评论 0原文

我正在使用 JBoss EAP 4.3。

我目前正在研究使用内置 JBoss TreeCache 作为 Hibernate 二级缓存时的并发策略的不同选项。我已经设置了它,并且通过查看日志验证了缓存是否正在工作,但我不确定真正使用的并发策略是什么以及它是如何工作的。

对于每个实体,我可以在 @Cache 注释中设置以下“使用”值之一:NONE、READ_ONLY、NONSTRICT_READ_WRITE 、READ_WRITE事务

另一方面,在我的 JBossTreeCache 配置文件中,我可以将整个缓存的 IsolationLevel 设置为以下之一:NONEREAD_UNCOMMITTEDREAD_COMMITTEDREPEATABLE_READSERIALIZABLE(或仅使用OPTIMISTIC)。

当一次查看一个配置选项时,文档非常清楚,但我想知道当您组合不同的选项时会发生什么。

例如,如果您为实体设置 @Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL),但为 JBossTreecache 配置 NONE 作为 IsolationLevel,会发生什么?

我还相信 JBossTreeCache 仅支持 NONEREAD_ONLYTRANSACTIONAL 使用,但是 IsolationLevel code> 你可以将它们结合起来吗?如果您使用例如 NONSTRICT_READ_WRITE 会发生什么?

这里总共应该有 5x6 种不同的组合,但并非所有组合都有意义..

有人可以帮我解决这个问题吗?

I am using JBoss EAP 4.3.

I'm currently looking into the different options for concurrency strategy when using the built-in JBoss TreeCache as a second level cache for Hibernate. I have set it up and I have verified that the cache is working by looking into the logs, but I am not sure what concurrency strategy is really used and how it is intended to work.

For each Entity, I can set one of the following "usage" values in the @Cache annotation: NONE, READ_ONLY, NONSTRICT_READ_WRITE, READ_WRITE, TRANSACTIONAL.

On the other hand, in my JBossTreeCache configuration file I can set IsolationLevel to one of the following for the entire cache: NONE, READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE (or just use OPTIMISTIC).

When looking into the configuration options one at a time, the documentation is quite clear, but I wonder what happens when you combine the different options.

For example, if you set @Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL) for an entity but configure NONE as IsolationLevel for the JBossTreecache, what happens?

I also believe that JBossTreeCache only supports NONE, READ_ONLY and TRANSACTIONAL usage, but what IsolationLevel are you allowed to combine them with? And what happens if you use for example NONSTRICT_READ_WRITE?

Alltogether there should be like 5x6 different combinations here, but not all of them makes sense..

Can anyoone help me sorting this out?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

你在我安 2024-10-24 12:37:01

隔离级别是一个棘手的问题。

例如,如果您为实体设置 @Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL),但为 NONE 配置为 IsolationLevel代码>JBossTreecache,会发生什么?

大多数情况下,在生产中很难发现错误......您应该明白,通过使用读写缓存,您实际上使自己陷入了分布式事务及其所有“优点”中。

好的,关于组合:
当对象不改变时,应该使用 Hibernate 中的只读缓存设置。例如,对于国家/地区词典。缓存并发级别 NONE 或 READ_ONLY 应与其一起使用。

当缓存对象发生更改时,应使用非严格读写,但这种情况很少发生,并且出现竞争条件的可能性很小。例如,对于时区字典 - 时区可能偶尔会出现/消失,但这种情况可能每年发生几次。同样,缓存并发级别 NONE 或 READ_ONLY 应该与它一起使用。

现在,更多有趣的组合。

Hibernate 中的事务性缓存并不安全,Hibernate 假定缓存更新是事务性的,但没有采取任何措施来确保这一点。因此,您必须使用成熟的外部 XA(分布式事务)协调器,并且您真的真的真的不想要它,除非您真的知道自己在做什么。最有可能的是,您必须使用完整的 EJB3 容器来支持 XA 管理器,尽管可以使用外部事务管理器,例如 http://www。 atomikos.com/ 带有普通的 servlet + Spring。显然,您需要使用 TRANSACTIONAL 缓存。

“READ_WRITE”是一个有趣的组合。在这种模式下,Hibernate 本身充当轻量级 XA 协调器,因此它不需要成熟的外部 XA。其工作原理的简短描述:

  1. 在此模式下,Hibernate 自行管理事务。所有数据库操作都必须在事务内,自动提交模式将不起作用。
  2. 在flush()期间(在事务生命周期中可能会出现多次,但通常发生在提交之前),Hibernate 会遍历会话并搜索更新/插入/删除的对象。然后,这些对象首先保存到数据库中,然后在缓存中锁定并更新,以便并发事务既不能更新也不能读取它们。
  3. 如果事务随后回滚(显式地或由于某些错误),则锁定的对象将被简单地释放并从缓存中逐出,以便其他事务可以读取/更新它们。
  4. 如果事务提交成功,则锁定的对象将被简单地释放,其他线程可以读取/写入它们。

这里有几个要点:

可能的可重复读取违规。想象一下,我们有事务 A (tA) 和事务 B (tB),它们同时启动,并且都加载对象 X,tA 然后修改该对象,然后提交 tA。在许多使用快照隔离的数据库(Oracle、PostgreSQL、FireBird)中,如果 tB 再次请求对象 X,它应该收到与事务开始时相同的对象状态。但是,READ_WRITE 缓存可能会违反此条件 - 那里没有快照隔离。 Hibernate 试图通过在缓存对象上使用时间戳来解决这个问题,但在计时器分辨率较差的操作系统上(Windows 上为 15.6 毫秒),它肯定会让一些竞争溜走。

可能的乐观过时对象版本 - 如果您非常不幸在 Windows 上工作,并且有多个事务以相同的时间戳提交,则有可能获得过时的对象版本。

Isolation level is a tricky issue.

For example, if you set @Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL) for an entity but configure NONE as IsolationLevel for the JBossTreecache, what happens?

Mostly, hard-to-find bugs in production... You should understand that by using read-write cache you essentially mire yourself in distributed transactions with all their 'niceties'.

Ok, about combinations:
Read-only cache setting in Hibernate should be used when your objects do not change. For example, for a country dictionary. Cache concurrency level NONE or READ_ONLY should be used with it.

Non-strict-read-write should be used when your cached objects change, but that happens rarely and chances for race conditions are small. For example, for a timezone dictionary - timezones might appear/disappear occasionally, but that happens may be a couple times a year. Again, cache concurrency level NONE or READ_ONLY should be used with it.

Now, to more interesting combinations.

Transactional caches in Hibernate are NOT safe, Hibernate assumes that cache updates are transactional but does nothing to ensure it. So you MUST use a full-blown external XA (distributed transactions) coordinator, and you really really really do not want it unless you really really know what you're doing. Most likely, you'll have to use the full EJB3 container for XA-manager support though it's possible to use external transaction manager like http://www.atomikos.com/ with plain servlets + Spring. Obviously, you need to use TRANSACTIONAL caches with it.

'READ_WRITE` is an interesting combination. In this mode Hibernate itself works as a lightweight XA-coordinator, so it doesn't require a full-blown external XA. Short description of how it works:

  1. In this mode Hibernate manages the transactions itself. All DB actions must be inside a transaction, autocommit mode won't work.
  2. During the flush() (which might appear multiple time during transaction lifetime, but usually happens just before the commit) Hibernate goes through a session and searches for updated/inserted/deleted objects. These objects then are first saved to the database, and then locked and updated in the cache so concurrent transactions can neither update nor read them.
  3. If the transaction is then rolled back (explicitly or because of some error) the locked objects are simply released and evicted from the cache, so other transactions can read/update them.
  4. If the transaction is committed successfully, then the locked objects are simply released and other threads can read/write them.

There are couple of fine points here:

Possible repeatable read violation. Imagine that we have Transaction A (tA) and Transaction B (tB) which start simultaneously and both load object X, tA then modifies this object and then tA is committed. In a lot of databases which use snapshot isolation (Oracle, PostgreSQL, FireBird), if tB requests object X again it should receive the same object state as in the beginning of the transaction. However, READ_WRITE cache might violate this condition - there's no snapshot isolation there. Hibernate tries to work around it by using timestamps on cached objects but on OSes with poor timer resolution (15.6ms on Windows) it is guaranteed to let some races slip through.

Possible optimistic stale object versions - it IS possible to get stale object versions if you're very unlucky to work on Windows, and have several transactions commit with the same timestamp.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文