zoukankan      html  css  js  c++  java
  • 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);
        }
     
  • 相关阅读:
    省选模拟47 题解
    省选模拟46 题解
    死磕 java集合之PriorityQueue源码分析
    拜托,面试别再问我堆(排序)了!
    死磕 java集合之ConcurrentSkipListSet源码分析——Set大汇总
    死磕 java集合之CopyOnWriteArraySet源码分析——内含巧妙设计
    死磕 java集合之TreeSet源码分析
    死磕 java集合之LinkedHashSet源码分析
    死磕 java集合之HashSet源码分析
    死磕 java集合之ConcurrentSkipListMap源码分析——发现个bug
  • 原文地址:https://www.cnblogs.com/zhangzhixi/p/14230072.html
Copyright © 2011-2022 走看看