zoukankan      html  css  js  c++  java
  • 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("转账成功!");
        }

  • 相关阅读:
    现代软件工程 第一章 概论 第4题——邓琨
    现代软件工程 第一章 概论 第9题——邓琨
    现代软件工程 第一章 概论 第7题——张星星
    现代软件工程 第一章 概论 第5题——韩婧
    hdu 5821 Ball 贪心(多校)
    hdu 1074 Doing Homework 状压dp
    hdu 1074 Doing Homework 状压dp
    hdu 1069 Monkey and Banana LIS变形
    最长上升子序列的初步学习
    hdu 1024 Max Sum Plus Plus(m段最大子列和)
  • 原文地址:https://www.cnblogs.com/whtt/p/11793315.html
Copyright © 2011-2022 走看看