在春天懒惰加载一对多

时间:2015-08-13 18:58:51

标签: java spring hibernate jpa transactions

我坚持这个问题。基本上,我在实体UserBook之间有一对多的关系(用户可以有很多书),两个事务存储库和事务服务。我将JPA与hibernate实现一起使用。

当我尝试访问延迟加载的书籍列表时,我得到NullPointerException,当我启用SQL日志时,我注意到没有调用sql查询。如果我改变为渴望它按预期工作。

以下是我认为与此问题相关的代码:

User.java

@Entity
public class User {
...
   @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch =        FetchType.LAZY)
   @JsonIgnore
   private List<Book> rentedBooks;

Book.java

@Entity
public class Book {
...
    @ManyToOne(optional = true)
    @JoinColumn(name = "user_ID")
    @JsonProperty("user")
    private User user;

BookRepository.java

@Repository
@Transactional(Transactional.TxType.MANDATORY)
public class BookRepository {
    @PersistenceContext
    public EntityManager em;

UserRepository.java

@Repository
@Transactional(Transactional.TxType.MANDATORY)
public class UserRepository {
    @PersistenceContext
    EntityManager em;

BookService.java

@Service
@Transactional(Transactional.TxType.REQUIRED)
public class BookServices {
...
public void rentBook(String bookID, String fbID) {
        if (!userRepository.checkIfUserExists(fbID)) {
            User user = new User(fbID);
            userRepository.addUser(user);
        }
        User user = userRepository.findByUserByFacebookID(fbID);
        Book book = bookRepository.findBookByGoogleBookID(bookID);

        book.setStatus(Status.rented);
        book.setUser(user);
        bookRepository.updateBook(book);

        //user.getRentedBooks() is null
        user.getRentedBooks().add(book);
    }

我注意到如果用户不存在且创建getRentedBooks为空,但如果它是之前创建的,则getRentedBooks不为null并且在延迟加载时按预期工作。

这是我的配置:

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="packagesToScan" value="com.polarcape" />
    <!--<property name = "hibernate.show_sql" value = "true" />-->
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
    </property>
    <property name="jpaProperties">
        <props>
        <prop key="hibernate.hbm2ddl.auto">update</prop>
        <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
        <prop key="hibernate.show_sql">true</prop>
        </props>
    </property>
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

<tx:annotation-driven transaction-manager="transactionManager"/>

2 个答案:

答案 0 :(得分:0)

初始化List<Book>

User对象的UserService
User user = userRepository.findByUserByFacebookID(fbID);
Hibernate.initialize(user.getRentedBooks()); //Initialize the lazy-loaded collection
Book book = bookRepository.findBookByGoogleBookID(bookID);

快速介绍Hibernate.initialize()的需求:(来自文档here

  

如果是的话,Hibernate会抛出一个LazyInitializationException   未初始化的集合或代理是在范围之外访问的   会话,即拥有该集合或拥有该集合的实体   对代理的引用处于分离状态。

在您的情况下,List<Book>是未初始化的集合

答案 1 :(得分:0)

在常见情况下,在将bookuser关联后,您必须刷新更改。然后你只需要刷新 user实例。

在你的情况下,你也可以这样做但是程序性更正确保持对象模型一致,你应该将book添加到user.rentedBooks集合