论坛首页 Java企业应用论坛

open session in view 好吗?值得探讨!

浏览 11909 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2004-07-29  
在一些较简单的应用中,可以不用DTO而直接将PO传到view中,对于仅仅提供read的view操作,很多需求需要PO的集合。这种情况下,需要在curent thread保存一个open的session。所以就有了open session in view 模式。但是在MVC中,这种引入session的逻辑到view中,确实不大好看。随着velocity freemarker等模板技术的到来使得view还是很独立的,open session在这种情况下,确实很不适合!作为替代,应该可以在DAO中对所有的延迟装载的集合进行初始装载,然后回传到view,当然在这种情况下,会有较多副作用,但是不考虑这些副作用,他所带来的代码的简洁,层次的清晰,开发的独立等等好处就是很吸引人的拉!
不知道,你们在PO传递到View层的时候,是怎么处理这种延迟装载的问题。如果大家有讨论的兴趣,我可以继续贴上我差不多开发好的的代码,更详细的讨论这个话题。
当然,对于绝对反对PO传递到View的人来说,这个帖子就不是他们来讨论的地方了。
   发表时间:2004-07-29  
引用
当然,对于绝对反对PO传递到View的人来说,这个帖子就不是他们来讨论的地方了。


这种没有意义的话就不用说了吧。
这论坛上好像不少人说问题不说重点,扯东扯西,敲敲打打。
0 请登录后投票
   发表时间:2004-07-29  
简单的应用当然好。特别是连上来的用户不多的应用。

要用也简单,使用spring吧,不要你写一行代码--指的是opensessioninview的,至于配置当然也是要的,不过这比自己写可简单多了
0 请登录后投票
   发表时间:2004-07-29  
BeanUtil类目的是为了对延迟装载集合进行装载。他这是调用get方法进行装载,我就在session中调用它来实现集合装载。多用户情况下,性能将是大的损失!这个很严重哦,但是对于一些需要访问集合数据的action来说,可以在DAO中限定这个方法,
package com.eibm.persistence.springhibernate;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Iterator;
/**
 *@author firebody
 * utility class for dealing with java beans
 */
public class BeanUtil {
  /**
   * dumps the properties names and values of a bean
   * into a string
   * @param bean the JavaBean to be intropected
   * @return String a dump of the property names and values
   */
  public static String toString( Object bean ); {
	StringBuffer buf = new StringBuffer();;
	if( bean != null ); {
	  try {
		BeanInfo binfo = Introspector.getBeanInfo( bean.getClass(); );;
		PropertyDescriptor[] properties = binfo.getPropertyDescriptors();;
		if( properties != null ); {
		  for( int i = 0; i < properties.length; i++ ); {
			Method readMethod = properties[i].getReadMethod();;
			if( readMethod != null ); {
			  buf.append( properties[i].getName(); );;
			  buf.append( " = " );;
			  Object obj = readMethod.invoke( bean, null );;
			  if( obj != null ); {
				buf.append( obj.toString(); );;
			  }
			  else {
				buf.append( "<empty>" );;
			  }
			  buf.append( "\n" );;
			}
		  }
		}
	  }
	  catch( Exception e ); {
		// ignore exceptions thrown, this is a development aid
	  }
	}
	return buf.toString();;
  }
  public static void loadCollectionsForLazy( Object bean ); {
	  
	  if( bean != null ); {
		try {
		  BeanInfo binfo = Introspector.getBeanInfo( bean.getClass(); );;
		  PropertyDescriptor[] properties = binfo.getPropertyDescriptors();;
		  if( properties != null ); {
			for( int i = 0; i < properties.length; i++ ); {
			  Method readMethod = properties[i].getReadMethod();;
			  if( readMethod != null ); {
			  
				Object object=readMethod.invoke( bean, null );;
				if(object instanceof Collection);
					initCollection(object);;
				/*System.out.println("In BeanUtil invokeAllReadMethods,The readed Methods:\n"+
					"ReadMethod:\n"+readMethod.getName();+" Object:\n"+object);;*/
			  }
			}
		  }
		}
		catch( Exception e ); {
		  // ignore exceptions thrown, this is a development aid
		}
	  }
	  
	}
	/**
	 * 
	 * @param o
	 */
	private static void initCollection(Object o);{
		
		Collection collection=(Collection);o;
		Iterator iter=collection.iterator();;
		Object tmp;
		while(iter.hasNext(););{
			tmp=iter.next();;
		}
		
	}
}


package com.eibm.persistence.springhibernate;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Session;
import net.sf.hibernate.SessionFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.CleanupFailureDataAccessException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.orm.hibernate.SessionFactoryUtils;

/**
 * Convenient super class for Hibernate data access objects.
 *
 * <p>Requires a SessionFactory to be set, providing a HibernateTemplate
 * based on it to subclasses. Can alternatively be initialized directly via a
 * HibernateTemplate, to reuse the latter's settings like SessionFactory,
 * flush mode, exception translator, etc.
 *
 * <p>This base class is mainly intended for HibernateTemplate usage
 * but can also be used when working with SessionFactoryUtils directly,
 * e.g. in combination with HibernateInterceptor-managed Sessions.
 * Convenience getSession and closeSessionIfNecessary methods are provided
 * for that usage.
 *
 * @author firebody
 * @since 28.07.2003
 * @see #setSessionFactory
 * @see #setHibernateTemplate
 * @see org.springframework.orm.hibernate.HibernateTemplate
 * @see org.springframework.orm.hibernate.HibernateInterceptor
 */
public abstract class MyHibernateDaoSupport implements InitializingBean {

	protected final Log logger = LogFactory.getLog(getClass(););;

	private MyHibernateTemplate hibernateTemplate;

	/**
	 * Set the Hibernate SessionFactory to be used by this DAO.
	 */
	public final void setSessionFactory(SessionFactory sessionFactory); {
	  this.hibernateTemplate = new MyHibernateTemplate(sessionFactory);;
	}

	/**
	 * Return the Hibernate SessionFactory used by this DAO.
	 */
	public final SessionFactory getSessionFactory(); {
		return hibernateTemplate.getSessionFactory();;
	}

	/**
	 * Set the HibernateTemplate for this DAO explicitly,
	 * as an alternative to specifying a SessionFactory.
	 */
	public final void setHibernateTemplate(MyHibernateTemplate hibernateTemplate); {
		this.hibernateTemplate = hibernateTemplate;
	}

	/**
	 * Return the HibernateTemplate for this DAO,
	 * pre-initialized with the SessionFactory or set explicitly.
	 */
	public final MyHibernateTemplate getHibernateTemplate(); {
	  return hibernateTemplate;
	}

	public final void afterPropertiesSet(); throws Exception {
		if (this.hibernateTemplate == null); {
			throw new IllegalArgumentException("sessionFactory or hibernateTemplate is required");;
		}
		initDao();;
	}

	/**
	 * Subclasses can override this for custom initialization behavior.
	 * Gets called after population of this instance's bean properties.
	 * @throws Exception if initialization fails
	 */
	protected void initDao(); throws Exception {
	}


	/**
	 * Get a Hibernate Session, either from the current transaction or
	 * a new one. The latter is only allowed if the "allowCreate" setting
	 * of this bean's HibernateTemplate is true.
	 * @return the Hibernate Session
	 * @throws DataAccessResourceFailureException if the Session couldn't be created
	 * @throws IllegalStateException if no thread-bound Session found and allowCreate false
	 * @see org.springframework.orm.hibernate.HibernateTemplate
	 */
	protected final Session getSession();
		throws DataAccessResourceFailureException, IllegalStateException {
		return getSession(this.hibernateTemplate.isAllowCreate(););;
	}

	/**
	 * Get a Hibernate Session, either from the current transaction or
	 * a new one. The latter is only allowed if "allowCreate" is true.
	 * @param allowCreate if a new Session should be created if no thread-bound found
	 * @return the Hibernate Session
	 * @throws DataAccessResourceFailureException if the Session couldn't be created
	 * @throws IllegalStateException if no thread-bound Session found and allowCreate false
	 * @see org.springframework.orm.hibernate.SessionFactoryUtils#getSession(SessionFactory, boolean);
	 */
	protected final Session getSession(boolean allowCreate);
		throws DataAccessResourceFailureException, IllegalStateException {
		return (!allowCreate ?
			SessionFactoryUtils.getSession(getSessionFactory();, false); :
				SessionFactoryUtils.getSession(getSessionFactory();,
											   this.hibernateTemplate.getEntityInterceptor();,
																			 this.hibernateTemplate.getJdbcExceptionTranslator();););;
	}

	/**
	 * Convert the given HibernateException to an appropriate exception from
	 * the org.springframework.dao hierarchy. Will automatically detect
	 * wrapped SQLExceptions and convert them accordingly.
	 * <p>Delegates to the convertHibernateAccessException method of this
	 * DAO's HibernateTemplate.
	 * @param ex HibernateException that occured
	 * @return the corresponding DataAccessException instance
	 * @see #setHibernateTemplate
	 * @see org.springframework.orm.hibernate.HibernateTemplate#convertHibernateAccessException
	 */
	protected final DataAccessException convertHibernateAccessException(HibernateException ex); {
		return this.hibernateTemplate.convertHibernateAccessException(ex);;
	}

	/**
	 * Close the given Hibernate Session if necessary, created via this bean's
	 * SessionFactory, if it isn't bound to the thread.
	 * @param session Session to close
	 * @throws DataAccessResourceFailureException if the Session couldn't be closed
	 * @see org.springframework.orm.hibernate.SessionFactoryUtils#closeSessionIfNecessary
	 */
	protected final void closeSessionIfNecessary(Session session);
		throws CleanupFailureDataAccessException {
		SessionFactoryUtils.closeSessionIfNecessary(session, getSessionFactory(););;
	}

}


/*
 * Created on 2004-7-29
 *
 * To change the template for this generated file go to
 * Window&Preferences&Java&Code Generation&Code and Comments
 */
package com.eibm.persistence.springhibernate;
import java.io.Serializable;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Session;
import net.sf.hibernate.SessionFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate.HibernateCallback;
import org.springframework.orm.hibernate.HibernateTemplate;
/**
 * @author firebody
 * To change the template for this generated type comment go to
 * Window&Preferences&Java&Code Generation&Code and Comments
 */
public class MyHibernateTemplate
	extends HibernateTemplate{
		
		/**
		 * Create a new MyHibernateTemplate instance.
		 */
		public MyHibernateTemplate(); {
			super();;
		}

		/**
		 * Create a new MyHibernateTemplate instance.
		 * @param sessionFactory SessionFactory to create Sessions
		 */
		public MyHibernateTemplate(SessionFactory sessionFactory); {
			super(sessionFactory);;
			setSessionFactory(sessionFactory);;
			afterPropertiesSet();;
		}

		/**
		 * Create a new MyHibernateTemplate instance.
		 * @param sessionFactory SessionFactory to create Sessions
		 * @param allowCreate if a new Session should be created
		 * if no thread-bound found
		 */
		public MyHibernateTemplate(SessionFactory sessionFactory, boolean allowCreate); {
			super(sessionFactory,allowCreate);;
			setSessionFactory(sessionFactory);;
			setAllowCreate(allowCreate);;
			afterPropertiesSet();;
		}



		public Object loadForBeanCollections(final Class entityClass, final Serializable id); throws DataAccessException {
			return execute(new HibernateCallback(); {
				public Object doInHibernate(Session session); throws HibernateException {
					Object object= session.load(entityClass, id);;
					System.out.println("load Entity:"+id+"     "+"Now initial the "+id+" Entity 's collections-------------------------");;
					
					BeanUtil.loadCollectionsForLazy(object);;
					return object;
				}
			});;
		}



}

DAO :
/*
 * Created on 2004-7-29
 *
 * To change the template for this generated file go to
 * Window&Preferences&Java&Code Generation&Code and Comments
 */
package com.eibm.persistence;

import java.util.Collection;
import java.util.List;
import java.io.Serializable;
import com.eibm.domain.entity.Entity;
import com.eibm.persistence.springhibernate.MyHibernateDaoSupport;

/**
 * @author firebody
 *
 * To change the template for this generated type comment go to
 * Window&Preferences&Java&Code Generation&Code and Comments
 */
public class EntityDAOMyHibernateImpl
	extends MyHibernateDaoSupport
	implements EntityDAO {

		/* (non-Javadoc);
		 * @see com.eibm.persistent.EntityDAO#addEntity(com.eibm.domain.entity.Entity);
		 */
		public Entity createEntity(Entity entity); throws Exception {
			Serializable id=getHibernateTemplate();.save(entity);;
			 return (Entity);getHibernateTemplate();.load(entity.getClass();,id);;
		}

		/* (non-Javadoc);
		 * @see com.eibm.persistent.EntityDAO#findEntity(java.lang.Class, long);
		 */
		public Entity findEntity(Class type, long id); throws Exception {
			return (Entity);getHibernateTemplate();.load(type,new Long(id););;
		
		}

		/* (non-Javadoc);
		 * @see com.eibm.persistent.EntityDAO#updateEntity(com.eibm.domain.entity.Entity);
		 */
		public Entity updateEntity(Entity entity); throws Exception {
			getHibernateTemplate();.update(entity);;
			return (Entity);getHibernateTemplate();.load(entity.getClass(); , new Long(entity.getId();); );;
		
		}

		/* (non-Javadoc);
		 * @see com.eibm.persistent.EntityDAO#delEntity(com.eibm.domain.entity.Entity);
		 */
		public Entity removeEntity(long id); throws Exception {
			Entity entity=(Entity);getHibernateTemplate();.load(Entity.class , new Long(id););;
			if(entity != null);{
				getHibernateTemplate();.delete(entity);;
				return entity;
			}
			
			return null;
		}
		public void removeEntity(Entity entity); throws Exception{
			getHibernateTemplate();.delete(entity);;
		}
		public List findAllEntities(); throws Exception{
			return getHibernateTemplate();.find("from Entity as entity where entity.id != 0");;
		
			//return getHibernateTemplate();.find("from " + Entity.class.getName(););;
		
		
		}
		public void removeEntities(Collection entities); throws Exception{
			getHibernateTemplate();.deleteAll(entities);;
		}
}

上面代码带来的好处:
1)层次更清晰
2)对于view的操作更加简便,不用传递session到view中,比如这样举个例子:
Group group=(Group);dao.findEntity(Entity.class , new Long(1););;
req.setAttribute("group",group);;

视图编辑人员可以这样在视图开发:
#foreach ($user in ${group.users} );
    <br>$user.name
    <br>$user.email
#end

上面的代码就已经很简洁了!当然这只是在实体类较为简单或者设计层次较为合理的情况下,才能发挥更好的更简洁的代码!
0 请登录后投票
   发表时间:2004-07-31  
这个做法不是open session in view吧?
通过调用getter,将延迟加载的数据读了进来。我也用过这种方式,事实上我认为这个方式更好。可以完全分开view与业务层。这个方式加载数据后就可以关闭session了。但由于没有元数据支持,还得手工指定哪些数据应该加载--我用了个笨方法,自己用类来封装元数据。否则的话,逐个调用getter,那不如不用延迟数据加载。

只加载需要的数据,加载完后关掉session,我认为这是改善性能最经济的办法。

我是用spring的beanwarpperimpl包装了一下object,然后就可以按名调用相应的getter了——当时还是用open session in view ,就把这个包装后的object直接丢到页面了,用velocity展现数据。通过按名调用增加了一点灵活性,做起来稍微好一点而已。
0 请登录后投票
   发表时间:2004-07-31  
无明 写道
这个做法不是open session in view吧?
通过调用getter,将延迟加载的数据读了进来。我也用过这种方式,事实上我认为这个方式更好。可以完全分开view与业务层。这个方式加载数据后就可以关闭session了。但由于没有元数据支持,还得手工指定哪些数据应该加载--我用了个笨方法,自己用类来封装元数据。否则的话,逐个调用getter,那不如不用延迟数据加载。

只加载需要的数据,加载完后关掉session,我认为这是改善性能最经济的办法。

我是用spring的beanwarpperimpl包装了一下object,然后就可以按名调用相应的getter了——当时还是用open session in view ,就把这个包装后的object直接丢到页面了,用velocity展现数据。通过按名调用增加了一点灵活性,做起来稍微好一点而已。

呵呵,看看我的原文:
引用

open session在这种情况下,确实很不适合!作为替代,应该可以在DAO中对所有的延迟装载的集合进行初始装载,然后回传到view,

已经很强调了,不过这里还需要更改一下,不要覆写Load,而是另开一个load (booelan flag 。。)方法,不然会在删除或者更新集合的时候出现问题。
0 请登录后投票
   发表时间:2004-08-01  
呵呵,我不是说这样做更好吗?这样分层更为彻底

我现在比较头疼的就是在对延迟装载的集合进行初始装载的方式

我并不想将所有延迟装载的集合都加载,只想加载页面要用的,因此觉得不该DAO中加载,而是在业务层加载
0 请登录后投票
   发表时间:2004-08-01  
无明 写道
呵呵,我不是说这样做更好吗?这样分层更为彻底

我现在比较头疼的就是在对延迟装载的集合进行初始装载的方式

我并不想将所有延迟装载的集合都加载,只想加载页面要用的,因此觉得不该DAO中加载,而是在业务层加载

要实现你的需求应该也是很简单的!可以这样构造一个method
Object load(Class type,Serializable id,boolean isLoadCollectionItem,String propertyName) {
     ...利用reflect与beanutil内省class,然后调用复合property的method,对集合进行遍历。

}

在你的业务层你可以这样写:
假设有个POJO:
class BeanA{
      .....
      public Set getBeanBs(){
         ....
       }
       ....
      public  Set getBeanCs() {
            ...
       }
    ....
}
如果要装载BeanCs集合的全部数据,你可以这样调用load
parent=(Parent)dao.load(BeanA.class , id,true,"beanCs" );
这样load出来的parent,即使在脱离session后,它对getBeanCs()返回的集合已经装载了所有数据,而别的集合我们并没有装载它的数据!
为了可扩展,你可以把这些配置写道XML文件,在load entity之前,读取配置文件的信息,来动态决定这个entity的那些集合需要装载数据!
0 请登录后投票
   发表时间:2004-08-02  
我有一个问题, 如果lazy loading的Collection里的元素, 其本身还有lazy loading的Collection, 那么不用open session in view的话, 如何能够简洁的处理呢?

我对于lazy loading的想法是, Hibernte为什么不采用re-open session的方式来处理呢? 查看过email list上关于这方面的讨论, hibernate team说这样会照成事务方面的问题. 但是我们对于这种lazy loading的应用, 通常都是在页面上做呈现, 不会对collection进行写的操作, 而对于读取到脏数据的问题, 影响不大.

所以我们是否可以考虑扩展Hibernate, 让其采用re-open a new session来处理lazy loading?

另外, 建议版主把这个帖子移动到hibernate讨论区去, 这样讨论的人可能会多一些.
0 请登录后投票
   发表时间:2004-08-02  
Quake Wang 写道
我有一个问题, 如果lazy loading的Collection里的元素, 其本身还有lazy loading的Collection, 那么不用open session in view的话, 如何能够简洁的处理呢?

我对于lazy loading的想法是, Hibernte为什么不采用re-open session的方式来处理呢? 查看过email list上关于这方面的讨论, hibernate team说这样会照成事务方面的问题. 但是我们对于这种lazy loading的应用, 通常都是在页面上做呈现, 不会对collection进行写的操作, 而对于读取到脏数据的问题, 影响不大.

所以我们是否可以考虑扩展Hibernate, 让其采用re-open a new session来处理lazy loading?

另外, 建议版主把这个帖子移动到hibernate讨论区去, 这样讨论的人可能会多一些.

移来移去,我都找不到了!!呵呵
re-open a new session可行吗?这个问题很值得探讨!
re-open的概念也不是很清楚!是不是可以这样理解?:
1)re-oepn session代表一个全新设计的session实现对象!向sessionfactory声明,我需要一个re-open的session,sessioFactory创建一个特殊的session给你,再你调用close时并没有释放session cache,sessionfactory还需要为你保存这个session引用,以使得你在以后有可能的reopen而返回给你继续使用!
2)re-open session只是一个普通的现有的sesisonImpl,我们在关闭的时候这样调用:close(boolean reopenFlag),hibernate要做的就是在sessionFactory实现这个方法,以及对你的reopen提供一整套的实现!工作是不是很大呢?
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics