首页 文章

@Transactional注释在哪里?

提问于
浏览
452

您应该将 @Transactional 放在 DAO 类和/或它们的方法中,还是更好地注释使用DAO对象调用的Service类?或者注释"layers"是否有意义?

19 回答

  • 12

    理想情况下,服务层(Manager)代表您的业务逻辑,因此应使用_635448注释.Service层可以调用不同的DAO来执行数据库操作 . 让我们假设您在服务方法中有N个DAO操作的情况 . 如果您的第一个DAO操作失败,其他人可能仍然通过,您将最终导致不一致的DB状态 . 注释服务层可以帮助您避免这种情况 .

  • 4

    我更喜欢在方法级别的服务层上使用 @Transactional .

  • 0

    @Transactional 在服务层中使用,该服务层通过使用控制器层( @Controller )和服务层调用DAO层( @Repository )来调用,即数据库相关操作 .

  • 274

    enter image description here

    @Transactional 应该在服务层上使用,因为它包含业务逻辑 . DAO层通常只有数据库CRUD操作 .

    // the service class that we want to make transactional
    @Transactional
    public class DefaultFooService implements FooService {
    
        Foo getFoo(String fooName);
    
        Foo getFoo(String fooName, String barName);
    
        void insertFoo(Foo foo);
    
        void updateFoo(Foo foo);
    }
    

    Spring doc:https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/transaction.html

  • 37

    我认为交易属于服务层 . 它是了解工作单元和用例的人 . 如果您将几个DAO注入到需要在单个事务中协同工作的服务中,那么这是正确的答案 .

  • 37

    一般而言,我同意其他人的观点,即交易通常是在服务级别上启动的(取决于您当然需要的粒度) .

    但是,与此同时,我也开始将 @Transactional(propagation = Propagation.MANDATORY) 添加到我的DAO层(以及其他不允许启动事务但需要现有事务的层),因为在忘记在调用者中启动事务时,更容易检测错误(例如服务) . 如果您的DAO使用强制传播进行注释,则会收到一个异常,指出在调用该方法时没有活动事务 .

    我还有一个集成测试,其中我检查所有bean(bean post processor)以获取此注释,如果在不属于服务层的bean中存在除了Mandatory之外的传播的 @Transactional 注释,则会失败 . 这样我确保我们不会在错误的层上启动事务 .

  • 29

    Transactional Annotations应围绕所有不可分割的操作 .

    例如,您的电话是“更改密码” . 这包括两个操作

    • 更改密码 .

    • 审核变更 .

    • 通过电子邮件向客户端发送密码已更改 .

    所以在上面,如果审核失败,那么密码更改是否也会失败?如果是这样,那么交易应该在1和2左右(所以在服务层) . 如果电子邮件失败(可能应该具有某种故障安全性,因此它不会失败)那么它应该回滚更改密码和审核吗?

    这些是你在决定把 @Transactional 放在哪里时需要问的问题 .

  • 17

    通常的情况是在服务层级别上进行注释,但这实际上取决于您的要求 .

    在服务层上添加注释将导致比DAO级别上的注释更长的事务 . 取决于可以解决问题的事务隔离级别,因为并发事务不会看到彼此的更改,例如 . 可重复阅读 .

    对DAO进行注释将使事务保持尽可能短,缺点是服务层公开的功能不会在单个(可回滚)事务中完成 .

    如果传播模式设置为默认值,则注释两个图层没有意义 .

  • 15

    传统Spring体系结构的正确答案是在服务类上放置事务语义,这是其他人已经描述过的原因 .

    Spring 天的一个新兴趋势是朝着domain-driven design(DDD) . Spring Roo很好地举例说明了这一趋势 . 我们的想法是使域对象POJO比典型的Spring架构(通常它们是anemic)要多得多,特别是将事务和持久性语义放在域对象本身上 . 如果所有's needed is simple CRUD operations, the web controllers operate directly on the domain object POJOs (they'在此上下文中作为实体运行,并且域对象之间需要某种协调,则可以使用 @Transaction 按照传统使用服务bean句柄 . 您可以将域对象上的事务传播设置为类似 REQUIRED 的内容,以便域对象使用任何现有事务,例如在服务bean上启动的事务 .

    从技术上讲,这种技术使用了AspectJ和 <context:spring-configured /> . Roo使用AspectJ交互式定义将实体语义(事务和持久性)与域对象(基本上是字段和业务方法)分开 .

  • 3

    我将 @Transactional 放在 @Service 图层上并设置 rollbackFor 任何异常和 readOnly 以进一步优化事务 .

    默认情况下 @Transactional 将仅查找 RuntimeException (未经检查的异常),通过将回滚设置为 Exception.class (已检查的异常),它将回滚任何异常 .

    @Transactional(readOnly = false, rollbackFor = Exception.class)
    

    Checked vs. Unchecked Exceptions .

  • 13

    Or does it make sense to annotate both "layers"? - 注释服务层和dao层是否有意义 - 如果想要确保始终从DAO中具有传播"mandatory"的服务层调用(传播)DAO方法 . 这将为从UI层(或控制器)调用DAO方法提供一些限制 . 此外 - 当特别是对DAO层进行单元测试时 - 对DAO进行注释也将确保对其进行交易功能测试 .

  • 5

    另外,Spring建议仅在具体类而不是接口上使用注释 .

    http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html

  • 2

    对于数据库级别的事务

    大多数时候我在DAO的方法中使用了 @Transactional 级别,所以配置可以专门用于方法/使用默认值(必需)

    • DAO 's method that get data fetch (select .. ) - don' t需要 @Transactional 这可能会导致一些开销,因为事务拦截器/和AOP代理也需要执行 .

    • DAO的插入/更新方法将获得 @Transactional

    非常好的博客transctional

    对于申请级别 -
    我正在使用事务性的业务逻辑我希望能够在出现意外错误时回滚

    @Transactional(rollbackFor={MyApplicationException.class})
    public void myMethod(){
    
        try {    
            //service logic here     
        } catch(Throwable e) {
    
            log.error(e)
            throw new MyApplicationException(..);
        }
    }
    
  • 1

    通常,应该在服务层放置一个事务 .

    但如前所述,操作的原子性告诉我们注释在哪里是必要的 . 因此,如果您使用像Hibernate这样的框架,其中对对象的单个“保存/更新/删除/修改”操作可能会修改多个表中的多个行(因为通过对象图层级联),当然还应该对这种特定的DAO方法进行事务管理 .

  • 1

    最好将它放在服务层中!昨天我遇到的一篇文章清楚地解释了这一点!这是the link,你可以看看!

  • 7

    @Transactional 应在所有不可分割的操作周围放置注释 . 使用 @Transactional 事务传播是自动处理的 . 在这种情况下,如果当前方法调用另一个方法,那么该方法将具有加入正在进行的事务的选项 .

    让我们举个例子:

    我们有2个模型,即 CountryCity . CountryCity 模型的关系映射就像一个 Country 可以有多个城市所以映射就像,

    @OneToMany(fetch = FetchType.LAZY, mappedBy="country")
    private Set<City> cities;
    

    这里国家映射到多个城市,并提取它们 Lazily . 因此,当我们从数据库中检索Country对象时,我们将获得 @Transactinal 的角色,然后我们将获得Country对象的所有数据但不会获得城市集,因为我们正在获取城市 LAZILY .

    //Without @Transactional
    public Country getCountry(){
       Country country = countryRepository.getCountry();
       //After getting Country Object connection between countryRepository and database is Closed 
    }
    

    当我们想要从country对象访问City of Cities时,我们将在该Set中获取null值,因为Set的对象只创建了这个Set没有初始化那里有数据来获取Set的值我们使用 @Transactional 即,

    //with @Transactional
    @Transactional
    public Country getCountry(){
       Country country = countryRepository.getCountry();
       //below when we initialize cities using object country so that directly communicate with database and retrieve all cities from database this happens just because of @Transactinal
       Object object = country.getCities().size();   
    }
    

    所以基本上 @Transactional 是服务可以在单个事务中进行多次调用而不关闭与 endpoints 的连接 .

  • 467

    首先让我们定义我们必须使用 transaction 的位置?

    我认为正确答案是 - 当我们需要确保将一系列操作作为一个原子操作完成时,或者即使其中一个操作失败也不会进行任何更改 .

    众所周知,将业务逻辑放入服务中 . 因此,服务方法可能包含必须作为单个逻辑工作单元执行的不同操作 . 如果是这样 - 那么这种方法必须标记为 Transactional . 当然,并非每种方法都需要这样的限制,因此您不需要将整个服务标记为事务性的 .

    甚至更多 - 不要忘记考虑到 @Transactional 显然,可能会降低方法性能 . 为了查看整个图片,您必须知道事务隔离级别 . 知道这可能会帮助您避免在不一定需要的地方使用@Transactional .

  • 1

    服务层是添加 @Transactional 注释作为此处存在的大多数业务逻辑的最佳位置,它包含详细级别的用例行为 .

    假设我们将它添加到DAO,并且从服务我们调用2个DAO类,一个失败并且其他成功,在这种情况下,如果 @Transactional 不在服务上,则一个DB将提交而其他将回滚 .

    因此,我的建议是明智地使用此注释,并仅在服务层使用 .

    Github project- java-algos

  • 77

    最好将 @Transactional 保存在DAO和服务层之间的单独中间层中 . 由于回滚非常重要,您可以将所有数据库操作放在中间层,并在服务层中编写业务逻辑 . 中间层将与您的DAO层交互 .

    这将在许多情况下帮助您,例如 ObjectOptimisticLockingFailureException - 只有在您的交易结束后才会发生此异常 . 所以,你不能在中间层捕获它,但你现在可以捕获你的服务层 . 这个会如果你在服务层有@Transactional,则无法实现 . 虽然你可以捕获控制器,但控制器应该尽可能干净 .

    如果您在完成所有保存,删除和更新选项后以单独的线程发送邮件或短信,则可以在中间层完成交易后在服务中执行此操作 . 同样,如果您在服务层中提及@Transactional,即使您的交易失败,您也会收到邮件 .

    因此,拥有一个中间@Transaction层将有助于使您的代码更好,更容易处理 . 否则,如果在DAO层中使用,则可能无法回滚所有操作 . 如果在Service层中使用,则在某些情况下可能必须使用 AOP (面向方面编程) .

相关问题