锁定老帖子 主题:实现跨事务的Hibernate懒加载
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2010-05-07
最后修改:2010-05-07
最近使用Eclipse插件制作一个项目管理工具,由于涉及的数据结构比较复杂,简单的展示一棵导航树就涉及到至少20个表关联查询(其中包含大量的自关联及循环关联),刚开始数据量较小时尚可应付,当运行一段时间后,数据量达到万级以后,性能就相当差了,仔细看了一下,由Hibernate翻译过来的一条SQL就显示了十屏以上,汗一个先,所以下定决心优化一下。
protected Object initialize(final Object proxy) { if (proxy instanceof HibernateProxy) return initializeHibernateProxy((HibernateProxy) proxy); else if (proxy instanceof PersistentCollection) return initializePersistentCollection((PersistentCollection) proxy); return proxy; } private Object initializePersistentCollection(final PersistentCollection persistentCollection) { if (persistentCollection.getRole() != null && !persistentCollection.wasInitialized() && ((AbstractPersistentCollection) persistentCollection).getSession() == null) { return getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException, SQLException { final SessionImplementor sessionImplementor = (SessionImplementor) session; final CollectionPersister collectionPersister = sessionImplementor.getFactory().getCollectionPersister(persistentCollection.getRole()); sessionImplementor.getPersistenceContext().addUninitializedDetachedCollection(collectionPersister, persistentCollection); persistentCollection.setCurrentSession(sessionImplementor); persistentCollection.forceInitialization(); sessionImplementor.getPersistenceContext().clear(); persistentCollection.unsetSession(sessionImplementor); return persistentCollection; } }); } return persistentCollection; } private Object initializeHibernateProxy(final HibernateProxy proxy) { final LazyInitializer lazyInitializer = proxy.getHibernateLazyInitializer(); if (lazyInitializer.isUninitialized() && lazyInitializer.getSession() == null) { return getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException, SQLException { lazyInitializer.setSession((SessionImplementor) session); lazyInitializer.initialize(); lazyInitializer.unsetSession(); return proxy; } }); } return proxy; } 按道理,为了尽可能的减少对原有结构的侵入,应该对所有实体类的GET方法作代理,判断数据是否已被加载,如果没加载,则调用initialize方法先加载数据后再返回,可是我至今没有发现Hibernate提供类似的Intercepter,应该是可以使用第三方的代理来实现,这块我再研究一下,目前的实现方式是对实体类的GET方法硬编码: public ComponentTypeBean getComponentTypeBean() { return (ComponentTypeBean) initialize(componentTypeBean); } @SuppressWarnings("unchecked") public Set<PageComponentBean> getPageComponentBeans() { return (Set<PageComponentBean>) initialize(pageComponentBeans); } 显然这样作可以实现预期效果,但并不理想,不知道Hibernate是否提供了实体类的GET代理,等有时间再翻一下文档。
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2010-05-08
是不是可以考虑AOP方式呢?
|
|
返回顶楼 | |
发表时间:2010-05-10
iamlibo 写道 是不是可以考虑AOP方式呢?
直接使用Spring的AOP应该是行不通的,因为Hibernate内部在创建实体类的时候肯定不会使用Spring的工厂,Hibernate应该提供了自己的工厂,只是猜想。 |
|
返回顶楼 | |
发表时间:2010-07-01
一定是小辉。
|
|
返回顶楼 | |
发表时间:2010-07-01
fancy888 写道 iamlibo 写道 是不是可以考虑AOP方式呢?
直接使用Spring的AOP应该是行不通的,因为Hibernate内部在创建实体类的时候肯定不会使用Spring的工厂,Hibernate应该提供了自己的工厂,只是猜想。 spring 也提供对aspectj的支持的,并不需要使用bean容器就可以实现AOP的 可以使用编译时织入或者使用spring提供的加载时织入,只有使用Spring的运行时织入才会依赖Spring bean容器 |
|
返回顶楼 | |
发表时间:2010-07-15
关于Hibernate的拦截机制和监听机制强大,通常可以实现你所说的CS拦截问题。我们公司全年的项目中财务报表日志中等多个地方使用,貌似可以解决,详细请看
http://topmanopensource.iteye.com/blog/538213 |
|
返回顶楼 | |
浏览 4075 次