使用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 Hibernate模板 学习总结相关推荐

  1. java hibernate详细_Java事务管理学习之Hibernate详细介绍

    hibernate是jdbc轻量级的封装,本身不具备事务管理的能力,在事物管理层面,一般是委托于底层的jdbc和jta来完成调度的.下面这篇文章主要给大家介绍了Java事务管理学习之Hibernate ...

  2. Java新手如何学习Spring、Struts、Hibernate三大框架?

    spring,hibernate,struts 是JavaEE方向企业使用较多的几个框架技术,所以就会很多人想去学习这几个框架,当然这几个框架流行的时间也比较长了,相对资料也会比较多,但是适合新手的并 ...

  3. java程序员学习路线以及我的学习经验

    本文作者为优知学院创始人陈睿(mike),作者有10年以上技术&产品经验,曾任百度研发经理.携程定制旅游CTO. " 这是一篇完整的java程序员学习线路图,一共分为六个阶段. 我以 ...

  4. java和Android学习书籍

    java书籍推荐: 入门 <Head First Java, 2nd Edition(中文版)> 这本书不仅内容丰富.有趣且通俗易懂,并且涵盖了所有 Java 相关的基础知识.如果你是 J ...

  5. Java 架构师学习路线

    Java 架构师学习路线 一. 框架源码专题 1. 应用框架Spring 1.1. Spring IOC源码剖析 1.2. Spring AOP 源码剖析 1.3. Spring MVC 源码剖析 1 ...

  6. JAVA萌新学习day25 css

    JAVA萌新学习day25 css 一.CSS概念: CSS :层叠样式表(英文全称:Cascading Style Sheets)是一种用来表现HTML(标准通用标记语言的一个应 用)或XML(标准 ...

  7. eclipse的安装以及JAVA的基本学习第一部分

    今天开始进行Java语言的学习 配置环境: 点击这个链接来下载这个eclipse包:eclipse 提取码:zzvy 首先我们打开压缩包 点击下面的应用程序 选择公共JRE,下面的安装目录不要修改 安 ...

  8. Hibernate基础学习2

    Hibernate基础学习2 测试hibernate的一级缓存,事务以及查询语句 1)Hibernate的一些相关概念 hibernate的一级缓存 1)缓存是为了提高该框架对数据库的查询速度 2)一 ...

  9. 2021年,Java开发者值得学习的13项技能

    本文分享自百度开发者中心2021年,Java开发者值得学习的13项技能 作者 | Olivia Cuthbert 译者 | 王强 策划 | 刘燕 如果你想在这个竞争激烈的世界里,成为一名熟练开发 Ja ...

最新文章

  1. Vue安装支持SCSS插件
  2. lampapache+mysql+php
  3. 使用intellij idea打开以前用maven的包
  4. matlab文件序号超出511,求教一段matlab的代码 - 数学 - 小木虫 - 学术 科研 互动社区...
  5. OpenStack运维(二):OpenStack计算节点的故障和维护
  6. 小程序组件库开发之抽奖游戏组件
  7. c语言if中文字符串比较好,如何在C语言中使用汉字作为if的判断语句?
  8. 虚拟机讲只读文件变为可读可写文件_Linux虚拟机文件系统突然变成只读
  9. Demo(3月28日)
  10. 玩转地图投影公式,通过例题对兰伯特投影与墨卡托投影求取正反解
  11. OpenCV测试摄像头帧率
  12. iOS修改手游服务器数据,IOS免越狱游戏存档修改教程】成长王国Grow Kingdom为例
  13. java自行车s码适合身高_选购单车时,身高和尺寸对应表
  14. 【转】Ouroboros:一个可证明安全的PoS区块链协议 (共识介绍)
  15. Vue项目关于省略号显示
  16. 威斯康星大学硕士计算机科学,2020年威斯康星大学-麦迪逊分校硕士热门专业
  17. StringUtils中isNotEmpty和isNotBlank及isBlank()和isEmpty()区别
  18. arp攻击----arpspoof
  19. CEA-2014(简述)
  20. scrapy中使用讯代理动态转发

热门文章

  1. MySQL 切换数据库、用户卡死:“You can turn off this feature to get a quicker startup with -A“处理方法
  2. vue cli 项目在打包时候报错解决方法
  3. 智能车声标定位相关算法优化
  4. 单片机\程序中的那些宏定义
  5. 74芯片引脚真值表汇总
  6. hdu 1588 Gauss Fibonacci 较难
  7. 第十一周项目实践2 用邻接表存储的图来实现基本应用
  8. 第一节 Image Processing Toolbox功能介绍
  9. Implement strStr()
  10. Python 基础语法(一)