gpt4 book ai didi

java - 在 Infinispan 中缓存类似父子关系的数据库索引

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

我的应用程序在 Wildfly 10.0.0 服务器上运行。我将我的实体存储在数据库中,但为了提高性能,我决定使用 Infinispan 缓存(缓存端模式)。应用程序性能有所提高,但仍然存在计算关系parent - children(Foo 和 SubFoos)的问题:

这是实体代码:

@Entity
class Foo
{
Long id;
}

@Entity
class SubFoo
{
Long id;
Long fooId;
}

这是服务代码:

public class FooService
{
@Inject
EntityManger em;

@Inject
Cache<Long, Foo> fooCache;

@Inject
Cache<Long, SubFoo> subFooCache;

public void save(Foo foo)
{
em.save(foo);
fooCache.put(foo.id, foo);
}

public void save(SubFoo subFoo)
{
em.save(subFoo);
subFooCache.put(subFoo.id, subFoo);
}

public void remove ....

public void update ....

public Foo get(Long fooId)
{
return fooCache.get(fooId);
}

public SubFoo get(Long subFooId)
{
return subFooCache.get(subFooId);
}


public List<SubFoo> findSubFoo(Long fooId)
{
return subFooCache.values().stream().filter( subFoo -> subFoo.fooId == fooId ).collect( Collector.list() );
}
}

问题是findSubFoo 方法。每次都要检查所有的subFoos 集合。而且这种方式对应用性能影响还是很大的。

infinispan 是否可以模拟数据库索引的使用或以其他方式解决该问题?

方法一

我尝试使用 TreeCache 将列表存储为缓存值,并保持并发性和事务性支持。 treeNode 将 FooId 作为节点根路径,将 subFooId 作为叶子。当请求数量较少时,这种方法是可以的。在许多请求中,状态不一致,短状态缺乏一致性。似乎 Tx 已提交并且刷新了一个缓存(实体 subFoo 正常),但第二个(foo2subFoo)尚未刷新。但过了一小段时间后,一切正常,数据的一致性又恢复了。

源代码:

带有生产者的缓存提供者:

@ApplicationScoped
public class CacheProvider
{
private EmbeddedCacheManager cacheManager;

@PostConstruct
public void init()
{
final GlobalConfiguration globalConfig =
new GlobalConfigurationBuilder().nonClusteredDefault().globalJmxStatistics()
.allowDuplicateDomains( true ).build();

final Configuration entityDefaultConfig =
new ConfigurationBuilder().transaction().transactionMode( TransactionMode.TRANSACTIONAL )
.lockingMode( LockingMode.OPTIMISTIC )
.eviction().strategy( EvictionStrategy.NONE ).build();

final Configuration indexDefaultConfig = new ConfigurationBuilder()
.transaction().transactionMode( TransactionMode.TRANSACTIONAL )
.eviction().strategy( EvictionStrategy.NONE )
.invocationBatching().enable()
.build();

cacheManager = new DefaultCacheManager( globalConfig );

cacheManager.defineConfiguration( "Foos", entityDefaultConfig );
cacheManager.defineConfiguration( "SubFoos", entityDefaultConfig );
cacheManager.defineConfiguration( "Foo2SubFoos", indexDefaultConfig );
}

@Produces
public Cache<Long, Foo> createFooCache()
{
final Cache<Long, Foo> entityCache = cacheManager.getCache( "Foos" );
return entityCache;
}

@Produces
public Cache<Long, SubFoo> createSubFooCache()
{
final Cache<Long, SubFoo> entityCache = cacheManager.getCache( "SubFoos" );
return entityCache;
}

@Produces
public TreeCache<Long, Boolean> createFoo2SubFoos()
{
Cache<Long, Boolean> cache = cacheManager.getCache("Foo2SubFoos");

final TreeCacheFactory treeCacheFactory = new TreeCacheFactory();
final TreeCache<Long, Boolean> treeCache = treeCacheFactory.createTreeCache( cache );

return treeCache;
}
}

我扩展了我的 FooService 以支持 TreeCache:当添加、删除或删除 subFoo id 时,foo2SubFoo 缓存也会刷新。

public class FooService
{
@Inject
EntityManger em;

@Inject
Cache<Long, Foo> fooCache;

@Inject
Cache<Long, SubFoo> subFooCache;

@Inject
TreeCache<Long, Boolean> foo2SubFoosCache;


public void save(Foo foo)
{
em.save(foo);
fooCache.put(foo.id, foo);
}

public void save(SubFoo subFoo)
{
em.save(subFoo);
subFooCache.put(subFoo.id, subFoo);

Fqn fqn = Fqn.fromElements( subFoo.fooId );
foo2SubFoosCache.put( fqn, subFoo,id, Boolean.TRUE );
}

public void remove ....

public void update ....

public Foo get(Long fooId)
{
return fooCache.get(fooId);
}

public SubFoo get(Long subFooId)
{
return subFooCache.get(subFooId);
}


public List<SubFoo> findSubFoo(Long fooId)
{
Fqn fqn = Fqn.fromElements( fooId );
return foo2SubFoosCache.getKeys(fooId).stream().map( subFooId -> subFooCache.get(subFooId)).collect( Collector.list() );
}
}

最佳答案

Infinispan 具有索引功能。查找“Infinispan 查询”。

就我个人而言,我不太喜欢在缓存中建立索引。供应商之间的功能非常不同,即使存在。对于像您这样的问题,我看不到进行索引编制的理由。我建议尝试适用于任何缓存的最简单的解决方案。

解决方案一:

添加另一个缓存,本质上是从 foo ID 到 subFoo ID 的索引:Cache<Long, List<Long>>

由于此缓存仅存储 ID,因此没有数据重复。

解决方案 2:

将 subFoo ID 添加到父实体的缓存中:

class CachedFoo {
Foo foo;
List<Long> subFooIds;
}

Cache<Long, CachedFoo> fooCache;

解决方案 3:

如果您没有那么多数据并且findSubFoo很少使用,请考虑使用签名 Cache<Long, List<SubFoo> 的进程缓存中的替代方案.进程内缓存应该存储对象引用而不是数据值,因此您没有冗余。

关于java - 在 Infinispan 中缓存类似父子关系的数据库索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39196100/

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