我无法弄清楚这一点。得到“线程中的异常”主“org.hibernate.LazyInitializationException:懒得初始化角色集合:org.sandy.domain.Location.items,没有关闭会话或会话” 我知道会话已关闭,但tx:annotation-driver @Transactional应确保打开会话。它与EAGER提取工作正常。哦,是的 - 这是通过apress pro spring 3的例子。
但也许我没有得到这个概念 - 我的意思是当我在SomeService中调试“getFirst()”时我可以看到集合中的所有项目但是一旦返回命中 - 抛出LazyInit异常......
package org.sandy.main;
import org.sandy.domain.Item;
import org.sandy.domain.Location;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.stereotype.Service;
@Service(value = "main")
public class EntryPoint {
@Autowired
private SomeService ss;
public static void main(String args[]) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:*-beans.xml");
ctx.refresh();
EntryPoint entryPoint = (EntryPoint) ctx.getBean("main");
Item item = new Item();
Location location = new Location();
item.setLocation(location);
location.getItems().add(item);
entryPoint.getSs().save(location);
System.out.println(entryPoint.getSs().findFirst());
ctx.registerShutdownHook();
}
public SomeService getSs() {
return ss;
}
public void setSs(SomeService ss) {
this.ss = ss;
}
}
和服务
package org.sandy.main;
import org.sandy.domain.Item;
import org.sandy.domain.Location;
import org.sandy.repo.ItemRepo;
import org.sandy.repo.LocationRepo;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service(value = "ss")
@Repository
@Transactional
public class SomeService {
@Autowired
private ItemRepo itemRepo;
@Autowired
private LocationRepo locationRepo;
@Transactional
public void save(Location location) {
locationRepo.save(location);
}
@Transactional(readOnly = true)
public List<Item> findFirst() {
System.out.println("ONE");
Iterable<Location> it = locationRepo.findAll();
System.out.println("TWO");
Location l = it.iterator().next();
System.out.println("THREE");
List<Item> r = l.getItems();
return r;
}
@Transactional
public Iterable finAll() {
return locationRepo.findAll();
}
public void setItemRepo(ItemRepo itemRepo) {
this.itemRepo = itemRepo;
}
public void setLocationRepo(LocationRepo locationRepo) {
this.locationRepo = locationRepo;
}
}
和位置回购
package org.sandy.repo;
import org.sandy.domain.Location;
import org.springframework.data.repository.CrudRepository;
public interface LocationRepo extends CrudRepository<Location, Long> {
}
实体:
@Entity
@Table(name = "Locations")
public class Location extends Entry {
private List<Item> items = new ArrayList<Item>();
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "location")
public List<Item> getItems() {
return items;
}
public void setItems(List<Item> items) {
this.items = items;
}
}
package org.sandy.domain;
import javax.persistence.*;
@Entity
@Table(name = "Items")
public class Item extends Entry {
private Location location;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn()
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
}
所有强大的xml bean配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<jdbc:embedded-database id="dataSource" type="H2" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" >
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="packagesToScan" value="org.sandy.domain" />
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.H2Dialect
</prop>
<prop key="hibernate.max_fetch_depth">3</prop>
<prop key="hibernate.jdbc.fetch_size">50</prop>
<prop key="hibernate.jdbc.batch_size">10</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.enable_lazy_load_no_trans">true</prop>
</props>
</property>
</bean>
<context:annotation-config/>
<jpa:repositories base-package="org.sandy.repo" entity-manager-factory-ref="emf" transaction-manager-ref="transactionManager" />
<context:component-scan base-package="org.sandy" />
</beans>
答案 0 :(得分:2)
这段代码
System.out.println(entryPoint.getSs().findFirst());
相当于
/* 1 */ SomeService ss = entryPoint.getSs();
/* 2 */ List<Item> items = ss.findFirst(); // Session opens and closes for @Transactional
/* 3 */ String toPrint = items.toString(); // no more Session
/* 4 */ System.out.println(toPrint);
因此,您可以看到Session
边界仅包含findFirst()
调用。如果您正懒惰地加载实体,那么在第3行,items
中的元素不会被初始化。当您尝试在每个元素上调用toString()
的{{1}}内拨打List#toString()
时,您将获得toString()
。
在使用实体之前,您应该完全初始化实体。这必须在Session边界内完成。