Caching is part of the DAL and does not belong in the BLL.
Let's take hibernate as an example, it use a caching system to store your entity's. Hibernate is responsible and know how to control his cache, (dirty read, flushing data etc)
You don't want to cluttered your BLL with all this low-level data logic.
I believe that the caching should be done in the business layer. The moment you try to get the data from DAL, you can check if the data is available in cache system.runtime.caching, then use cache data otherwise fetch data from the database. Moreover if you want to invalidate cache due to some reason, you can do it by calling a function in the business later.
The whole purpose in separating business logic from data is so that you can swap them out as business requirements or technology changes. By intermixing them, you are defeating this logic, and therefore, on a theoretical level you are correct. In the real world however, I think you need to be a bit more pragmatic. What's the real life expectancy of the application , what is the likelihood that the technology is going to change, and how much extra work is involved in keeping the two cleanly separated?
My initial reaction would be the same as yours, to let the data layer cache the information. This can even be integrated in with a strategy to subscribe to changes in the database, or implement polling to ensure the data is kept up-to-date.
However, if you intend to re-use the data layer in other projects, or even if not, it might not be a bad idea to implement a new business layer between the existing one and the data layer to handle caching decisions. Because ultimately, caching is a not just a performance issue, it does involve business decisions about concurrency and other matters.
An n-tier system is just that, you're not limited on how many levels you want to seperate things into.
I know I'm over two years late to the game but I wanted to add something:
If you have an interface defined for your DAL, you can write a caching mechanism that follows that interface and manages 'cache vs. hit the data source' concerns without the technology or source-specific DAL code having to worry about it and without the BLL having to worry about it. Example:
internal interface IThingsGateway
{
public Thing GetThing(int thingId);
public void UpdateThing(ThingUpdateInfo info);
}
internal class MsSqlThingsGateway : IThingsGateway
{
// implementation specific to MsSql here
}
internal class CachingThingsGateway : IThingsGateway
{
private IThingsGateway underlyingImplementation;
public CachingThingsGateway(IThingsGateway implementation)
{
this.underlyingGateway = implementation;
}
public Thing GetThing(int thingId)
{
if (this.HasCachedThing(thingId))
{
return this.GetCachedThing(thingId);
}
var thing = this.underlyingGateway.GetThing(thingId);
this.SetCachedThing(thingId);
return thing;
}
public void UpdateThing(ThingUpdateInfo info)
{
this.underlyingGateway.UpdateThing(info);
this.ClearCachedThing(info.ThingId);
}
}
And I would use this same approach if I needed to check multiple data sources for a thing: write an implementation of IThingsGateway that handles the logic of juggling the various data sources, delegating to the appropriate one... then wrap that in the CachingThingsGateway. Client code will ultimately obtain an IThingsGateway reference from some factory or container, which is where the wrapping and instantiating would occur.
And all of this really doesn't take that much extra effort. If you use caching you will have to write that code anyways, and the overhead generated by putting it in another class with the same interface is minimal at worst.
发布评论
评论(5)
我100%同意你的观点。
缓存是 DAL 的一部分,不属于 BLL。
让我们以 hibernate 为例,它使用缓存系统来存储您的实体。 Hibernate 负责并知道如何控制他的缓存(脏读、刷新数据等),
您不想让所有这些低级数据逻辑弄乱您的 BLL。
问候
I agree with you 100%.
Caching is part of the DAL and does not belong in the BLL.
Let's take hibernate as an example, it use a caching system to store your entity's. Hibernate is responsible and know how to control his cache, (dirty read, flushing data etc)
You don't want to cluttered your BLL with all this low-level data logic.
Regards
我认为缓存应该在业务层完成。当您尝试从DAL获取数据时,您可以检查缓存system.runtime.caching中是否有数据可用,然后使用缓存数据,否则从数据库中获取数据。而且如果因为某种原因想让缓存失效,可以通过稍后调用业务中的函数来实现。
I believe that the caching should be done in the business layer. The moment you try to get the data from DAL, you can check if the data is available in cache system.runtime.caching, then use cache data otherwise fetch data from the database. Moreover if you want to invalidate cache due to some reason, you can do it by calling a function in the business later.
将业务逻辑与数据分离的全部目的是,以便您可以随着业务需求或技术的变化而交换它们。通过混合它们,你就打败了这种逻辑,因此,在理论层面上你是正确的。然而,在现实世界中,我认为你需要更加务实一点。应用程序的实际预期寿命是多少,技术发生变化的可能性有多大,以及需要多少额外的工作才能将两者完全分开?
The whole purpose in separating business logic from data is so that you can swap them out as business requirements or technology changes. By intermixing them, you are defeating this logic, and therefore, on a theoretical level you are correct. In the real world however, I think you need to be a bit more pragmatic. What's the real life expectancy of the application , what is the likelihood that the technology is going to change, and how much extra work is involved in keeping the two cleanly separated?
我最初的反应和你的一样,让数据层缓存信息。这甚至可以与订阅数据库中的更改的策略集成,或实施轮询以确保数据保持最新。
但是,如果您打算在其他项目中重用数据层,或者即使不想重用,在现有业务层和数据层之间实现一个新的业务层来处理缓存决策也可能不是一个坏主意。因为归根结底,缓存不仅仅是一个性能问题,它确实涉及有关并发性和其他事务的业务决策。
n 层系统就是这样,您不限制将事物分成多少层。
My initial reaction would be the same as yours, to let the data layer cache the information. This can even be integrated in with a strategy to subscribe to changes in the database, or implement polling to ensure the data is kept up-to-date.
However, if you intend to re-use the data layer in other projects, or even if not, it might not be a bad idea to implement a new business layer between the existing one and the data layer to handle caching decisions. Because ultimately, caching is a not just a performance issue, it does involve business decisions about concurrency and other matters.
An n-tier system is just that, you're not limited on how many levels you want to seperate things into.
我知道我迟到了两年多,但我想添加一些内容:
如果您为 DAL 定义了一个接口,您可以编写一个遵循该接口的缓存机制并管理“缓存与命中数据源”技术或特定于源的 DAL 代码不必担心,BLL 也不必担心。示例:
如果我需要检查某个事物的多个数据源,我将使用相同的方法:编写一个 IThingsGateway 的实现来处理处理各种数据源的逻辑,并将其委托给适当的数据源。 ..然后将那个包装在
CachingThingsGateway
中。客户端代码最终将从某个工厂或容器获取ITingsGateway
引用,这是进行包装和实例化的地方。而所有这一切实际上并不需要太多额外的努力。如果您使用缓存,则无论如何都必须编写该代码,并且将其放入具有相同接口的另一个类中所产生的开销在最坏的情况下也是最小的。
I know I'm over two years late to the game but I wanted to add something:
If you have an interface defined for your DAL, you can write a caching mechanism that follows that interface and manages 'cache vs. hit the data source' concerns without the technology or source-specific DAL code having to worry about it and without the BLL having to worry about it. Example:
And I would use this same approach if I needed to check multiple data sources for a thing: write an implementation of
IThingsGateway
that handles the logic of juggling the various data sources, delegating to the appropriate one... then wrap that in theCachingThingsGateway
. Client code will ultimately obtain anIThingsGateway
reference from some factory or container, which is where the wrapping and instantiating would occur.And all of this really doesn't take that much extra effort. If you use caching you will have to write that code anyways, and the overhead generated by putting it in another class with the same interface is minimal at worst.