Spring 事务管理:

一、事务概念:

1、什么是事务?

  事务是应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消。也就是事务具有原子性,一个事务中的一系列的操作要么全部成功,要么一个都不做。 
  事务的结束有两种,当事务中的所以步骤全部成功执行时,事务提交。如果其中一个步骤失败,将发生回滚操作,撤消撤消之前到事务开始时的所以操作

2、事务的特性?

事务有四个特性:

  (1)原子性:事务是数据库的逻辑工作单位,事务中包含的各操作要么都做,要么都不做 

  (2)一致性:事 务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。因此当数据库只包含成功事务提交的结果时,就说数据库处于一致性状态。如果数据库系统 运行中发生故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是 不一致的状态。 

  (3)隔离性:一个事务的执行不能其它事务干扰。即一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。

  (4)持久性:指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其执行结果有任何影响。 

3、不考虑隔离性,产生的读问题?

  (1)脏读:脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。

  (2)不可重复读:事务A多次读取数据,同时事务B对该数据修改并且提交,导致事务A读到的数据不一致

  (3)幻读:在事务A读取数据的时候,事务B向数据中增加或者删除数据,导致事务读取的数据与原读取的数据不一致

4、解决读问题?

 设置隔离级别

二、Spring中的事务管理API

1、Spring事务管理方式

第一种方式:编程式事务管理(一般不用)

第二种方式:生命式事务管理

  (1)基于xml配置文件

  (2)基于注解方式

2、spring事务管理的api介绍

Spring事务管理高层抽象主要包括3个接口:

(1)PlatformTransactionManager:事务管理器

  Spring针对不同的dao层框架,提供接口不同的实现类:

spring事物管理日志_spring

  - 首先要配置事务管理器

  - 

(2)TransactionDefinition:事务定义信息(隔离、传播、超时、只读)

(3)TransactionStatus:事务具体运行状态

 三、搭建转账的环境

1、创建数据库,表account

  

spring事物管理日志_spring_02

2、创建service 和 dao 类,完成注入关系

 (1)service 又叫业务逻辑层

 (2)dao 层单纯对数据库操作,在 dao 层不添加业务

 (3)具体的需求,张三转账1000给李四

  张三少了1000

  李四多了1000

采用事务,解决了数据的不一致性等问题,采用声明式的事务管理方式(xml配置)和声明式的事务管理(注解方式)

- 声明式的事务管理方式(xml配置)

OrdersService.java



package com.itcast.service;

import cn.itcast.dao.OrdersDao;

public class OrdersService {

    private OrdersDao ordersDao;

    public void setOrdersDao(OrdersDao ordersDao) {
        this.ordersDao = ordersDao;
    }
    //调用Dao方法
    //业务逻辑层
    public void accountMoney(){
        //减少钱
        ordersDao.lessMoney();
        //增加层
        ordersDao.moreMoney();
    }
}



 

OrdersDao.java



package cn.itcast.dao;

import org.springframework.jdbc.core.JdbcTemplate;

public class OrdersDao {

    //注入属性JDBCTemplate
    private JdbcTemplate jdbcTemplate;

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
    
    //减少钱的方法
    public void lessMoney(){
        String sql="update account set salary=salary-? where username=?";
        jdbcTemplate.update(sql,1000,"zhangsan");
    }
    //增加钱的方法
    public void moreMoney(){
        String sql="update account set salary=salary+? where username=?";
        jdbcTemplate.update(sql,1000,"lisi");
    }
    
    
}



 

    使用AspectJ 的XML 配置声明式事务

    (1)配置事务管理器

    (2)配置事务增强器

    (3)配置AOP切面产生代理



<!-- 第一步:配置事务管理器 -->
        <bean id="transactionManager"  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <!-- 注入dataSource -->
            <property name="dataSource" ref="dataSource"></property>
        </bean>
        
        <!--第二步: 配置事务的增强 -->
        <tx:advice id="txadvice" transaction-manager="transactionManager">
            <!--做事务操作  -->
            <tx:attributes>
                <!-- 设置进行事务操作的方法匹配规则 -->
                <!-- 如果方法以account开头,都可以用事务规则 -->
                <tx:method name="account*" propagation="REQUIRED"/>
            </tx:attributes>
        </tx:advice>
        <!-- 第三步:配置AOP切面 -->
        <aop:config>
            <!-- 1、切入点 -->
            <aop:pointcut expression="execuyion(* com.itcast.service.OrdersService.*(..))" id="pointcut1"/>
            <!-- 2、切面 -->
            <aop:advisor advice-ref="txadvice" pointcut-ref="pointcut1"/>
        </aop:config>



完整XML文件:



<?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:content="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 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/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
        <!-- bean definitions here -->
    
        <!-- 配置  c3p0 -->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <!-- 注入属性值 -->
            <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
            <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
            <property name="user" value="root"></property>
            <property name="password" value="123"></property>
        </bean>
        
        <!-- 第一步:配置事务管理器 -->
        <bean id="transactionManager"  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <!-- 注入dataSource -->
            <property name="dataSource" ref="dataSource"></property>
        </bean>
        
        <!--第二步: 配置事务的增强 -->
        <tx:advice id="txadvice" transaction-manager="transactionManager">
            <!--做事务操作  -->
            <tx:attributes>
                <!-- 设置进行事务操作的方法匹配规则 -->
                <!-- 如果方法以account开头,都可以用事务规则 -->
                <tx:method name="account*" propagation="REQUIRED"/>
            </tx:attributes>
        </tx:advice>
        <!-- 第三步:配置AOP切面 -->
        <aop:config>
            <!-- 1、切入点 -->
            <aop:pointcut expression="execuyion(* com.itcast.service.OrdersService.*(..))" id="pointcut1"/>
            <!-- 2、切面 -->
            <aop:advisor advice-ref="txadvice" pointcut-ref="pointcut1"/>
        </aop:config>
        
        
        <!-- 配置对象 -->
        <bean id="ordersService" class="com.itcast.service.OrdersService">
            <!-- 注入dao 对象 -->
            <property name="ordersDao" ref="ordersDao"></property>
        </bean>
        <bean id="ordersDao" class="cn.itcast.dao.OrdersDao">
            <!-- 注入模板 -->
            <property name="jdbcTemplate" ref="jdbcTemplate"></property>
        </bean>
        
        
        <!-- 创建JdbcTemplate对象 -->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <!-- 把dataSource 传到 jdbcTemplate里面-->
            <property name="dataSource" ref="dataSource"></property>
        </bean>
        
        
</beans>



测试代码:



@Test
    public void test(){
        ApplicationContext context =new ClassPathXmlApplicationContext("orders.xml");
        OrdersService ordersService=(OrdersService) context.getBean("ordersService");
        ordersService.accountMoney();
    }



 

  - 声明式的事务管理方式(注解方式)

    (1)配置事务管理器

    (2)配置事务注解

    (3)在要使用事务的方法所在的类上面添加注解

XML配置:



<?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:content="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 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/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
        <!-- bean definitions here -->
    
        <!-- 配置  c3p0 -->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <!-- 注入属性值 -->
            <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
            <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
            <property name="user" value="root"></property>
            <property name="password" value="123"></property>
        </bean>
        
        <!--(1)配置事务管理器 -->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
        <!-- (2)开启事务的注解 -->
        <tx:annotation-driven transaction-manager="transactionManager"/>
        <!-- (3)在要使用事务的方法所在的类上面添加注解 -->
        
        
        
        <!-- 配置对象 -->
        <bean id="ordersService" class="com.itcast.service.OrdersService">
            <!-- 注入dao 对象 -->
            <property name="ordersDao" ref="ordersDao"></property>
        </bean>
        <bean id="ordersDao" class="cn.itcast.dao.OrdersDao">
            <!-- 注入模板 -->
            <property name="jdbcTemplate" ref="jdbcTemplate"></property>
        </bean>
        
        
        <!-- 创建JdbcTemplate对象 -->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <!-- 把dataSource 传到 jdbcTemplate里面-->
            <property name="dataSource" ref="dataSource"></property>
        </bean>
        
        
</beans>



OrdersService.java



package com.itcast.service;

import org.springframework.transaction.annotation.Transactional;

import cn.itcast.dao.OrdersDao;

@Transactional
public class OrdersService {

    private OrdersDao ordersDao;

    public void setOrdersDao(OrdersDao ordersDao) {
        this.ordersDao = ordersDao;
    }
    //调用Dao方法
    //业务逻辑层
    public void accountMoney(){
        //减少钱
        ordersDao.lessMoney();
        //如果发生异常,数据库自动回滚
        double i=2/0;
        //增加层
        ordersDao.moreMoney();
    }
}