一尘不染

在控制台应用程序中将spring-data-jpa与hibernate一起使用时如何延迟加载

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


阅读 205

收藏
2020-06-20

共1个答案

一尘不染

一种解决方案是通过以下方式制作User.orders一个 热切的 收藏

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

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

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

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

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