我对Hibenate延迟加载有一些奇怪的问题。我有2个实体ProcessEntity和SectionEntity。 ProcessEntity可以有许多SectionEntity,而SectionEntity应该知道它属于哪个ProcessEntity(@OneToMany)。我遇到的问题是当我使用hibernateTemplate.get(id)
加载ProcessEntity然后调用我的自定义函数fetchLazyCollections(entity, ...)
时,它会循环实体方法,直到找到PersistentCollection,然后强制对该方法进行延迟加载。
当ProcessEntity的Set lazy加载时,它会递归加载SectionEntity中的所有数据,这意味着它会加载ProcessEntity,它会加载加载ProcessEntity的SectionEntity,依此类推!当我尝试序列化数据时,这会导致堆栈溢出,并且必须对性能造成严重影响。当我进行HQL查询等时,这不会发生。
以下是我对实体的设置:
ProcessEntity:
@javax.persistence.Entity(name = "processes")
public class ProcessEntity extends Entity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id = Entity.UNSAVED_ID;
...
@OneToMany(fetch=FetchType.LAZY, mappedBy="process")
private Set<SectionEntity> sections = new HashSet<SectionEntity>();
...
public Set<SectionEntity> getSections() {
return sections;
}
public void setSections(Set<SectionEntity> sections) {
this.sections = sections;
}
...
}
SectionEntity:
@javax.persistence.Entity(name = "sections")
public class SectionEntity extends Entity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id = Entity.UNSAVED_ID;
...
@ManyToOne(fetch = FetchType.LAZY, targetEntity = ProcessEntity.class)
@JoinColumn(name="process", referencedColumnName="id")
private ProcessEntity process;
@Override
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
...
public ProcessEntity getProcess() {
return process;
}
public void setProcess(ProcessEntity process) {
this.process = process;
}
...
}
fetchLazyCollections:
public <E extends Entity> E fetchLazyCollections(E entity, String... specifiedCollections) {
if(getCurrentSession() == null) {
throw new SessionException("No session found for fetching collections.");
}
// Fetch the collections using reflection
Class<? extends Entity> clazz = entity.getClass();
for(Method method : clazz.getMethods()) {
Class<?> returnType = method.getReturnType();
if(ReflectUtils.isClassCollection(returnType)) {
// Check if the collection type is specified via the getter
List<String> specified = Arrays.asList(specifiedCollections);
if(!specified.isEmpty()) {
if(!specified.contains(method.getName())) {
continue;
}
}
try {
// Check that the collection is persistent
Collection collection = (Collection) method.invoke(entity);
if(collection instanceof PersistentCollection) {
collection.size(); // invokes lazy loading
}
}
catch (IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
e.printStackTrace();
}
}
}
return entity;
}
我在后端使用Spring来使用@Transactional
。这是我的Hibernate弹簧模块(@Configuration):
@Configuration
@Import({
MappingModule.class
})
@ImportResource("classpath:nz/co/doltech/ims/properties.xml")
@EnableTransactionManagement
public class HibernateModule {
private static int statisticId = 0;
private @Value("#{app['root.path']}") String projectPath;
private @Value("#{app['database.jndiname']}") String databaseJndiName;
private @Value("#{app['hibernate.dialect']}") String hibernateDialect;
private @Value("#{app['hibernate.hbm2ddl']}") String hibernateHbm2dll;
private @Value("#{app['hibernate.show_sql']}") String hibernateShowSql;
private @Value("#{app['hibernate.format_sql']}") String hibernateFormatSql;
private @Value("#{app['hibernate.generate_statistics']}") String hibarnateStatistics;
private @Value("#{app['hibernate.cache.provider_class']}") String hibarnateCacheProviderClass;
private @Value("#{app['hibernate.cache.use_query_cache']}") String hibarnateQueryCache;
private @Value("#{app['hibernate.cache.use_second_level_cache']}") String hibarnateSecondLevelCache;
private @Value("#{app['hibernate.cache.use_structured_entries']}") String hibernateStructuredEntries;
private @Value("#{app['net.sf.ehcache.configurationResourceName']}") String hibernateEhcacheResource;
private @Value("#{app['flyway.enabled']}") String flywayEnabled;
private @Value("#{app['flyway.basePath']}") String flywayBasePath;
@Bean(name="dataSource")
public JndiObjectFactoryBean getDriverManagerDataSource() {
JndiObjectFactoryBean dataSource = new JndiObjectFactoryBean();
dataSource.setJndiName(databaseJndiName);
dataSource.setCache(true);
return dataSource;
}
@Bean(name="sessionFactory")
@DependsOn({"dataSource", "flyway"})
public AnnotationSessionFactoryBean getAnnotationSessionFactoryBean() {
AnnotationSessionFactoryBean sessionFactory = new AnnotationSessionFactoryBean();
sessionFactory.setDataSource((DataSource) getDriverManagerDataSource().getObject());
sessionFactory.setPackagesToScan(new String[] {
projectPath + ".server.entities",
projectPath + ".server.entities.joins"
});
Properties props = new Properties();
props.setProperty("hibernate.dialect", hibernateDialect);
props.setProperty("hibernate.show_sql", hibernateShowSql);
props.setProperty("hibernate.hbm2ddl.auto", hibernateHbm2dll);
props.setProperty("hibernate.format_sql", hibernateFormatSql);
props.setProperty("hibernate.generate_statistics", hibarnateStatistics);
props.setProperty("hibernate.cache.provider_class", hibarnateCacheProviderClass);
props.setProperty("hibernate.cache.use_query_cache", hibarnateQueryCache);
props.setProperty("hibernate.hibernate.cache.provider_configuration_file_resource_path", hibernateEhcacheResource);
props.setProperty("hibernate.use_second_level_cache", hibarnateSecondLevelCache);
props.setProperty("hibernate.cache.use_structured_entries", hibernateStructuredEntries);
props.setProperty("javax.persistence.validation.mode", "none");
// caching resource
//props.setProperty("net.sf.ehcache.configurationResourceName", hibernateEhcacheResource);
//props.setProperty("hibernate.transaction.manager_lookup_class", "nz.co.doltech.ims.server.persistence.TransactionManagerLookup");
//props.setProperty("hibernate.transaction.factory_class", "org.hibernate.transaction.JTATransactionFactory");
sessionFactory.setHibernateProperties(props);
return sessionFactory;
}
@Bean(name="transactionManager")
@DependsOn("sessionFactory")
public HibernateTransactionManager getHibernateTransactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(getAnnotationSessionFactoryBean().getObject());
return transactionManager;
}
@Bean(name="hibernateTemplate")
@DependsOn("sessionFactory")
public HibernateTemplate getHibernateTemplate() {
HibernateTemplate hibernateTemplate = new HibernateTemplate();
hibernateTemplate.setSessionFactory(getAnnotationSessionFactoryBean().getObject());
return hibernateTemplate;
}
@Bean(name="jmxExporter")
@DependsOn("hibernateStatisticsBean")
public MBeanExporter getJmxExporter() {
MBeanExporter exporter = new MBeanExporter();
Map<String, Object> map = new HashMap<>();
Properties props = AppProperties.getProperties();
String name = props.getProperty(AppProperties.CLIENT_MODULE_NAME);
String type = props.getProperty(AppProperties.CLIENT_RELEASE_STAGE);
map.put("Hibernate:"+name+"[" + ++statisticId + "]-"+type+"=Statistics",
getHibernateStatisticsBean());
exporter.setBeans(map);
return exporter;
}
@Bean(name="hibernateStatisticsBean")
public StatisticsService getHibernateStatisticsBean() {
StatisticsService statsBean = new StatisticsService();
statsBean.setStatisticsEnabled(true);
statsBean.setSessionFactory(getAnnotationSessionFactoryBean().getObject());
return statsBean;
}
@Bean(name="incidentDao")
@DependsOn("hibernateDao")
public IncidentHibernateDao getIncidentDao() {
IncidentHibernateDao incidentDao = new IncidentHibernateDao();
//incidentDao.registerBroadcasterId(AtmosphereConst.UPDATE_ID_KEY);
return incidentDao;
}
@Bean(name="transactionTemplate")
@DependsOn({"transactionManager"})
@Scope("prototype")
public TransactionTemplate getTransactionTemplate() {
return new TransactionTemplate(getHibernateTransactionManager());
}
}
这是Hibernate输出:
hibernateDao.get(...) called:
Hibernate: select processent0_.id as id27_0_, processent0_.description as descript2_27_0_, processent0_.name as name27_0_, processent0_.nametoken as nametoken27_0_, processent0_.order_value as order5_27_0_, processent0_.removed as removed27_0_ from processes processent0_ where processent0_.id=?
hibernateDao.fetchLazyCollections(...) called:
Hibernate: select incidentjo0_.process_id as process3_27_1_, incidentjo0_.incident_id as incident2_1_, incidentjo0_.process_id as process3_1_, incidentjo0_.incident_id as incident2_21_0_, incidentjo0_.process_id as process3_21_0_, incidentjo0_.completed as completed21_0_ from incident_process incidentjo0_ where incidentjo0_.process_id=?
Hibernate: select sections0_.process as process27_1_, sections0_.id as id1_, sections0_.id as id29_0_, sections0_.description as descript2_29_0_, sections0_.name as name29_0_, sections0_.order_value as order4_29_0_, sections0_.process as process29_0_, sections0_.removed as removed29_0_ from sections sections0_ where sections0_.process=?
从那时起没有其他任何东西被召唤。
有谁知道这里发生了什么?我没有想法。
感谢我能得到的任何帮助!
干杯, 本