spring 封装了hibernate dao的操作:学习中遇到的问题,以及自己的见解
一、使用了由spring框架提供的对hibernate3的封装。这样做无非是为了使用spring提供的对事务的统一管理。当我们用到由spring所封装的hibernate的时候一定会用到一个类:HibernateTemplate.这是一个对持久层处理封装的非常完整的类,包括对session的管理(事实上session的获取于释放是一个令人头疼的问题)等等,我们通常会使用HibernateTemplate的excute方法来进行数据库操作(即使我们调用的也许是别的类似于find、get之类的方法,但是实质上最终还是转变为了调用excute方法)。
1.这里采用的方法:HibernateBaseDao (自定义一个类)
/**
*package org.springframework.orm.hibernate3.support.HibernateDaoSupport;
*HibernateDaoSupport是spring中的类
*/
HibernateBaseDao extends HibernateDaoSupport{
这中间是一系列实现的对数据库的crud操作
public void executeBatchUpdate(final List sqls) {
//new HibernateDaoSupport().
getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
try{
Connection con = session.connection();
Statement st = con.createStatement();
for (int i = 0; i < sqls.size(); i++) {
String sql= (String) sqls.get(i);
st.addBatch( sql );
log.debug("exec sqls["+i+"]"+sql);
}
if(sqls.size()>0)
st.executeBatch();
}catch (SQLException ex) {
ex.printStackTrace();
throw new DataAccessResourceFailureException(ex.getMessage());
}
return null;
}
});
}
------获取连接-----------
public Connection getJDBCConnection() {
return (Connection)getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
return session.connection();
}
});
}
}
我们系统中的dao实现类daoimpl 中需要用到 用到HibernateBaseDao 中的方法
那么我们只需要将HibernateBaseDao 的对象通过spring注入到daoimpl中即可
public class BaseDAOImp implements IBaseDAO {
private HibernateBaseDao hibernateBaseDao;
public static Log log = LogFactory.getLog(BaseDAOImp.class);
public void setHibernateBaseDao(HibernateBaseDao hibernateBaseDao) {
this.hibernateBaseDao = hibernateBaseDao;
}
public void saveVo(VO obj) {
//
hibernateBaseDao.saveObject(obj);
}
public void removeVo(VO obj) {
//
hibernateBaseDao.removeObject(obj);
}
-------------------总结-------------
通常这样操作我们需要给类HibernateBaseDao 注入一个SessionFactory的实例,他的作用就是获取jdbc连接
<bean id="hibernateBaseDao" class="com.sitech.crmpd.core.dao.HibernateBaseDao">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="chnds" /> //数据源
</property>
<property name="mappingDirectoryLocations">
<list>
<value>/sitech/res/s99899/hbm</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>
<prop key="hibernate.use_outer_join">false</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.query.factory_class">org.hibernate.hql.classic.ClassicQueryTranslatorFactory</prop>
</props>
</property>
</bean>
这里的疑问:hibernateBaseDao 继承自HibernateDaoSupport()类而这个类其实是没有sessionFactory这个属性的。哪是从哪里来的这个属性呢,又是如何注入的呢
通过看源码发现了注入的方式:
1.HibernateDaoSupport类有
public abstract class HibernateDaoSupport extends DaoSupport {
private HibernateTemplate hibernateTemplate;//属性
public final void setSessionFactory(SessionFactory sessionFactory) {
this.hibernateTemplate = createHibernateTemplate(sessionFactory); //有了这个方法,那么它的子类HibernateDaoSupport 也就有了这个方法,spring会调用这个方法进行注入(注入方式:是看是否有这个set方法,如:setSessionFactory),
}
protected HibernateTemplate createHibernateTemplate(SessionFactory sessionFactory) {//在上面的set方法中会调用这个方法
return new HibernateTemplate(sessionFactory);//这里调用构造方法
}
public final SessionFactory getSessionFactory() {
return (this.hibernateTemplate != null ? this.hibernateTemplate.getSessionFactory() : null);//方法
}
)
HibernateTemplate 类:
public class HibernateTemplate extends HibernateAccessor implements HibernateOperations {
public HibernateTemplate(SessionFactory sessionFactory) {
setSessionFactory(sessionFactory);//这个方法是调用的父类的方法,如下面所示
afterPropertiesSet();
}
}
HibernateAccessor 类
public abstract class HibernateAccessor implements InitializingBean, BeanFactoryAware {
protected final Log logger = LogFactory.getLog(getClass());
private SessionFactory sessionFactory;
private Object entityInterceptor;
private SQLExceptionTranslator jdbcExceptionTranslator;
private int flushMode = FLUSH_AUTO;
private String[] filterNames;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
}
----------------------------------------------------
二、关于回调函数
说明:HibernateCallback是一个接口
public interface HibernateCallback {
Object doInHibernate(Session session) throws HibernateException, SQLException;
}
如:
public Connection getJDBCConnection() {
return (Connection)getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
return session.connection();
}
});
}
这里使用了回调的方式;
1.HibernateTemplate,内联类
2.内联类实现接口HibernateCallback的doInHibernate 方法
3.HibernateTemplate拥有一个参数为HibernateCallback接口类型的函数execute(HibernateCallback action)方法.
4.调用HibernateTemplate的get方法时,将内联类传给了excute方法
5.执行excute方法时,(你调用它)
已取得内联类,就可以随时回调它所实现的HibernateCallback接口中的方法了,
这时它反过来调用你的方法(它调用你),这就是回调了.
Javaeye两个会员的理解,我觉得比较到位.
概括:(
就是调用系统的一个方法,传进去一个接口的实现类 or 匿名类。
然后系统的方法调用接口申明的方法,并且注入相应的参数 )
这里Excute方法的参数是一种匿名类的方式。为什么要采用匿名类呢(不管怎么说匿名类看起来总是让人觉得不舒服)?这个地方是否必须采用匿名类呢?
1、回调:excute方法会回调HibernateCallback类型的doInHibernate方法;
2、匿名类参数:我们为excute方法提供的参数并不是一个真正创建出来的;
3、动态创建回调方法:
如果不采用匿名类,我们需要做的是为HibernateCallback创建一个实现类,并且实现doInHibernate方法
但是最要命的问题是doInHibernate方法的实现对于我们的实际需求来说每一次调用可能都是不一样的(在doInHibernate方法中我们使用session进行数据库操作,对于不同的业务逻辑,方法实现必定是不一样的),采用了匿名类我们不用在代码重创建新的类型,而且可以动态的创建我们所需要的回调函数。
这里的回调是这样的
首先是 getHibernateTemplate().execute()-->execute中HibernateCallback .doInHibernate();
实现回调的地方
public Object execute(HibernateCallback action, boolean exposeNativeSession) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");
Session session = getSession();
boolean existingTransaction = 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 = (exposeNativeSession ? 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());
}
}
}
}