SpringMVC+Spring+Hibernate集成问题
在项目框架搭建时使用SpringMVC+Spring+Hibernate集成遇到如下问题:
org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition. at org.springframework.orm.hibernate4.HibernateTemplate.checkWriteOperationAllowed(HibernateTemplate.java:1128) at org.springframework.orm.hibernate4.HibernateTemplate$12.doInHibernate(HibernateTemplate.java:621) at org.springframework.orm.hibernate4.HibernateTemplate$12.doInHibernate(HibernateTemplate.java:618)
分析错误:
Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition. 写操作在只读模式下不被允许((FlushMode.MANUAL): 把你的Session改成FlushMode.COMMIT/AUTO或者清除事务定义中的readOnly标记。
错误原因:
OpenSessionInViewFilter在getSession的时候,会把获取回来的session的flush mode 设为FlushMode.NEVER。然后把该sessionFactory绑定到TransactionSynchronizationManager,使request的整个过程都使用同一个session,在请求过后再去除该sessionFactory的绑定,最后closeSessionIfNecessary根据该session是否已和transaction绑定来决定是否关闭session。在这个过程中,若HibernateTemplate 发现自当前session有不是readOnly的transaction,就会获取到FlushMode.AUTO Session,使方法拥有写权限。也即是,如果有不是readOnly的transaction就可以由Flush.NEVER转为Flush.AUTO,拥有insert,update,delete操作权限,如果没有transaction,并且没有另外人为地设flush model的话,则doFilter的整个过程都是Flush.NEVER。 所以受transaction(声明式的事务)保护的方法有写权限,没受保护的则没有。
解决办法:
方法一:
spring-servlet.xml: <context:component-scan base-package="com.ittx.spring002.controller" > <!-- 只扫描base-package指定包下@Controller注解 --> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /> </context:component-scan> applicatioContext.xml: <context:component-scan base-package="com.ittx.spring002"> <!-- 除了base-package包下@Controller注解全都扫描 --> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" /> </context:component-scan>
方法二 :
Dao层HibernateTemplate操作数据时,使用execute方法回调方式实现,如下: 原方式:getHibernateTemplate().save(user); 更改后方式:getHibernateTemplate().execute(new HibernateCallback<User>() { @Override public User doInHibernate(Session session) throws HibernateException { session.save(user); return null; } });
方法三:
合并spring-servlet.xml和applicationContext.xml
错误问题引申知识点一:
事务实现方式:
1.用代码实现事务管理
session.beginTrasaction(); session.save(); session.getTrasaction().commit();
2.用注解来实现事务管理
<tx:annotation-driven transaction-manager="txManager" /> <!-- 声明式容器事务管理 --> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="save*" propagation="REQUIRED" /> <tx:method name="add*" propagation="REQUIRED" /> hibernate4必须配置为开启事务 否则 getCurrentSession()获取不到 <tx:method name="get*" propagation="REQUIRED" read-only="true" /> </tx:attributes> </tx:advice> <aop:config expose-proxy="true"> 只对业务逻辑层实施事务 <aop:pointcut id="txPointcut" expression="execution(* com.ittx.spring002.server..*.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" /> </aop:config>
3.用注解来实现事务管理
<bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <!-- 用注解来实现事务管理 --> <tx:annotation-driven transaction-manager="txManager" />
错误问题引申知识点二:
使用说明
<context:component-scan base-package="com.ittx.spring002" />
在xml配置了这个标签后,spring可以自动去扫描base-pack下面或者子包下面的Java文件,如果扫描到有@Component @Controller@Service等这些注解的类,则把这些类注册为bean
注意:如果配置了
1. <context:include-filter> 2. <context:exclude-filter>
在说明这两个子标签前,先说一下
转载请注明来源:SpringMVC+Spring+Hibernate集成问题