DAO 模式——交易适合哪里?
所以我已经完成了这个通用的 DAO 事情,从表面上看它似乎没问题。 它基本上是根据 Hibernate 人员的 CaveatEmptor 示例应用程序建模的。
最重要的是,我有一个业务层......应用程序的核心。 它完全不知道任何特定的 DAO 实现。
到目前为止一切似乎都很好,直到我开始考虑交易。 如果事务留给客户端来实现,那么我到底如何保持层之间的良好分离呢? 也就是说,我目前正在使用 Hibernate,并且我不太想将特定于 hibernate 的事务添加到我的业务层代码中。
我可以使用开始、提交和回滚方法创建一个简单的事务接口,并将实现传递给我的业务层...但是...我不确定...
所以这是挑战:你能推荐吗有没有一种方法可以让我在不使用 Spring(或 EJB,或任何其他附加框架)的情况下做到这一点?
So I've got this generic DAO thing going on and at face value it appears to be ok. It's basically modeled after the CaveatEmptor sample application from the Hibernate guys.
On top of that I have a business layer...the guts of the application. It's completely unaware of any specific DAO implementation.
Everything up to this point seems fine, until I start thinking about transactions. If transactions are left to the client to implement, then how in the world do I maintain the nice separation I've got going on between my layers? That is, I'm using Hibernate at the moment, and I don't really feel much like adding hibernate-specific transactions to my business layer code.
I could create a simple transaction interface with begin, commit, and rollback methods and pass an implementation to my business layer...but...I'm not sure...
So here is the challenge: can you recommend a way for me to do this without using the word Spring (or EJB, or any other additional framework)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您有权认为该应用程序是协调事务的好地方,因为这允许组合由各种服务/管理器/或您想称呼它们的任何内容实现的更复杂的操作。
一个简单的解决方案是定义一个 ITransaction 接口,并使用某种类型的工厂或 DI 从应用程序中隐藏实际的 ITransaction 实现者。 我使用 nHibernate 在 .net 中像这样推出了自己的产品,本质上我有一个基类,我的所有管理器(在本例中,管理器包含一组逻辑实体的业务逻辑,例如可能使用一个或多个存储库的成员资格、订单)。 我的基类有一个 ITransaction BeginTransaction(),它根据配置文件动态创建类型。
然后,该类与 nHibernate 的 Session 一起开始并提交事务。
Your right that the application is a good place to cordinate transactions as this allows composition of more complex actions implemented by various services / managers / or whatever you want to call them.
An easy solution is to define an ITransaction interface, and use some type of factory or DI to hide the actual ITransaction implementor from your application. I rolled my own like this in .net using nHibernate and essentially I have a base class that all my managers (A manager in this case contains business logic for a logical set of entities like Membership, Order which might use one or more repositories). My base class has a ITransaction BeginTransaction(), which dynamically creates a type based on a configuration file.
This class then works with nHibernate's Session to begin and commit transactions.
我记得 Martin Fowler建议将对事务的控制保留在业务层,因为事务是一个业务问题。 (如果您设计 BankAccount 类,则事务是域语言的一部分)。
您可以尝试实现 TransactionScope,就像在 .NET 中一样,它的工作原理与此
相同(不完全一样,但如果您是 Java 人员,这对您来说会更明确)
将您的业务层与您可以添加的任何 DAO 技术解耦您的域语言中的 TransactionFactory,它返回您使用 Commit 和 Rollback 方法定义的 ITransactionScope(接口)。 这样你的领域层就不会绑定到你的 DAO 层,只有 TransactionFactory 的具体实现是绑定的。
I remember that Martin Fowler advices to keep the control of the transaction in the business layer because transaction is a business problem. (If you design a BankAccount class, a transaction is part of the domain language).
You can try to implement a TransactionScope as in .NET it works something like that
It's the same thing as (not exactly but if you are a Java guy, it's more explicit to you)
To decouple your business layer from any DAO technologies you can add a TransactionFactory in your domain language, which return a ITransactionScope (an interface) that you have defined with a Commit and Rollback methods. This way your domain layer is not bound to your DAO layer, only a concrete implementation of TransactionFactory is.
在 Web 应用程序中,我划分事务的方法是利用 HTTP 请求/响应周期,其中每个原子业务操作在这些周期之一的范围内、在单个专用线程中执行。
无论使用哪种 Web 框架(Struts、JSF、GWT 等),通常都存在可以执行事务划分的“接缝”。 在 Struts 中,它可以是 Action 基类。 在 GWT 中,它可以是 RemoteServiceImpl 基类。
因此,使用该中心访问点来打开事务(在允许执行特定于应用程序的代码之前),如果没有出现异常,则通过提交来终止事务,否则进行回滚(在执行特定于应用程序的代码之后) 。
我在一个大型且复杂的商业 Web 应用程序中广泛应用了这种策略,事实证明它非常有效。
In a web app, what I do to demarcate transactions is to take advantage of the HTTP request/response cycle, where each atomic business operation executes in the scope of one of these cycles, in a single dedicated thread.
Whatever web framework is used (Struts, JSF, GWT, etc.), there typically exists a "seam" where transaction demarcation can be performed. In Struts, it can be a base Action class. In GWT, it can be a base RemoteServiceImpl class.
So, use that central point of access to open the transaction (before allowing the application-specific code to execute), and to terminate it with a commit if no exceptions bubbled up or a rollback otherwise (after the application-specific code was executed).
I applied this strategy extensively in a large and complex business web app, and it proved to work very well.
也许这对于答案来说有点太晚了,但是为特定事务创建另一个位于业务层和 dao 层之间的类怎么样? 例如,如果 DAO 中的方法 a() 和 b() 要在某个特定 foo() 业务方法的事务中运行,那么创建类似 fooInTransaction() 的东西来启动事务并调用 a() 和 b()它。 业务方法 foo() 委托给它。
这将使业务代码保持干净,并且可以通过重构来避免重复。
Maybe this is a bit too late for an answer, but how about creating another class for specific transactions, which sits between the business layer and the dao layer? E.g. if methods a() and b() from a DAO are to be run in a transaction for some specific foo() business method, then create something like fooInTransaction() that starts a transaction and calls a() and b() in it. The business method foo() delegates to it.
This will keep the business code clean and duplication can be avoided by re-factoring.
过去,我将事务逻辑放在 DAO 层次结构的根 DAO 中,该 DAO 层次结构与模型中代表系统中单个实体实体的对象层次结构相匹配。
即,如果您有一个 X,它有许多 Y,并且您希望同时存储和检索 X 及其 Y 作为单个复合对象,那么您的 X 的 DAO 也应该调用 Y 的 DAO。然后您可以将围绕 X 的 DAO 中的 add() 和 update() 方法中的所有内容进行事务 - 甚至将 Y DAO 包设为私有以将其隐藏在主要业务逻辑之外。
即,而不是业务逻辑:
您只需:(
该 DAO 内部有成功/提交/回滚逻辑)
但这并不能涵盖所有情况,您的可能会有所不同(例如我的工作与 JDBC 一起使用,我不知道)不知道 Hibernate 是如何工作的或者是否可能)。
In the past I've put the transaction logic in the root DAO for a hierarchy of DAOs that match to a hierarchy of Objects in your model that represent a single solid entity in the system.
I.e., if you have and X that has many Ys, and you want to store and retrieve Xs and their Ys at the same time as a single compound object, then your DAO for X should also call the DAO for Y. Then you can put a transaction around everything in your add() and update() methods in the DAO for X - and even make the Y DAO package private to hide it from your main business logic.
I.e., instead of business logic:
You would just have:
(with the success / commit / rollback logic internal to that DAO)
However this doesn't cover every situation, and yours may be different (for example mine works with JDBC, I don't know how Hibernate works or if it is possible there).