我正在使用具有使用ECache配置的hibernate的broadleaf演示应用程序。我还有一个外部应用程序,它直接与同一个db进行交互。 当我使用外部应用程序更新数据库时,我的broadleaf应用程序不知道这些更改会在创建新实体时抛出重复的主键。我试图通过定期清除hibernate缓存来解决这个问题,这使得hibernate能够从头开始构建缓存,因此一切都会同步。 我正在使用以下代码清除二级缓存。
Cache cache = sessionFactory.getCache();
String entityName = "someName";
cache.evictEntityRegion(entityName);
但是,这似乎不起作用。
我甚至尝试使用 visualvm 等JMX监听器手动清除cahche。但这也行不通。我仍然在我的API中获得旧的主键值。这是因为只有二级缓存被清除而离开一级缓存?我被困在这里。任何人都可以帮忙解决这个问题吗?
更新: 假设我有应用 A 和 B 。 A使用broadleaf,B使用原始SQL查询插入db。我使用应用程序A创建几个订单,然后我使用应用程序B直接在db中插入几个订单,同时我用max(order_id)+ 1更新SEQUENCE_GENERATOR表。之后当我尝试使用应用程序A创建订单时,它会抛出重复的主键例外。我试图调试问题,我发现 IdOverrideTableGenerator 仍在提供我的旧主键。这让我对二级缓存感到好奇。 broadleaf不使用 SEQUENCE_GENERATOR 来启动主键生成的引用并维护缓存中的当前状态吗?在我的情况下,即使更新SEQUENCE_GENERATOR也无法确保新鲜且唯一的主键。
答案 0 :(得分:2)
如果您希望实现在运行时识别新实体,那么您需要对外部导入进行L2缓存失效。否则,您必须等待缓存区域上配置的TTL过期,以便您的应用程序查看新记录。
然而,在Broadleaf的情况下,L2缓存与Hibernate如何确定主键没有任何直接关联。 Broadleaf利用表生成器策略以高性能和集群安全的方式获取一批ID。您可能会注意到架构中名为SEQUENCE_GENERATOR的表。此表包含为不同域类获取的各种id范围。每当Hibernate需要为插入时抓取一批新ID时,它将与此表交互以注册一系列新的ID以进行检出。这应该保证集群中的任何节点都不会尝试插入具有冲突ID的实体。
在您的情况下,您需要保证外部进程可以以非冲突的方式执行插入。为此,我认为您需要为要调用的外部进程创建一个API,以执行相同的" id checkout"代表该调用进程的操作。然后,您的导入代码(可能位于其他地方)将具有一系列可以安全使用的ID。支持您创建的API的代码应执行与Hibernate通常执行的操作相同的操作,以获取实体插入的一批ID。您可以查看org.hibernate.id.enhanced.TableGenerator,了解它的外观示例,并为您自己的目的创建类似的内容。