@Service
public class SingleCityService implements ICityService {
private static final Logger logger = LoggerFactory.getLogger(SingleCityService.class);
@Autowired
CityMmtRepo cityMmtRepo;
@Autowired
MmtCityService mmtCityService;
@Autowired
RestCityService restCityService;
@PostConstruct
public void init() {
CityServiceFactory.getInstance().registor(EnumCity.SINGLE_CITY, this);
}
/**
* Method to validate if action type is to Create city or Update city
*
* @param request
* @return CityServiceResponse
*/
@Override
public CityServiceResponse serveRequest(CityServiceRequest request) throws ResourceException, InvalidCityCreateException, SQLException {
ValidatorFactory.getInstance().getRequestValidator(Validator.SINGLE_CITY_VALIDATOR).validate(request);
if (CityActionType.CREATE.toString().equals(request.getEventType().getActionType())) {
return createCity(request);
}
return updateCity(request);
}
/**
* Method to create city and fetch matched cities from cache.
*
* @param request
* @return CityServiceResponse
* @throws ResourceException
*/
private CityServiceResponse createCity(CityServiceRequest request) throws ResourceException {
logger.info("Inside SingleCityService: Starting createCity for request: {}", request.toString());
/**
* forceUpdate signifies if user still want to create city after getting conflicts.
*/
if (ResourceConstants.TRUE.equalsIgnoreCase(request.getCityDetails().get(0).getForceUpdate())) {
return saveCity(request, ResourceConstants.CREATED);
}
CityCacheServiceResponse cityCacheServiceResponse = restCityService.getCityMatchingFromCityCache(request);
CityServiceResponse cityServiceResponse = new CityServiceResponse();
if (ResourceConstants.FAILURE.equalsIgnoreCase(cityCacheServiceResponse.getStatus())) {
cityServiceResponse.setStatus(ResourceConstants.FAILURE);
cityServiceResponse.setDescription(cityCacheServiceResponse.getDescription());
} else {
if (cityCacheServiceResponse.getCity().get(0).getMatchedCity().isEmpty()) {
return saveCity(request, ResourceConstants.SUCCESS);
} else {
cityServiceResponse.setStatus(ResourceConstants.CONFLICTING_CITIES_UI_DISPLAY_MSG);
cityServiceResponse.setCity(CityServiceMapperUtil.cacheResponse(cityCacheServiceResponse));
}
}
return cityServiceResponse;
}
/**
* To update city.
*
* @param request
* @return CityServiceResponse
* @throws ResourceException
*/
private CityServiceResponse updateCity(CityServiceRequest request) throws ResourceException, InvalidCityCreateException {
logger.info("Inside SingleCityService, Starting updateCity for request: {}", request.toString());
CityMmtEntity cityMmtEntity = mmtCityService.fetchCityToEdit(request.getCityDetails().get(0).getCityCd());
request = CityServiceMapperUtil.mapCityToBeUpdated(cityMmtEntity, request);
return saveCity(request, ResourceConstants.UPDATE);
}
/**
* To create or update city in DB and Push city in Cache.
*
* @param request
* @param status
* @return CityServiceResponse
* @throws ResourceException
*/
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public CityServiceResponse saveCity(CityServiceRequest request, String status) throws ResourceException {
CityMmtEntity cityMmtEntity = CityServiceMapperUtil.getCityEntity(request);
logger.info("Inside SingleCityService: saveCity: Saving city data in DB for cityCode: {}", cityMmtEntity.getChtCitycd());
cityMmtEntity = mmtCityService.SaveToDb(cityMmtEntity);
int i = 1/0;
int k = i;
logger.info("Inside SingleCityService: saveCity: Syncing city to ES API for cityCode: {}", cityMmtEntity.getChtCitycd());
request.getCityDetails().get(0).setCityCd(cityMmtEntity.getChtCitycd());
request.getCityDetails().get(0).setLastUpdatedOn(cityMmtEntity.getChtCityLastUpdDt());
SyncCityCacheRequest syncCityCacheRequest = CityServiceMapperUtil.mapCityCacheRequest(request);
SyncCityCacheResponse syncCityCacheResponse = restCityService.syncCityToCityCache(syncCityCacheRequest);
CityServiceResponse cityServiceResponse = new CityServiceResponse();
cityServiceResponse.setStatus(status);
cityServiceResponse.setDescription(syncCityCacheResponse.getSyncCityDetails().get(0).getDescription());
return cityServiceResponse;
}
}
//我的服务类中有一个方法 saveCity,如您所见,我在其中放置了 @transactional,但它不起作用,数据库不会在出现异常时回滚。 //saveToDb 是建立在 Jpa Repository 上的另一个服务(如下)中的方法
@Service
public class MmtCityServiceImpl implements MmtCityService {
private static final Logger logger = LoggerFactory.getLogger(MmtCityServiceImpl.class);
@Autowired
private CityMmtRepo cityMmtRepo;
/**
* To save city in DB
*
* @param cityMmtEntity
* @return {@link CityMmtEntity}
*/
public CityMmtEntity SaveToDb(CityMmtEntity cityMmtEntity) throws ResourceException {
try {
logger.info("Inside MmtCityServiceImpl: Starting SaveToDb to save city for CityMmtEntity: {}", cityMmtEntity.toString());
return cityMmtRepo.save(cityMmtEntity);
} catch (Exception e) {
logger.error("MmtCityServiceImpl : Exception while saving/updating city in database, Exception: {}", e);
throw new ResourceException(ResourceErrors.SAVE_CITY_ERROR.getErrorCode(), ResourceErrors.SAVE_CITY_ERROR.getErrorDescription());
}
}
//我将 k = 1/0 放在我们将实体保存到数据库的步骤旁边以抛出运行时异常,只是为了检查@Transactional 是否正常工作,但异常实体不会从数据库回滚。 //实际上我从另一个服务(其方法是 SyncCityToCache)抛出异常服务是:-
@Service
public class RestCityServiceImpl implements RestCityService {
private static final Logger logger = LoggerFactory.getLogger(RestCityService.class);
@Autowired
RestTemplate restTemplate;
@Value("${rest.elatic-cache-sync.end.point}")
private String cacheSyncEndPoint;
@Value("${rest.elatic-search-cache.end.point}")
private String cacheSearchEndPoint;
@Value("${rest.elatic-cache.end.point}")
private String cacheEndPoint;
public SyncCityCacheResponse syncCityToCityCache(SyncCityCacheRequest syncCityCacheRequest) throws ResourceException {
SyncCityCacheResponse syncCityCacheResponse = null;
try {
logger.info("RestCityService: Hitting CityCacheServiceAPI to push city for request: {}", syncCityCacheRequest.toString());
syncCityCacheResponse = restTemplate.postForObject(new URI(cacheSyncEndPoint), syncCityCacheRequest.getSyncCityDetails(), SyncCityCacheResponse.class);
if (ResourceConstants.FAILURE.equalsIgnoreCase(syncCityCacheResponse.getStatus())) {
throw new ResourceException(ResourceErrors.SYNC_API_ERROR.getErrorCode(),
ResourceErrors.SYNC_API_ERROR.getErrorDescription() + " " + syncCityCacheResponse.getSyncCityDetails().get(0).getDescription());
}
} catch (RestClientException | URISyntaxException e) {
logger.error("RestCityService : Exception while hitting cache to push city, Exception:{}", e);
throw new ResourceException(ResourceErrors.SYNC_API_ERROR.getErrorCode(),
ResourceErrors.SYNC_API_ERROR.getErrorDescription() + " " + syncCityCacheResponse.getSyncCityDetails().get(0).getDescription());
}
return syncCityCacheResponse;
}
最佳答案
Spring 使用 AOP 将事务性应用于用 @Transactional
注释的方法。 Spring ,by default ,使用代理向现有类添加行为。通常这不是问题,但代理的一个问题是只有外部方法调用通过代理,来自对象内部的方法调用不通过代理。 (另见 understanding AOP proxies )。
现在,当您从同一对象内部调用您的 @Transactional
方法时,它不会通过代理,因此会忽略 @Transactional
。要修复您的顶级方法应该是 @Transactional
(serveRequest
方法)。
该方法也是您想要完全完成或完全失败的工作单元。所以简单的解决方案是注释您的 serveRequest
方法。
关于java - 为什么@Transactional 在我的代码中不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51604216/