24

Spring 框架基础(05):事务管理机制,和实现方式

 4 years ago
source link: http://www.cnblogs.com/cicada-smile/p/11985733.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

本文源码: GitHub·点这里 || GitEE·点这里

一、Spring事务管理

1、基础描述

Spring 事务管理的本质就是封装了数据库对事务支持的操作,使用JDBC的事务管理机制,就是利用 java.sql.Connection 对象完成对事务的提交和回滚。

Connection conn = DriverManager.getConnection();
try {  
    // 自动提交设置为false
    conn.setAutoCommit(false);
    // 执行增删改查操作
    // 当操作成功后手动提交
    conn.commit();  
} catch (Exception e) {
    // 出现异常,回滚所有操作
    conn.rollback();
    e.printStackTrace();
} finally {
    conn.colse();
}

2、事务常见概念

  • 事务

事务是指作为单个逻辑工作单元执行的一系列操作(SQL语句)。这些操作要么全部成功,要么全部不成功。

  • 特性:ACID
原子性(Atomicity):事务中的多个操作要么都成功要么都失败
一致性(consistency):事务的执行的前后数据的完整性保持一致
隔离性(isolation):事务执行的过程中,不应该受到其他事务的干扰
持久性(durability):事务一旦结束,数据就持久到数据库
  • 隔离问题

脏读:一个事务读到另一个事务没有提交的数据

不可重复读:一个事务前后多次读取相同数据,数据内容不一致,update场景问题

虚读(幻读):一个事务前后多次读取,数据总量不一致,insert场景问题

  • 隔离级别

read uncommitted :

事务可以读取另一个未提交事务的数据。

read committed

事务要等另一个事务提交后才能读取数据,解决脏读。

repeatable read

在开始读取数据时,事务开启,不再允许修改操作,解决:脏读、不可重复读。

serializable

最高事务隔离级别,事务串行化顺序执行,解决脏读、不可重复读、幻读。但是效率低下,耗数据库性能。

3、事务管理API描述

  • PlatformTransactionManager

平台事务管理器,Spring管理事务,必须使用事务管理器进行事务配置时,核心方法:获取事务,提交事务,回滚事务。

  • TransactionDefinition

该对象封装事务详情(事务定义、事务属性),例如:隔离级别、是否只读、超时时间 等。

  • TransactionStatus

用于记录当前事务运行状态。例如:是否有保存点,事务是否完成。Spring底层根据状态进行相应操作。

4、事务案例SQL语句

CREATE TABLE user_account(
  id INT PRIMARY KEY AUTO_INCREMENT,
  username VARCHAR(50),
  money INT
) ENGINE=InnoDB DEFAULT CHARSET=utf8;;
INSERT INTO user_account(username,money) VALUES('jack','5000');
INSERT INTO user_account(username,money) VALUES('tom','5000');
SELECT * FROM user_account ;

二、编程式事务管理

1、核心配置文件

<!-- 配置事物管理器 -->
<bean id="txManager"
      class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>
<!-- 创建事物模板 -->
<bean id="transactionTemplate"
      class="org.springframework.transaction.support.TransactionTemplate">
    <property name="transactionManager" ref="txManager" />
</bean>
<!-- 配置转账接口 -->
<bean id="userAccountService"
      class="com.spring.mvc.service.impl.UserAccountServiceImpl">
    <property name="jdbcTemplate" ref="jdbcTemplate" />
    <property name="transactionTemplate" ref="transactionTemplate" />
</bean>

2、演示案例

@Service
public class UserAccountServiceImpl extends JdbcDaoSupport implements UserAccountService {
    // 注入事物模板
    private TransactionTemplate transactionTemplate ;
    public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
        this.transactionTemplate = transactionTemplate;
    }
    @Override
    public void remittance(String remitTer, String receiver, int money) {
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            public void doInTransactionWithoutResult(TransactionStatus arg0) {
                outMoney(remitTer,money);
                // System.out.println(1/0);
                innerMoney(receiver,money);
            }
        });
    }
    private void outMoney (String remitTer, int money){
        String outSql = "update user_account set money = money - ? where username = ?";
        this.getJdbcTemplate().update(outSql, money ,remitTer);
    }
    private void innerMoney (String receiver, int money){
        String inSql = "update user_account set money = money + ? where username = ?";
        this.getJdbcTemplate().update(inSql, money,receiver);
    }
}

三、事务代理工厂

1、核心配置

<!-- 配置转账接口 -->
<bean id="userAccountService01"
      class="com.spring.mvc.service.impl.UserAccountServiceImpl01">
    <property name="jdbcTemplate" ref="jdbcTemplate" />
</bean>
<!-- 配置事务代理工厂 -->
<bean id="proxyAccountService"
      class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="proxyInterfaces" value="com.spring.mvc.service.UserAccountService01" />
    <property name="target" ref="userAccountService01" />
    <property name="transactionManager" ref="txManager" />
    <property name="transactionAttributes">
        <props>
            <!-- 默认传播行为、隔离级别 -->
            <prop key="remittance">PROPAGATION_REQUIRED,ISOLATION_DEFAULT</prop>
            <!-- 异常仍然提交事务
            <prop key="remittance">PROPAGATION_REQUIRED,ISOLATION_DEFAULT,+java.lang.Exception</prop>
            -->
        </props>
    </property>
</bean>

配置说明:

proxyInterfaces
target
transactionManager
transactionAttributes
prop.key

事务行为:

PROPAGATION
ISOLATION
readOnly
-Exception
+Exception

2、演示案例

@Service
public class UserAccountServiceImpl01 extends JdbcDaoSupport implements UserAccountService01 {
    @Override
    public void remittance(String remitTer, String receiver, int money) {
        outMoney(remitTer,money);
        System.out.println(1/0);
        innerMoney(receiver,money);
    }
    private void outMoney (String remitTer, int money){
        String outSql = "update user_account set money = money - ? where username = ?";
        this.getJdbcTemplate().update(outSql, money ,remitTer);
    }
    private void innerMoney (String receiver, int money){
        String inSql = "update user_account set money = money + ? where username = ?";
        this.getJdbcTemplate().update(inSql, money,receiver);
    }
}

3、测试代码

public class Tx_Test_02 {
    @Test
    public void test1 (){
        String xmlPath = "spring-jdbc-tx-02.xml";
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlPath);
        UserAccountService01 accountService = (UserAccountService01)
                                    context.getBean("proxyAccountService");
        accountService.remittance("jack","tom",1000);
    }
}

四、XML配置事务

首先配置事务管理器,然后配置事务属性,最后基于AOP编程配置事务切入点。

1、核心配置

<!-- 配置事物管理器 -->
<bean id="txManager"
      class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>
<!-- 配置转账接口 -->
<bean id="userAccountService01"
      class="com.spring.mvc.service.impl.UserAccountServiceImpl01">
    <property name="jdbcTemplate" ref="jdbcTemplate" />
</bean>
<!-- 配置事物详情 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
        <tx:method name="remittance"
                   propagation="REQUIRED"
                   isolation="DEFAULT"/>
    </tx:attributes>
</tx:advice>
<!-- 事务切入点,基于AOP编程 -->
<aop:config>
    <aop:advisor
         advice-ref="txAdvice"
         pointcut="execution(* com.spring.mvc.service.UserAccountService01.*(..))"/>
</aop:config>

五、基于事务注解

配置事务管理器,并启动事务注解的支持,在目标类或目标方法添加 @Transactional 核心注解即可。

1、核心配置

<!-- 配置事物管理器 -->
<bean id="txManager"
      class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>
<!-- 支持事务注解 -->
<tx:annotation-driven transaction-manager="txManager" />

2、注解用法

注解写在接口方法上,或者接口实现的方法上效果一样。

public interface UserAccountService02 {
    @Transactional(rollbackFor = Exception.class)
    void remittance(String remitTer, String receiver, int money) ;
}

六、源代码地址

GitHub·地址
https://github.com/cicadasmile/spring-mvc-parent
GitEE·地址
https://gitee.com/cicadasmile/spring-mvc-parent

YNvuq2m.png!web


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK