Spring事务管理

1、概念

  • 事务: 逻辑上的一组操作,这组操作要么全部成功,要么全部失败。
  • 特性:
    • 原子性:不可分割
    • 统一性:数据完整性要一致
    • 隔离线:线程安全(多个用户并发访问数据)
    • 持久性:事务被提交后,数据的改变就是永久性的,及时数据库发生故障也不能对其有任何影响

2、事务管理高层抽象接口

  • PlatformTransaction:事务管理器
    • spring为不同的持久化框架提供了不同的PlatformTtansactionManager接口实现:
事务说明
org.springframework.jdbc.datasource.DataSourceTransactionManager使用Spring JDBC或mybatis进行持久化数据时使用
org.springframework.orm.hibernate3.HibernateTransactionManager使用Hibernate3.0进行持久化数据时使用
org.springframework.jpa.JpaTransactionManager使用JPA进行持久化时使用
org.springframework.jdo.JdpTransactionManager当持久化机制是Jdo时使用
org.springframework.transaction.jta.JtaTransactionManager使用一个JTA实现来管理事务,在一个事务跨越多个资源时必须使用
  • TransactionDefinition: 事务定义信息(隔离、传播、超时、只读)
    • 事务隔离级别:
隔离级别说明
DEFAULT使用后端数据库默认的隔离级别(Spring中的选择项)
READ_UNCOMMITED允许 你读取还未提交的改变了的数据。可能导致脏、幻、不可重复读
REPEATABLE_READ对相同的字段的多次读取是一致的,除非数据被事务本身改变。可防止脏、不可重复读,但幻读仍有可能发生
SERIALIZABLE完全服从ACID的隔离级别,确保不发生脏、幻、不可重复读。这在所有隔离级别中是最慢的,它是典型的通过完全锁定在事务中涉及的数据表来完成的
    • 脏读:一个事务读取了另一个事务该写的但还未提交的数据,如果这些数据被回滚,则读到的数据时无效的。
    • 不可重复读:在同一事务中,多次读取同一数据返回的结果有所不同
    • 幻读:一个事务读取了几行记录后,另一个事务插入一些记录,幻读就发生了,再后来的查询中,第一个事务就会发现有些原理没有的记录
    • 事务传播行为
事务传播行为类型说明
PROPAGATION_REQUIRED支持当前事务,如果不存在就新建一个
PROPAGATION_SUPPORTS支持当前事务,如果不存在,就不使用事务
PROPAGATION_MANDATORY支持当前事务,如果不存在,就抛出异常
PROPAGATION_REQUIRES_NEW如果有事务存在,挂起当前事务,创建一个新的事务
PROPAGATION_NOT_SUPPORTED以非事务方式运行,如果有事务存在,挂起当前事务
PROPAGATION_NEVER以非事务方式运行,如果有事务存在,抛出异常
PROPAGATION_NESTED如果当前事务存在,则嵌套事务执行
  • TransactionStatus: 事务具体运行状态

3、事务管理方式

3.1、编程式事务管理(很少用到)

  • 在AccountService中使用TransactionTemplate
  • TransactionTemplate依赖DataSourceTransactionManager
  • DataSourceTransactionManager依赖DataSource构造
  <!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->  
    <bean id="transactionManager"  
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
        <property name="dataSource" ref="dataSource" />  
    </bean>  
    
    <!-- 配置事务管理模板:Spring为了简化事务管理的代码而提供的类 -->
    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="transactionManager"></property>
    </bean>

service实现,包含了事务管理

package com.sysker.spring.dome.service.impl;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

import com.sysker.spring.dome.dao.AccountDao;
import com.sysker.spring.dome.service.AccountService;

@Service
public class AccountServiceImpl implements AccountService {
    
    @Autowired
    private AccountDao accountDao;
    
    @Autowired
    private TransactionTemplate transactionTemplate;
    
    @Override
    public void transfer(String out, String in, String money) {
        /**
         * 事务管理,execute()方法中创建了一个匿名内部类,在匿名内部类中操作业务,即可实现事务管理
         */
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                accountDao.outMoney(out, money);
                int i = 1/0;
                accountDao.inMoney(in, money);
                
            }
        });
        
        
    }

}

测试类

package com.sysker.spring.dome.test;


import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.sysker.spring.dome.service.AccountService;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring-mybatis.xml"})
public class TestMybatis {
    private static Logger logger = Logger.getLogger(TestMybatis.class);
    @Resource
    private AccountService accountService = null;
    
    @Test
    public void test1() {
        accountService.transfer("aaa", "bbb", "200");
        logger.info("success");
        
    }
    
}
  • 缺点: 在开发中需要修改过java代码,在实际开发中不会用到
3.2、声明式事务事务管理
  • 使用XML配置声明式事务(原始方式)(很少用到)
    • 使用TransactionProxyFactoryBean
<!-- 配置事务管理器 -->
<bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
<!-- 配置业务层的代理 -->
 <bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" >
 <!-- 配置目标对象 -->
    <property name="transactionManager" ref="transactionManager"></property>
    <!-- 注入事务管理器 -->
    <property name="target" ref="accountService"></property>
    <!-- 注入事务属性 -->
    <property name="transactionAttributes">
        <props>
        <!-- 
        prop的格式:
            PROPAGATION : 事务的传播行为,必须有
            ISOLATION   : 事务的隔离级别
            readOnly    :只读
            -Exception  :发生哪些异常回滚事务
            +Exception  :发生哪些异常不回滚事务
        
        -->
            <prop key="*">PROPAGATION_REQUIRED</prop>
        </props>
    </property>
 </bean>
    • prop格式:
      • PROPAGATION,ISOLATION,readOnly,-Exception,+Exception
      • 传播行为,隔离级别,只读事务,发生这些异常回滚事务,发生这些异常提交事务

测试类

package com.sysker.spring.dome.test;


import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.sysker.spring.dome.service.AccountService;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring-mybatis.xml"})
public class TestMybatis {
    private static Logger logger = Logger.getLogger(TestMybatis.class);
    @Resource(name="accountServiceProxy")
    private AccountService accountService;
    
    @Test
    public void test1() {
        accountService.transfer("aaa", "bbb", "200");
        logger.info("success");
        
    }
    
}

service实现,包含了事务管理

package com.sysker.spring.dome.service.impl;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

import com.sysker.spring.dome.dao.AccountDao;
import com.sysker.spring.dome.service.AccountService;

@Service
public class AccountServiceImpl implements AccountService {
    
    @Autowired
    private AccountDao accountDao;
    
    
    @Override
    public void transfer(String out, String in, String money) {
                accountDao.outMoney(out, money);
                int i = 1/0;
                accountDao.inMoney(in, money);
                
        
        
    }

}
  • 基于AOP的事务管理(实际开发会经常用到)
<!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
    
    <!-- 基于aop的事务管理 -->
    <tx:advice id="txAdvice"
        transaction-manager="transactionManager">
        <tx:attributes>
        <!-- 
            PROPAGATION : 事务的传播行为,必须有
            ISOLATION   : 事务的隔离级别
            readOnly    :只读
            rollback-for  :发生哪些异常回滚事务
            no-rollback-for  :发生哪些异常不回滚事务
            timeout : 过期信息
        -->
            <tx:method name="transfer" />
        </tx:attributes>
    </tx:advice>
 <!-- 配置切面 -->
    <aop:config>
    <!-- 配置切点 -->
        <aop:pointcut id="fooServiceOperation"
            expression="execution(* com.sysker.spring.dome.service.impl.*.*(..))" />
            <!-- 配置切面 -->
        <aop:advisor advice-ref="txAdvice"
            pointcut-ref="fooServiceOperation" />
    </aop:config>

service实现,包含了事务管理

package com.sysker.spring.dome.service.impl;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

import com.sysker.spring.dome.dao.AccountDao;
import com.sysker.spring.dome.service.AccountService;

@Service
public class AccountServiceImpl implements AccountService {
    
    @Autowired
    private AccountDao accountDao;
    
    
    @Override
    public void transfer(String out, String in, String money) {
                accountDao.outMoney(out, money);
                int i = 1/0;
                accountDao.inMoney(in, money);
                
        
        
    }

}

测试类

package com.sysker.spring.dome.test;


import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.sysker.spring.dome.service.AccountService;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring-mybatis.xml"})
public class TestMybatis {
    private static Logger logger = Logger.getLogger(TestMybatis.class);
    @Resource(name="accountService)
    private AccountService accountService;
    
    @Test
    public void test1() {
        accountService.transfer("aaa", "bbb", "200");
        logger.info("success");
        
    }
    
}
  • 基于注解的事务管理 (实际开发会经常用到)
<!-- 配置事务管理器 -->
<!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
    
    !-- 基于注解的事务管理 -->
    <tx:annotation-driven transaction-manager="transactionManager" />

service实现,包含了事务管理

package com.sysker.spring.dome.service.impl;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

import com.sysker.spring.dome.dao.AccountDao;
import com.sysker.spring.dome.service.AccountService;

@Service
@Transactional
public class AccountServiceImpl implements AccountService {
    
    @Autowired
    private AccountDao accountDao;
    
    
    @Override
    public void transfer(String out, String in, String money) {
                accountDao.outMoney(out, money);
                int i = 1/0;
                accountDao.inMoney(in, money);
                
        
        
    }

}

测试类

package com.sysker.spring.dome.test;


import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.sysker.spring.dome.service.AccountService;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring-mybatis.xml"})
public class TestMybatis {
    private static Logger logger = Logger.getLogger(TestMybatis.class);
    @Resource(name="accountService)
    private AccountService accountService;
    
    @Test
    public void test1() {
        accountService.transfer("aaa", "bbb", "200");
        logger.info("success");
        
    }
    
}

转载于:https://www.cnblogs.com/caoleiCoding/p/9286589.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值