9、Spring中的事务

1、事务的ACID

  • 原子性
  • 一致性
  • 隔离性
    • 多个业务可能操作同一个资源,防止数据损坏
  • 持久性
    • 事务一旦提交,无论系统发生什么问题,结果都不会再被影响,被持久化的写到存储器中!

声明式事务: AOP

编程式事务:需要再代码中,进行事务的管理

spring处理事务需要做什么?

spring处理事务的模型,使用的步骤:都是固定的。把事务使用的信息提供给spring就可以了
1)事务内部提交,
回滚事务:使用的事务管理器对象,代替你完成commit, rollback
事务管理:器是一个接口和他的众多实现类。
接口:       PlatformTransactionManager. ,
定义了事务重要方法commit ,rollback
实现类:    spring把每--种数据库访问技术对应的事务处理类都创建好了。
mybatis访问数据库-
    - spring创建好的是DataSourceTransactionManager
hibernate访问数据库-
    - spring创建的是HibernateTransactionManager
怎么使用:
    你需要告诉spring你用是那种数据库的访问技术,怎么告诉spring呢?
声明数据库访问技术对于的事务管理器实现类,
在spring的配置文件中使用<bean>声明就可以了
例如,你要使用mybatis访问数据库,你应该在xml配置文件中配置:
<bean id=xxx"class="...DataSourceTransactionManacer" >
2)事务的传播行为:
控制业务方法是不是有事务的,是什么样的事务的。
7个传播行为,表示你的业务方法调用时,事务在方法之间是如果使用的。
    PROPAGATION_ REQUIRED;
    spring默认,没有事务就新建事务
    PROPAGATION_ REQUIRES_ NEW;
    总是新建一个事务,如果有事务就将当前事务挂起、
  PROPAGATION_ SUPPORTS;
    方法在执行时有事务也可以,没有事务也不影响-->查询操作
    以上三个需要掌握的
  PROPAGATION MANDATORY
  PROPAGATION_ NESTED
  PROPAGATION_ NEVER
  PROPAGATION_ NOT_ SUPPORTED

spring框架中处理事务的方案一、(使用配置文件):

-原始数据

1、一个业务接口:UserMapper

public interface UserMapper {
    // 查询所有用户
    List<User> getUserAll();

    // 添加用户
    int addUser(User user);

    // 删除用户
    int deleteUser(int id);
}

2、业务接口的实现类:UserMapperImpl

import com.zhixi.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;

import java.util.List;

public class UserMapperImpl implements UserMapper {
    private SqlSessionTemplate sqlSession;

    public void setSqlSession(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }

    /**
     * 查询所有用户
     */
    public List<User> getUserAll() {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        addUser(new User(5,"小五","123"));
        deleteUser(4);
return mapper.getUserAll();
    }

    /**
     * 添加用户
     */
    public int addUser(User user) {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.addUser(user);
    }

    /**
     * 根据用户id删除用户
     */
    public int deleteUser(int id) {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.deleteUser(id);
    }
}

3、UserMapper.xml定义CRUD方法

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zhixi.dao.UserMapper">


    <select id="getUserAll" resultType="user">
        select * from user;
    </select>

    <insert id="addUser" parameterType="user">
        insert into user (id,name,pwd) values (#{id},#{name},#{pwd});
    </insert>


    <delete id="deleteUser" parameterType="int">
        deletes from user where id = #{id}
    </delete>
</mapper>

4、测试文件

@Test
    public void test1() {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        UserMapper userMapper = context.getBean("userMapperImpl", UserMapper.class);

        List<User> userAll = userMapper.getUserAll();
        for (User user : userAll) {
            System.out.println(user);
        }
    }

说明:
  1.在UserMapperImpl类中查询用户方法的时候,增加了一个添加用户的方法,一个删除用户的方法、

  2.在xml中故意把删除方法写错,在以往经验,肯定会报错,删除4号用户不会执行成功,然后添加5号用户的方法会执行

3.通过上面的结果可以看到,添加用户的方法确实执行了,但是并不符合我们的事务业务规范,同时成功或者同时失败

4、spring的配置文件中添加spring事务

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd

        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd">

    <import resource="classpath:applicationContext.xml"/>

    <bean id="userMapperImpl" class="com.zhixi.dao.UserMapperImpl">
        <property name="sqlSession" ref="sqlSession"/>
    </bean>

    <!--开启Spring中的事务-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--对配置的连接mysql的jdbc执行事务操作-->
        <constructor-arg ref="datasource"/>
    </bean>


    <!--结合Aop实现事务的植入-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--
            给哪些方法配置事务:
             name:方法名称
                 1 )完整的方法名称,不带有包和类。
                 2 )方法可以使用通配符,*表示任意字符
             propagation : 传播行为,REQUIRED【默认】
             isolation:隔离级别,默认DEFAULT
             rollback-for:你指定的异常类名,全限定类名。发生异常一定回滚
         -->
        <tx:attributes>
            <tx:method name="addUser" propagation="REQUIRED" isolation="DEFAULT"/>
            <tx:method name="getUserAll" propagation="REQUIRED"/>
            <tx:method name="deleteUser" propagation="REQUIRED"/>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

    <!--配置事务切入-->
    <aop:config>
        <!--
            配置切入点表达式:指定哪些包中类, 要使用事务
            id:切入点表达式的名称,唯一值
            expression :切入点表达式, 指定哪些类要使用事务, aspectj会创建代理对象
        -->
        <aop:pointcut id="exPoint" expression="execution(* com.zhixi.dao.*.*(..))"/>
        <!--配置增强类-->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="exPoint"/>
    </aop:config>
</beans>

5、测试

  我们把数据还原到之前的、再来执行一下上面的语句,看下5号用户还会不会被添加成功了、

可以看到我们的sql确实执行错误了,但是5号用户并没有被添加成功,说明了事务成功!

 =====================================================================================================================================

我们再把delete语句修改正确,看是不是会执行:添加5号用户,删除4号用户:

执行成功!

spring框架中处理事务的方案二、(使用注解):

1 spring框架中提供的事务处理方案
2 1.适合中小项目使用的注解方案。
3 spring框架自己用aop实现给业务方法增加事务的功能,使 用@Transactional注解增加事务。
4 @Transactional注解是spring框架自己注解,放在public方法的上面,表示当前方法具有事务。
5 可以给注解的属性赋值,表示具体的隔离级别,传播行为,异常信息等等

  @Transactional的可选属性:

  • propagation:用于设置事务传播属性。该属性类型为Propagation 枚举,默认值为lsolation.REQUIRED
  • isolation:用于设置事务隔离级别。该属性类型为Isolation 枚举,默认值为lsolation.DEFAULT。
  • readOnly:用于设置该方法对数据库的操作是否是只读的。该属性为boolean, 默认值为true,在数据库查询时可设置为真

  • rollbackFor:表示方法抛出什么异常,才进行回滚、

  @Transactional注解的步骤:

1.需要在spring的xml配置文件声明事务管理器对象,和指定数据库:
    <!--开启Spring中的事务-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--对配置的连接mysql的jdbc执行事务操作-->
        <constructor-arg ref="datasource"/>
    </bean>
2.开启事务注解驱动,告诉spring框架,我要使用注解的方式管理事务。

<tx:advice id="transactionInterceptor" transaction-manager="transactionManager">

    </tx:advice>
<tx:annotation-driver id="transactionInterceptor" transaction-manager="transactionManager">    
</tx:advice>
 

spring使用aop机制,创建@Transactional所在的类 代理对象,给方法加入事务的功能。
spring给业务放法加入事务:
    在你的业务方法执行之前,先开启事务,在业务方法之后提交或回滚事务,使用aop的环绕通知:
Around("你要增加的事务功能的业务方法名称") 0bject myAround() { spring开启事务 try{ 业务代码 spring事务管理.commit(); }catch(Exception e){ spring事务管理.rollback(); } }

3、在方法上面加入@Transaction
  下面黄色背景的注解参数可以直接写成:@Transactional,或者可以直接把注解加到public类上,说明这个类下所有的方法都是被事务管理
   /**
     * 添加用户
     */
    @Transactional(
            propagation = Propagation.REQUIRED,
            isolation = Isolation.DEFAULT,
            readOnly = false,
            rollbackFor = {Exception.class}
    )
    public int addUser(User user) {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.addUser(user);
    }
 
原文地址:https://www.cnblogs.com/zhangzhixi/p/14230072.html