• Spring事务终极版...


    1.什么是事务

      事务(TRANSACTION) 是作为单个逻辑工作单元执行的一系列操作。

      多个操作作为一个整体向系统提交,要么都执行,要么都不执行

      事务是一个无可再分的逻辑单元

    2.事务的特性

      四个属性,简称ACDI属性

      原子性(Atomicity)

        事务是一个完整的操作,事务的各个操作都是不可再分的,要么都执行,要么都不执行

      一致性(Consistency)

        当事务完成后,数据必须处于一致性

      隔离性(Isolation)

        并发事务之间相互隔离,独立,他不应以任何形式依赖于或影响其他事务

      持久性(Durability)

        事务完成后,他对数据的修改是永久性的;

    3.隔离问题

      脏读

        一个事务读到另一个事务没有提交的数据

      不可重复读

        一个事务读到另一个事务已经提交的数据(正常现象,主要发生在update)

      幻读(虚读)

        一个事务读到另一个事务已经提交的数据(正常现象,主要发生在insert)

    4.隔离级别

      read uncommitted:

        读未提交。存在3个问题(脏读,可重复读,虚读)

      read committed:

        读已提交。解决脏读,存在2个问题(可重复读,虚读)

      repeatable read:

        可重复读。解决:脏读、不可重复读,存在1个问题。(虚读)

      serializable :

        串行化。都解决,单事务。

      注意:这里是以级别从低到高排列的,不过他们的效率却是以高到低的,(一般使用第二、三个)

    5.保存点

      适用于多个事务都需要提交,不过有必须提交的事务,有的事务可提交

      需求:AB(必须),CD(可选)

        Connection conn = null;

        Savepoint savepoint = null;  //保存点,记录操作的当前位置,之后可以回滚到指定的位置。(可以回滚一部分)

        try{

          //1 获得连接

          conn = ...;

          //2 开启事务

          conn.setAutoCommit(false);

          A

          B

         //设置一个保存点

          savepoint = conn.setSavepoint();

          C

          D

          //3 提交事务

          conn.commit();

        } catche(){

          if(savepoint != null){   //CD异常

             // 回滚到CD之前

             conn.rollback(savepoint);

             // 提交AB

             conn.commit();

          } else{   //AB异常

             // 回滚AB

             conn.rollback();

          }

        }

    6.转账案例:(使用事务的代理工厂)

      需求:

        A账户给B账户转账,A账户减多少钱,B账户就需要增加多少钱

        若出现异常,事务回滚到事务发生之前的状态

      数据库表:

      

       导入依赖:(这里的Spring-jdbc以来中包含jdbcTemplate)

        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-jdbc</artifactId>
          <version>5.1.5.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>5.1.32</version>
        </dependency>

      创建entity

    public class Student {
        private Integer stuid;
        private String stuname;
        private Integer age;
    
        public Integer getStuid() {
            return stuid;
        }
    
        public void setStuid(Integer stuid) {
            this.stuid = stuid;
        }
    
        public String getStuname() {
            return stuname;
        }
    
        public void setStuname(String stuname) {
            this.stuname = stuname;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }

      创建Dao

    public interface IStudentdao {
          //加年龄
        public int jiaage(Integer sum);
        //减年龄
        public int jianage(Integer sum);
    }

      创建Daoimpl(这里我使用的是注释实现jdbcTemplate)

    @Repository
    public class IStudentdaoimpl implements IStudentdao {
    
        @Resource
        private JdbcTemplate jdbcTemplate;
    
        @Override
        public int jiaage(Integer sum) {
            String sql="update student set age=age+? where stuid=1";
            int update = this.jdbcTemplate.update(sql, sum);
            return update;
        }
    
        @Override
        public int jianage(Integer sum) {
            String sql="update student set age=age-? where stuid=2";
            int update = this.jdbcTemplate.update(sql, sum);
            return update;
        }
    
    }

      创建Service(因为加钱减钱是一步操作,所以在这里整合为一个方法)

    public interface IStudentservice {
        //转账
        public int zhuanzhang();
    }

      创建Serviceimpl

    @Service("iStudentservice")
    public class IStudentserviceimpl implements IStudentservice {
    
        @Resource
        private IStudentdao iStudentdao;
    
        public IStudentdao getiStudentdao() {
            return iStudentdao;
        }
    
        public void setiStudentdao(IStudentdao iStudentdao) {
            this.iStudentdao = iStudentdao;
        }
    
    Propagation.REQUIRES_NEW)
        @Override
        public int zhuanzhang() {
    
            int jiaage = iStudentdao.jiaage(10);
    
            //模拟一个异常
            //int asd=5/0;
    
            int jianage = iStudentdao.jianage(10);
    
            return jianage+jiaage;
        }
    }

      数据源文件

    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/student?useUniCode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull
    jdbc.username=root
    jdbc.password=123

      大配置文件

    <?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:tx="http://www.springframework.org/schema/tx"
           xmlns:aop="http://www.springframework.org/schema/aop"
           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/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">
            <!--扫描注解-->
            <context:component-scan base-package="com.JdbcTemplate"/>
    
            <!--记载配置文件-->
            <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
    
            <!--DateSource模板
            DriverManagerDataSource:Spring默认的数据源
            数据源还有:c3p0   dbcp
            -->
            <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
                <property name="driverClassName" value="${jdbc.driver}"></property>
                <property name="url" value="${jdbc.url}"></property>
                <property name="username" value="${jdbc.username}"></property>
                <property name="password" value="${jdbc.password}"></property>
            </bean>
    
    
    
            <!--植入JdbcTemplate-->
            <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
                <property name="dataSource" ref="dataSource"></property>
            </bean>
            <!--配置Spring的事务管理器,默认在发生异常的情况下回滚,否则提交-->
            <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                <!--植入数据源-->
                <property name="dataSource" ref="dataSource"></property>
            </bean>
    
    
            <!--Spring事务的代理工厂-->
            <bean id="transactionFactory" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
            <!--指定事务管理器-->
                <property name="transactionManager" ref="transactionManager"></property>
            <!--目标对象-->
                <property name="target" ref="iStudentservice"></property>
            <!--设置方法-->
                <property name="transactionAttributes">
                    <props>
                <!--指定隔离级别和传播行为--> <prop key="zhuanzhang">ISOLATION_READ_COMMITTED,PROPAGATION_REQUIRES_NEW</prop> </props> </property> </bean> </beans>

      测试

    //工厂
        @Test
        public void shi(){
            IStudentservice stu = (IStudentservice)atc.getBean("transactionFactory");
            int zhuanzhang = stu.zhuanzhang();
            System.out.println("转账成功!");
        }

       修改Serviceimpl(模拟一个异常)

    @Service("iStudentservice")
    public class IStudentserviceimpl implements IStudentservice {
    
        @Resource
        private IStudentdao iStudentdao;
    
        public IStudentdao getiStudentdao() {
            return iStudentdao;
        }
    
        public void setiStudentdao(IStudentdao iStudentdao) {
            this.iStudentdao = iStudentdao;
        }
    
    
        @Transactional(isolation = Isolation.REPEATABLE_READ,propagation = Propagation.REQUIRES_NEW)
        @Override
        public int zhuanzhang() {
    
            int jiaage = iStudentdao.jiaage(10);
    
            //模拟一个异常
            int asd=5/0;
    
            int jianage = iStudentdao.jianage(10);
    
            return jianage+jiaage;
        }
    }

      继续测试

     

    7.使用Aop事务

      修改大配置文件

    <?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:tx="http://www.springframework.org/schema/tx"
           xmlns:aop="http://www.springframework.org/schema/aop"
           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/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">
            <!--扫描注解-->
            <context:component-scan base-package="com.JdbcTemplate"/>
    
            <!--记载配置文件-->
            <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
    
            <!--DateSource模板
            DriverManagerDataSource:Spring默认的数据源
            数据源还有:c3p0   dbcp
            -->
            <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
                <property name="driverClassName" value="${jdbc.driver}"></property>
                <property name="url" value="${jdbc.url}"></property>
                <property name="username" value="${jdbc.username}"></property>
                <property name="password" value="${jdbc.password}"></property>
            </bean>
    
    
    
            <!--植入JdbcTemplate-->
            <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
                <property name="dataSource" ref="dataSource"></property>
            </bean>
    <!--配置Spring的事务管理器,默认在发生异常的情况下回滚,否则提交-->
            <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                <!--植入数据源-->
                <property name="dataSource" ref="dataSource"></property>
            </bean>
    <!--AOP管理事务-->
    <tx:advice id="transactionAdvice" transaction-manager="transactionManager">
    <!--实现事务的方法-->
    <tx:attributes>
    <tx:method name="zhuan*" isolation="READ_COMMITTED" propagation="REQUIRES_NEW"/>
    </tx:attributes>
    </tx:advice>

    <aop:config>
    <aop:pointcut id="pointcut" expression="execution(* *..service.*.*(..))"/>
    <aop:advisor advice-ref="transactionAdvice" pointcut-ref="pointcut"/>
    </aop:config>

    </beans>

      测试

    //aop
        @Test
        public void aopshi(){
            IStudentservice stu = (IStudentservice)atc.getBean("iStudentservice");
            int zhuanzhang = stu.zhuanzhang();
            System.out.println("转账成功!");
        }

       模拟一个异常后

     8.使用注释实现事务

      修改大配置文件

    <?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:tx="http://www.springframework.org/schema/tx"
           xmlns:aop="http://www.springframework.org/schema/aop"
           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/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">
            <!--扫描注解-->
            <context:component-scan base-package="com.JdbcTemplate"/>
    
            <!--记载配置文件-->
            <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
    
            <!--DateSource模板
            DriverManagerDataSource:Spring默认的数据源
            数据源还有:c3p0   dbcp
            -->
            <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
                <property name="driverClassName" value="${jdbc.driver}"></property>
                <property name="url" value="${jdbc.url}"></property>
                <property name="username" value="${jdbc.username}"></property>
                <property name="password" value="${jdbc.password}"></property>
            </bean>
    
    
    
            <!--植入JdbcTemplate-->
            <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
                <property name="dataSource" ref="dataSource"></property>
            </bean>
    
    
            <!--配置Spring的事务管理器,默认在发生异常的情况下回滚,否则提交-->
            <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                <!--植入数据源-->
                <property name="dataSource" ref="dataSource"></property>
            </bean>
        <!--注解-->
        <tx:annotation-driven/>
    </beans>

      修改Serviceimpl文件

    @Service("iStudentservice")
    public class IStudentserviceimpl implements IStudentservice {
    
        @Resource
        private IStudentdao iStudentdao;
    
        public IStudentdao getiStudentdao() {
            return iStudentdao;
        }
    
        public void setiStudentdao(IStudentdao iStudentdao) {
            this.iStudentdao = iStudentdao;
        }
    
        @Transactional(isolation = Isolation.REPEATABLE_READ,propagation = Propagation.REQUIRES_NEW)
        @Override
        public int zhuanzhang() {
    
    
            int jiaage = iStudentdao.jiaage(10);
    
            //模拟一个异常
            int asd=5/0;
    
            int jianage = iStudentdao.jianage(10);
    
            return jianage+jiaage;
        }
    }

      测试

    //注解
        @Test
        public void zhujie(){
            IStudentservice stu = (IStudentservice)atc.getBean("iStudentservice");
            int zhuanzhang = stu.zhuanzhang();
            System.out.println("转账成功!");
        }

  • 相关阅读:
    洛谷P1352没有上司的舞会+树形二维DP
    高精度模板(从洛谷题解中骗来的
    Codeforces#398 &767C. Garland 树形求子节点的和
    LuoGu-P1122 最大子树和+树形dp入门
    HDU-3549Flow Problem 最大流模板题
    Codeforces Round #486 (Div. 3)988E. Divisibility by 25技巧暴力||更暴力的分类
    Codeforces Round #486 (Div. 3)988D. Points and Powers of Two
    数据结构&字符串:01字典树
    数据结构:可持久化平衡树
    数据结构:并查集-拆点
  • 原文地址:https://www.cnblogs.com/whtt/p/11793315.html
Copyright © 2020-2023  润新知