@Transactional不适用于Spring Boot和JDBC

2019年6月20日 36点热度 0条评论

我的服务应将数据保存到父数据库表和子数据库表中,并在发生错误时回滚。我尝试使用硬编码的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, ...);
    }

}

道:

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

解决方案如下:

我遇到了类似的问题。我假设您在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 MyBean2 (NamedParameterJdbcTemplate jdbcTemplate, MyDAO myDao) {
        this.jdbcTemplate = jdbcTemplate;
        this.myDao= myDao;
    }

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