繁体   English   中英

@Transactional 不适用于 Spring Boot 和 JDBC

[英]@Transactional not working with Spring Boot and JDBC

我的服务应该将数据保存到父和子数据库表,并在发生错误时回滚。 我尝试使用硬编码的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对其的解释是:

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

所以我创建了另一个类来封装我的 DAO 方法调用,而是使用它的方法并且它起作用了。

所以对于这种情况,它可能是这样的:

我的豆:

@Service
public class MyBean {

    MyBean2 bean2;

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

我的豆2:

@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, ...);
    }
}

尝试这个:

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

推荐使用:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM