我有一个小型控制台应用程序,我使用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 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从webapp运行时,我没有遇到此问题。
答案 0 :(得分:13)
一种解决方案可以是通过
使User.orders
成为急切获取的集合
@OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
private Set<Order> orders = new HashSet<Order>();
默认情况下,实体关联会延迟加载。这意味着orders
Set实际上只是一个代理对象,在您调用方法之前,它不会被初始化。这很好,因为除非需要,否则不会加载关联的Order
对象。但是,如果您尝试在正在运行的事务之外访问未初始化的集合,则会导致问题。
如果您知道在大多数情况下您将需要用户订单,那么切实地提取关联是有意义的。否则,您必须确保在事务中初始化/加载集合。您提到的OpenSessionInViewFilter
确保在请求处理期间事务保持打开状态,这就是您在webapp中没有此问题的原因。
如果您必须保持延迟加载,请尝试使用Spring的TransactionTemplate
将代码包装在main方法中:
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
...
}
});
答案 1 :(得分:7)
然而,我找到了一种方法。这个方法在我的服务实现中:
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());
如果没有这个,集合仍然不会被初始化,你会收到错误。
答案 2 :(得分:-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();
}
}