九、Spring事务

1.什么是事务?

逻辑上的一组操作,组成这组操作的各个单元,要么全都成功,要么全都失败。

2.事务的特性?

  • 原子性:事务不可分割
  • 一致性:事务执行前后数据完整性保持一致
  • 隔离性:一个事务的执行不应该受到其他事务的干扰
  • 持久性:一旦事务结束,数据就持久化到数据库

3.如果不考虑隔离性会引发安全性问题?

  • 读问题:
  1. 脏读 :一个事务读到另一个事务未提交的数据
  2. 不可重复读 :一个事务读到另一个事务已经提交的update的数据,导致一个事务中多次查询结果不一致
  3. 虚读、幻读 :一个事务读到另一个事务已经提交的insert的数据,导致一个事务中多次查询结果不一致
  • 写问题:
  1. 丢失更新

4.如何解决读问题?

  • 设置事务的隔离级别
  1. Read uncommitted :未提交读,任何读问题解决不了。
  2. Read committed :已提交读,解决脏读,但是不可重复读和虚读有可能发生。
  3. Repeatable read :重复读,解决脏读和不可重复读,但是虚读有可能发生。
  4. Serializable :解决所有读问题。

5.Spring的事务管理的API

  • PlatformTransactionManager

PlatformTransactionManage:平台事务管理器 是一个接口,下面有两个实现类:

  1. DataSourceTransactionManager
    底层使用JDBC管理事务
  2. HibernateTransactionManager
    底层使用Hibernate管理事务
  • TransactionDefinition

事务定义信息:用于定义事务的相关的信息,隔离级别、超时信息、传播行为、是否只读

  • TransactionStatus

事务状态:用于记录在事务管理过程中,事务的状态的对象

  • 事务管理的API的关系
  1. 在事务管理过程中,产生各种状态,将这些状态的信息记录到事务状态的对象中。
  2. Spring进行事务管理的时候,首先平台事务管理器根据事务定义信息进行事务的管理,

6.Spring的事务的七种传播行为

  • 什么是传播行为?

一个业务方法当中,调用另一个业务的方法

  • 保证多个操作在同一个事务中:
  1. PROPAGATION_REQUIRED

默认值,如果A中有事务,使用A中的事务,如果A没有,创建一个新的事务,将操作包含进来

  1. PROPAGATION_SUPPORTS

支持事务,如果A中有事务,使用A中的事务。如果A没有事务,不使用事务。

  1. PROPAGATION_MANDATORY

如果A中有事务,使用A中的事务。如果A没有事务,抛出异常。

  • 保证多个操作不在同一个事务中
  1. PROPAGATION_REQUIRES_NEW

如果A中有事务,将A的事务挂起(暂停),创建新事务,只包含自身操作。如果A中没有事务,创建一个新事务,包含自身操作。

  1. PROPAGATION_NOT_SUPPORTED

如果A中有事务,将A的事务挂起。不使用事务管理。

  1. PROPAGATION_NEVER

如果A中有事务,报异常。

  • 嵌套式事务
    PROPAGATION_NESTED

嵌套事务,如果A中有事务,按照A的事务执行,执行完成后,设置一个保存点;
执行B中的操作,如果没有异常,执行通过,如果有异常,可以选择回滚到最初始位置,也可以回滚到保存点

7.Spring事务编程(注解形式)

  • 定义Dao接口和Dao实现类:
//接口
public interface AccountDao {
    /*加钱*/
    public void addMoney(String name, Double money);
    /*减钱*/
    public void minusMoney(String name, Double money);
}
//实现类
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {   
    @Override
    public void addMoney(String name, Double money) {
        this.getJdbcTemplate().update("update account set money= money+? where name=?",money,name);
    }
    @Override
    public void minusMoney(String name, Double money) {
        this.getJdbcTemplate().update("update account set money=money-? where name =?",money,name);
    }
}
  • 定义业务接口和业务实现类
//接口
public interface AccountService {
    public void transferMoney(String from, String to, Double money);
}
//实现类
@Transactional /*事务注解*/
public class AccountServiceImpl implements AccountService {
    private AccountDao accountDao;
    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }
    @Override
    public void transferMoney(String from, String to, Double money) {
        accountDao.minusMoney(from, money);
        //int i=1/0;
        accountDao.addMoney(to, money);
    }
}
  • jdbc.properties
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///spring
jdbc.username=root
jdbc.password=123
  • applicationContext.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 ">
    
    <!--加载属性文件-->
    <context:property-placeholder location="classpath:jdbc.properties"/>
    <!--druid-->
    <bean id="druid" class="com.alibaba.druid.pool.DruidDataSource">
        <!--key值 不能和name 一样-->
        <property name="driverClassName" value="${jdbc.driverClass}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    <!--AccoutDao-->
    <bean id="accoutDao" class="com.itlike.demo4.AccountDaoImpl">
        <property name="dataSource" ref="druid"></property>
    </bean>
    <!--AccoutService-->
    <bean id="accoutService" class="com.itlike.demo4.AccountServiceImpl">
        <property name="accountDao" ref="accoutDao"></property>
    </bean>
    <!--配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="druid"/>
    </bean>
    <!--开启注解  增强-->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
  • 定义测试类:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AccountServiceTest {
    @Resource(name="accoutService")
    private AccountService accountService;
    @Test
    public void Test(){
        accountService.transferMoney("zs","ls",100d);
    }
}

运行测试类,当程序运行异常时,就会执行事务回滚!

猜你喜欢

转载自blog.csdn.net/A15815635741/article/details/84350753