OpenSessionInViewFilter

OpenSessionInViewFilter

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

问题描述

我有一个小型的控制台应用程序,并且使用spring-data-jpa和hibernate。在独立的控制台应用程序中,当使用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扩展PagingAndSortingRepository< User,Long> {

public ArrayList< User> findByFirstNameIgnoreCase(String firstName);

服务impl:

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

public ArrayList< User> findByFirstNameIgnoreCase(String firstName){
ArrayList< User> users = new ArrayList< User>();
users = userRepository.findByFirstNameIgnoreCase(firstName);
返回用户;
}

我的主要方法:

  ... 
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从webapp运行此应用程序时,我没有此问题。

解决方案

一个解决方案可以使 User.orders 和 em> collection by

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

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



如果您知道大多数情况下您需要用户订单,使协会热切地获取是有道理的。否则,你将不得不确保集合在事务中被初始化/加载。您提到的 OpenSessionInViewFilter 可确保事务在请求处理期间保持打开状态,这就是为什么您在web应用程序中不存在此问题。



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

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


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>();
...
}

repository:

public interface UserRepository extends PagingAndSortingRepository<User, Long> {

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

service 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;
}

my main method:

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

the foreach loop gets an exception:

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

Please note that I do not have this problem when running this from an webapp with some kind of OpenSessionInViewFilter.

解决方案

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>();

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.

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.

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和hibernate进行延迟加载收集的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-29 14:27