Spring事务管理

在这里不细说什么是事务了,想明白什么是事务的,可以查阅相关资料,直接进入主题。

Spring中事务管理

   Spring事务管理高层抽象主要包括3个接口:

  •  PlatformTransactionManager  事务管理器

                        

  • TransactionDefinition     事务定义信息(隔离、传播、超时、只读)

          隔离设置:isolation="DEFAULT"(默认),其他配置选项可查看下方   “事务隔离级别” 

          传播设置:propagation="REQUIRED"(默认),其他配置选项可查看下方   “事务的传播行为”

          超时设置:timeout=-1 (默认) ,代表事务永不超时  直到提交。在实际开发中可以根据情况进行实时的调整,一般为30s

          只读设置:read-only=false (默认)代表当前事务可读可写。 =true 时代表当前事务只可读

             

  • TransactionStatus       事务具体运行状态

             

三个接口中事务管理器PlatformTransactionManager:

                    Spring为不同的持久化框架提供了不同PlatformTransactionManager接口实现(红色字体标记较重要)

org.springframework.jdbc.datasource.DataSourceTransactionManager

使用Spring JDBC或iBatis 进行持久化数据时使用

org.springframework.orm.hibernate3.HibernateTransactionManager

使用Hibernate3.0版本进行持久化数据时使用

org.springframework.orm.jpa.JpaTransactionManager

使用JPA进行持久化时使用

org.springframework.jdo.JdoTransactionManager

当持久化机制是Jdo时使用

org.springframework.transaction.jta.JtaTransactionManager

使用一个JTA实现来管理事务,在一个事务跨越多个资源时必须使用

三个接口中事务定义信息TransactionDefinition:

事务隔离级别(红色字体标记较重要):

DEFAULT                         使用后端数据库默认的隔离级别(spring中的的选择项)

READ_UNCOMMITED     允许你读取还未提交的改变了的数据。可能导致脏、幻、不可重复读

READ_COMMITTED        允许在并发事务已经提交后读取。可防止脏读,但幻读和 不可重复读仍可发生

REPEATABLE_READ         对相同字段的多次读取是一致的,除非数据被事务本身改变。可防止脏、不可重复读,但幻读仍可能发生。

SERIALIZABLE                 完全服从ACID的隔离级别,确保不发生脏、幻、不可重复读。这在所有的隔离级别中是最慢的,它是典型的通过完全锁定在事务中涉及的数据表来完成的。

事务的传播行为(不是JDBC事务管理,用来解决实际开发的问题.)传播行为:解决业务层之间的调用的事务的关系

指的是对当前事务的支持,默认是REQUIRED

事务传播行为类型                                        说明

PROPAGATION_REQUIRED                 支持当前事务,如果不存在 就新建一个  例如: A,B    如果A有事务,B使用A的事务,如果A没有事务,B就开启一个新的事务.(A,B是在一个事务中。)

PROPAGATION_SUPPORTS                支持当前事务,如果不存在,就不使用事务   例如: A,B    如果A有事务,B使用A的事务,如果A没有事务,B就不使用事务.

PROPAGATION_MANDATORY           支持当前事务,如果不存在,抛出异常           例如:A,B    如果A有事务,B使用A的事务,如果A没有事务,抛出异常.

PROPAGATION_REQUIRES_NEW        如果有事务存在,挂起当前事务,创建一个新的事务   例如:A,B    如果A有事务,B将A的事务挂起,重新创建一个新的事务.(A,B不在一个事务中.事务互不影响.)

PROPAGATION_NOT_SUPPORTED     以非事务方式运行,如果有事务存在,挂起当前事务  例如: A,B    非事务的方式运行,A有事务,就会挂起当前的事务.

PROPAGATION_NEVER                        以非事务方式运行,如果有事务存在,抛出异常        例如:A,B    非事务的方式运行,A有事务,就会抛出异常

PROPAGATION_NESTED                      如果当前事务存在,则嵌套事务执行  基于SavePoint技术.  例如: A,B    A有事务,A执行之后,将A事务执行之后的内容保存到SavePoint.B事务有异常的话,用户需要自己设置事务提交还是回滚.

Spring事务支持两种事务管理

   1.编程时事务管理

                在实际应用中很少使用

                通过TransactionTemplate手动管理事务

    2.使用XML配置文件声明式事务

                开发中推荐使用(代码侵入性最小)

                Spring的声明式事务是通过AOP实现的

下面通过转账案例演示spring中如何管理事务:

直接上代码了。

UserdaoI.java:

public interface UserDaoI {
     
     void inMoney(String name,int money);
     
     void outMoney(String name,int money);
}

UserDaoImpl.java:

@Repository

public class UserDaoImpl  implements UserDaoI{

     @Autowired

     private JdbcTemplate jdbcTemlate;

     

     @Override

     public void inMoney(String name, int money) {

           // TODO Auto-generated method stub

           String sql="update t_user set money=money+? where name=?";

           Object[] objects=new Object[]{money,name};

           jdbcTemlate.update(sql, objects);

     }

     

     @Override

     public void outMoney(String name, int money) {

           // TODO Auto-generated method stub

           String sql="update t_user set money=money-? where name=?";

           Object[] objects=new Object[]{money,name};

           jdbcTemlate.update(sql, objects);

     }

}

 UserService.java:         

@Service
public class UserService {
     @Autowired
     private UserDaoI userDao=new UserDaoImpl();
     
     public void transfer(){
                userDao.inMoney("张三", 10);
                int i=1/0;
                userDao.outMoney("李四", 10);
     }
}

  beans.xml:

<?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:context="http://www.springframework.org/schema/context"
     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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
     <!-- 引入第三方 properties配置 -->
     <context:property-placeholder location="classpath:jdbc.properties"/>
     
     <context:annotation-config/>
     
     <context:component-scan base-package="com.baidu.service,com.baidu.dao"></context:component-scan>
     
     <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
           <!-- ${key} 可以读取properties文件中配置 key对应value -->
           <property name="driverClass" value="${jdbc.driver}"></property>
           <property name="jdbcUrl" value="${jdbc.url}"></property>
           <property name="user" value="${jdbc.username}"></property>
           <property name="password" value="${jdbc.password}"></property>
     </bean>
     <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
           <property name="dataSource" ref="dataSource"></property>
     </bean>
     
     <!-- 配置事务管理器
           id:不建议修改,就叫transactionManager 
            如果要进行注解的事务,那么事务管理器必须名字是transactionManager 
     -->
     <!-- 事务管理器 -->
     <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <!-- 注入连接池 -->
           <property name="dataSource" ref="dataSource"></property>
     </bean>
     
     <!-- 配置事务增强 -->
     <tx:advice id="txAdvice" transaction-manager="transactionManager">
                <!-- 增强(事务)的属性的配置 -->
                <tx:attributes>
                            <!--
                                isolation:DEFAULT    :事务的隔离级别.
                                propagation            :事务的传播行为.
                                read-only            :false.不是只读
                                timeout                :-1
                                no-rollback-for        :发生哪些异常不回滚
                                rollback-for        :发生哪些异常回滚事务
                                -->
                           <tx:method name="transfer" propagation="REQUIRED"/><!-- name:测试方法中方法名称-->
                </tx:attributes>
     </tx:advice>
     
     <!-- AOP相关配置 -->
     <!-- aop配置定义切面和切点的信息 -->
     <aop:config>
                <!-- 定义切点:哪些类的哪些方法应用增强 -->
                <aop:pointcut expression="expression=execution(* com.baidu.service..*(..))" id="poi1"/>
                <!-- 定义切面: -->
                <aop:advisor advice-ref="txAdvice" pointcut-ref="poi1"/>
     </aop:config>
</beans>

jdbc.properties:

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc\:mysql\://localhost\:3306/laok
jdbc.username=root
jdbc.password=root

测试方法:

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations="classpath:beans.xml")

public class TestTrans {

     @Autowired

     private UserService userService;

     

     @Test

     public void test1(){

           userService.transfer();

     }

}

可以看到,运行结果报错,而且数据库的值也没有变,说明操作事务成功。

在管理多方法的事务时,在beans.xml配置文件中可以这样配置,

在配置事务增强部分可以这样:

<!-- 配置事务增强 -->
     <tx:advice id="txAdvice" transaction-manager="transactionManager">
                <tx:attributes>
                           <tx:method name="transfer" propagation="REQUIRED"  read-only="true" isolation="DEFAULT" timeout="-1"/>
                           <tx:method name="get*"/>
                           <tx:method name="set*"/>
                           <tx:method name="find*"/>
                           <tx:method name="update*"/>
                </tx:attributes>
     </tx:advice>

get*、set*、find*、update*等等,每个名词后面的*代表了以get、set等等名词开头的所有相关方法, 统一进行事务处理,但要注意其他属性配置,列表展示等功能要只读,其他修改功能要可读可写

使用注解配置声明事务:

beans.xml:

<?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:context="http://www.springframework.org/schema/context"
     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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
     <!-- 引入第三方 properties配置 -->
     <context:property-placeholder location="classpath:jdbc.properties"/>
     
     <context:annotation-config/>
     
     <context:component-scan base-package="com.baidu.service,com.baidu.dao"></context:component-scan>
     
     <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
           <!-- ${key} 可以读取properties文件中配置 key对应value -->
           <property name="driverClass" value="${jdbc.driver}"></property>
           <property name="jdbcUrl" value="${jdbc.url}"></property>
           <property name="user" value="${jdbc.username}"></property>
           <property name="password" value="${jdbc.password}"></property>
     </bean>
     <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
           <property name="dataSource" ref="dataSource"></property>
     </bean>
     
     <!-- 配置事务管理器
           id:不建议修改,就叫transactionManager
     -->
     <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
           <property name="dataSource" ref="dataSource"></property>
     </bean>
     
     <!-- 开启注解的事务配置 -->
     <tx:annotation-driven/>
</bean>

可以对某个方法进行事务管理:

UserService.java:

@Service
public class UserService {
     @Autowired
     private UserDaoI userDao=new UserDaoImpl();
     
     @Transactional(propagation=Propagation.REQUIRED,readOnly=false,timeout=-1,isolation=Isolation.DEFAULT)
     public void transfer(){
           
                userDao.inMoney("张三", 10);
                int i=1/0;
                userDao.outMoney("李四", 10);
     }
}

可以对该类中所有方法进行事务管理:

UserService.java:

@Service
@Transactional//如果将注解放置到类级别,那么代表所有的方法都要加事务的
public class UserService {
     @Autowired
     private UserDaoI userDao=new UserDaoImpl();
     
     @Transactional(propagation=Propagation.REQUIRED,readOnly=false,timeout=-1,isolation=Isolation.DEFAULT)
     public void transfer(){
           
                userDao.inMoney("张三", 10);
                int i=1/0;
                userDao.outMoney("李四", 10);
     }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值