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);
        }
     
  • 相关阅读:
    [洛谷P4248][AHOI2013]差异
    [洛谷P4070][SDOI2016]生成魔咒
    [洛谷P3979]遥远的国度
    [CF551E]GukiZ and GukiZiana
    [洛谷P4721]【模板】分治 FFT_求逆
    [洛谷P4721]【模板】分治 FFT
    一键智能抠图-原理与实现
    国防科技大学单张RGB-D图像预测物体对称性
    在OpenCV中使用色彩校正
    Deformable DETR DETR 存在收敛速度慢等缺陷。为了解决这些问题,本文可变形 DETR,其注意力模块仅关注于参考点附近的一小部分采样点作为注意力模块中的 key 元素。可变形 DETR 可以在比 DETR 少 9/10 的训练轮数下,达到更好的性能(尤其是在小目标上)。在 COCO 基准上的大量实验表明了该方法的有效性。
  • 原文地址:https://www.cnblogs.com/zhangzhixi/p/14230072.html
Copyright © 2011-2022 走看看