2011-03-21 78 views
0

说我有以下部署为本地SLSB通用的DAO:应该在EJB 3.0 DAO中使用em.flush来抽象持久层?

public interface CrudService { 

public <T> T create(T t); 

public <T> T find(Object id, Class<T> type); 

public <T> T update(T t); 

public void delete(Object t); 

public List<Object> findByNamedQuery(String queryName); 

public List<Object> findByNamedQuery(String queryName, int resultLimit); 

public List<Object> findByNamedQuery(String namedQueryName, Map<String, Object> parameters); 

public List<Object> findByNamedQuery(String namedQueryName, Map<String, Object> parameters, int resultLimit); 

}

这DAO是从许多其他SLSB服务使用。我想从业务逻辑中抽象出整个持久层(所有操作和异常)。我创建了@AroundInvoke方法拦截像下面,把它放在DAO的类层次:

@AroundInvoke 
public Object wrapExceptions(InvocationContext context) throws Exception { 
    try { 
      return context.proceed();   
    } catch(Exception e) { 
       throw mapToApplicationException(e) 
    } 
} 

没有异常被捕获,并因此映射具有DAO方法的默认实现。 但是如果我在持久化结束时使用flush,更新和删除它的工作方式 - 那没关系。

现在我的问题是:它是唯一能让它工作的方法吗?我知道调用flush是相当沉重的,如果我需要打电话让我们说更新多次,这将是一个严重的瓶颈。

编辑: 另一种选择是使用BMT,但它会导致与tx.begin()等被污染的所有门面方法......克里斯·巴比奇答案后

编辑:

我根据克里斯的提议有些疑问。处理服务层中的PersisteceExceptions会导致混合图层透明度。但这对我来说并不是最糟糕的。假设我有服务门面使用我的服务或DAO集。服务门面方法需要在自己的事务上执行,所以我会使用CMT并用@TransactionAttribute(REQUIRES_NEW)标记它。这样做没有地方可以有异常处理点(拦截器不起作用,因为交易仍在进行中 - 这与上述情况相同)。所以我看到两种方法:要么有所有的外观方法使用BMT并处理所有的tx.begin(),tx.commit()等东西,要么有另一个“Facade for Facade”拥有@TransactionAttribute(从不),然后调用交易门面和处理它是例外。

+0

记住生命周期拦截器不需要在服务本身中定义。您希望将常见拦截逻辑(如错误处理)分离为可应用于多个类,服务等的独立拦截器类。此分隔可让您将业务功能与标准异常之间的关注区分开来处理。 – 2011-03-24 22:08:59

+0

至于持久性异常与其他异常之间的区别,取决于异常处理的目标。你在乎什么是例外情况或者发生了错误情况?您是试图实现一个通用的错误处理框架,还是需要以不同的方式处理每种类型的错误?通过异常处理,您应该实现一个通用处理框架,并且只能手动处理需要处理的异常或需要应用程序更改其处理流程的异常。其余的应该由你的错误框架自动处理。 – 2011-03-24 22:11:24

+0

也许我没有说清楚。我的前夫。处理拦截器实际上是一个独立的类。根据异常处理,我希望我的服务门面客户端只处理除了所有javax.persistence.PersistenceException之外的自定义应用程序定义的异常。 – veilsoen 2011-03-25 08:30:29

回答

0

我想这一切都取决于你想要做什么。如果您希望所有数据立即插入到数据库中,并且可以立即使用该插入导致的任何问题,那么您实际上只有两种选择:专门在EntityManager上调用flush(),这将导致所有批处理数据源操作成为执行,或者指定一个事务以DAO方法开始和结束(这里有不同的选项,但我不会在这里进入)。这两个选项都会对性能和成功的业务事务定义产生负面影响。

JPA实现中的一个特性就是PersistenceContext的概念。 PersistenceContext是一组被管理的实体。这些实体的生命周期由EntityManager管理。 EntityManager的部分职责是管理PersistenceContext的更改何时与数据源同步。 EntityManager可能会对PersistenceContext进行一些更改批处理,并在稍后的时间点(如在事务提交期间)同步它们。在这种情况下,如果将数据插入数据库时​​出现问题,则可能会在稍后的某个时间才能看到异常。对em.flush()的调用会立即导致数据源同步,从而引发数据库插入期间可能发生的任何异常。

异常处理的一个好方法是只将它添加到需要它的地方。将它添加到抛出RuntimeExceptions的底层方法并不一定是一个好的候选者。如果想要添加一致的错误处理(例如转换为常见的RuntimeException),那么您希望在公共入口点(例如业务层或类似的位置)执行此操作。这使您可以限制需要维护的异常处理总量,尤其是因为错误实际上可能发生在应用程序中的任何位置。我还建议您在主要事务入口点处有异常处理,因为这是您需要管理任何意外异常的地方,只有在事务提交期间才会发生异常,特别是在使用乐观锁定时。

只是有些想法,希望他们帮助。

+0

非常感谢您的回答。我编辑了我的文章,对您的解决方案有一些想法。 – veilsoen 2011-03-24 10:06:26