当前位置: 首页 > 知识库问答 >
问题:

@Transactional Annotation未执行回滚[重复]

应翰飞
2023-03-14

我试图创建一个API转移资金,即提款和存款。我使用@Transactional注释执行事务。但是也有某些条件,即如果银行帐号不存在,则应该通过运行时异常。我会在里面附加代码。现在,当调用transferBalanceMethod时,如果存款人的银行账户不存在,那么提取的金额也应该回滚。但这并没有发生。意味着当资金从A账户转移到B账户1000卢比时,如果B的存款发生异常,那么A账户中的提款也应该被撤回。我尝试了@Transactional annotation和Exception类的rollbackFor属性,也尝试了为存款和取款方法添加@transaction annotation,但我们使用了相同的事务,因为我们使用propogation Required**

Model Class//This is the Model Class
//All Imports

@Entity
public class BankAccount {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Integer id;

    @Column(name = "bankAccountNumber", nullable = false,unique = true)
    @NotNull
    @Size(min = 5, message = "Bank account number should be greater than 5 characters")
    private String bankAccountNumber;

    @NotNull
    @Column(name = "balance", nullable = false)
    @Min(1000)
    private Long balance;

//Getter Setter and Constructor

**Controller File**//This is the Controller Class

//All imports and other stuff such as @RestController, @Autowired   

@GetMapping("/bankaccount/transfer")
public void transferBalance(@RequestParam("bankAccountNo1") String bankAccountNo1, @RequestParam("bankAccountNo2") String bankAccountNo2,
            @RequestParam("balance") Long balance) throws RuntimeException
    {
        bankService.transferBalance(bankAccountNo1,bankAccountNo2, balance);
    }

}

**Service File:-**//This is Service Layer
//All imports

@Service
public class BankService {

    @Autowired
    private BankRepository bankRepository;

    @Autowired
    private ModelMapper modelMapper;

    public List<BankAccountDTO> getAllBankAccount() {
        List<BankAccountDTO> bankAccountDTO = new ArrayList<BankAccountDTO>();
        List<BankAccount> bankAccount = bankRepository.findAll();
        for (BankAccount b : bankAccount) {
            bankAccountDTO.add(modelMapper.map(b, BankAccountDTO.class));
        }
        return bankAccountDTO;
    }

    public ResponseEntity<?> getIndividualBankAccount(String bankAccountNumber) {
        BankAccount bankAccount = bankRepository.findByBankAccountNumber(bankAccountNumber);
        if (bankAccount == null) {
            return new ResponseEntity<>("Account not found", HttpStatus.BAD_REQUEST);
        } else {
            return new ResponseEntity<>(
                    modelMapper.map(bankRepository.findByBankAccountNumber(bankAccountNumber), BankAccountDTO.class),
                    HttpStatus.OK);
        }
    }

    public Object addBankAccount(BankAccountDTO bankAccountDTO) {
        return bankRepository.save(modelMapper.map(bankAccountDTO, BankAccount.class));
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void depositBalance(String bankAccountNumber, Long balance) throws RuntimeException {
        BankAccount bankAccNo = bankRepository.findByBankAccountNumber(bankAccountNumber);

        if (bankAccNo == null) {
            throw new RuntimeException("Bank Accout Number is not found : " + bankAccountNumber);
        } else {
            if (balance <= 0) {
                throw new RuntimeException("Please deposit appropriate balance");
            } else {
                Long amount = bankAccNo.getBalance() + balance;
                bankAccNo.setBalance(amount);
                bankRepository.save(bankAccNo);
            }
        }

    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void withdrawBalance(String bankAccountNumber, Long balance) throws RuntimeException {
        BankAccount bankAccNo = bankRepository.findByBankAccountNumber(bankAccountNumber);
        if (bankAccNo == null) {
            throw new RuntimeException("Bank Account not found :" + bankAccountNumber);
        } else {
            if (balance <= 0) {
                throw new RuntimeException("Please withdraw appropriate balance");
            } else {
                Long amount = bankAccNo.getBalance() - balance;
                if (amount < 1000) {
                    throw new RuntimeException("Sorry Cannot withdraw.Your minimum balance should be thousand rupees!");
                } else {
                    bankAccNo.setBalance(amount);
                    bankRepository.save(bankAccNo);
                }
            }
        }
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = RuntimeException.class)
    public void transferBalance(String bankAccountNo1, String bankAccountNo2, Long balance) throws RuntimeException {
        try {
            withdrawBalance(bankAccountNo1, balance);
            depositBalance(bankAccountNo2, balance);

        } catch (RuntimeException e) {
            throw e;
        }

    }

}

共有1个答案

鞠嘉志
2023-03-14

只有运行时异常才会在spring事务注释中触发回滚操作,如果您使用的是自定义注释,则需要确保从RuntimeException中执行然后扩展,或者向事务中添加特定的rollback子句,以便事务在特定的异常中回滚。

也许这个答案会对您有用:Spring事务:在异常或Throwable上回滚

这里还有spring的官方事务文档:https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/transaction.html

 类似资料:
  • 我正在使用boto3访问AWS Dynamodb表并批量写入它,下面是示例代码: 是否可以使用BatchWriteItem对整个批执行回滚?(例如,在块中除外)。 谢谢

  • 我的问题是liquibase没有回滚我的一些变更集,这些变更集是在我试图回滚的变更集上设置标签后执行的。 例如,我创建了两个按正常方式执行的变更集(A和B)。然后,我创建了另一个变更集,它将变更集B的标记设置为Release1。并且这个变更集也按预期工作。但是,我随后执行另外5个变更集,所有变更集都使用回滚命令。而且这些也执行得很好。 现在,这个回滚不应该回滚在执行release1标记之后执行的任

  • 问题内容: 我有一个JavaScript Ajax调用(jQuery.ajax),它不执行成功回调函数。 我在firebug中看到,该请求已发布,并且按预期返回了有关json的正确结果。怎么了? 问题答案: 很多次,我都遇到过类似的问题,大多数时候,原因是json格式错误。尝试以文本数据类型获取结果,看看这是否是您的问题。 另外,我想问一下您是否使用了“&jsoncallback =?”之类的参数

  • 问题内容: 通过将用户的IP,失败的尝试次数和最后的尝试时间记录到名为的MySQL数据库表中,我有一种简单的登录系统保护机制。但是,当我尝试使用以下代码在数据库中插入新条目时,execute()函数将返回false并无法执行。 代码如下: 我是php和MySQL的新手,通过研究,我发现SQL语法显然需要在查询的VALUE部分的字段周围加上引号,例如: 但是我在这里发现它实际上使查询停止工作(仍然尝

  • 批处理是重复的动作-无论是作为一个简单的优化,或作为工作的一部分。策划和归纳重复以及提供一个相当于迭代器的框架,Spring Batch提供RepeatOperations接口,这个RepeatOperations接口看起来像是这样: public interface RepeatOperations { RepeatStatus iterate(RepeatCallback callba

  • 问题内容: 我正在尝试加载GeoJSON文件并使用它作为D3 v5 的基础绘制一些图形。 问题在于浏览器正在跳过调用中包含的所有内容。我尝试插入断点进行测试,但是浏览器跳过了它们,我无法弄清原因。 下面的代码段。 该代码从最初的继续,但是我忽略了所有代码,因为我怀疑问题在于调用本身。 问题答案: 签名已经改为从D3V4到V5。它已从现已弃用的模块d3请求移至新的d3提取模块。从v5开始,D3使用F