gpt4 book ai didi

java - 为什么SimpleJdbcCall会忽略@Transactional注解

转载 作者:行者123 更新时间:2023-12-02 00:11:34 28 4
gpt4 key购买 nike

我想在服务方法中执行一些与数据库相关的操作。最初看起来像这样:

@Override
@Transactional
public void addDirectory(Directory directory) {
//some cheks here
directoryRepo.save(directory);
rsdhUtilsService.createPhysTable(directory);
}

第一个方法 directoryRepo.save(directory); 只是简单的 JPA 保存操作,第二个方法 rsdhUtilsService.createPhysTable(directory);JDBCTemplate 从它自己的服务调用存储过程。问题是:如果 JPA 或 SimpleJdbcCall 操作中发生任何异常,事务将回滚,并且与 JPA 相关的任何内容都不会被保留,但如果在 JPA 操作中发生异常,SimpleJdbcCall 的结果将不会受事务回滚的影响。为了说明此行为,我删除了 JAP 操作,将 @Transactional 标记为 (readOnly = true) 并从另一个服务中移动了所有与 JDBCTemplate 相关的逻辑到当前的。

@Service
public class DirectoriesServiceImpl implements DirectoriesService {

private final DirectoryRepo directoryRepo;

private final MapSQLParamUtils sqlParamUtils;

private final JdbcTemplate jdbcTemplate;

@Autowired
public DirectoriesServiceImpl(DirectoryRepo directoryRepo, MapSQLParamUtils sqlParamUtils, JdbcTemplate jdbcTemplate) {
this.directoryRepo = directoryRepo;
this.sqlParamUtils = sqlParamUtils;
this.jdbcTemplate = jdbcTemplate;
}

@Override
@Transactional(readOnly = true)
public void addDirectory(Directory directory) {
directoryRepo.save(directory);

new SimpleJdbcCall(jdbcTemplate).withSchemaName("RSDH_DICT").withCatalogName("UTL_DICT")
.withFunctionName("create_dict")
.executeFunction(String.class, sqlParamUtils.getMapSqlParamForCreatePhysTable(directory));
}

}

因此,@Transactional 注释被忽略,我可以看到新记录保留在数据库中。我只通过 application.properties 配置了一个数据源,以下是 JDBCTemlate 配置方式

@Component
class MapSQLParamUtils {

private final DataSource dataSource;

@Autowired
MapSQLParamUtils(DataSource dataSource) {
this.dataSource = dataSource;
}

@Bean
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource);
}

}

所以我的问题是:为什么@TransactionalSimpleJdbcCall忽略以及如何配置JPAJDBCTemlate使用相同的事务管理器。

更新:这就是我在 Controller 中使用此服务的方式

@RestController
@RequestMapping(value = "/api/v1/directories")
public class DirectoriesRESTControllerV1 {

private final DirectoriesService directoriesService;

@Autowired
public DirectoriesRESTControllerV1(DirectoriesService directoriesService) {
this.directoriesService = directoriesService;
}

@PostMapping
@PreAuthorize("hasPermission('DIRECTORIES_USER', 'W')")
public ResponseEntity createDirectory(@NotNull @RequestBody DirectoryRequestDTO createDirectoryRequestDTO) {
Directory directoryFromRequest = ServiceUtils.convertDtoToEntity(createDirectoryRequestDTO);
directoriesService.addDirectory(directoryFromRequest);
return ResponseEntity.noContent().build();
}

}

最佳答案

  1. 如前所述,这里的问题是 JPA 不会在调用存储库方法时立即执行 sql 查询。要强制执行它,您可以使用显式 entityManager.flush():
@Autowired
private javax.persistence.EntityManager entityManager;
...

@Override
@Transactional(readOnly = true)
public void addDirectory(Directory directory) {
directoryRepo.save(directory);
entityManager.flush();

new SimpleJdbcCall(jdbcTemplate).withSchemaName("RSDH_DICT").withCatalogName("UTL_DICT")
.withFunctionName("create_dict")
.executeFunction(String.class, sqlParamUtils.getMapSqlParamForCreatePhysTable(directory));
}
  • 要通过 hibernate 查看真实的 SQL 查询,您可以启用选项 show_sql,如果您的应用程序是 spring-boot,则此配置会启用它:
  • spring.jpa:
    show-sql: true
    properties:
    hibernate:
    format_sql: true

    logging.level:
    org.hibernate.SQL: DEBUG
  • 关于交易管理器。如果entityManager刷新还不够,您可能需要复合事务管理器,它可以处理JPA和DataSource。 Spring数据共享有ChainedTransactionManager 。注意:你应该小心对待它。我在我的项目中这样使用它:
  •     @Bean(BEAN_CONTROLLER_TX)
    public PlatformTransactionManager controllerTransactionManager(EntityManagerFactory entityManagerFactory) {
    return new JpaTransactionManager(entityManagerFactory);
    }

    @Bean(BEAN_ANALYTICS_TX)
    public PlatformTransactionManager analyticsTransactionManager(DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
    }

    /**
    * Chained both 2 transaction managers.
    *
    * @return chained transaction manager for controller datasource and analytics datasource
    */
    @Primary
    @Bean
    public PlatformTransactionManager transactionManager(
    @Qualifier(BEAN_CONTROLLER_TX) PlatformTransactionManager controllerTransactionManager,
    @Qualifier(BEAN_ANALYTICS_TX) PlatformTransactionManager analyticsTransactionManager) {
    return new ChainedTransactionManager(controllerTransactionManager, analyticsTransactionManager);
    }

    关于java - 为什么SimpleJdbcCall会忽略@Transactional注解,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58116550/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com