如何查找交易问题

时间:2020-05-24 15:08:02

标签: spring hibernate spring-boot jpa spring-data-jpa

最近我读了一篇有关@Transactional注释的文章。

https://dzone.com/articles/spring-transactional-amp-exceptions

但是我不知道如何在我的应用程序中找到这类问题。但是,我尝试编写测试用例。我正在使用https://www.archunit.org/

public class TransactionalAnnotationTest {

    List<String> names = new ArrayList<>();

    @Test
    public void testTransactionalWithCheckedExceptionMustSetRollbackFor() {
        JavaClasses importedClasses = new ClassFileImporter().importPackages("com.example.demo");
        List<String> issuesList = new ArrayList<>();
        for (JavaClass clz : importedClasses) {
            clz.getMethods().stream().filter(m -> m.isAnnotatedWith(Transactional.class)
                    && m.getModifiers().contains(JavaModifier.PUBLIC))
                    .filter(m -> m.getThrowsClause().containsType(JavaClass.Predicates.assignableTo(Exception.class)))
                    .filter(m -> !m.getAnnotationOfType(Transactional.class).readOnly()
                            && !Arrays.asList(m.getAnnotationOfType(Transactional.class).rollbackFor())
                            .contains(Throwable.class))
                    .forEach(m -> {
                        String name = String.format("%s.%s", clz.getName(), m.getName());
                        issuesList.add(name);
                    });
        }
        if (!issuesList.isEmpty()) {
            throw new RuntimeException(issuesList + " method must contains rollbackFor.");
        }
    }

}

但是,这并未找到所有问题。例如,

AccountService.java

@Service
public class AccountService {
//This will rollback
    @Transactional(rollbackFor = Throwable.class)
    public void transferMoney(int condition) throws Exception {
        Account from = accountRepository.getOne(1L);
        Account to = accountRepository.getOne(2L);
        accountService2.debitFromAccount(from, 100);
        accountService2.creditToAccount(to, 100, condition);
    }

    //This will not rollback as it does not have @Transactional
    public void transferMoney2(int condition) throws Exception {
        Account from = accountRepository.getOne(3L);
        Account to = accountRepository.getOne(4L);
        accountService2.debitFromAccount(from, 200);
        accountService2.creditToAccount(to, 200, condition);
    }

    //This will not rollback as it does have @Transactional but no rollback
    @Transactional
    public void transferMoney3(int condition) throws Exception {
        Account from = accountRepository.getOne(3L);
        Account to = accountRepository.getOne(4L);
        accountService2.debitFromAccount(from, 200);
        accountService2.creditToAccount(to, 200, condition);
    }

    //This will rollback as the accountService2.transferMoney()
    // contains rollback
    public void transferMoney4(int condition) throws Exception {
        accountService2.transferMoney(condition);
        someMethod(condition);
    }

    //This will not rollback as transferMoney has annotation
    // but the method is of same class so that Transactional
    // is of no use
    public void transferMoney5(int condition) throws Exception {
        transferMoney(condition);
        someMethod(condition);
    }

    //This will not rollback as transferMoney has annotation
    // but the method is of same class so that Transactional
    // is of no use
    public void transferMoney6(int condition) throws Exception {
        transferMoney(condition);
        someMethod2(condition);
    }

    // does not have any repository code
    public void someMethod(int condition) throws Exception {
        if(condition == 2) {
            throw new Exception("Exception from some method");
        }
        //some more code can be present
    }

    // does not have any repository code but unintentionally
    // have @Transactional annotation
    @Transactional
    public void someMethod2(int condition) throws Exception {
        if(condition == 2) {
            throw new Exception("Exception from some method");
        }
        //some more code can be present
    }
}

AccountService2.java

public class AccountService2 {
@Transactional(rollbackFor = Throwable.class)
    public void transferMoney(int condition) throws Exception {
        Account from = accountRepository.getOne(1L);
        Account to = accountRepository.getOne(2L);
        debitFromAccount(from, 100);
        creditToAccount(to, 100, condition);
    }

    public void debitFromAccount(Account from, int amount) {
        from.setAmount(from.getAmount()-amount);
        accountRepository.save(from);
    }

    public void creditToAccount(Account to, int amount, int condition) throws Exception {
        if(1 == condition) {
            throw new Exception("Error during credit");
        }
        to.setAmount(to.getAmount()+amount);
        accountRepository.save(to);
    }
}

testTransactionalWithCheckedExceptionMustSetRollbackFor()测试用例返回

java.lang.RuntimeException: [com.example.demo.service.AccountService.transferMoney3, com.example.demo.service.AccountService.someMethod2] method must contains rollbackFor.

这里com.example.demo.service.AccountService.someMethod2是错误的,而且 它不返回 [com.example.demo.service.AccountService.transferMoney2, com.example.demo.service.AccountService.transferMoney5, com.example.demo.service.AccountService.transferMoney6]

所以我想知道是否存在任何图书馆或任何其他优雅的方式来发现此类问题。

0 个答案:

没有答案