继承HibernateDaoSupport引发的错误总结,spring对hibernate的集成

来源:互联网 发布:汉字域名 编辑:程序博客网 时间:2024/04/29 17:44

错误内容如下:

八月 16, 2016 11:56:03 上午 org.apache.catalina.core.StandardContext listenerStart
SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'drugTypeService' defined in file [D:\ff-env\output-tomcat\tomcat-single\wtpwebapps\fftg\WEB-INF\classes\com\fufang\fftg\manager\service\impl\DrugTypeServiceImpl.class]: Post-processing failed of bean type [class com.fufang.fftg.manager.service.impl.DrugTypeServiceImpl] failed; nested exception is java.lang.IllegalStateException: @Resource annotation requires a single-arg method:public com.fufang.fftg.manager.dao.IDrugTypeDaocom.fufang.fftg.manager.service.impl.DrugTypeServiceImpl.getDrugTypeDao()

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyMergedBeanDefinitionPostProcessors(AbstractAutowireCapableBeanFactory.java:929)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513)
       。。。。。

       。。。。。
Caused by: java.lang.IllegalStateException: @Resource annotation requires a single-arg method: public com.fufang.fftg.manager.dao.IDrugTypeDao com.fufang.fftg.manager.service.impl.DrugTypeServiceImpl.getDrugTypeDao()
  复制的之前人写的代码,类继承了HibernateDaoSupport:

@Repository(value = "drugTypeDaoImpl")
public class DrugTypeDaoImpl extends HibernateDaoSupport implements IDrugTypeDao {
@Autowired
private SessionFactory sessionFactory;

此时启动报错,在网上搜了一下解决了问题作此记录:

   在继承HibernateDaoSupport时要在spring的配置文件中动态配置:

    <bean id="drugTypeDaoImpl" class="com.fufang.fftg.manager.dao.impl.DrugTypeDaoImpl">
<property name="sessionFactory" ref="sessionFactory"></property>
   </bean>

原因:

Spring的Hibernate ORM 框架带来了方便的HibernateDaoSupport类,你的DAO类可以继承它:  

public class StudentDaoHibernate extends HibernateDaoSupport implements StudentDao{ 
 .................  } 
 如果你选择这种设计,就需要动态注入SessionFactory而HibernateDaoSupport包含这个属性.这个类提供了一个方便的方法getHibernateTemplate(); 就能得到HibernateTemplate的一个实例.它也有getSession()和releaseSession,以便于你应为某些原因而不使用HibernateTempate的情况下执行Hibernate操作。  HibernateDaoSupport提供了基于AOP事务的自动处理,程序员完全可以不用理会事务的开始与提交。在JDBC中一个Connection对象使用一个事务,那么在Hibernate中一个事务肯定要关联一个SessionFactory了,然而这个SessionFactory却没有在DAO中体现。其实主要的原因是HibernateDaoSupport类已经默默地做了封装的工作,它用一个setSessionFactory方法将SessionFactory进行注入,所以继承自HibernateDaoSupport类的DAO都会具有SessionFactory的属性,从而可以通过SessionFactory创建Session实例操作数据库。  在继承HibrnateDaoSupport的DAO实现里,Hibernate Session的管理完全不需要Hibernate代码打开,而由Spring来管理。Spring会根据实际的操作,采用“每次事务打开一次session”的策略,自动提高数据库访问的性能。
Spring为Hibernate的DAO提供工具类:HibernateDaoSupport。该类主要提供了两个方法:
public final HibernateTemplate getHibernateTemplate()
public final void setSessionFactory(SessionFactory sessionFactory)
其中,setSessionFactory方法接收来自Spring的applicationContext的依赖注入,接收了配置在Spring 中的SessionFactory实例,getHibernateTemplate方法用来利用刚才的SessionFactory生成Session, 再生成HibernateTemplate来完成数据库的访问。

典型的继承HibernateDaoSupport的DAO代码如下:

public class UserDAOImpl extends HibernateDaoSupport implements UserDAO{
public void save(Users transientInstance) {
log.debug("saving Users instance");
try {
getHibernateTemplate().save(transientInstance);
log.debug("save successful");
} catch (RuntimeException re) {
log.error("save failed", re);
throw re;
}
}
………………
}
实 际上,DAO的实现依然借助了HibernateTemplate的模板访问方式,只是,HibernateDaoSupport将依赖注入 SessionFactory的工作已经完成,获取HibernateTemplate的工作也已经完成。注意,这种方法须在Spring的配置文件中配 置SessionFactory。
在继承HibrnateDaoSupport的DAO实现里,Hibernate Session的管理完全不需要Hibernate代码打开,而由Spring来管理。Spring会根据实际的操作,采用“每次事务打开一次 session”的策略,自动提高数据库访问的性能。

综上,个人认为继承此类主要作用是方便对session的管理和事务的管理,提到此类的事务管理进一步总结如下:



在谈Spring事务管理之前我们想一下在我们不用Spring的时候,在Hibernate中我们是怎么进行数据操作的。在Hibernate中我们每次进行一个操作的的时候我们都是要先开启事务,然后进行数据操作,然后提交事务,关闭事务,我们这样做的原因是因为Hibernate默认的事务自动提交是false,他是需要我们人为的手动提交事务,假如你不想每次都手动提交事务的话,你可以在hibernate.cfg.xml我文件中把它设置为事务自动提交:


<property name="hibernate.connection.autocommit">true</property> 


当我们Spring对我们的Hibernate进行整合之后,我们的代码又出现了什么变化呢?整合,之后,我们不再是每次都去拿Session进行数据操作了,也不需要每次都开启事务,提交事务了,我们只需要Spring给我们提供的一个HibernateTemplate,我们直接用这个类里面给我们提供的数据操作方法就可以操作数据了。我们在也看不到关于事务的代码了,那Spring究竟有没有在他的操作方法里面封装事务处理呢?有的人直接HibernateTemplate里面提供的方法操作数据,成功了,有的人却又失败了,这到底是怎么回事呢?其实这里要看我们是怎样集成我们的Hibernate和Spring,如果在集成的过程中,我们抛弃了hibernate.cfg.xml文件,直接在Spring的的配置文件中进行配置数据源的话,那你直接用HibernateTemplate里面提供的方法是可以成功操作数据的,如果你还是用hibernate.cfg.xml来配置数据源,在Spring的配置文件中引用hibernate.cfg.xml文件,那么你不能成功,这其中的原因就是因为如果你用 hibernate.cfg.xml文件配置数据源,就像我们前面说的,Hibernate默认是手动提交事务,而HibernateTemplatel提供的方法里面并没有提供事务提交,而如果你用Spring的配置文件来配置数据源,Sping默认是自动提交的,所以就会成功,如果你想把Spring设置为手动提交你可以在起配置文件中进行配置:


<property name="defaultAutoCommit">
    <value>false</value>
</property> 


纵然我们把它的事务提交方式设置为自动,它可以进行数据操作,但是这样并不满足我们实际的业务需求,因为有时候在我保存一个数据之后,我希望他能继续保存另一条数据,我希望在保存完两条或者多条之后一起进行事务提交,这样即使出错,我们可以回滚,取保数据的一致性,要么都成功要么都失败,这时候我们就不能每保存完一条数据之后事务就自动提交,因为这样它们不在同一个事务当中,我们不能保证数据的一致行。所以这时候我们就需要手动的来配置我们的事务,这就需要用到Spring为Hibernate提供的事务管理机制,Spring提供的事务管理可以分为两类:编程式的和声明式的,编程式,其实就是在代码里面来控制,像Hibernate操作数据一样,开启事务,提交事务,这种方式有一定的局限性,所以我们一般是用声明式来配置我们的事务。


声明式事务配置主要分以下几步:


1、声明式事务配置


    配置事务管理器;
    事务的传播特性;
    那些类那些方法使用事务。

<!-- 配置事务管理器 指定其作用的sessionFactory把事务交给Spring去处理 -->

    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory">
    <ref bean="sessionFactory"/>
    </property>
    </bean>

<!-- 配置事务的传播特性 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
    <tx:method name="save*" propagation="REQUIRED"/>
    <tx:method name="delete*" propagation="REQUIRED"/>
    <tx:method name="update*" propagation="REQUIRED"/>
    <tx:method name="get*" read-only="true" propagation="NOT_SUPPORTED"/>
    <tx:method name="*" read-only="true"/>
    </tx:attributes>
    </tx:advice>

<!-- 那些类的哪些方法参与事务 -->
    <aop:config>
    <aop:pointcut id="allServiceMethod" expression="execution(* com.coe.service.*.*(..))"/>
    <aop:advisor pointcut-ref="allServiceMethod" advice-ref="txAdvice"/>
    </aop:config> 

我们在配置事务的时候,我们一般是把事务边界设置到service层,也就是你的业务逻辑层,因为我们很多时候都是在我们的业务逻辑层来完成我们一些列的数据操作,如果放到Dao数据层,其粒度太小了。另外,如果我们把事务配置在业务逻辑层的话,对我们的二级缓存也是有好处的,这个大家以后实际操作的时候会发现。

2、编写业务逻辑方法

这时候我们就可以在我们业务逻辑层用HibernateTemplate里面提供的数据操作方法来编写我们的业务逻辑方法了,当然我们的方法必须要是以我们事务配置里面配置的一样,用save,delete,update,get做我们的方法的开头。需要注意的是,默认情况下运行期异常才会回滚(包括继承了RuntimeException子类),普通异常是不会滚的。


0 0
原创粉丝点击