31

我有一个小型控制台应用程序,我正在使用 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);
}

服务内涵:

@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 的 webapp 运行它时,我没有这个问题。

4

3 回答 3

15

一种解决方案User.orders是通过

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

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

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

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

TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
    @Override
    protected void doInTransactionWithoutResult(TransactionStatus status) {
    ...
    }
});
于 2013-02-18T14:58:18.667 回答
9

不过,我找到了一种方法。此方法在我的服务实现中:

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

注意:这是@zagyi 在他的评论之一中所建议的,但也要注意声明:Hibernate.initialize(user.getOrders());没有这个集合仍然不会被初始化,你会得到一个错误。

于 2013-02-20T10:05:39.233 回答
-2

这对我有用:

@Component
public class Test {

    @Inject 
    OrderDAO orderDAO;

    @PersistenceUnit
    private EntityManagerFactory emf;

    @PostConstruct
    public void test(){
        EntityManager em= emf.createEntityManager();
        for (Order o:orderDAO.findAll()){
            o=em.find(o.getClass(),o.getId());
            System.out.println(o.getLazyField());
        }
        em.close();
    }
}
于 2013-08-07T00:42:42.060 回答