Spring Transactions 和通用 DAO 和服务的最佳实践

Posted

技术标签:

【中文标题】Spring Transactions 和通用 DAO 和服务的最佳实践【英文标题】:Best practices for Spring Transactions and generic DAOs & Services 【发布时间】:2013-06-08 13:17:38 【问题描述】:

我使用 Spring 和 JPA (EclispeLink) 开发 Java EE 应用程序。我们开发了一个用户友好的界面来管理数据库表。随着我现在对 Spring 和 Transactions 有了更多的了解,我决定重构我的代码以添加更好的事务管理。问题是如何最好地处理通用 DAO、通用服务和 Spring 事务?

我们目前的解决方案是:

处理所有常见数据库操作(查找、创建、更新、删除...)的通用 BasicDAO 一个 DaoFactory,其中包含所有实体类型的 BasicDao 实现映射(只需要基本的数据库操作),并获取 spring 注入的 entitymanager 以将其传递给 daos 提供通用服务的通用 BasicService(实际上直接链接到 dao 方法) ServiceFactory 包含所有实体类型的 BasicService 实现映射,它获取 daoFactory 注入并将其传递给服务。它有一个方法“getService(Class T)”来为控制器提供正确的服务。 对应于正确实体类型的控制器将其请求委托给通用控制器,后者使用反射处理请求参数并从服务工厂的映射中检索正确的服务以调用更新/创建/删除方法。

问题是,当我在通用服务上添加 @Transactionnal 注释并且我的 serviceFactory 在其映射中创建类型化服务时,这些服务似乎没有正在运行的活动事务。

1) 由于通用性和只有 spring 管理的服务可以进行事务的事实,这是否正常?

2) 解决我的问题的最佳解决方案是什么:

创建只实现通用服务的托管类型服务并将它们直接注入到我的 serviceFactory 中? 删除这些基础服务的服务层? (但也许我的 dao 通用层上的事务也会遇到同样的问题......) 其他建议?

我在网上阅读了一些与这些要点相关的问题,但找不到像这里这样笼统的例子,所以我希望有人能给我建议...提前谢谢!

【问题讨论】:

你不能继承注解... 这实际上不是关于继承...而是关于泛型类型的实例化(例如:IService projectService = new BasicService()// projectService 无法处理指定的事务在 BasicService 中,因为它不是托管实体...) 不要那样实例化你的服务 我也有类似的问题***.com/questions/16774962/… 【参考方案1】:

对于基本获取,您不需要服务层。

服务层用于处理多个聚合根 - 即涉及多个不同实体的复杂逻辑。

我的通用存储库实现如下所示:

public class DomainRepository<T> 

    @Resource(name = "sessionFactory")
    protected SessionFactory sessionFactory;

 public DomainRepository(Class genericType) 
        this.genericType = genericType;
    

 @Transactional(readOnly = true)
    public T get(final long id) 
        return (T) sessionFactory.getCurrentSession().get(genericType, id);
    

@Transactional(readOnly = true)
    public <T> List<T> getFieldEquals(String fieldName, Object value) 
        final Session session = sessionFactory.getCurrentSession();
        final Criteria crit = session.createCriteria(genericType).
                add(Restrictions.eq(fieldName, value));
        return crit.list();
    
//and so on ..

用 spring 实例化的不同类型:

<bean id="tagRepository" class="com.yourcompnay.data.DomainRepository">
        <constructor-arg value="com.yourcompnay.domain.Tag"/>
</bean>

并且可以这样引用:

@Resource(name = "tagRepository")
private DomainRepository<Tag> tagRepository;

并且也可以为复杂实体手动扩展。

【讨论】:

以上是关于Spring Transactions 和通用 DAO 和服务的最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

Distributed transactions in Spring, with and without XA

Spring JTA multiple resource transactions in Tomcat with Atomikos example

Spring transactions - 新事务中的异常导致父事务中的回滚

Hive 官方手册翻译 -- Hive Transactions (Hive 事务)

spring boot微服务通用部署启动脚本

经理/交易的目的是啥?