Hibernate 为什么将@Transactional与@Service一起使用,而不是与@Controller一起使用

Hibernate 为什么将@Transactional与@Service一起使用,而不是与@Controller一起使用,hibernate,spring-mvc,service,controller,transactional,Hibernate,Spring Mvc,Service,Controller,Transactional,我在stack overflow的文章中看到了很多评论,我发现了一些关于@Transactional与@Service或@Controller一起使用的东西 通常,应该将事务放在服务层 “通常情况下,在服务层级别进行注释” “认为事务属于服务层。它了解工作单元和用例。如果将多个DAO注入到需要在单个事务中协同工作的服务中,这是正确的答案。” 与@service layer一起使用@transactional的缺点 如果我有两个方法,例如saveUser()和saveEmail()(因为我将电子邮

我在stack overflow的文章中看到了很多评论,我发现了一些关于@Transactional@Service@Controller一起使用的东西

通常,应该将事务放在服务层

“通常情况下,在服务层级别进行注释”

“认为事务属于服务层。它了解工作单元和用例。如果将多个DAO注入到需要在单个事务中协同工作的服务中,这是正确的答案。”

与@service layer一起使用@transactional的缺点

如果我有两个方法,例如saveUser()和saveEmail()(因为我将电子邮件存储在数据库中,以便以后发送,就像队列一样),我会在我的服务中创建一个方法saveuserandsendmail(用户用户),这将是事务性的

这意味着我在服务层创建了许多方法,而不是像下面那样保存一个通用方法

public <T> long save(T entity) throws DataAccessException {
    Session session = sessionFactory.getCurrentSession();
    long getGenVal=(Long) session.save(entity);
    return getGenVal;
}
在@Transactional on Service的情况下,前两个实体成功保存,但第三个实体未回滚所有事务

如果@Controller上的@Transactional发生异常,则所有事务都会回滚

为什么堆栈溢出会问:“不要在控制器中执行事务,将它们放在服务层类中。”?
您询问的是最佳实践,最佳实践是在服务层中标记
@Transactional
,因为
@Controller
不应该知道MVC逻辑中的数据持久性。
@Service
基于分析生成的用例构建,了解工作单元,并考虑重用:如果您从web上下文切换到桌面上下文(例如,或其他可视前端)如果
@Controller
层不存在,则不会出现问题,因为所有这些都封装在服务层中。
@Service
是一种契约,表示层中的修改不需要重写
@Service
代码。
但是Spring并不关心事务边界放在哪里,您可以放在
@Controller
上,但您的应用程序可能更难维护


我希望这足够清楚。对不起,如果没有;英语不是我的母语。

控制器位于视图层,可以随时更改。该服务仍然拥有工作单元,无论访问哪个视图,都应正确运行。我的答案仍然有效。

我创建了一个使用其他(非事务性)服务的上层服务。上层服务是事务性的

@Service
public class Service1Impl implements Servcie1 {
    public Object method11(){...}
    public Object method12(){...}
}

@Service
public class Service2Impl implements Service2 {
    public method21(){...}
}

public interface Service1 {
    public Object method11();
    public Object method12();
}

public interface Service2 {
    public Object method21();
}

@Transactional
public interface UpperLayerService {}

@Service
public class UpperLayerServiceImpl implements UpperLayerService {
    @Autowired
    private Service2 service2;
    @Autowired
    private Service3 service3;

    public Object doWork() {
        Object o1 = service1.method11();
        Object o2 = service1.method12();
        Object o3 = service2.method21();
        ....
        Object res = null;//...Any code
        return res;
    }
}

正如其他人所知,不鼓励使用接口注释


Spring建议只使用
@Transactional
注释具体类(以及具体类的方法),而不是注释接口。当然,您可以将
@Transactional
注释放置在接口(或接口方法)上,但这仅适用于使用基于接口的代理的情况。Java注释不是从接口继承的这一事实意味着,如果您使用基于类的代理(
proxy target class=“true”
)或基于编织的方面(
mode=“aspectj”
),则代理和编织基础结构无法识别事务设置,并且对象不会被包装在事务代理中,这绝对是不好的。

这意味着我必须创建许多保存方法,例如
saveAccount
saveAccountAudit
saveAccountAuditEntries
?我认为最好的解决方案是在
控制器
服务
之间创建另一个级别的层。在我看来,
controller
只处理调用,并准备vars来处理和执行逻辑。
服务
处理所有数据库内容。应该位于
控制器
服务
之间的模型可以执行一些逻辑。在您的示例中,执行少量保存操作是对数据执行操作的逻辑。这意味着将它们放入
model
并使用
transactional
扭曲
model
如果需要,您的
saveUser()
saveEmail()
方法应该在DAO层中。然后,在服务层中使用
saveuserandsendmail(User-User)
方法进行事务处理。
@Service
public class Service1Impl implements Servcie1 {
    public Object method11(){...}
    public Object method12(){...}
}

@Service
public class Service2Impl implements Service2 {
    public method21(){...}
}

public interface Service1 {
    public Object method11();
    public Object method12();
}

public interface Service2 {
    public Object method21();
}

@Transactional
public interface UpperLayerService {}

@Service
public class UpperLayerServiceImpl implements UpperLayerService {
    @Autowired
    private Service2 service2;
    @Autowired
    private Service3 service3;

    public Object doWork() {
        Object o1 = service1.method11();
        Object o2 = service1.method12();
        Object o3 = service2.method21();
        ....
        Object res = null;//...Any code
        return res;
    }
}