如何从控制台应用程序中使用spring-data-jpa和hibernate进行延迟加载收集?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (21)

我有一个小型的控制台应用程序,我用hibernate的spring-data-jpa。在独立的控制台应用程序中,当使用spring-data-jpa及其存储库时,我真的无法弄清楚如何延迟初始化集合。这是我的一些代码:

@Entity
public class User {
...
    @OneToMany(cascade=CascadeType.ALL)
    @JoinColumn(name="USER_ORDER_ID")
    private Set<Order> orders = new HashSet<Order>();
...
}

库:

public interface UserRepository extends PagingAndSortingRepository<User, Long> {

    public ArrayList<User> findByFirstNameIgnoreCase(String firstName);
}

服务impl:

@Service
@Repository
@Transactional
public class UserServiceImpl implements UserService {
    @Autowired
    private UserRepository userRepository;

public ArrayList<User> findByFirstNameIgnoreCase(String firstName) {
    ArrayList<User> users = new ArrayList<User>();
    users = userRepository.findByFirstNameIgnoreCase(firstName);
    return users;
}

我的主要方法:

...
user = userRepository.findByFirstNameIgnoreCase("john").get(0);
orders = user.getOrders();
for (Order order : orders) {
  LOGGER.info("getting orders: " + order.getId());
}    

foreach循环得到一个异常:

EVERE:未能延迟初始化角色集合:com.aki.util.User.orders,没有会话或会话已关闭org.hibernate.LazyInitializationException:未能延迟初始化角色集合:

请注意,当从具有某种OpenSessionInViewFilter的Web应用程序运行此应用程序时,我没有这个问题。

提问于
用户回答回答于

一个解决方案可以是通过User.orders一个热切的收集

@OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
private Set<Order> orders = new HashSet<Order>();

实体关联在默认情况下是延迟加载的。这意味着ordersSet实际上只是一个代理对象,在你调用一个方法之前它不会被初始化。这很好,因为Order除非需要,否则关联的对象将不会被加载。但是,如果尝试在正在运行的事务之外访问未初始化的集合,则可能会导致问题。

如果你知道在大多数情况下你需要用户订单,那么让这个关联热切地被提取是有意义的。否则,你将不得不确保集合在事务中被初始化/加载。在OpenSessionInViewFilter你提到确保了交易的请求处理过程中保持打开状态,这就是为什么你没有在YOUT的webapp这个问题。

如果你必须保持延迟加载,请尝试使用Spring TransactionTemplate将代码包装在主要方法中:

TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
    @Override
    protected void doInTransactionWithoutResult(TransactionStatus status) {
    ...
    }
});
用户回答回答于

但是,我找到了一种方法。这个方法在我的服务实现中:

public Set<Order> fetchUserOrders(Long userId) {
    User user = userRepository.findOne(userId);
    Hibernate.initialize(user.getOrders());
    Set<Order> orders = user.getOrders();
    return orders;
}

扫码关注云+社区