Я хочу сделать некоторые связанные с БД действия в сервисном методе.Изначально это выглядит так:
@Override
@Transactional
public void addDirectory(Directory directory) {
//some cheks here
directoryRepo.save(directory);
rsdhUtilsService.createPhysTable(directory);
}
Метод Firs directoryRepo.save(directory);
- это просто простое действие сохранения JPA, второе rsdhUtilsService.createPhysTable(directory);
- это JDBCTemplate
вызов хранимой процедуры из своей собственной службы.Проблема заключается в том, что если в действии JPA или SimpleJdbcCall возникает какое-либо исключение, транзакция будет откатываться, и ничто, связанное с JPA, не будет сохранено, но если в действии JPA произойдет исключение only , результатом 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);
}
}
Итак, мои вопросы: почему @Transactional
игнорируется SimpleJdbcCall
и как настроить 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();
}
}