【发布时间】:2020-01-26 17:13:33
【问题描述】:
我想在服务方法中做一些与数据库相关的操作。最初它看起来像这样:
@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 配置的DataSource,下面是JDBCTemlate 的配置方式
@Component
class MapSQLParamUtils {
private final DataSource dataSource;
@Autowired
MapSQLParamUtils(DataSource dataSource) {
this.dataSource = dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource);
}
}
所以我的问题是:为什么SimpleJdbcCall 会忽略@Transactional 以及如何配置JPA 和JDBCTemlate 以使用相同的事务管理器。
更新: 这就是我在控制器中使用此服务的方式
@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();
}
}
【问题讨论】:
-
请出示您拨打
addDirectory的代码。 -
@chrylis 我已经更新了我的问题
-
没有时间阅读和参与,但铃声响起:JPA 可能并不总是与 JDBC 结合,这取决于 JPA 缓存。
-
@chrylis,@vipul tnx,但我想我找到了原因。我猜是因为
withFunctionName("create_dict")到底做了什么。我们使用 Oracle 作为我们的数据库,因此create_dict函数创建了一个数据库表,并且此操作在完成后无法回滚。如果我使用@Transactional,其中的所有操作似乎都表现得异步,因此当directoryRepo.save(directory)启动时,程序会继续执行rsdhUtilsService.createPhysTable(directory)而无需等待先前方法调用的结果,如果是刹车,createPhysTable(directory)的结果不能被回滚
标签: java spring-boot spring-data-jpa spring-jdbc spring-transactions