事务注解 @Transactional一般的话为什么都加在service层而不加在dao层

原文地址:https://blog.csdn.net/panyangxu/article/details/77431873

什么是事务?


在数据库中,所谓事务是指一组逻辑操作单元即一组sql语句。当这个单元中的一部分操作失败,整个事务回滚,只有全部正确才完成提交。判断事务是否配置成功的关键点在于出现异常时事务是否会回滚

事务四大特性


1. 原子性(Atomicity) 
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生

2. 一致性(Consistency) 
事务必须使数据库从一个一致性状态变换到另外一个一致性状态。(数据不被破坏

3.隔离性(Isolation) 
事务的隔离性是指一个事务的执行不能被其他事务干扰.

4.持久性(Durability) 
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的.即使系统重启也不会丢失.


结合事务的特点,为什么加在service层就很好解释了。如果我们的事务注解@Transactional加在dao层,那么只要与数据库做增删改,就要提交一次事务,如此做事务的特性就发挥不出来,尤其是事务的一致性,当出现并发问题是,用户从数据库查到的数据都会有所偏差。 
一般的时候,我们的service层可以调用多个dao层,我们只需要在service层加一个事务注解@Transactional,这样我们就可以一个事务处理多个请求,事务的特性也会充分的发挥出来。

也可以这么说:

因为一个Service完成一个服务,但是可能会调用很多个DAO层的功能,如果Transaction放在DAO层的话,做完一个DAO,就会提交一次事务,永久修改数据库,后面在调用另外一个DAO,但是throws Exception,对于整个的Service来说,应该是要完全回滚的,但是只能回滚到当前的DAO

所以这就破坏了事务的ACID

有一些项目的事务是在Controller层。

<think>嗯,用户的问题是关于系统设计中是否可能只复用DAO而不复用逻辑,也就是Service。首先,我需要理解DAOService各自的作用。根据提供的引用内容,DAO主要负责数据访问,比如直接和数据库交互,执行CRUD操作。而Service处理业务逻辑,协调多个DAO操作,确保业务规则的执行。 用户提到他们看到有些地方Service似乎只是调用DAO,没有太多实际代码,所以可能觉得复用DAO而不用Service可以节省代码量。但根据引用[2]和[4],Service其实有它的必要性,比如处理事务、业务规则,避免代码重复,遵循单一职责原则。所以直接复用DAO而不考虑Service可能会带来问题。 接下来,我需要分析可行性和优缺点。可行性方面,技术上当然可以直接调用DAO,特别是在简单场景中,比如CRUD操作不需要复杂业务逻辑时。但如果是复杂业务,多个DAO操作需要事务管理,或者有业务规则,这时候没有Service就会导致代码分散,难以维护。 优点的话,可能包括减少级,简化代码,适合简单项目。缺点就比较多了,比如业务逻辑分散,重复代码,事务管理困难,耦合度高,扩展性差,还有违反设计原则如单一职责。这些都需要详细说明,并引用提供的资料来支持。 另外,用户可能是在考虑系统设计时的次划分,或者在做一些旧系统的重构,想要复用现有的DAO但不想引入Service。这时候需要权衡利弊,可能适合简单应用,但复杂系统会面临维护问题。 最后,生成相关问题的时候,需要围绕分架构、合并次的影响、事务处理、适用场景以及实际案例来提问,这样可以帮助用户更深入理解问题。</think>### 是否可以在系统设计中只复用DAO而不复用逻辑? #### 可行性分析 从技术实现面看,**直接复用DAO而不复用逻辑是可行的**,尤其是在以下场景中: 1. **简单CRUD操作**:若系统仅需直接操作数据库(如增删改查),无需复杂业务逻辑,DAO可直接被视图调用[^4]。 2. **快速原型开发**:小型项目或临时性需求中,省略逻辑可减少代码级,加快开发速度。 3. **特定工具类场景**:若DAO已封装通用数据操作(如分页查询、批量插入),且业务逻辑无复用价值时,可直接调用DAO[^3]。 #### 优点 1. **减少代码级**:省去逻辑后,调用链路变为`视图DAO`,降低架构复杂度。 2. **开发效率提升**:适用于业务逻辑极简的场景,避免编写冗余的Service接口和实现类[^2]。 3. **资源占用更低**:减少对象创建和方法调用栈深度,理论上能略微提升性能。 #### 缺点 1. **业务逻辑分散**:核心业务规则可能直接分散在视图中,导致代码重复(如多个视图需校验订单状态时需重复编写校验逻辑)[^2]。 2. **事务管理困难**:跨多个DAO操作的原子性难以保证(如转账操作需同时更新两个账户,若直接调用DAO则需手动控制事务)[^4]。 3. **耦合度升高**:视图直接依赖DAO,若需更换数据源或调整数据访问逻辑,需修改所有调用点[^3]。 4. **违反分原则**:破坏了经典三架构(表现-业务-数据)的职责分离,可能导致代码维护成本增加[^1]。 5. **可扩展性受限**:添加缓存、日志等横切关注点时,需侵入视图代码而非通过Service统一处理[^4]。 #### 典型场景对比 | 场景 | 适用性 | 示例 | |---------------------|--------|-------------------------------| | 简单数据透传 | ✅ | 后台管理系统的基础数据维护 | | 复杂业务流程 | ❌ | 电商订单创建(涉及库存、支付)| | 高频数据读操作 | ⚠️ | 报表数据查询(需权衡性能需求)| | 多数据源协同操作 | ❌ | 银行跨行转账 | #### 建议方案 1. **分渐进式设计**: - 初期简单场景可直接复用DAO - 随着业务复杂化逐步引入Service - 通过`门面模式(Facade)`封装多个DAO操作[^3] 2. **逻辑轻量化**: - 采用`贫血模型`,将业务逻辑移至工具类 - 通过`@Transactional`注解实现声明式事务管理[^4] 3. **接口规范化**: - 即使暂时不实现Service,也应定义接口规范 - 遵循`实体类名+Service`的命名规则,为后续扩展预留空间 #### 示例代码对比 **直接调用DAO:** ```java // 视图直接操作DAO UserDao userDao = new UserDaoImpl(); boolean success = userDao.updatePassword(userId, newPassword); ``` **通过逻辑调用:** ```java // 通过Service封装业务规则 UserService userService = new UserServiceImpl(); boolean success = userService.changePassword(userId, oldPassword, newPassword); // Service内部实现 public boolean changePassword(Long userId, String old, String new) { User user = userDao.findById(userId); if (!user.getPassword().equals(hash(old))) return false; return userDao.updatePassword(userId, hash(new)); } ``` ### 相关问题
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值