【问题标题】:@Transaction not being rolled back in spring mvc@Transaction 没有在 spring mvc 中回滚
【发布时间】:2019-06-29 04:22:22
【问题描述】:

我有基于类的配置,所以用于回滚事务。我使用了 jdbcTemplate。我的 bean 声明如下:

    @Bean
    public DriverManagerDataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("oracle.jdbc.driver.OracleDriver");
        dataSource.setUrl("jdbc:oracle:thin:@192.168.1.5:1521:DCGCDB");
        dataSource.setUsername("PCA_OWNER");
        dataSource.setPassword("PCA_OWNER");

        return dataSource;
    }
<!--for transaction bean-->
@Bean
public PlatformTransactionManager txManager() {
    return new DataSourceTransactionManager(dataSource());
}

所以在我的服务类中我已经声明了@Transactional 但它不起作用:

@Service
public class ProcessAnexOneServiceImpl implements ProcessAnexOneService {

 @Autowired
 private SelectionCustomOfficeService selectionCustomOfficeService;

 @Autowired
 private LetterDocService letterDocService;

 @Autowired
 private LetterService letterService;

 @Override
 @Transactional
 public void insertProcessAnexOne(ProcessAnexOne processAnexOne, String entryBy) {

  BigDecimal zeroValue = new BigDecimal(0);

  Letter letter = new Letter(processAnexOne.getLetter().getLetterId(), processAnexOne.getLetter().getInout(),
   processAnexOne.getLetter().getInoutNo());
 letter.setEntryBy(entryBy);

  //1st insert Transaction happens here
  BigDecimal letterNo = letterService.insertLetter(letter);
  //1st insert Transaction ends here
  System.out.println("letterNo from db is" + letterNo);


    //2nd insert Transaction happens here 
  for (BigDecimal docId: processAnexOne.getDocId()) {
   LetterDoc letterDoc = new LetterDoc(letterNo, singledocId, null, null);

   letterDocService.insertLetterDoc(letterDoc, entryBy);


  }
 //2nd insert Transaction ends here 

   //3rd insert Transaction happens here 
  for (LetterDocOther letterDoc: processAnexOne.getLetterDocOthers()) {
   System.out.println("entered hereasfdsafsdsdfg");
   LetterDoc letterD = new LetterDoc(letterNo, letterDoc.getDocId(), null, "I",
    letterDoc.getOthersDescription());
   letterD.setEntryBy(entryBy);
   letterDocService.insertLetterDocWithDescription(letterD);
  }
 //3rd insert Transaction ends here 
 }

}

我有三个事务将在这个服务类中的三个不同的表上命中。所以我的问题是,当第一个事务完成并且第二个事务出现错误时,第一个事务中没有任何回滚发生。在那种情况下,我仍然在我的表中看到第一笔交易的数据,但第二笔交易出现错误。我已经为回滚声明了@Transaction 注释,并且也尝试过 (rollbackOn=Exception.class) 但如果出现错误,它不会回滚第一个事务。

在我的 pom.xml 中我添加了:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>4.3.7.RELEASE</version>
</dependency>

LetterServiceImpl.java

@Service
public class LetterServiceImpl implements LetterService {

    @Autowired
    private LetterDao letterDao;

    @Override
    @Transactional(rollbackOn=Exception.class)
    public BigDecimal insertLetter(Letter letter) {
        BigDecimal letter1=letterDao.saveLetter(letter);
        return letter1;
    }
}

LetterDaoImpl.java

@Override
    public BigDecimal saveLetter(Letter letter) {
        try {
        System.out.println("hitted123 here");
        SimpleJdbcCall simpleJdbcCall = new SimpleJdbcCall(jdbcTemplate).withProcedureName("PCPR_ADD_LETTER");
        Map<String, Object> inParamMap = new HashMap<String, Object>();
        System.out.println(letter.getLetterId());
        inParamMap.put("P_LETTER_NO",null);
        inParamMap.put("P_LETTER_ID",letter.getLetterId());
        inParamMap.put("P_SIGNATARY",letter.getSignatary());
        inParamMap.put("P_LETTER_BOX",letter.getLetterBox());
        inParamMap.put("P_ENTRY_BY",letter.getEntryBy());
        inParamMap.put("P_R_STATUS","I");
        inParamMap.put("P_REMINDER_YES_NO","N");

        System.out.println("hitted1234 here");
        SqlParameterSource in = new MapSqlParameterSource(inParamMap);
        System.out.println("hitted123456789 here");
        //Map<String, Object> out = simpleJdbcCall.execute(in);
        BigDecimal letterNO =  (BigDecimal) simpleJdbcCall.execute(in).get("P_LETTER_NO");

        System.out.println("hitted12345 here"+letterNO);
        return letterNO;
        } catch(Exception e) {
            e.printStackTrace();
        }
        return null;

    }

【问题讨论】:

  • 显示insertLetter是如何定义的
  • insertLetter 的方法工作正常,它返回一个 BigDecimal(数字)值并被其他方法使用。
  • 它上面是否有@Transactional 注释及其方法?
  • 不等我编辑帖子看看
  • 好的,我已经添加了代码

标签: java spring spring-mvc jdbc transactions


【解决方案1】:

根据Spring Doc,对于未处理的异常会自动完成回滚。在这种情况下,您正在处理它,以便事务管理器不会看到有错误。

另一方面,任何类型的未经检查的异常(扩展 RuntimeException 的异常)都会发生回滚,而无需在 @Transactional 注释中声明它们。但是,checked 注释(你需要在 catch 块中处理的注释)需要在 @Transactional 注释中声明。

最后我建议你在最高级别的方法中添加回滚,即开始事务的方法,以确保事务行为。

【讨论】:

  • 我应该删除什么或进行更改以使其正确?我应该在 saveLetter() 中删除 try catch 块吗?
  • 是的,请记住,通常休眠会将异常转换为未经检查的,因此代码更干净且可移植。因此,您可能会遇到的所有异常都未经检查,应该被@Transactional 捕获。
  • 另外,尽量避免catch(Exception e){e.printStackTrace();}如果方法中不知道如何处理异常,重新抛出异常
  • 我没有使用休眠先生,我使用的是 jdbcTemplate
  • 哦...好的,那么您可能遇到的异常将被检查,您需要将它们添加到@Transactional注释中
【解决方案2】:

问题出在 LetterDaoImpl.java 上,您在方法 saveLetter 中发现了任何异常。如果您捕获了异常并且没有将其扔回,则不会获得回滚。

此外,您应该检查注释 @Transactional,因为我很确定语法是 rollbackFor() 而不是 rollbackOn()。

出于调试事务的目的,我通常在调试级别为 org.springframework.jdbc.datasource.DataSourceTransactionManager 启用日志。

【讨论】:

  • 我应该怎么做才能使它正确?你能帮帮我吗?
  • 我不喜欢捕捉 DAO 内部的异常,但如果你愿意,你可以在记录错误后抛出一个新的异常: throw new RuntimeException(e);
猜你喜欢
  • 1970-01-01
  • 2018-09-15
  • 2019-07-27
  • 1970-01-01
  • 2017-07-22
  • 2018-11-13
  • 1970-01-01
  • 2016-05-03
  • 2017-03-27
相关资源
最近更新 更多