Spring MVC Transactional Best Practices for this

时间:2016-07-01 15:24:32

标签: java spring hibernate controller transactional

我有一个控制器方法来检索用户,然后我已经映射了他们的UserConfig,然后使用该UserConfig我检索MainBrands(用户配置的惰性集合)。

让我澄清一下:

用户实体:

@Entity
@Table(name = "app_user")
public class User extends BaseEntity {

    private UserConfig userConfig;        

    @OneToOne(mappedBy = "user", cascade = CascadeType.ALL)
    public UserConfig getUserConfig() {
        return userConfig;
    }

    //more props..
}

UserConfig实体:

@Entity
@Table(name = "user_config")
public class UserConfig extends BaseEntity {

    private Set<MainBrand> mainBrands;

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(...)
    public Set<MainBrand> getMainBrands() {
        return mainBrands;
    }

    //more props..

}

我的UserService:

public interface UserService {

    public User getById(Long id);

}

所以我的问题是关于交易注释的“最佳实践”。我不止一次读过,把@Transactional放在Controller级别,这是不好的做法。但在这种情况下,我想在Controller做:

@RequestMapping(method = RequestMethod.GET, value = "/")
public ModelAndView getMainPage(Long userId) {

    ModelAndView = new ModelAndView("/home");

    //do stuff

    User user = userService.getById(userId);

    //some stuff with user
    modelAndView.addObject("username", user.getUsername());
    //...

    List<String> brandsNames = new ArrayList<>();

    for(MainBrand mainBrand : user.getUserConfig().getMainBrands()){
        brandsNames.add(mainBrand.getName());
    }
}

如果由于LazyInitializationException而未将@Transactional注释放在Controller级别,那将失败。

所以,这是我所想到的选择:

1)用户调用“UserConfigService”(现在没有创建),如userConfigService.getUserConfigByUserId(userId):这让我觉得如果我已经在User上绑定了上课,为什么我会再打一次?而我只是为这种方法创建一项新服务。

2)将@Transactional注释放在控制器级别:这会给我带来另一个问题,但在这篇文章中并不关心。

3)调用getUserConfig()&amp;在UserService的getUainConfig()。getMainBrands()然后集合初始化:不喜欢因为每当我使用getById时它会初始化集合,即使我不需要它。

那么这个案例的好习惯是什么?在互联网上总是有完美而美丽的例子,但是当我们开始为项目提供一些业务逻辑时,很难有一个干净的代码。

谢谢,对不起我的英语。

1 个答案:

答案 0 :(得分:0)

LazyInitializationException 与事务无关,它与对象之间的关系有关,如果对象具有惰性关系,则必须在 userService.getById(userId)中获取MainBrands对象 返回用户之前的查询方法。

事务性注释必须在服务类中,您可以根据需要创建任意数量的服务类。