我有一个方法应该创建一个以这种方式定义的子图:
public Post createAndLink(Appuser appuser, Post post, String linkTo) {
Transaction tx = template.getGraphDatabaseService().beginTx();
Post savedPost = null;
if(post != null && appuser != null){
post.setCreatedBy(appuser);
if(post.getId() == null && post.getId() == ""){
post.setId("IND"+GenerateUUID.getUUID());
}
System.out.println(">>> Id created : "+post.getId());
//Date check
String d = post.getDate();
if(d != null && d.length() == 11 && ConversionUtils.isNumeric(d.substring(0, 4))
&& ConversionUtils.isNumeric(d.substring(5, 7)) && ConversionUtils.isNumeric(d.substring(8, 10))){
if(!ConversionUtils.isPastDate(d)){
System.out.println("Cannot save post with date after today");
return null;
}
}
System.out.println(">>> Date created : "+post.getDate());
//People check
Set<People> people = new HashSet<People>();
if(post.getPeople() != null){
for(People p : post.getPeople()){
People pFromDb = peopleService.findById(p.getId());
people.add(pFromDb != null ? pFromDb : new People("PPL"+GenerateUUID.getUUID(), p.getName()));
}
post.setPeople(people);
}
System.out.println(">>> People created : "+post.getPeople());
//Place check
if(post.getPlace() != null){
Place pFromDb = placeService.findById(post.getPlace().getId());
post.setPlace(pFromDb != null ? pFromDb : new Place(post.getPlace().getId()));
}
System.out.println(">>> Place created : "+post.getPlace());
System.out.println("Post checking OK.");
savedPost = repository.findById(linkTo);
if(savedPost != null){
Set<Post> linked = new HashSet<Post>();
linked.add(savedPost);
post.setLinkedPosts(linked);
}
template.save(post);
System.out.println("=====> [saveWithUser]: Saved OK!");
tx.success();
tx.close();
}
return savedPost;
}
我从我的服务方法中删除了所有@Transactional注释和事务集合(控制器和存储库未标记为Transactional)。
现在,当我从控制器A调用此方法时,tx属于Placebo类型。当我从控制器B调用它时,tx类型是TopLevel。
我甚至通过从控制器B调用控制器A方法进行测试(如下例所示)并且它完美地工作(使用TopLevel Tx)。当我采取相反的方式时,Tx是安慰剂。
控制器A:
@RequestMapping(value="/newandlinksimilar/{linkedTo}", method=RequestMethod.POST)
public @ResponseBody boolean createAndLinkNewSimilar(@RequestBody Post post, @PathVariable String linkedTo){
Post created = null;
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (post!= null && !(auth instanceof AnonymousAuthenticationToken)) {
AppuserDetails userDetails = (AppuserDetails)auth.getPrincipal();
Appuser currentUser = appuserService.findByLogin(userDetails.getUsername());
created = postService.createAndLinkSimilar(currentUser, post, linkedTo);
}
return created;
}
控制器B:
@autowired
private ControllerA controllerA;
@RequestMapping("/init")
public ModelAndView init(){
//I create a new Post object "post" with dummy data
controllerA.createAndLinkSimilar(post,"XXXXXX");
//Or postService.createAndLinkSimilar(appuser,post,"XXXXXX");
return new ModelAndView("home");
}
两个测试都是通过GUI ajax调用控制器方法完成的。
我无法理解Spring何时以及如何选择交易类型?!
答案 0 :(得分:1)
Placebo事务是Neo4j中的嵌套事务,它们是在已经运行顶级事务时创建的,并且仅在以下情况下影响顶级事务:
所以某种程度上(可能是一些开放式事务视图自动)已经在您的应用程序中围绕您的第一个控制器(A)或之前调用的内容创建了顶级tx,就像您的服务没有正确完成它的事务一样,所以他们还在跑。
也许你在没有打电话的情况下早点返回。
我还建议使用try-with-resource模式,该模式会在块结束时自动关闭事务,否则在close
中执行finally
。
try (Transaction tx = db.beginTx()) {
... your database code ...
tx.success()
}