Spring+Hibernate整合时关于Hibernate事务管理的问题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Peng_Hong_fu/article/details/53379282

这里写图片描述


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.

这是我在学习Spring整合Hibernate时遇到最头疼的问题,初学者解决很困难,主要是因为在 Spring 配置Hibernate事务的方法有很多种(有tx标签,代理,注释等方法),所有关于解决的方法有很多,我开始也是一头雾水。下面是我测试的三种方式.

测试项目的结构

这里写图片描述

Spring通过Bean创建对象,一种面向接口编程的思想;测试项目中,业务层实现类中注入了Dao层, 具体由DAO层实现类和数据库交互。

其他文件没有给出,项目实例博客:http://blog.csdn.net/peng_hong_fu/article/details/53384010
源代码:http://pan.baidu.com/s/1nvdf0Id

利用tx标签配置事务

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop 
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
  http://www.springframework.org/schema/tx  
   http://www.springframework.org/schema/tx/spring-tx.xsd ">

   <!--配置Bean-->
    <bean id="stockServiceBean" class="com.jxust.service.impl.StockServiceImpl" >
        <property name="stockDao" ref="stockDaoBean" />
   </bean>

   <bean id="stockDaoBean" class="com.jxust.dao.impl.StockDaoImpl" >
        <property name="sessionFactory" ref="sessionFactory"></property>
   </bean>
       .
       .
       <!-- 省略了其他一些配置-->
       .
       .
    <!-- 配置事务容器 -->
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
     <!-- 配置事务通知属性 -->  
    <tx:advice id="txAdvice" transaction-manager="transactionManager">  
        <!-- 定义事务传播属性 -->  
        <tx:attributes>  
            <tx:method name="insert*" propagation="REQUIRED" />  
            <tx:method name="update*" propagation="REQUIRED" />  
            <tx:method name="edit*" propagation="REQUIRED" />  
            <tx:method name="save*" propagation="REQUIRED" />  
            <tx:method name="add*" propagation="REQUIRED" />  
            <tx:method name="new*" propagation="REQUIRED" />  
            <tx:method name="set*" propagation="REQUIRED" />  
            <tx:method name="remove*" propagation="REQUIRED" />  
            <tx:method name="delete*" propagation="REQUIRED" />  
            <tx:method name="change*" propagation="REQUIRED" />  
            <tx:method name="get*" propagation="REQUIRED" read-only="true" />  
            <tx:method name="find*" propagation="REQUIRED" read-only="true" />  
            <tx:method name="load*" propagation="REQUIRED" read-only="true" />  
            <tx:method name="*" propagation="REQUIRED" read-only="true" />  
        </tx:attributes>  
    </tx:advice>  
    <!-- 定义事务入口 需要aspectjweaver-1.x.x.jar包-->
    <aop:config>
        <aop:pointcut id="allDaoMethod" expression="execution(* com.jxust.dao.*.*(..))" />
        <aop:advisor advice-ref="txAdvice" pointcut-ref="allDaoMethod" />
    </aop:config> 

</beans>

除了配置Bean和<aop:config>之外,其他的都是大同小异
<aop:pointcut id="allDaoMethod" expression="execution(* com.jxust.dao.*.*(..))" />
expression 需要配置成,dao层实现类的路径,因为这里是指向各种增删改查,和数据库交互的类。(*号的写法能匹配很多到类)

* 号后要空一格,否则会出现下面的异常

expecting 'name pattern' at character position 29
execution(*com.jxust.dao.*.*(..))
                             ^

利用代理配置事务

使用代理,指的是,具体执行数据库交互的Dao层实现类的Bean,交给代理Bean管理,因为代理Bean继承了定义事务规则的抽象Bean,所有能对Dao层实现类进行事务管理。

    <bean id="stockServiceBean" class="com.jxust.service.impl.StockServiceImpl" >
        <property name="stockDao" ref="userDaoProxy" />
    </bean>

使用代理后,业务层实现类中,注入的Dao层,就要是这个代理Bean了,userDaoProxy 为代理Bean的Id。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop 
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
  http://www.springframework.org/schema/tx  
   http://www.springframework.org/schema/tx/spring-tx.xsd ">
    <!--配置Bean-->
    <bean id="stockServiceBean" class="com.jxust.service.impl.StockServiceImpl" >
        <property name="stockDao" ref="userDaoProxy" />
    </bean>

    <bean id="stockDaoBean" class="com.jxust.dao.impl.StockDaoImpl" >
        <property name="sessionFactory" ref="sessionFactory"></property>
    </bean>

    <!--利用代理配置事务。  -->
    <!-- 配置事务容器 -->
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
    <!-- 定义事务规则 -->
    <bean id="transactionProxy"
        class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
        abstract="true">
        <property name="transactionManager" ref="transactionManager" />
        <property name="transactionAttributes">
            <props>
                <prop key="sav*">PROPAGATION_REQUIRED</prop>
                <prop key="update*">PROPAGATION_REQUIRED</prop>
                <prop key="delete*">PROPAGATION_REQUIRED</prop>
                <prop key="*">PROPAGATION_REQUIRED</prop>
            </props>
        </property>
    </bean>
    <!-- 定义事务入口 -->
    <bean id="userDaoProxy" parent="transactionProxy">
        <property name="target" ref="stockDaoBean"></property>
    </bean>

</beans>

事务注解的方式

开启事务注解方式,配置最简单,也方便查看具体方法是否使用了事务。

    <!-- 配置事务管理器 -->
    <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"></property>
    </bean>

    <!-- 开启事务注解 -->
    <tx:annotation-driven transaction-manager="transactionManager"  />

在业务层的实现类中,要使用@Transactional注解

package com.jxust.service.impl;

import org.springframework.transaction.annotation.Transactional;

import com.jxust.dao.StockDao;
import com.jxust.model.Stock;
import com.jxust.service.StockService;
/**
 * 股票业务层实现类
 * @author Peng
 * @Date2016年11月28日下午2:37:07
 */
@Transactional
public class StockServiceImpl implements StockService {

    //注入Dao层
    private StockDao stockDao;

    public void setStockDao(StockDao stockDao) {
        this.stockDao = stockDao;
    }
    .
    .
    .

@Transactional注解

属性 类型 描述
value String 可选的限定描述符,指定使用的事务管理器
propagation enum: Propagation 可选的事务传播行为设置
isolation enum: Isolation 可选的事务隔离级别设置
readOnly boolean 读写或只读事务,默认读写
timeout int (in seconds granularity) 事务超时时间设置
rollbackFor Class对象数组,必须继承自Throwable 导致事务回滚的异常类数组
rollbackForClassName 类名数组,必须继承自Throwable 导致事务回滚的异常类名字数组
noRollbackFor Class对象数组,必须继承自Throwable 不会导致事务回滚的异常类数组
noRollbackForClassName 类名数组,必须继承自Throwable 不会导致事务回滚的异常类名字数组

@Transactional 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。

@Transactional(readOnly = true)
public class FooServiceImpl implements FooService {

  public Foo getFoo(String fooName) {
    // do something
  }

  //方法上注解属性会覆盖类注解上的相同属性
  @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
  public void updateFoo(Foo foo) {
    // do something
  }
}

参考

spring中使用parent属性来减少配置:https://my.oschina.net/u/1984151/blog/295996
Spring中如何配置Hibernate事务 http://blog.csdn.net/jianxin1009/article/details/9202907
Spring配置事务中的 transactionAttributes 各属性含义 http://blog.csdn.net/jianxin1009/article/details/9202907
Spring框架笔记 http://blog.csdn.net/peng_hong_fu/article/details/53089012

展开阅读全文

没有更多推荐了,返回首页