@Transactional不使用Spring Boot和JDBC

时间:2018-06-01 08:39:56

标签: java spring spring-boot

我的服务应该将数据保存到父数据库表和子数据库表,并在出现错误时回滚。我尝试使用硬编码的RuntimeException强制执行错误,并发现无论如何都要提交事务。 我错过了什么? 我使用的是Spring Boot 2,包括spring-boot-starter-jdbc依赖项。

数据库是Oracle 11g。

主要配置:

@SpringBootApplication
@EnableTransactionManagement
public class MyApplication extends SpringBootServletInitializer{

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(MyApplication.class);
    }

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

服务层:

    @Service
    public class MyBean {

    private final NamedParameterJdbcTemplate jdbcTemplate;        
    private final MyDAO myDao;

    @Autowired
    public MyBean (NamedParameterJdbcTemplate jdbcTemplate, MyDAO myDao) {
        this.jdbcTemplate = jdbcTemplate;
        this.myDao= myDao;
    }

    @Override
    @Transactional
    public void saveData(...){
        myDao.saveData(jdbcTemplate, ...);
    }

}

DAO:

public void saveData(jdbcTemplate, ...){
    saveDataInParentDatatable(jdbcTemplate, ...);
    saveDataInChildDatatable(jdbcTemplate, ...);
}
private void saveDataInChildDatatable(jdbcTemplate, ...){
    throw new RuntimeException();
}

3 个答案:

答案 0 :(得分:1)

我遇到了类似的问题。我假设您正在使用MyBean的另一个方法调用MyBean.saveData方法。

经过大量搜索,尝试和失败之后,我找到了以下链接:http://ignaciosuay.com/why-is-spring-ignoring-transactional/

其中解释说,当被调用的方法与被调用的方法位于同一类中时,@ Transactional注释将被忽略。其Spring explanation是:

  

“在代理模式(默认)下,仅外部方法调用   通过代理进入的邮件被拦截。这意味着   自我调用实际上是目标对象内的一种方法   目标对象的另一种方法,不会导致实际   运行时的事务,即使被调用的方法标记有   @交易。另外,必须完全初始化代理以提供   预期的行为,因此您不应该依赖于此功能   初始化代码,即@PostConstruct。”

所以我创建了另一个类来封装我的DAO方法调用,改用了它的方法,并且可以正常工作。

因此,在这种情况下,可能类似于:

MyBean:

@Service
public class MyBean {

    MyBean2 bean2;

    public void saveData(...){
        bean2.saveData(jdbcTemplate, ...);
    }
}

MyBean2:

@Service
public class MyBean2 {

    private final NamedParameterJdbcTemplate jdbcTemplate;        
    private final MyDAO myDao;

    @Autowired
    public MyBean (NamedParameterJdbcTemplate jdbcTemplate, MyDAO myDao) {
        this.jdbcTemplate = jdbcTemplate;
        this.myDao= myDao;
    }

    @Override
    @Transactional
    public void saveData(...){
        myDao.saveData(jdbcTemplate, ...);
    }
}

答案 1 :(得分:0)

推荐使用:

@Transactional(rollbackFor = {Exception.class, RuntimeException.class})

答案 2 :(得分:0)

试试这个:

@Transactional(propagation = Propagation.MANDATORY, rollbackFor = Exception.class)