如何在使用 spring-data-jpa 和休眠时从控制台应用程序延迟加载收集 [英] how to lazy load collection when using spring-data-jpa, with hibernate, from an console application

查看:11
本文介绍了如何在使用 spring-data-jpa 和休眠时从控制台应用程序延迟加载收集的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个小型控制台应用程序,我正在使用 spring-data-jpa 和 hibernate.在独立的控制台应用程序中,我真的不知道如何在使用 spring-data-jpa 及其存储库时延迟初始化集合.这是我的一些代码:

I have an small console application and I am using spring-data-jpa with hibernate. I really can not figure out how to lazy initialize collections when using spring-data-jpa with its repositories, in an standalone console application. Here is some of my code:

@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);
}

服务实现:

@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 循环出现异常:

the foreach loop gets an exception:

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

EVERE: failed to lazily initialize a collection of role: com.aki.util.User.orders, no session or session was closed org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role:

请注意,从带有某种 OpenSessionInViewFilter 的 Web 应用程序运行此程序时,我没有遇到此问题.

推荐答案

一种解决方案是让 User.orders 成为一个 急切地获取集合

One solution can be to make User.orders an eagerly fetched collection by

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

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

Entity associations are lazily loaded by default. This means that the orders Set is actually just a proxy object that won't get initialized until you invoke a method on it. This is good, because the associated Order objects won't get loaded unless they are needed. However, this can cause problems, if you try to access the uninitialized collection outside of a running transaction.

如果您知道在大多数情况下您将需要用户的订单,那么急切地获取关联是有意义的.否则,您将必须确保集合在事务中被初始化/加载.您提到的 OpenSessionInViewFilter 确保事务在请求处理期间保持打开状态,这就是为什么您的 web 应用程序中没有这个问题.

If you know that in most of the cases you will need the User's Orders, it makes sense to make the association eagerly fetched. Otherwise you will have to ensure that the collection gets initialized/loaded inside a transaction. The OpenSessionInViewFilter you mentioned makes sure that the transaction stays open during the request processing, that is why you don't have this issue in yout webapp.

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

In case you must keep it lazily loaded, try using Spring's TransactionTemplate to wrap the code in your main method:

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

这篇关于如何在使用 spring-data-jpa 和休眠时从控制台应用程序延迟加载收集的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆