我想在服务方法中执行一些与数据库相关的操作。最初看起来像这样:
@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相关的nothig,但是如果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
注释被忽略,我可以看到新记录保留在DB中。
我仅通过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();
}
}
答案 0 :(得分:1)
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));
}
show_sql
,以防您的应用程序是春季启动,该配置可以启用它:spring.jpa:
show-sql: true
properties:
hibernate:
format_sql: true
logging.level:
org.hibernate.SQL: DEBUG
@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);
}
答案 1 :(得分:-1)
请尝试:
@Transactional(rollbackFor = Exception.class)
public void addDirectory(Directory directory){
@Transactional仅回退未检查异常的事务。对于检查的异常及其子类,它将提交数据。因此,尽管在这里引发了一个异常,但由于它是一个已检查的异常,因此Spring会忽略它并将数据提交到数据库中。
因此,如果抛出Exception或它的子类,请始终将其与@Transactional批注一起使用,以告诉Spring如果发生检查的异常,则回滚事务。
这非常简单,只需在@Transactional中使用以下内容:
@Transactional(rollbackFor = Exception.class)