关于HibnernateDaoSupporrt(转载。备忘,不是很重要)

3。HibernateDaoSupport 基类:

一个回调实现能够有效地在任何Hibernate数据访问中使用。HibernateTemplate 会确保当前Hibernate的 Session 实例的正确打开和关闭,并直接参与到事务管理中去。 Template实例不仅是线程安全的,同时它也是可重用的。因而他们可以作为外部对象的实例变量而被持有。对于那些简单的诸如find、load、saveOrUpdate或者delete操作的调用,HibernateTemplate 提供可选择的快捷函数来替换这种回调的实现。 不仅如此,Spring还提供了一个简便的 HibernateDaoSupport 基类,这个类提供了 setSessionFactory(..) 方法来接受一个 SessionFactory 对象,同时提供了 getSessionFactory() 和 getHibernateTemplate() 方法给子类使用。实例如下:

Java代码 复制代码 收藏代码
  1. public class ProductDaoImpl extends HibernateDaoSupport implements ProductDao {
  2. public Collection loadProductsByCategory(String category) throws DataAccessException {
  3. return this.getHibernateTemplate().find(
  4. "from test.Product product where product.category=?", category);
  5. }
  6. }
public class ProductDaoImpl extends HibernateDaoSupport implements ProductDao {

    public Collection loadProductsByCategory(String category) throws DataAccessException {
        return this.getHibernateTemplate().find(
            "from test.Product product where product.category=?", category);
    }
}

4。HibernateDaoSupport 基类使用技巧:

HibernateDaoSupport这也是使用HibernateTemplate的方法之一,只是需要dao继承这个类:

Java代码 复制代码 收藏代码
  1. public class LogDaoImpl extends HibernateDaoSupport implements LogDao {
  2. @Override
  3. public void save(Log log) {
  4. this.getHibernateTemplate().save(log);
  5. //this.save(log);
  6. System.out.println("log save...");
  7. }
  8. }
public class LogDaoImpl extends HibernateDaoSupport implements LogDao {
	@Override
	public void save(Log log) {		
			this.getHibernateTemplate().save(log);
			//this.save(log);
		System.out.println("log save...");
	}
}

dao继承了HibernateDaoSupport类,而这个又拥有sessionFactory和hibernateTemplate的setXXX方法,只要我在初始化这个dao时,注入两个其中一个就可以了。但是这两个setXX方法都为final的,因为不可以重写,这样就不能使用annotation的方式了,只能使用xml的方法了。HibernateDaoSupport部分源代码如下:

Java代码 复制代码 收藏代码
  1. public abstract class HibernateDaoSupport extends DaoSupport{
  2. private HibernateTemplate hibernateTemplate;
  3. public final void setSessionFactory(SessionFactory sessionFactory) {
  4. //......
  5. }
  6. }
  7. public final void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
  8. this.hibernateTemplate = hibernateTemplate;
  9. }
  10. public final HibernateTemplate getHibernateTemplate() {
  11. return this.hibernateTemplate;
  12. }
  13. //.......其他方法
  14. }
public abstract class HibernateDaoSupport extends DaoSupport{
      private HibernateTemplate hibernateTemplate;
    
     public final void setSessionFactory(SessionFactory sessionFactory) {
		//......
		}
	}

public final void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
		this.hibernateTemplate = hibernateTemplate;
	}

public final HibernateTemplate getHibernateTemplate() {
	  return this.hibernateTemplate;
	}
//.......其他方法
}

xml注入方法如下:

Java代码 复制代码 收藏代码
  1. <bean id="logDaoImpl" class="example.dao.impl.LogDaoImpl">
  2. <property name="hibernateTemplate" ref="hibernateTemplate"></property>
  3. </bean>
<bean id="logDaoImpl" class="example.dao.impl.LogDaoImpl">
  	<property name="hibernateTemplate" ref="hibernateTemplate"></property>
  </bean>

但是问题又来了,如果dao有多个(甚至几个以上),这样就会有大量的xml配置文件,每个dao需要一个配置一个bean,并且在这个bean中需要注入一个sessionFactory或是hibernateTemplate,这样的工作量是非常的大,并且容易出错。
针对有大量的dao我们提供一个解决方案:
我们可以创建一个类,并且这个类来继承hibernateDaoSupport这个类,由于hibernateDaoSupport类的sessionFactory和hibernateTemplate的setXXX方法是final的,因此不能重写,但我们可以在这个类中注入一个sessionFactory或hibernateTemplate但是setXXX方法名,用其它的。然后让dao来继承这个类,这就dao就可以使用annotation方式注解了。代码如下:

Java代码 复制代码 收藏代码
  1. @Component
  2. public class SuperDao extends HibernateDaoSupport {
  3. @Resource(name="hibernateTemplate")
  4. public void setSuperHibernateTemplate(HibernateTemplate hibernateTemplate ){
  5. //在这里为父类HibernateDaoSuppport注入hibernateTemplate或是sessionFactory
  6. super.setHibernateTemplate(hibernateTemplate);
  7. }
  8. }
@Component
public class SuperDao extends HibernateDaoSupport {
	@Resource(name="hibernateTemplate")
	public void setSuperHibernateTemplate(HibernateTemplate hibernateTemplate ){
		//在这里为父类HibernateDaoSuppport注入hibernateTemplate或是sessionFactory
		super.setHibernateTemplate(hibernateTemplate);
	}
}

其它的dao继承这个就可以了,如下所示:

Java代码 复制代码 收藏代码
  1. @Component
  2. public class LogDaoImpl extends SuperDao implements LogDao {
  3. @Override
  4. public void save(Log log) {
  5. this.getHibernateTemplate().save(log);
  6. //this.save(log);
  7. System.out.println("log save...");
  8. }
  9. }
@Component
public class LogDaoImpl extends SuperDao implements LogDao {
	@Override
	public void save(Log log) {
			this.getHibernateTemplate().save(log);
			//this.save(log);
		System.out.println("log save...");
	}
}

其他的用法不在这里累述,请参看Spring的参考文档.下面重点说说Spring HibernateTemplate模板方法与Callback机制.

二。HibernateTemplate源码分析

下面以save()方法为例进行说明,先看源代码:

HibernateCallback接口的代码如下, 它只有一个方法doInHibernate方法:

Java代码 复制代码 收藏代码
  1. public interface HibernateCallback {
  2. Object doInHibernate(Session session) throws HibernateException, SQLException;
  3. }
public interface HibernateCallback {
       Object doInHibernate(Session session) throws HibernateException, SQLException;
}

HibernateTemplate中的具体操作的方法,如save(),update()的具体实现都采用匿名类的方式实现了该接口,在doInHibernate中完成具体的操作。以save()方法为例:

Java代码 复制代码 收藏代码
  1. public Serializable save(final Object entity) throws DataAccessException {
  2. return (Serializable) executeWithNativeSession(new HibernateCallback() {
  3. public Object doInHibernate(Session session) throws HibernateException {
  4. checkWriteOperationAllowed(session);
  5. return session.save(entity);
  6. }
  7. });
  8. }
public Serializable save(final Object entity) throws DataAccessException {
		return (Serializable) executeWithNativeSession(new HibernateCallback() {
			public Object doInHibernate(Session session) throws HibernateException {
				checkWriteOperationAllowed(session);
				return session.save(entity);
			}
		});
	}

这段代码重点注意以匿名类的方式实现了 HibernateCallback接口.

然后是executeWithNativeSession()方法如下,在此方法中调用核心方法doExecute,如下所示:

Java代码 复制代码 收藏代码
  1. public Object executeWithNativeSession(HibernateCallback action) {
  2. return doExecute(action, false, true);
  3. }
public Object executeWithNativeSession(HibernateCallback action) {
		return doExecute(action, false, true);
	}

在这个方法中使用本地已存在的Session去执行此次save操作,doExecute代码如下所示:

Java代码 复制代码 收藏代码
  1. /**
  2. * Execute the action specified by the given action object within a Session.
  3. * @param action callback object that specifies the Hibernate action
  4. * @param enforceNewSession whether to enforce a new Session for this template
  5. * even if there is a pre-bound transactional Session
  6. * @param enforceNativeSession whether to enforce exposure of the native
  7. * Hibernate Session to callback code
  8. * @return a result object returned by the action, or <code>null</code>
  9. * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
  10. */
  11. protected Object doExecute(HibernateCallback action, boolean enforceNewSession, boolean enforceNativeSession)
  12. throws DataAccessException {
  13. Assert.notNull(action, "Callback object must not be null");
  14. Session session = (enforceNewSession ?
  15. SessionFactoryUtils.getNewSession(getSessionFactory(), getEntityInterceptor()) : getSession());
  16. boolean existingTransaction = (!enforceNewSession &&
  17. (!isAllowCreate() || SessionFactoryUtils.isSessionTransactional(session, getSessionFactory())));
  18. if (existingTransaction) {
  19. logger.debug("Found thread-bound Session for HibernateTemplate");
  20. }
  21. FlushMode previousFlushMode = null;
  22. try {
  23. previousFlushMode = applyFlushMode(session, existingTransaction);
  24. enableFilters(session);
  25. Session sessionToExpose =
  26. (enforceNativeSession || isExposeNativeSession() ? session : createSessionProxy(session));
  27. Object result = action.doInHibernate(sessionToExpose);
  28. flushIfNecessary(session, existingTransaction);
  29. return result;
  30. }
  31. catch (HibernateException ex) {
  32. throw convertHibernateAccessException(ex);
  33. }
  34. catch (SQLException ex) {
  35. throw convertJdbcAccessException(ex);
  36. }
  37. catch (RuntimeException ex) {
  38. // Callback code threw application exception...
  39. throw ex;
  40. }
  41. finally {
  42. if (existingTransaction) {
  43. logger.debug("Not closing pre-bound Hibernate Session after HibernateTemplate");
  44. disableFilters(session);
  45. if (previousFlushMode != null) {
  46. session.setFlushMode(previousFlushMode);
  47. }
  48. }
  49. else {
  50. // Never use deferred close for an explicitly new Session.
  51. if (isAlwaysUseNewSession()) {
  52. SessionFactoryUtils.closeSession(session);
  53. }
  54. else {
  55. SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());
  56. }
  57. }
  58. }
  59. }
/**
	 * Execute the action specified by the given action object within a Session.
	 * @param action callback object that specifies the Hibernate action
	 * @param enforceNewSession whether to enforce a new Session for this template
	 * even if there is a pre-bound transactional Session
	 * @param enforceNativeSession whether to enforce exposure of the native
	 * Hibernate Session to callback code
	 * @return a result object returned by the action, or <code>null</code>
	 * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
	 */
	protected Object doExecute(HibernateCallback action, boolean enforceNewSession, boolean enforceNativeSession)
			throws DataAccessException {

		Assert.notNull(action, "Callback object must not be null");

		Session session = (enforceNewSession ?
				SessionFactoryUtils.getNewSession(getSessionFactory(), getEntityInterceptor()) : getSession());
		boolean existingTransaction = (!enforceNewSession &&
				(!isAllowCreate() || SessionFactoryUtils.isSessionTransactional(session, getSessionFactory())));
		if (existingTransaction) {
			logger.debug("Found thread-bound Session for HibernateTemplate");
		}

		FlushMode previousFlushMode = null;
		try {
			previousFlushMode = applyFlushMode(session, existingTransaction);
			enableFilters(session);
			Session sessionToExpose =
					(enforceNativeSession || isExposeNativeSession() ? session : createSessionProxy(session));
			Object result = action.doInHibernate(sessionToExpose);
			flushIfNecessary(session, existingTransaction);
			return result;
		}
		catch (HibernateException ex) {
			throw convertHibernateAccessException(ex);
		}
		catch (SQLException ex) {
			throw convertJdbcAccessException(ex);
		}
		catch (RuntimeException ex) {
			// Callback code threw application exception...
			throw ex;
		}
		finally {
			if (existingTransaction) {
				logger.debug("Not closing pre-bound Hibernate Session after HibernateTemplate");
				disableFilters(session);
				if (previousFlushMode != null) {
					session.setFlushMode(previousFlushMode);
				}
			}
			else {
				// Never use deferred close for an explicitly new Session.
				if (isAlwaysUseNewSession()) {
					SessionFactoryUtils.closeSession(session);
				}
				else {
					SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());
				}
			}
		}
	}

doExecute这个方法有点过于复杂,不容易理解,现在我用差不多是伪代码的形式来把doExecute这个方法的大概意思写出为,以便大家理解:

Java代码 复制代码 收藏代码
  1. public class MyHibernateTemplate {
  2. public Object executeWithNativeSession(HibernateCallback action) {
  3. return doExecute(action, false, true);
  4. }
  5. protected Object doExecute(HibernateCallback action, boolean enforceNewSession, boolean enforceNativeSession){
  6. Session session = null;
  7. try {
  8. session = getSession();
  9. session.beginTransaction();
  10. action.doInHibernate(session);
  11. session.getTransaction().commit();
  12. } catch (Exception e) {
  13. session.getTransaction().rollback();
  14. }finally{
  15. //....进行额外处理
  16. }
  17. return null;
  18. }
  19. private Session getSession() {
  20. // TODO Auto-generated method stub
  21. return new Session();
  22. }
  23. }
public class MyHibernateTemplate {

	public Object executeWithNativeSession(HibernateCallback action) {
		return doExecute(action, false, true);
	}
	
	protected Object doExecute(HibernateCallback action, boolean enforceNewSession, boolean enforceNativeSession){
		Session session = null;
		try {
			session = getSession();
			session.beginTransaction();
			action.doInHibernate(session);
			session.getTransaction().commit();
		} catch (Exception e) {
			session.getTransaction().rollback();
		}finally{
			//....进行额外处理
		}
		return null;
	}

	private Session getSession() {
		// TODO Auto-generated method stub
		return new Session();
	}
}

如果你觉得使用匿名内部类传参的方式不好理解,你可以先写一个特定针对save操作的实现类来帮助理解它,如下所示:

Java代码 复制代码 收藏代码
  1. public class HibernateSaveCallbackImpl implements HibernateCallback {
  2. private Object object ;
  3. public HibernateSaveCallbackImpl(){}
  4. public HibernateSaveCallbackImpl(Object object){
  5. this.object = object;
  6. }
  7. public Object doInHibernate(Session session) throws HibernateException,
  8. SQLException {
  9. session.save(object);
  10. return null;
  11. }
  12. }
public class HibernateSaveCallbackImpl implements HibernateCallback {

	private Object object ;
	public HibernateSaveCallbackImpl(){}
	public HibernateSaveCallbackImpl(Object object){
		this.object = object;
	}
	public Object doInHibernate(Session session) throws HibernateException,
			SQLException {
		session.save(object);
		return null;
	}
}

然后再实例化一个HibernateSaveCallbackImpl对象传给MyHibernateTemplate进行使用,如下所示:

Java代码 复制代码 收藏代码
  1. public static void main(String[] args) {
  2. HibernateCallback callback = new HibernateSaveCallbackImpl();
  3. HibernateCallback callback2 = new HibernateSaveCallbackImpl("save this object");
  4. new MyHibernateTemplate().executeWithNativeSession(callback);
  5. }
public static void main(String[] args) {
		HibernateCallback callback = new HibernateSaveCallbackImpl();
		HibernateCallback callback2 = new HibernateSaveCallbackImpl("save this object");
		new MyHibernateTemplate().executeWithNativeSession(callback);
	}

当MyHibernateTemplate中的doExecute方法执行时,执行到

Java代码 复制代码 收藏代码
  1. action.doInHibernate(session);
action.doInHibernate(session);

时,它会先去执行你传入的引用(也就是你自己)的方法。所以称为回调,这与模板模式中的钩子函数基本是一样的。其实回调,简单的可以说是:将自己的引用传给别的方法,在别的方法里面,通过自己的引用调用自己的方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值