简体   繁体   English

使用Spring,Hibernate和Ehcache缓存整个数据库

[英]Cache a whole database using Spring, Hibernate, and Ehcache

I am working on an application which relies on caching using mostly reads and some updates. 我正在开发一个应用程序,该应用程序主要使用读取和某些更新来进行缓存。

The technology stack I am using is Spring + Hibernate + Ehcache. 我使用的技术堆栈是Spring + Hibernate + Ehcache。 I need to serve the requests using the cache and not hit the database at all. 我需要使用缓存为请求提供服务,而根本不访问数据库。 The approach I am following is to cache all of the data at the application start up using queries such as getSession().createCriteria(<Entity>.class).list() and then ask Hibernate for entities using a session.get() call so that it uses the second level cache to resolve. 我采用的方法是使用诸如getSession().createCriteria(<Entity>.class).list()查询在应用程序启动时缓存所有数据,然后使用session.get()向Hibernate询问实体调用,以便它使用二级缓存进行解析。

One challenge I see is my entity classes have a lot of collection and association attributes (Many-to-Many with extra columns, One-to-Many, One-to-One). 我看到的一个挑战是我的实体类具有很多集合和关联属性(多对多带有额外的列,一对多,一对一)。

I have two approaches for such a cache: 对于这种缓存,我有两种方法:

  1. Keep all relationships as EAGER fetch. 保留所有关系,以获取EAGER。 The cache will be filled with the data with a big query containing left outer joins on startup. 启动时,缓存中将使用包含左外部联接的大查询填充数据。 I am concerned that loading data eagerly may cause unnecessary long running queries returning multiple rows. 我担心急于加载数据可能会导致不必要的长时间运行的查询返回多行。

  2. Keep relationships as LAZY and iterate over all the rows and call .getSetOf<Entity> to load related entities. 将关系保持为LAZY并遍历所有行,然后调用.getSetOf<Entity>以加载相关的实体。 I am concerned that I will be virtually iterating all of the data at startup and I'm not sure if whether this is a good practice. 我担心在启动时实际上会对所有数据进行迭代,因此我不确定这是否是一个好习惯。

Since the associations in Hibernate are associated using composition and foreign keys and not stored as individual IDs, loading of such associations/collections seems to be overhead. 由于Hibernate中的关联是使用组合键和外键关联的,而不是作为单独的ID存储的,因此加载此类关联/集合似乎很麻烦。

I would have preferred having table data in different cache regions with their foreign key relationships as just IDs (not compositions/collections). 我更希望表数据位于不同的缓存区域中,它们的外键关系只是ID(而不是合成/集合)。 I would have cached all such entities in different regions and would have combined the results at runtime by iterating over those regions. 我将所有这些实体缓存在不同的区域中,并在运行时通过遍历这些区域来组合结果。

Can anyone suggest what approach should I follow? 谁能建议我应该采用哪种方法? If there is any alternate approach, do suggest. 如果有其他替代方法,请提出建议。

I am working on a project having technology stack spring+hibernate+hazelcast . 我正在一个项目中进行技术堆栈spring + hibernate + hazelcast I am using hibernate 2nd level cache also. 我也在使用休眠二级缓存 We also load data into cache on server startup. 我们还将在服务器启动时将数据加载到缓存中。 According to me you should not do all collections of an entity eager as it makes the object very heavy.We are using mixed approach.Some of our collections are eager and some are lazy depending upon the requirement. 根据我的说法,您不应该对一个急切的实体进行所有收集,因为它会使对象变得很沉重。我们正在使用混合方法。根据需要,我们的一些收集是渴望的,有些是懒惰的。 If your collection has very large data then make it lazy otherwise make it eager. 如果您的馆藏数据非常庞大,请使其变得懒惰,否则请使其热心。 One more thing we are doing,we are using LEFT JOIN FETCH in queries which loads the collections also if collections are defined lazy.For eg:- 我们正在做的另一件事,就是在查询中使用LEFT JOIN FETCH ,如果集合定义为lazy,也将加载集合。例如:

SELECT DISTINCT userInfo FROM UserInfo userInfo
LEFT JOIN FETCH userInfo.userRoles
LEFT JOIN FETCH userInfo.regions
LEFT JOIN FETCH userInfo.countries

In my entity UserInfo , i have made region Eager (because regions are less in number) and countries Lazy (because countries are more in number).Now my this query still returns userInfo object fully loaded with countries and region.And due to Left Join Fetch no multiple queries get executed. 在我的实体UserInfo中,我使region Eager (因为区域数较少)和country Lazy (因为国家数较多)。现在,此查询仍返回已满载国家和地区的userInfo对象。提取不会执行多个查询。

I hope this can help you. 希望对您有所帮助。

It's not clear from your description if your application controls access to the database. 从您的描述还不清楚您的应用程序是否控制对数据库的访问。

  • If not then the performance documentation states you risk having stale data. 如果不是,则性能文档指出您可能会拥有过时的数据。 What do you do in this case? 在这种情况下您该怎么办?
  • If it is and only if you really need to minimize the number of db hits then I wouldn't use Hibernate nor Ehcache. 如果是这样,并且只有在您真的需要最大程度地减少数据库命中次数时,我才不会使用Hibernate或Ehcache。 Not much ORM going on except for the initial load which in my opinion doesn't make it much of a usecase for Hibernate. 除了初始负载外,ORM进行的工作不多,我认为这并不能成为Hibernate的用例。 I'd use Spring JDBC with a batch select on startup. 我会在启动时使用Spring JDBC进行批处理选择。 This will reduce the number of calls and a possible out of memory exception (a "normal" select statement references its read data, so as you progress throug the records you'll have more references which cannot be GC'ed). 这将减少调用次数,并减少可能的内存不足异常(“正常”的select语句将引用其读取的数据,因此随着记录的进行,您将拥有无法被GC引用的更多引用)。 It also reduces your technology stack with 1 burden less. 它还减少了1负担,从而减少了您的技术堆栈。 You can update the cache and database as soon as you change state. 您可以在更改状态后立即更新缓存和数据库。 You may need to take into account the transaction scope. 您可能需要考虑交易范围。 Left joins can be tackled within your mapper. 左联接可以在您的映射器中解决。 I'd also drop the OO approach and use arrays or maps of data. 我还将放弃面向对象的方法,并使用数组或数据映射。 Encapsulating each group of data with an object just for the sake of it may be overkill (memory consumption, cpu, ...). 仅出于对象的目的而用对象封装每组数据可能会过大(内存消耗,CPU,...)。 Especially the load-it-all-once requirement makes me think not a lot of interaction is happening here. 特别是一次全部加载的要求使我认为这里没有发生很多交互。 And drop Ehcache. 并删除Ehcache。 If you really need to minimize you database calls you can as well put everything in a Map as no eviction strategy is necessary. 如果确实需要最小化数据库调用,则可以将所有内容都放入Map中,因为不需要逐出策略。

Just to make it clear, I'm not anti OO or Hibernate or Ehcache. 为了清楚起见,我不是反对OO或Hibernate或Ehcache。 I'm just wondering if they're a good fit for your (limited) description. 我只是想知道它们是否适合您(有限的)说明。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM