Java Hibernate模板 学习总结

使用Hibernate模板



与Hibernate进行交互的主要接口是org.hibernate.Session。这个Session接口提供了基本的数据访问功


能,比如从数据库保存、更新、删除和加载对象。通过Hibernate的Session接口,程序的DAO能够执行任


何存留功能。


获得Hibernate Session对象引用的标准方式是实现Hibernate的SessionFactory接口。SessionFactory


负责打开、关闭和管理Hibernate Session,以及其他一些功能。


就像JdbcTemplate把JDBC的繁琐工作抽离出去一样,Spring的HibernateTemplate在Hibernate Session


之上提供了一个抽象层,其主要功能是简化打开和关闭Hibernate会话,并且把Hibernate的特定异常转


化为表5.1列出的Spring ORM异常之一。(对于Hibernate 2来说,这意味着把受检异常


HibernateException转化为一个免检的Spring异常。)
========

SPRING中HIBERNATETEMPLATE类的使用

  实际情况中,对于编程事务的操作最好还是使用


org.springframework.transaction.support.TransactionTemplate,因为HibernateTemplate在实际操


作中并不是想象的那样,具体如下:


目的:使用HibernateTemplate执行execute(new HibernateCallback())方法,从


HibernateCallback中得到session,
在此session中做多个操作,并希望这些操作位于同一个事务中。
  如果你这样写(1):
  public static void main(String ss[]) {
  CtxUtil.getBaseManager().getHibernateTemplate().execute(new HibernateCallback() {
  public Object doInHibernate(Session session) throws HibernateException, SQLException {
  // 保存stu1
  Student stu1 = new Student();
  stu1.setName("aaaa");// 在数据库中,name字段不允许为null
  session.save(stu1);
  session.flush();//实际上,如果不是程序员"手痒"来调用这个flush(),HibernateTemplate中


session的事务处理
还是很方便的
  Student stu2 = new Student();
  session.save(stu2);// 没有设置name字段,预期会报出例外
  session.flush();
  return null;
  }
  });
  }
  你期望spring在执行完execute回调后,在关闭session的时候提交事务,想法是很好的,但spring


并不会这么做。
让我们来看看在 Hibernate的源代码中,session.beginTransation()做了什么事。看如下代码(2)



  public Transaction beginTransaction() throws HibernateException {
  errorIfClosed();
  if ( rootSession != null ) {
  // todo : should seriously consider not allowing a txn to begin from a child session
  // can always route the request to the root session
  log.warn( "Transaction started on non-root session" );
  }
  Transaction result = getTransaction();
  result.begin();
  return result;
  }
  这个方法中的result是一个org.hibernate.transaction.JDBCTransaction实例,而方法中的


getTransaction()
方法源代码为(3):
  public Transaction getTransaction() throws HibernateException {
  if (hibernateTransaction==null) {
  log.error(owner.getFactory().getSettings()
  .getTransactionFactory().getClass());
  hibernateTransaction = owner.getFactory().getSettings()
  .getTransactionFactory()
  .createTransaction( this, owner );
  }
  return hibernateTransaction;
  }
  再次追踪,owner.getFactory()。getSettings() .getTransactionFactory()的


createTransaction()方法
源代码如下(4):
  public Transaction createTransaction(JDBCContext jdbcContext, Context 


transactionContext)
  throws HibernateException {
  return new JDBCTransaction( jdbcContext, transactionContext );
  }
  它返回了一个JDBCTransaction,没什么特别的。
  在代码2中,执行了result.begin(),其实也就是JDBCTransaction实例的begin()方法,来看看


(5):
  public void begin() throws HibernateException {
  if (begun) {
  return;
  }
  if (commitFailed) {
  throw new TransactionException("cannot re-start transaction after failed commit");
  }
  log.debug("begin");
  try {
  toggleAutoCommit = jdbcContext.connection().getAutoCommit();
  if (log.isDebugEnabled()) {
  log.debug("current autocommit status: " + toggleAutoCommit);
  }
  if (toggleAutoCommit) {
  log.debug("disabling autocommit");
  jdbcContext.connection().setAutoCommit(false);//把自动提交设为了false
  }
  } catch (SQLException e) {
  log.error("JDBC begin failed", e);
  throw new TransactionException("JDBC begin failed: ", e);
  }
  callback = jdbcContext.registerCallbackIfNecessary();
  begun = true;
  committed = false;
  rolledBack = false;
  if (timeout > 0) {
  jdbcContext.getConnectionManager().getBatcher().setTransactionTimeout(timeout);
  }
  jdbcContext.afterTransactionBegin(this);
  }


在直接使用Hibernate时,要在事务结束的时候,写上一句:tx.commit(),这个commit()的源码为



  public void commit() throws HibernateException {
  if (!begun) {
  throw new TransactionException("Transaction not successfully started");
  }
  log.debug("commit");
  if (!transactionContext.isFlushModeNever() && callback) {
  transactionContext.managedFlush(); // if an exception occurs during
  // flush, user must call
  // rollback()
  }
  notifyLocalSynchsBeforeTransactionCompletion();
  if (callback) {
  jdbcContext.beforeTransactionCompletion(this);
  }
  try {
  commitAndResetAutoCommit();//重点代码,它的作用是提交事务,并把connection的autocommit属


性恢复为true
  log.debug("committed JDBC Connection");
  committed = true;
  if (callback) {
  jdbcContext.afterTransactionCompletion(true, this);
  }
  notifyLocalSynchsAfterTransactionCompletion(Status.STATUS_COMMITTED);
  } catch (SQLException e) {
  log.error("JDBC commit failed", e);
  commitFailed = true;
  if (callback) {
  jdbcContext.afterTransactionCompletion(false, this);
  }
  notifyLocalSynchsAfterTransactionCompletion(Status.STATUS_UNKNOWN);
  throw new TransactionException("JDBC commit failed", e);
  } finally {
  closeIfRequired();
  }
  }
  上面代码中,commitAndResetAutoCommit()方法的源码如下:
  private void commitAndResetAutoCommit() throws SQLException {
  try {
  jdbcContext.connection().commit();//这段不用说也能理解了
  } finally {
  toggleAutoCommit();//这段的作用是恢复connection的autocommit属性为true
  }
  }
  上述代码的toggleAutoCommit()源代码如下:
  private void toggleAutoCommit() {
  try {
  if (toggleAutoCommit) {
  log.debug("re-enabling autocommit");
  jdbcContext.connection().setAutoCommit(true);//这行代码的意义很明白了吧
  }
  } catch (Exception sqle) {
  log.error("Could not toggle autocommit", sqle);
  }
  }
  因此,如果你是直接使用hibernate,并手动管理它的session,并手动开启事务关闭事务的话,完


全可以保证你的
事务(好像完全是废话)。
  但是,如果你用的是HibernateTemplate,如同源代码1一样,则不要指望spring在关闭session的时


候为你提交事务
(罪魁祸首就是在代码1中调用了session.flush())。因为在使用代码1时,spring中得到session的


方式如下:
Session session = (entityInterceptor != null ? sessionFactory.openSession


(entityInterceptor) :
sessionFactory。openSession());简单地说它就是得到了一个session,而没有对connection的 


autocommit()
作任何操作,spring管理范围内的session所持有的connection是autocommit=true 的,spring借助这个


属性,在它关
闭session时,提交数据库事务。,因此如果你在源代码1中加上一句话:
  public static void main(String ss[]) {
  CtxUtil.getBaseManager().getHibernateTemplate().execute(new HibernateCallback() {
  public Object doInHibernate(Session session) throws HibernateException, SQLException {
  log.info(session.connection().getAutoCommit());//打印一下事务提交方式
  // 保存stu1
  Student stu1 = new Student();
  stu1.setName("aaaa");// 在数据库中,name字段不允许为null
  session.save(stu1);
  session.flush();
  Student stu2 = new Student();
  session.save(stu2);// 没有设置name字段,预期会报出例外
  session.flush();
  return null;
  }
  });
  }
  运行后,它打出的结果是true,也就是说,虽然保存stu2时会报出例外,但如果commit属性为true


,则每一个到
达数据库的sql语句会立即被提交。换句话说,在调用完session.save(stu1)后,调用session.flush


(),会发送
sql语句到数据库,再根据commit 属性为true,则保存stu1的操作已经被持久到数据库了,尽管后面的


一条insert语
句出了问题。
  因此,如果你想在HibernateCallback中使用session的事务,需要如下写:
  public static void main(String ss[]) {
  CtxUtil.getBaseManager().getHibernateTemplate().execute(new HibernateCallback() {
  public Object doInHibernate(Session session) throws HibernateException, SQLException {
  session.connection().setAutoCommit(false);
  //保存stu1
  Student stu1=new Student();
  stu1.setName("aaaa");//在数据库中,name字段不允许为null
  session.save(stu1);
  session.flush();
  Student stu2 = new Student();
  session.save(stu2);//没有设置name字段,预期会报出例外
   session.flush();
  session.connection().commit();
  //至于session的关闭就不用我们操心了
  return null;
  }
  });
  }


运行上述代码,没问题了。至此,可能有些读者早就对代码1不满意了:为什么每次save()以后要调用


flush()?这是
有原因的。下面我们来看看把session.flush()去掉后会出什么问题。改掉后的代码如下:
  public static void main(String ss[]) {
  CtxUtil.getBaseManager().getHibernateTemplate().execute(new HibernateCallback() {
  public Object doInHibernate(Session session) throws HibernateException, SQLException {
  session.connection().setAutoCommit(false);
  // 保存stu1
  Student stu1 = new Student();
  stu1.setName("aaaa");// 在数据库中,name字段不允许为null
  session.save(stu1);
  // session.flush();
  Student stu2 = new Student();
  session.save(stu2);// 没有设置name字段,预期会报出例外
  // session.flush();
  session.connection().commit();
  return null;
  }
  });
  }
  运行上述代码,后台报数据库的not null错误,这个是合理的,打开数据库,没有发现新增记录,


这个也是合理的。
你可能会说:由于事务失败,数据库当然不可能会有任何新增记录。好吧,我们再把代码改一下,去除


not null的错误,
以确保它能正常运行。代码如下:
  public static void main(String ss[]) {
  CtxUtil.getBaseManager().getHibernateTemplate().execute(new HibernateCallback() {
  public Object doInHibernate(Session session) throws HibernateException, SQLException {
  session.connection().setAutoCommit(false);
  // 保存stu1
  Student stu1 = new Student();
  stu1.setName("aaaa");// 在数据库中,name字段不允许为null
  session.save(stu1);
  // session.flush();
  Student stu2 = new Student();
  stu2.setName("asdfasdf");//好了,这个字段设过值,不会再报not null错误了
  session.save(stu2);
  // session.flush();
  session.connection().commit();
  return null;
  }
  });
  }
  至此再运行上述代码,出现了一个奇怪的问题:虽然控制台把insert语句打出来了,但是:数据库


没有出现任何新的记录。
  究其原因,有二:
  一、 session.connection()。commit()确实导致数据库事务提交了,但是此刻session并没有


向数据库发送任何语句。
  二、在spring后继的flushIfNecessary()和closeSessionOrRegisterDeferredClose()方法中,


第一个方法向数据
库发送sql语句,第二个方法关闭session,同时关闭connection,然后问题在于:connection已经在程


序中被手动设置为
auttocommit=false了,因此在关闭数据库时,也不会提交事务。
  解决这个问题很容易,在程序中手动调用session.flush()就可以了。如下代码:
  public static void main(String ss[]) {
  CtxUtil.getBaseManager().getHibernateTemplate().execute(new HibernateCallback() {
  public Object doInHibernate(Session session) throws HibernateException, SQLException {
  session.connection().setAutoCommit(false);
  //保存stu1
  Student stu1=new Student();
  stu1.setName("aaaa");//在数据库中,name字段不允许为null
  session.save(stu1);
  Student stu2 = new Student();
  session.save(stu2);//没有设置name字段,预期会报出例外
  session.flush();//向数据库发送sql
  session.connection().commit();
  return null;
  }
  });
  }
  运行上述代码,打开数据库查看,没有新增任何记录。在代码中新加一行stu2.setName("aaa");


再次运行代码,
发现数据库表中多了两条记录。事务操作成功。
  至此,虽然操作成功,但事情还没有结束。这是因为spring在调用doInHibernate()的后继的步骤


中,还要进行
flushIfNecessary()操作,这个操作其实最后调用的还是session.flush()。因为在程序中已经手动


调用过
session.flush(),所以由spring调用的session.flush()并不会对数据库发送sql(因为脏数据比对


的原因)。
虽然不会对结果有什么影响,但是多调了一次flush(),还是会对性能多少有些影响。能不能控制让


spring不调
用session.flush()呢?可以的,只要加上一句代码,如下所示:
  public static void main(String ss[]) {
  CtxUtil.getBaseManager().getHibernateTemplate().setFlushMode(0);//0也就是FLUSH_NEVER
  CtxUtil.getBaseManager().getHibernateTemplate().execute(new HibernateCallback() {
  public Object doInHibernate(Session session) throws HibernateException, SQLException {
  session.connection().setAutoCommit(false);
  //保存stu1
  Student stu1=new Student();
  stu1.setName("aaaa");//在数据库中,name字段不允许为null
  session.save(stu1);
  Student stu2 = new Student();
  stu2.setName("sdf");
  session.save(stu2);//没有设置name字段,预期会报出例外
  session.flush();
  session.connection().commit();
  return null;
  }
  });
  }
  通过设置HibernateTemplate的flushMode=FLUSH_NEVER来通知spring不进行session.flush()的调


用,则spring
的flushIfNecessary()将不进行任何操作,它的flushIfNecessary()源代码如下:
  protected void flushIfNecessary(Session session, boolean existingTransaction) throws 


HibernateException {
  if (getFlushMode() == FLUSH_EAGER || (!existingTransaction && getFlushMode() != 


FLUSH_NEVER)) {
  logger.debug("Eagerly flushing Hibernate session");
  session.flush();
  }
  }
  至此,代码1中的main()终于修改完毕。但事实上,这样的操作无疑是比较麻烦的,因此如果在


spring中想利
用session进行事务操作时,最好还是用TransactionTemplate(编程式事务)或是声明式事务比较方便


一些。
  本例通过这么一个虽然简单但又绕来绕去的例子,主要是说明hibernate事务的一些内在特性,以及
HibernateTemplate中如何处理 session和事务的开关,让读者对HibernateTemplate的源代码处理细节


有一些了解,
希望能给读者有抛砖引玉的作用。
========

HibernateTemplate用法



private HibernateTemplate hibernateTemplate;


?


使用HbernateTemplate
HibernateTemplate提供持久层访问模板化,使用HibernateTemplate无须实现特定接口,它只需要提供


一个SessionFactory的引用,就可执行持久化操作。SessionFactoyr对象可通过构造参数传入,或通过


设值方式传入。如下:
//获取Spring上下文
ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml");
//通过上下文获得SessionFactory
SessionFactory sessionFactory = (SessionFactory) ctx.getBean(“sessionFactory”);
然后创建HibernateTemplate实例。HibernateTemplate提供如下三个构造函数
q HibernateTemplate()
q HibernateTemplate(org.hibernate.SessionFactory sessionFactory)
q HibernateTemplate(org.hibernate.SessionFactory sessionFactory, boolean allowCreate)
第一个构造函数,构造一个默认的HibernateTemplate实例,因此,使用HibernateTemplate实例之前,


还必须使用方法setSessionFactory(SessionFactory sessionFactory)来为HibernateTemplate传入


SessionFactory的引用。
第二个构造函数,在构造时已经传入SessionFactory引用。
第三个构造函数,其boolean型参数表明:如果当前线程已经存在一个非事务性的Session,是否直接返


回此非事务性的Session。
对于在Web应用,通常启动时自动加载ApplicationContext,SessionFactory和DAO对象都处在Spring上


下文管理下,因此无须在代码中显式设置,可采用依赖注入解耦SessionFactory和DAO,依赖关系通过配


置文件来设置,如下所示:
<?xml version="1.0" encoding="gb2312"?>
<!-- Spring配置文件的DTD定义-->
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<!-- Spring配置文件的根元素是beans-->
<beans>
<!--定义数据源,该bean的ID为dataSource-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!-- 指定数据库驱动-->
<property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property>
<!-- 指定连接数据库的URL--> 
<property name="url"><value>jdbc:mysql://wonder:3306/j2ee</value></property>
<!-- root为数据库的用户名-->
<property name="username"><value>root</value></property>
<!-- pass为数据库密码-->
<property name="password"><value>pass</value></property>
</bean>
<!--定义Hibernate的SessionFactory-->
<bean id="sessionFactory" 


class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<!-- 依赖注入数据源,注入正是上文定义的dataSource>
<property name="dataSource"><ref local="dataSource"/></property>
<!-- mappingResouces属性用来列出全部映射文件>
<property name="mappingResources">
<list>
<!--以下用来列出所有的PO映射文件-->
<value>lee/Person.hbm.xml</value>
</list>
</property>
<!--定义Hibernate的SessionFactory的属性 -->
<property name="hibernateProperties">
<props>
<!-- 指定Hibernate的连接方言-->
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<!-- 不同数据库连接,启动时选择create,update,create-drop-->
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<!-- 配置Person持久化类的DAO bean-->
<bean id="personDao" class="lee.PersonDaoImpl">
<!-- 采用依赖注入来传入SessionFactory的引用>
<property name="sessionFactory"><ref local="sessionFactory"/></property>
</bean>
</beans>
DAO实现类中,可采用更简单的方式来取得HibernateTemplate的实例。代码如下:
public class PersnDAOImpl implements PersonDAO
{
//以私有的成员变量来保存SessionFactory。
private SessionFactory sessionFactory;
//设值注入SessionFactory必需的setter方法
public void setSessionFactory(SessionFactory sessionFactory)
{
this.sessionFactory = sessionFactory;
}


public List loadPersonByName(final String name)
{
HibernateTemplate hibernateTemplate =
new HibernateTemplate(this.sessionFactory);
//此处采用HibernateTemplate完成数据库访问
}
}


10.6.1 HibernateTemplate的常规用法


HibernateTemplate提供非常多的常用方法来完成基本的操作,比如通常的增加、删除、修改、查询等操


作,Spring 2.0更增加对命名SQL查询的支持,也增加对分页的支持。大部分情况下,使用Hibernate的


常规用法,就可完成大多数DAO对象的CRUD操作。下面是HibernateTemplate的常用方法简介:
q void delete(Object entity):删除指定持久化实例
q deleteAll(Collection entities):删除集合内全部持久化类实例
q find(String queryString):根据HQL查询字符串来返回实例集合
q findByNamedQuery(String queryName):根据命名查询返回实例集合
q get(Class entityClass, Serializable id):根据主键加载特定持久化类的实例
q save(Object entity):保存新的实例
q saveOrUpdate(Object entity):根据实例状态,选择保存或者更新
q update(Object entity):更新实例的状态,要求entity是持久状态
q setMaxResults(int maxResults):设置分页的大小
下面是一个完整DAO类的源代码:
public class PersonDAOHibernate implements PersonDAO
{
//采用log4j来完成调试时的日志功能
private static Log log = LogFactory.getLog(NewsDAOHibernate.class);
//以私有的成员变量来保存SessionFactory。
private SessionFactory sessionFactory;
//以私有变量的方式保存HibernateTemplate
private HibernateTemplate hibernateTemplate = null;
//设值注入SessionFactory必需的setter方法
public void setSessionFactory(SessionFactory sessionFactory)
{
this.sessionFactory = sessionFactory;
}
//初始化本DAO所需的HibernateTemplate
public HIbernateTemplate getHibernateTemplate()
{
//首先,检查原来的hibernateTemplate实例是否还存在
if ( hibernateTemplate == null)
{
//如果不存在,新建一个HibernateTemplate实例
hibernateTemplate = new HibernateTemplate(sessionFactory);
}
return hibernateTemplate;
}
//返回全部的人的实例
public List getPersons()

//通过HibernateTemplate的find方法返回Person的全部实例
return getHibernateTemplate().find("from Person");
}


public void savePerson(Person person)

getHibernateT
========

使用HibernateTemplate进行数据库功能开发完成Spring+Hibernate架构

在Spring架构基础上 将其中的JdbcTemplate访问数据库的代码改成用HibernateTemplate访问数据库 最


后形成Spring+Hibernate的软件架构
 
准备工作:
1  删除目录\src\com\demo\spring\dao 该目录下面的代码是基于JdbcTemplate开发的DAO层代码 我们


将开发基于HibernateTemplate的DAO层来替换它
2  复制jar文件到当前项目的\WEB-INF\lib目录下 使项目来支持Hibernate事务 以及能够提供对


Hibernate映射文件的解析
dom4j-1.6.jar
antlr-2.7.5H3.jar
jta.jar
3  基于Hibernate的开发 都需要创建数据库表的映射文件和持久化类 将User.hbm.xml  


AbstractUser.java  User.java 复制到当前项目中\src\com\demo\hibernate\beans
 
开发过程:
需要在Bean配置文件中添加一系列组件 这些组件相互注入
dataSource 为sessionFactory提供数据源
sessionFactory Hibernate管理工厂 为userDAO的事务管理策略对象transactionManager提供


sessionFactory
transactionManager 为userDAO提供POJO类 利用被注入的数据源 定义一系列的业务操作函数 使用


JdbcTemplate来操作POJO类 实现对数据库的操作
UserDAOProxy userDAO的事务管理策略对象 该对象规定了userDAO的管理策略 因此他需要注入userDAO


作为被管理的对象 进行事务管理也需要提供事务管理器 因此需要注入transactionManager作为事务管


理器
Action类 该类是响应处理类 负责调度userDAO函数即可实现数据库的访问 而对于userDAO的访问都将在


UserDAOProxy的监管之下
图示:
                              dataSource  定义数据源
                                |  注入数据源
               sessionFactory
             注入Hibernate  |             | 注入Hibernate
            POJO         userDAO        transactionManager
                   注入DAO |       |  注入事务 |
                    Action类       UserDAOProxy
步骤:
1 创建数据源dataSource
2 创建sessionFactory 并注入dataSource
3 创建事务管理对象transactionManager 并注入sessionFactory 
4 创建userDAO 并注入sessionFactory
5 创建事务管理策略对象UserDAOProxy 并注入管理策略对象userDAO和所用的事务管理器


transactionManager
6 创建Action 并注入userDAO
详细步骤:
1 数据源配置
在applicationContext.xml中添加一个名称为dataSource的 指向的类为DBCP的数据源类
 
<!-- 配置数据源 -->
    <bean id="dataSource"
        class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
        <property name="driverClassName">
            <value>org.gjt.mm.mysql.Driver</value>
        </property>
        <property name="url">
            <value>jdbc:mysql://localhost:3306/demo</value>
        </property>
        <property name="username">
            <value>root</value>
        </property>
        <property name="password">
            <value></value>
        </property>
    </bean>
 
2 SessionFactory的配置
配置SessionFactory对象 为DAO层提供HIbernate的数据库连接对象 注入配置的dataSource对象
 
<!-- 配置Hibernate -->
    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource">
            <ref local="dataSource" />
        </property>
        <property name="mappingResources">
            <list>
                <value>com/demo/hibernate/beans/User.hbm.xml</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">
                    org.hibernate.dialect.MySQLDialect
                </prop>
                <prop key="hibernate.show_sql">true</prop>
            </props>
        </property>
    </bean>
 
3  配置事务
为SessionFactory对象增加事务配置组件 并注入上面配置的SessionFactory对象
 
<!-- 配置事务 -->
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory">
            <ref local="sessionFactory" />
        </property>
    </bean>
4  配置DAO组件
我们先配置该组件的Bean对象  一个基于HibernateTemplate的DAO类


com.demo.hibernate.dao.UserDAO.java 并为这个对象注入SessionFactory对象
 
<!-- 定义DAO -->
    <bean id="userDAO" class="com.demo.hibernate.dao.UserDAO">
        <property name="sessionFactory">
            <ref local="sessionFactory" />
        </property>
    </bean>
5  配置DAO事务
为上面配置的DAO对象配置事务组件 使得对userDAO的访问都在spring的事务监管下 改组件需要注入上


面配置的事务对象transactionManager DAO对象userDAO 并配置事务管理的策略
 
<!-- 定义DAO代理 -->
    <bean id="UserDAOProxy"
        class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="transactionManager">
            <ref bean="transactionManager" />
        </property>
        <property name="target">
            <ref local="userDAO" />
        </property>
        <property name="transactionAttributes">
            <props>
                <prop key="insert*">PROPAGATION_REQUIRED</prop>
                <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
            </props>
        </property>
    </bean>
 
6  创建Hibernate DAO 类
  首先创建一个接受类 com.demo.hibernate.dao.IUserDAO.java 创建接口的原因是为了让Spring的


AOP机制能够进行事务的管理 因为事务的管理是基于AOP实现的
在接口中声明要实现的操作函数
package com.demo.hibernate.dao;


import java.util.List;


import com.demo.hibernate.beans.User;


public interface IUserDAO {


    public boolean isValid(final String username, final String password);


    public boolean i***ist(String username);


    public void insertUser(User user);


    public User getUser(String userid);


    public List getUsers();


    public void deleteUser(String userid);
}
在UserDAO.java 中实现声明的函数
 
package com.demo.hibernate.dao;


import java.util.List;


import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;


import com.demo.hibernate.beans.User;


public class UserDAO extends HibernateDaoSupport implements IUserDAO {


    public boolean isValid(final String username, final String password) {
        List list = (List) getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session)
                    throws HibernateException {
                List result = session.createCriteria(User.class).add(
                        Restrictions.eq("username", username)).add(
                        Restrictions.eq("password", password)).list();
                return result;
            }
        });
        if (list.size() > 0) {
            return true;
        } else {
            return false;
        }
    }


    public boolean i***ist(final String username) {
        List list = (List) getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session)
                    throws HibernateException {
                List result = session.createCriteria(User.class).add(
                        Restrictions.eq("username", username)).list();
                return result;
            }
        });
        if (list.size() > 0) {
            return true;
        } else {
            return false;
        }
    }


    public void insertUser(User user) {
        getHibernateTemplate().saveOrUpdate(user);
    }


    public User getUser(String userid) {
        return (User) getHibernateTemplate().get(User.class,
                new Integer(userid));
    }


    public List getUsers() {
        return getHibernateTemplate().find("from User");
    }


    public void deleteUser(String userid) {
        Object p = getHibernateTemplate().load(User.class, new Integer(userid));
        getHibernateTemplate().delete(p);
    }
}
至此 就完成了使用HibernateTemplate访问数据库的DAO代码的开发了 下面修改Action中的业务函数来


调用DAO中的函数
7  修改LoginAction访问UserDAO进行登录验证
首先为LoginAction添加一个变量
 
UserDAO userDAO;    


    public UserDAO getUserDAO() {
        return userDAO;
    }


    public void setUserDAO(UserDAO userDAO) {
        this.userDAO = userDAO;
    }
 
为applicationContext.xml中的loginAction的配置注入userDAO变量
 
<!---定义Action-->
    <bean id="loginAction"
        class="com.demo.spring.actions.LoginAction">
        <property name="commandClass">
            <value>com.demo.spring.forms.LoginForm</value>
        </property>
        <!-- 指定DAO类 -->
        <property name="userDAO">
            <ref local="userDAO" />
        </property>
        <!-- 指定验证类 -->
        <property name="validator">
            <ref local="loginValidator" />
        </property>
        <!-- 指定失败要返回的页面 -->
        <property name="formView">
            <value>login</value>
        </property>
        <!-- 指定成功要返回的页面 -->
        <property name="successView">
            <value>welcome</value>
        </property>
    </bean>
修改LoginAction处理类中用户登录验证函数isValid() 使用被注入对象userDAO的isValid()函数
 
public boolean isValid(LoginForm loginForm) {
        /*if (loginForm.getUsername().equals("admin")
                || loginForm.getPassword().equals("admin")) {
            return true;
        } else {
            return false;
        }*/
        if(userDAO.isValid(loginForm.getUsername(), loginForm.getPassword())) {
            return true;
        } else {
            return false;
        }
    }
8  RegisterAction访问UserDAO进行用户注册 
方法如7
这样就形成了Spring+Hibernate架构  
========

hibernateTemplate内部实现原理



Spring中 Callback模式和Template模式合用 随处可见。下面以常用的HibernateTemplate为例进行简要


简述。
在HibernateTemplate模板类中有一个核心的方法:doExecute,这个核心的方法采用模板方法 完成相关


的固定 操作(建立连接,执行操作,释放连接) ,其中的具体步骤通过回调传入的对象(这个对象就


是实现了Callback接口的类)来完成。


[java] view plain copy print?
import org.springframework.orm.hibernate3.HibernateTemplate;  
@Component("userDaoImpl")  
public class UserDaoImpl implements UserDao {  
    private HibernateTemplate hibernateTemplate;  
    public HibernateTemplate getHibernateTemplate()  
    {  
        return hibernateTemplate;  
    }  
  
    @Resource(name="hibernatTemplate")  
    public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {  
        this.hibernateTemplate = hibernateTemplate;  
    }  
    @Override  
    public void save(User u) {          
        hibernateTemplate.save(u);  
        //这里可以直接save了,session已经被hibernateTemplate处理了。我们不需要关心它了。  
        //因为HibernateTemplate中已经注入了SessionFactory了,因为它自己会处理好session及其


事务的。  
        System.out.println("user save...");  
}}  


下面讲一下HibernateTemplate的内部实现原理


[java] view plain copy print?
//建立HibernateTemplate回调函数  
interface HibernateCallback  
{  
    //内部只有doInHibernate方法  
    public Object doInHibernate(Session session);  
}  
  
//建立Session类为实际该类为sessionFactory创建  
class Session  
{      
    //这里只列出createQuery方法,实际存在save,update,load等方法  
    public Object createQuery(String hql)  
    {  
        System.out.println(hql);  
        return "添加成功";  
    }  
}  
//HibernateTemplate类  
class BackCallTemplate  
{  
    //这里是执行的方法  
    public Object execute(HibernateCallback backCall)  
    {  
        //这个方法的请求处理交给doExceute;  
        return doExecute(backCall);  
    }  
  
    //它来做请求处理  
    public Object doExecute(HibernateCallback action)  
    {  
        //首先去判断是否已经有一个session对象,如果没有则创建一个,存在就返回Session对象  
        //Session session = (enforceNewSession ?SessionFactoryUtils.getNewSession


(getSessionFactory(), getEntityInterceptor()) : getSession());  
        Session session = new Session();  
        //这里执行架设函数  
        return action.doInHibernate(session);  
    }  
}  
public class TempateMain  
{  
    //这里仅仅使用main作测试  
    public static void main(String[] args)  
    {  
        //传递:  
        //1.得到HibernateTemplate对象  
        //2.向HibernateTemplate.execute方法中传递HibernateCallback对象  
        //3.覆写HibernateCallback对象  
      
        BackCallTemplate getHibernateTemplate = new BackCallTemplate();  
        //我们使用的是回调函数,在回调函数里处理行为  
        //疑问:怎么才能调用getHibernateTempleate.save(X x)呢?  
        //答:可将Main方法进行封装,通过方法参数传递参数即可!  
        String str = (String) getHibernateTemplate.execute(new HibernateCallback()  
        {  
            public Object doInHibernate(Session session)  
            {  
                return session.createQuery("select count(id) from table");  
            }  
        });  
          
        System.out.println(str);  
    }  
  
}  




参考文档:http://blog.csdn.net/itpinpai/article/details/8236547
========

你可能感兴趣的:(java,java,Web,Hibernate,Hibernate,template)