我用@Service创建了一些spring服务,并将它们标记为@Transactional。这是按预期工作的。
现在我创建了一个执行谷歌地图请求的小帮助服务。我已经删除了@Transaction注释,认为服务中的函数正在使用相同的事务。
@Transactional
@Service("hourService")
public class HourServiceImpl extends HourService {
private void updateLogbook(Hour hour) {
Logbook logbook = getLogbook(hour);
if (logbook != null) {
try {
List<String> locations = logbook.getHours().stream().sorted((t1, t2) -> t1.getStartTime().compareTo(t2.getStartTime())).filter(h -> !h.equals(hour)).map(Hour::getClient).map(Client::getAddress).collect(Collectors.toList());
locations.add(hour.getClient().getAddress());
String origin = getOrigin();
Double distance = mapService.getDistance(origin, origin, locations);
logbook.add(hour);
logbook.setProtect(true);
logbook.setDate(hour.getDate());
logbook.setDistance(distance / 1000.0);
logbook.setComment(getComment(logbook.getHours()));
logbookDao.update(logbook);
} catch (Exception e) {
logbook.remove(hour);
log.error("Failed to update Logbook Entry!", e);
}
}
}
}
和mapService
@Service("mapService")
public class MapServiceImpl extends MapService {
Logger log = LogManager.getLogger();
@Autowired
private Environment environment;
@Override
public Double getDistance(String origin, String destination, List<String> waypoints) throws Exception {
return sendDistanceRequest(origin, destination, waypoints.toArray(new String[waypoints.size()]));
}
private Double sendDistanceRequest(String origin, String destination, String... waypoints) throws Exception {
GeoApiContext context = new GeoApiContext().setApiKey(environment.getRequiredProperty("invoice.maps.key"));
DirectionsApiRequest request = DirectionsApi.newRequest(context);
request.mode(TravelMode.DRIVING);
request.origin(origin);
request.destination(destination);
request.waypoints(waypoints);
try {
log.info(String.format("Trying to get Distance for %s -> %s -> %s", origin, String.join(" -> ", waypoints), destination));
DirectionsResult result = request.await();
if (result.routes.length > 0 && result.routes[0].legs.length > 0) {
Double distance = 0d;
for (DirectionsLeg leg : result.routes[0].legs) {
distance += leg.distance.inMeters;
}
return distance;
}
} catch (Exception e) {
log.error("Failed to get maps response!", e);
}
throw new Exception(String.format("Something wrong with this route ... ORIGIN: %s, VIAS: %s, DEST: %s", origin, String.join("|", waypoints), destination));
}
}
现在我的问题是,调用mapService.getDistance(origin, origin, locations);
会给我一个org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: ...Logbook
。
这可以解释,因为日志实体没有保存,而且hibernate试图提交修改后的Hour实体......但是为什么会提交?它应该使用相同的交易!?!?!?
编辑1
我的问题与mapService无关。问题是getOrigin()
正在使用我的settingDao
来获取设置值。此调用提交当前事务并使用另一个事务来选择设置值。
所以问题是如何使用相同或嵌套?