当方法仅从DB中提取数据时,在服务中使用@Transactional。

时间:2017-09-13 09:04:13

标签: java spring-mvc spring-transactions

我刚刚发现了一段代码如下:

@Transactional
public List<Foo> giveMeFooMatchingSomeConstraints(Long param1, String param2) {
 List<Bar> bars = barDao.findBars(param1, param2);
 List<Foo> foos = fooDao.findFoosByBarIds(barService.getIds(bars));
 return foos; 
}

我只是好奇当一个方法只提取数据并且不修改它们时,使用@Transactional的目的是什么。上面这样的方法好吗?

1 个答案:

答案 0 :(得分:1)

是的,当您不使用Open*InView并使用方法中的惰性关系时,这是有道理的。

假设我们将这些实体与一对多关系联系起来:

@Entity(name = "user")
static class User extends AbstractPersistable<String> {
    private String username;

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) //by default fetching is lazy
    @JoinColumn(name = "user_id", foreignKey = @ForeignKey(name = "fk_user_roles"))
    private Set<Role> roles = new HashSet<>();

    public Set<Role> getRoles() {
        return this.roles;
    }
}

@Entity(name = "role")
static class Role extends AbstractPersistable<String> {
    private String name;

    private Role() {
    }

    public Role(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }
}

访问它们的存储库:

interface UserDao extends JpaRepository<User, String> {}

以及用于某些数据操作的服务 - 检索所有用户,通过它们进行迭代并获取所有角色:

@Service
static class UserService {
    private final UserDao userDao;

    UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    @Transactional // <---
    public Set<String> findUserRoles() {
        final List<User> users = this.userDao.findAll();
        return users.stream()
                .flatMap(user -> user.roles.stream())
                .map(Role::getName)
                .collect(Collectors.toSet());
    }
}

删除@Transactional以查看LazyInitializationException的{​​{1}}消息,因为没有人打开过它。

为避免在这种情况下出现混淆,最好将事务明确标记为只读:

no Session

因此读者会知道此方法无意修改任何数据,但仍需要事务(会话)。

Full example