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("转账成功!");
    }

 

 

posted @ 2019-11-04 17:41  梅川酷子灬  阅读(142)  评论(0编辑  收藏  举报