所以我已经开始使用这种通用DAO了,而且面值似乎没问题。它基本上是在Hibernate人员的CaveatEmptor示例应用程序之后建模的。
最重要的是,我有一个业务层......应用程序的内容。它完全没有意识到任何特定的DAO实现。
到目前为止,一切似乎都很好,直到我开始考虑交易。如果交易留给客户实施,那么我在世界上如何保持我在各层之间进行的良好分离?也就是说,我现在正在使用Hibernate,而且我真的不太喜欢在我的业务层代码中添加特定于hibernate的事务。我可以使用begin,commit和rollback方法创建一个简单的事务接口,并将实现传递给我的业务层...但是......我不确定......
所以这就是挑战:您能否为我推荐一种方法,而不使用Spring(或EJB或任何其他附加框架)这个词?
答案 0 :(得分:12)
我记得Martin Fowler建议在业务层中保持对交易的控制,因为交易是一个业务问题。 (如果您设计了BankAccount类,则事务是域语言的一部分。)
您可以尝试在.NET中实现TransactionScope,它可以像
那样工作using (TransactionScope ts = new TransactionScope())
{
...
}
这是一回事(不完全如此,但如果你是一个Java人,那你就更明确了)
TransactionScope scope = new TransactionScope();
try
{
...
scope.Commit();
}
catch(Exception ex)
{
scope.Rollback();
throw;
}
要将业务层与任何DAO技术分离,您可以在域语言中添加TransactionFactory,它返回您使用Commit和Rollback方法定义的ITransactionScope(接口)。这样你的域层就不会绑定到你的DAO层,只有TransactionFactory的具体实现是。
ITransactionScope scope = transactionFactory.CreateTransaction();
try
{
...
scope.Commit();
}
catch(Exception ex)
{
scope.Rollback();
throw;
}
答案 1 :(得分:6)
在Web应用程序中,我所做的划分事务的方法是利用HTTP请求/响应周期,其中每个原子业务操作在其中一个周期的范围内,在一个专用线程中执行。
无论使用何种Web框架(Struts,JSF,GWT等),通常都存在可以执行事务划分的“接缝”。在Struts中,它可以是一个基本的Action类。在GWT中,它可以是基本的RemoteServiceImpl类。
因此,使用该中心访问点来打开事务(在允许特定于应用程序的代码之前执行),并在没有异常冒泡或其他情况下(在特定于应用程序的代码之后)通过提交来终止它被执行了。)
我在一个庞大而复杂的商业网络应用中广泛应用了这一策略,事实证明它非常有效。
答案 2 :(得分:3)
对于答案来说,这可能有点太晚了,但如何为业务层和dao层之间的特定事务创建另一个类?例如。如果要在某个特定foo()业务方法的事务中运行来自DAO的方法a()和b(),则创建类似fooInTransaction()的东西,它启动一个事务并在其中调用()和b() 。业务方法foo()委托给它。
这将使业务代码保持清洁,并且可以通过重新分解来避免重复。
答案 3 :(得分:1)
您有权使应用程序成为协调事务的好地方,因为这样可以构成由各种服务/经理/或任何您想要调用它们的更复杂的操作。
一个简单的解决方案是定义ITransaction接口,并使用某种类型的工厂或DI来隐藏应用程序中的实际ITransaction实现者。我使用nHibernate在.net中编写了我自己的内容,基本上我有一个基类,我的所有管理器(在这种情况下,一个管理器包含一个逻辑实体集的业务逻辑,如Membership,Order可能使用一个或多个存储库)。我的基类有一个ITransaction BeginTransaction(),它根据配置文件动态创建一个类型。
该类然后与nHibernate的Session一起开始并提交事务。
答案 4 :(得分:1)
过去我将事务逻辑放在根DAO中,用于DAO层次结构,该层次结构与模型中表示系统中单个实体实体的对象层次结构相匹配。
也就是说,如果你有和X有很多Y,并且你想要同时存储和检索X和它们的Ys作为单个复合对象,那么你的DAO for X也应该为Y调用DAO。然后你可以在DAO for X中的add()和update()方法中放置一个事务 - 甚至将Y DAO包私有化,以将其隐藏在主业务逻辑中。 即,而不是业务逻辑:
XDAO xDAO = new XDAO(conn);
xDAO.startTransaction();
boolean success = xDAO.add(x);
if (success)
for (Y y : x.getYs()) {
success = YDAO.add(y);
if (!success) break;
}
if (success)
xDAO.commit();
else
xDAO.rollback();
你只需要:
XDAO xDAO = new XDAO(conn);
xDAO.add(x);
(该DAO内部的成功/提交/回滚逻辑)
然而,这并不能涵盖所有情况,你的可能会有所不同(例如我的使用JDBC,我不知道Hibernate是如何工作的,或者是否有可能)。