Spring(五)—— Spring对事务的管理

回顾

先来回顾一下事务的相关知识吧;

事务的概念:

  • 事务是一种SQL 语句的执行,要么成功,要么失败,不能出现部分成功,部分失败,具有原子性;
  • 事务所有的SQL全部执行完,才能提交(commit)事务,将数据存储到磁盘;
  • 事务执行过程中只要有SQL出现问题,那么事务就必须回滚到最初的状态;

事务的特征:ACID

  • A:事务的原子性;事务是一个不可分割的整体,事务必须具有原子特征,事务操作时,要么全部执行,要么全部不执行;
  • C:事务的一致性;一个事务执行之前和之后,数据库数据必须保持一致性状态;(比如银行转账时,金额总和不变);
  • I:事务的隔离性;当两个或者多个事务并发执行时,为保证数据的安全,将一个事务内的操作和其他事务隔离起来,不被其他正在执行的事务看到;
  • D:事务的持久性;事务完成之后,数据库保证数据库中的数据修改是永久性的,即使数据库出现故障,也能保证恢复数据;

事务隔离性使用不当会照成脏数据问题:

  • 脏读:一个事务读取了另一个事务未提交的数据;(当事务A和事务B并发操作时,事务A更新数据后,事务B读取到A未提交的数据,此时事务A回滚,事务B就读取到了事务A未提交的无效的脏数据);
  • 不可重复读:一个事务操作导致另一个事务读取到前后两次不同的数据;(例如,事务A和事务B进行并发操作,事务B查询读取数据后,事务A更新操作事务B读取的数据,此时事务B继续查询数据,会发现自己前后两次读取的数据结果不一致);
  • 幻读:一个事务的操作导致另一个事务前后两次查询的结果的数量不同;(例如,事务A和事务B进行并发操作,当事务B查询读取数据后,事务A操作新增或删除了一条满足事务B的条件的数据,此时事务B再次进行查询到前一次不存在的数据或者前一次没有的数据),(事务B读取了事务A新增的内容或者读不到事务A删除的数据);

在JDBC中,定义了以下5种事务隔离级别:

  • TRANSACTION_NONE。 表示不支持事务
  • TRANSACTION_READ_UNCOMMITTED。未提交读。说明在提交前一个事务可以看到另一个事务的变化。这样读”脏”数据,不可重复读和虚读都是被允许的。
  • TRANSACTION_READ_COMMITTED。已提交读。说明读取未提交的数据是不允许的。这个级别仍然允许不可重复读和虚读产生。
  • TRANSACTION_REPEATABLE_READ。可重复读。说明事务保证能够再次读取相同的数据而不会失败,但虚读仍然会出现。
  • TRANSACTION_SERIALIZABLE。可序列化/串行化。是最高的事务级别,它防止读脏数据,不可重复读和虚读。

现在开始看看Spring是如何管理事务的吧,它有两种实现方式,即通过配置或注解实现;

Spring对事务管理的两种实现方式

下面写的都是伪代码啊,重在Spring对事务的管理是怎么实现的:

通过配置实现

使用步骤:

  1. 引入依赖;
  2. 创建相关的类;
  3. 创建配置文件;
  4. 使用;

一、引入依赖;
和前面几节用的依赖一样,略;

二、创建类

里面是伪代码,并没有进行真正的数据库操作;

public class StudentDao {
    //插入多个学生是需要同时成功的,这就需要借助事务处理
    public void add() {
        //添加多个学生
        System.out.println("事务处理中");
        System.out.println("添加学生的方法");
    }
}

三、创建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: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/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--配置数据源 通过连接池c3p0来操作-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!--配置数据连接的核心配置-->
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mybatis"/>
        <property name="user" value="root"/>
        <property name="password" value="123456"/>
    </bean>

    <!--第一步 配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入dataSource-->
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--第二步 配置事务增强(AOP)即把事务当增强来处理-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--事务操作-->
        <tx:attributes>
            <!--设置进行事务操作的方法匹配 -->
            <!--name标签:匹配方法 add*: 所有的以add开头的方法都要进行事务操作-->
            <tx:method name="add*"/>
        </tx:attributes>
    </tx:advice>

    <!--第三步:配置切面-->
    <aop:config>
        <!--切入点 实际需要被增强的方法-->
        <aop:pointcut id="pointcut" expression="execution(* com.tulun7.dao.StudentDao.add(..))"/>
        <!--配置切面 将切入点进行增强的过程-->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
    </aop:config>

    <!--创建StudentDao对象,这个时候只要调用该对象的方法,就会进行事务处理-->
    <bean id="studentDao" class="com.tulun7.dao.StudentDao"/>
</beans>

四、使用

public class TestDemo1 {
    @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("事务/spring-transaction.xml");
        StudentDao studentDao = (StudentDao) context.getBean("studentDao");
        studentDao.add();
    }
}

在这里插入图片描述

通过注解实现

注解实现就更简单了,所以说在Spring里面更推荐使用注解;

使用步骤:

  1. 引入依赖;
  2. 创建相关的类;
  3. 创建配置文件;
  4. 使用;

一、引入依赖

和前面几节用的依赖一样,不过需要注意的是,因为这是使用注解实现,所以对版本的要求比较高,以前我引入的依赖都是 4.1.7 版本的,然后我写完它一直报错,我检查了几遍觉得没错啊,但就是报错,最后搜博客,有人说是包没引,但需要的就这些jar包,也没错,最后有博主说,是版本问题,最后我将 4.1.7 改成 4.3.9 就对了,所以注意这里需要改版本号;

二、创建相关的类

还是一样,只不过这里需要添加注解@Transactional,如果需要对这个类进行事务操作,将@Transactional添加到类前面就可以了,这里我只需要对这个方法进行事务操作,所以我就只添加在了add方法前面:

public class StudentDao1 {
    @Transactional
    public void add() {
        //添加多个学生
        System.out.println("事务处理中");
        System.out.println("添加学生的方法");
    }
}

三、创建配置文件

<?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" xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!--配置数据源 通过连接池c3p0来操作-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!--配置数据连接的核心配置-->
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mybatis"/>
        <property name="user" value="root"/>
        <property name="password" value="123456"/>
    </bean>

    <!--第一步 配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入dataSource-->
        <property name="dataSource" ref="dataSource"/>
    </bean>


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

    <!--第三步 在对应的类或者方法上面添加注解@Transactional-->

    <!--创建StudentDao对象,这个时候只要调用该对象的方法-->
    <bean id="studentDao" class="com.tulun7.dao.StudentDao1"/>

</beans>

四、使用

public class TestDemo2 {
    @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("事务/注解实现/spring.xml");
        StudentDao1 studentDao1 = (StudentDao1) context.getBean("studentDao");
        studentDao1.add();
    }
}

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章