您的位置:首页 > 编程语言 > Java开发

Spring整合Hibernate,不用HibernateDaoSupport与HibernateTemplate而用Hibernate自己的api分析说明

2015-08-31 15:19 627 查看
Spring整合Hibernate时,主要做了两件事:提供事务级session和声明式的事务控制。

在较早的Hibernate中,对于session的管理一般是one-session-per-operation的方式,即一次具体操作一个session。

Spring为了解决这个问题,引入了HibernateTemplate类。

先来看看它的文档中一段很有意思的话:

NOTE: As of Hibernate 3.0.1, transactional Hibernate access code can also be coded in plain Hibernate style. Hence, for newly started projects,consider adopting the standard Hibernate3 style of coding data access objects instead, based on SessionFactory.getCurrentSession().(Spring's
LocalSessionFactoryBean automatically supports Spring transaction management for the Hibernate3 getCurrentSession() method.)作者说:在新开始的工程,可以考虑用标准的Hibernate3的编码方式作为HibernateTemplate的替代。因为Hibernate3提供的SessionFactory.getCurrentSession()已经取代了以往那种每次操作都open一个新Session的方式,同时Spring的LocalSessionFactoryBean自动支持Hibernate3的getCurrentSession()的事务管理。也就是说,如果不用HibernateTemplate这咱Spring的专有API,而只用Hibernate3,我们一样可以受用Spring的事务管理。

来详细地看看HibernateTemplate,因为它毕竟简化了Hibernate的操作,但是在有些情况下,我们应该使用Hibernate而不是用HibernateTemplate。根据HibernateTemplate的文档注释,它做了两件事:1.简化了Hibernate的数据访问编码;2.自动地将HibernateExceptions转化为Spring的异常体系中的DataAccessExceptions(这是一个unchecked exception).

HibernateTemplate实现第一点,是通过回调来实现的,它的核心方法execute():

public Object execute(HibernateCallback action, boolean
exposeNativeSession)
throws DataAccessException

{

//这个Session是受Spring事务管理的

Session session = getSession();

//这个是怎么回事,还要再仔细看看,我想它应该是关系到Session在这个操作里操作完是否关闭的关键

boolean existingTransaction = SessionFactoryUtils .isSessionTransactional(session, getSessionFactory());

FlushMode previousFlushMode = null;

try {

previousFlushMode = applyFlushMode(session, existingTransaction);

enableFilters(session);

//在默认情况下,不把Sessin暴露给用户

Session sessionToExpose = (exposeNativeSession ? session : createSessionProxy (session));

//exposeNativeSession默认值为false

//这里是真正涉及到Hibernate操作的地方

Object result = action.doInHibernate(sessionToExpose);

flushIfNecessary(session, existingTransaction);

return result;

}

catch(...){

//将Hibernate代码抛出的HibernateException,SQLException

//转化为 DataAccessExceptions,如果有运 行时异常,将其抛出

}

finally {

if (existingTransaction) {

disableFilters(session);

if (previousFlushMode != null) {

session.setFlushMode(previousFlushMode);

}

}

else {

// Never use deferred close for an explicitly new Session.

if (isAlwaysUseNewSession()) {

//这里的默认值是false,所以此次操作结束后,session不会在此关闭

SessionFactoryUtils.closeSession(session);

}

else {

//没有硬性关闭Session,这是区别于Hibernate3以前版本的地方 SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());

}

}

}

}

真正的数据操作是在HibernateCallback
action中实现的,为了执行action中的操作,需要一个Session,这个Session是在execute()方法内部获得(不一定是新产生的)并传入的。另外,在操作执行完之后,这个Session没有硬性关闭,而是交由SessionFactoryUtils来决定是否立即关闭还是延迟关闭。有时间再看看SessionFactoryUtils .closeSessionOrRegisterDeferredClose()具体做了些什么。

用HibernateTemplate比起直接用Hibernate编码简洁了很多。但是,作者在文档中写到:The major advantage is its

automatic conversion to DataAccessExceptions, the major disadvantage that no checked application exceptions can get

thrown from within data access code.因为封闭得太好了,我们根本无法干预HibernateTemplate的方法内部,因此我们

不能抛出检查型的应用异常。如果我们想在某个方法的内部在某个条件下抛出自定义的应用异常,就要用Hibernate直接编码了,这是不应该用HibernateTemplate的情况。

作者在文档中还写到:It can be used within a service implementation via direct instantiation(实例)with a SessionFactory reference, or get prepared in an application context and given to services as bean reference. 为了使用

HibernateTemplate,我们需要一个SessionFactory,因为使用HibernateTemplate时需要获取Session,而Session是从SessionFactory获取的。我们可以在应用配置文件中,根据已配置的SessionFactory配置一个HibernateTemplate,或者在程序中要用时再根据已配置好的SessionFactory来产生一个HibernateTemplate。Spring提供了一个可配置的SessionFactory的工厂类,用以向容器暴露一个单例化的SessionFactory:LocalSessionFactoryBean。这个类的源码也很有意思,还要继续看一下。

为了进一步简化Hibernate的操作,Spring提供了一个用于DAO的基类HibernateDaoSupport:This base class is mainly

intended for HibernateTemplate usage。这个类只有唯一的成员变量private HibernateTemplate hibernateTemplate。但是我在想,Spring是不是做的太过分了?包装得太好了??

下边附上HibernateTemplate的一般使用方法:

hibernateTemplate的常用方法:
? void delete(Object entity):删除指定持久化实例
? deleteAll(Collection entities):删除集合内全部持久化类实例
? find(String queryString):根据HQL查询字符串来返回实例集合
? findByNamedQuery(String queryName):根据命名查询返回实例集合
? get(Class entityClass, Serializable id):根据主键加载特定持久化类的实例
? save(Object entity):保存新的实例
? saveOrUpdate(Object entity):根据实例状态,选择保存或者更新
? update(Object entity):更新实例的状态,要求entity是持久状态
? setMaxResults(int maxResults):设置分页的大小

HibernateDaoSupport:

Spring为Hibernate的DAO提供工具类:HibernateDaoASupport。该类主要提供如下两个方法,方便DAO的实现:

1、public final HibernateTemplate getHibernateTemplate()

2、public final void setSessionFactory(SessionFactory sessionFactory)

其中setSessionFactory方法用来接收Spring的ApplicationContext的依赖注入,可接收配置在Spring的SessionFactory实例,getHibernateTemplate方法则用来更具获得的SessionFactory产生Session,最后生成HibernateTeplate来完成数据库访问。

看到这些的时候似乎好像明白了以些,HibernateDaoSupport此类其实并不做太多的事情,它只有两个方法一个是获得getHibernateTemplate()和setSessionFacotry()。就像我们在配置文件中配置的那个sessionFactory属性。而getHibernateTemplate()方法就是常用的save、delete等CRUD基本操作。

HibernateTemplate 用于持久层的访问,该模板无需打开session及关闭Session。它只要获得SessionFactory的引用,就可以打开Session,并在持久化访问结束后关闭Session,程序开发只需要完成持久曾逻辑,通用的CRUD操作由HibernateTemplate完成.

其实Spring+hibernate访问数据库有以下几种方法:
1、 注入SessionFactory

在spring配置文件中,对Dao注入sessionFactory.比较简单。

如:

<bean id="UserInfoDao" class="com.hr2job.dao.impl.UserInfoDaoImpl">

<property name="sessionFactory" ref="sessionFactory"></property>

</bean>

这里的sessionFacotry注入不是给类的,而是给继承HibernateDaoSupport类的sessionFactory,在上面源码中可以看到。以前写SSH程序的时候就是用这个的,因为是不知道,这个好处就是我们不再需要关心关闭、是否连接成功等问题。主要是很方便。但是这个不好就是java只支持单继承,所以唯一的继承给了HibernateDaoSupport有点可惜。而且也没有必要这样做。
2、 注入HibernateTemplate

这种方法本质上跟上面的sessionFacotry一样,只不过进行了一层包装,好处就是Dao中的类就不用再继承那个HibernateDaoSuport了,不过要先配置好HibernateTemplate:

<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">

<property name="sessionFactory">

<ref bean="sessionFactory"/>

</property>

</bean>

非常的方便,我现在就在用这个了。其实并没有改多少,就是曾经的sessionFactroy改成了hibernatemplate。
3、 注入jdbcTemplate

这种方法适合那些不喜欢hibernate的save,delete等方法,喜欢自己写的N人吧。有时候jdbcTemplate查询的效率会很高。这可能是跟jdbc有关吧。

配置如下:

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">

<property name="dataSource">

<ref bean="dataSource" />

</property>

</bean>

springside中使用hibernate api 的dao层实现

/**
* 用于Dao层子类使用的构造函数.
* 通过子类的泛型定义取得对象类型Class.
* eg.
* public class UserDao extends SimpleHibernateDao<User, Long>
*/
public SimpleHibernateDao() {
}

/**
* 用于用于省略Dao层, 在Service层直接使用通用SimpleHibernateDao的构造函数.
* 在构造函数中定义对象类型Class.
* eg.
* SimpleHibernateDao<User, Long> userDao = new SimpleHibernateDao<User, Long>(sessionFactory, User.class);
*/
public SimpleHibernateDao(final SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}

/**
* 取得sessionFactory.
*/
public SessionFactory getSessionFactory() {
return sessionFactory;
}

/**
* 采用@Autowired按类型注入SessionFactory, 当有多个SesionFactory的时候在子类重载本函数.
*/
@Autowired
public void setSessionFactory(final SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}

/**
* 取得当前Session.
*/
public Session getSession() {
return sessionFactory.getCurrentSession();
}

/**
* 保存新增或修改的对象.
*/
public void save(final Object entity) {
Assert.notNull(entity, "entity不能为空");
getSession().saveOrUpdate(entity);
logger.debug("save entity: {}", entity);
}

/**
* 删除对象.
*
* @param entity 对象必须是session中的对象或含id属性的transient对象.
*/
public void delete(final Object entity) {
Assert.notNull(entity, "entity不能为空");
getSession().delete(entity);
logger.debug("delete entity: {}", entity);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: