七、spring学习之事物管理器

七、spring学习之事物管理器

一、spring事务简述

* spring中的事务管理,是借助spring的aop实现的
* 使用spring的事务管理:导入 spring-tx

事务管理器 : PlaformTransactionManager (接口)
1.DataSourceTransactionManager :对jdbc操作的事务控制(jdbcTemplate,mybatis)
2.HibernateTransactionManager :对hibernate操作的事务控制
3.JpaTransactionManager :对jpa操作的事务控制
aop处理方式
1.定义了一个处理事务的切面类
*即事务管理器
2.将切面类(事务管理器)交给spring容器管理
3.配置事务管理的aop

二、声明事务的流程:

 1.声明事务管理器、并交给spring管理 使用bean标签结合id、class属性即可,id一般默认transactionManager。
 2.tx:advice 配置事务的通知引用事务管理器,
       属性: 
       id :事务通知的唯一标识
       transaction-manager:引用的事务管理器,当事物管理器id为默认的transactionManager,此处的引用可不写
 3.配置事务的属性 主要配置的有三个
                1)propagation: 传播行为 常用的两个 REQUIRED  SUPPORTS
                2)read-only:   是否只读 配置可以提高查询效率 true只读 false非只读
                3)name :        方法名称 为不同的service方法引入不同的事务通知
                                         可以支持通配符的写法(*:代表任意字符串)

 4.配置aop:config 将事务通知的引入到切入点
            1)、aop:pointcut  设置切入点表达式
            2)、aop:advisor   将通知配置到切入点上
                 属性:
                 advice-ref    事务通知的引用
                 pointcut-ref  切入点的引用

spring事务属性的类型
read-only:是否是只读事务。默认false,不只读。
isolation:指定事务的隔离级别。默认值是使用数据库的默认隔离级别。
propagation:指定事务的传播行为。
timeout:指定超时时间。默认值为:-1。永不超时。
rollback-for:用于指定一个异常,当执行产生该异常时,事务回滚。产生其他异常,事务不回滚。
没有默认值,任何异常都回滚。
no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时,事务回
滚。没有默认值,任何异常都回滚。

三:事物的特性简述

1.事务的定义:事务是指多个操作单元组成的合集,多个单元操作是整体不可分割的,要么都操作不成功,要么都成功。其必须遵循四个原则(ACID)。

原子性(Atomicity):即事务是不可分割的最小工作单元,事务内的操作要么全做,要么全不做;
一致性(Consistency):在事务执行前数据库的数据处于正确的状态,而事务执行完成后数据库的数据还是应该处于正确的状态,即数据完整性约束没有被破坏;如银行转帐,A转帐给B,必须保证A的钱一定转给B,一定不会出现A的钱转了但B没收到,否则数据库的数据就处于不一致(不正确)的状态。
隔离性(Isolation):并发事务执行之间互不影响,在一个事务内部的操作对其他事务是不产生影响,这需要事务隔离级别来指定隔离性;
持久性(Durability):事务一旦执行成功,它对数据库的数据的改变必须是永久的,不会因比如遇到系统故障或断电造成数据不一致或丢失。

2Spring事务隔离级别:spring有五大隔离级别,其在TransactionDefinition接口中定义。看源码可知,其默isolation_default(底层数据库默认级别),其他四个隔离级别跟数据库隔离级别一致。

TablesAre
ISOLATION_DEFAULT用底层数据库的默认隔离级别,数据库管理员设置什么就是什么
ISOLATION_READ_UNCOMMITTED(读未提交)最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读)
ISOLATION_READ_COMMITTED(读提交)一个事务提交后才能被其他事务读取到(该隔离级别禁止其他事务读取到未提交事务的数据、所以还是会造成幻读、不可重复读)、解决脏读,Oracle、sql server默认级别
ISOLATION_REPEATABLE_READ(可重复读)可重复读,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(该隔离基本可防止脏读,不可重复读(重点在修改),但会出现幻读(重点在增加与删除))(MySql默认级别,更改可通过set transaction isolation level 级别)
ISOLATION_SERIALIZABLE(序列化)代价最高最可靠的隔离级别(该隔离级别能防止脏读、不可重复读、幻读)

关于读问题

读问题说明
丢失更新*两个事务同时更新一行数据,最后一个事务的更新会覆盖掉第一个事务的更新,从而导致第一个事务更新的数据丢失,这是由于没有加锁造成的;
幻读同样的事务操作过程中,不同时间段多次(不同事务)读取同一数据,读取到的内容不一致(一般是行数变多或变少)。
脏读一个事务读取到另外一个未提及事务的内容,即为脏读。
不可重复读幻读的重点在于插入与删除,即第二次查询会发现比第一次查询数据变少或者变多了,以至于给人一种幻象一样,而不可重复读重点在于修改,即第二次查询会发现查询结果比第一次查询结果不一致,即第一次结果已经不可重现了。

数据库隔离级别越高,执行代价越高,并发执行能力越差,因此在实际项目开发使用时要综合考虑,为了考虑并发性能一般使用提交读隔离级别,它能避免丢失更新和脏读,尽管不可重复读和幻读不能避免,但可以在可能出现的场合使用悲观锁或乐观锁来解决这些问题。
3spring中事物的传播行为(propagation:指定事务的传播行为)

传播行为含义
PROPAGATION_REQUIRED(XML文件中为REQUIRED)表示当前方法必须在一个具有事务的上下文中运行,如有客户端有事务在进行,那么被调用端将在该事务中运行,否则的话重新开启一个事务。(如果被调用端发生异常,那么调用端和被调用端事务都将回滚)
PROPAGATION_SUPPORTS(XML文件中为SUPPORTS)表示当前方法不必需要具有一个事务上下文,但是如果有一个事务的话,它也可以在这个事务中运行
PROPAGATION_MANDATORY(XML文件中为MANDATORY)表示当前方法必须在一个事务中运行,如果没有事务,将抛出异常
PROPAGATION_NESTED(XML文件中为NESTED)表示如果当前方法正有一个事务在运行中,则该方法应该运行在一个嵌套事务中,被嵌套的事务可以独立于被封装的事务中进行提交或者回滚。如果封装事务存在,并且外层事务抛出异常回滚,那么内层事务必须回滚,反之,内层事务并不影响外层事务。如果封装事务不存在,则同PROPAGATION_REQUIRED的一样
PROPAGATION_NEVER(XML文件中为NEVER)表示当方法务不应该在一个事务中运行,如果存在一个事务,则抛出异常
PROPAGATION_REQUIRES_NEW(XML文件中为REQUIRES_NEW)表示当前方法必须运行在它自己的事务中。一个新的事务将启动,而且如果有一个现有的事务在运行的话,则这个方法将在运行期被挂起,直到新的事务提交或者回滚才恢复执行。
PROPAGATION_NOT_SUPPORTED(XML文件中为NOT_SUPPORTED)表示该方法不应该在一个事务中运行。如果有一个事务正在运行,他将在运行期被挂起,直到这个事务提交或者回滚才恢复执行

4Spring事务支持
.spring提供了很多内置事务管理器,支持不同数据源。常见的有三大类

事务管理器支持的数据源
DataSourceTransactionManager:org.springframework.jdbc.datasource包下,数据源事务管理类,提供对单个javax.sql.DataSource数据源的事务管理,只要用于JDBC,Mybatis框架事务管理。
HibernateTransactionManagerorg.springframework.orm.hibernate3包下,数据源事务管理类,提供对单个org.hibernate.SessionFactory事务支持,用于集成Hibernate框架时的事务管理;注意:该事务管理器只支持Hibernate3+版本,且Spring3.0+版本只支持Hibernate 3.2+版本;
JtaTransactionManager位于org.springframework.transaction.jta包中,提供对分布式事务管理的支持,并将事务管理委托给Java EE应用服务器,或者自定义一个本地JTA事务管理器,嵌套到应用程序中。

PlatformTransactionManager接口定义如下

    public interface PlatformTransactionManager {  
             TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;//返回一个已经激活的事务或创建一个新的事务(具体由TransactionDefinition参数定义的事务属性决定),返回的TransactionStatus对象代表了当前事务的状态,其中该方法抛出TransactionException(未检查异常)表示事务由于某种原因失败。  
             void commit(TransactionStatus status) throws TransactionException;//用于提交TransactionStatus参数代表的事务。  
             void rollback(TransactionStatus status) throws TransactionException;//用于回滚TransactionStatus参数代表的事务。  

TransactionDefinition接口定义如下:

[java] view plain copy

    public interface TransactionDefinition {    
           int getPropagationBehavior();  //返回定义的事务传播行为  
           int getIsolationLevel(); //返回事务隔离级别  
           int getTimeout();  //返回定义的事务超时时间  
           boolean isReadOnly();  //返回定义的事务是否是只读的  
           String getName();  //返回事务名称  
    }   

TransactionStatus接口定义如下:

public interface TransactionStatus extends SavepointManager {    
       boolean isNewTransaction();  //返回当前事务是否是新的事务  
       boolean hasSavepoint();  //返回当前事务是否有保存点  
       void setRollbackOnly();  //设置事务回滚  
       boolean isRollbackOnly();  //设置当前事务是否应该回滚  
       void flush();  //用于刷新底层会话中的修改到数据库,一般用于刷新如Hibernate/JPA的会话,可能对如JDBC类型的事务无任何影响;  
       boolean isCompleted();  //返回事务是否完成  
}   

四、基于xml的事物管理

<?xml version="1.0" encoding="UTF-8"?>
<!-- 导入约束 :xsd -->
<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
        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
        ">

    <!-- 创建Service交给spring管理 -->
    <bean id="accountService" class="cn.it.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
    </bean>
    <!-- 创建Dao交给spring管理 -->
    <bean id="accountDao" class="cn.it.dao.impl.AccountDaoImpl2">
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
    </bean>
    <!-- 配置jdbcTemplate -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 注入基本元素,配置spring内置连接池对象 -->
    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <!-- 基本元素赋值 -->
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql:///springdb"></property>
    </bean>



    <!-- 一、配置事务管理器 -->
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
     <!-- 二、配置事务通知 : tx的名称空间 
                    对定位到的方法,添加不同的事务支持情况
                1)id:事务通知的唯一标识
                2)transaction-manager:引用事务管理器的id,
                                  当事务管理器id采用默认的transactionManager时可以不写
     -->

    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!--三、配置service实现类中,每一个方法对事务的支持情况
                    1)propagation:传播行为
                    2)read-only:是否只读
                    3)name : 方法名称
                         可以支持通配符的写法(*:代表任意字符串)
            -->

            <!-- 方式一 -->
            <tx:method name="*"  propagation="REQUIRED" read-only="false" />
            <tx:method name="find*"  propagation="SUPPORTS" read-only="true" />
            <!-- 方式二 -->
            <!--            
            <tx:method name="save*" propagation="REQUIRED" read-only="false" />
            <tx:method name="update*" propagation="REQUIRED" read-only="false" />
            <tx:method name="delete*" propagation="REQUIRED" read-only="false" />
            <tx:method name="insert*" propagation="REQUIRED" read-only="false" />
            <tx:method name="find*" propagation="SUPPORTS" read-only="true" />
            <tx:method name="get*" propagation="SUPPORTS" read-only="true" /> -->
        </tx:attributes>
    </tx:advice>



    <!-- 四、配置aop:定位需要添加事务的类和方法 -->
    <aop:config>
           <!-- 定义切入点 -->
           <aop:pointcut expression="execution(* cn.it.service.impl.*.*(..))" id="pt" />
           <!-- 定义事务通知 将切入点和事务通知联系起来 -->
           <aop:advisor advice-ref="txAdvice" pointcut-ref="pt" />
    </aop:config>

</beans>

五、基于xml结合anno|注解的事物管理

1、开启对事物注解的支持:tx:annotation-driven
2、配置事务管理器,交给spring管理
3、在各个service类和方法上绑定通知
一般用于涉及增删改
@Transactional(propagation=Propagation.REQUIRD,readOnly=false)
一般用于查询
@Transactional(propagation=Propagation.REQUIRD,readOnly=true)
使用原则:事务通知的配置遵循就近原则,可以配置在类上,表示该类采用的通知,也可以配置在方法上,表示该方法采用的通知,所以我们可以在类上配置该类使用较多的通知类型,然后在使用其他通知类型的方法上单独配置不同的通知。

配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!-- 导入约束 :xsd -->
<!-- 导入约束 :xsd -->
<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
        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
        ">
    <!-- 开启对注解的支持 IOC AOP 事物tx-->
    <!-- 开启包扫描 -->
    <context:component-scan base-package="cn.it"></context:component-scan>
    <!-- 开启aop注解支持 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    <!-- 开启对事物注解的支持 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>

    <!-- 二、配置事务管理器 -->
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 三、在各个service类和方法上绑定通知 -->

    <!-- 配置jdbcTemplate -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 注入基本元素,配置dbcp连接池对象 -->
    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <!-- 基本元素赋值 -->
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql:///springdb"></property>
    </bean>

    <!-- 配置c3p0连接池 -->
 <!--   <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="root"></property>
        <property name="password" value="111111"></property>
        <property name="jdbcUrl" value="jdbc:mysql:///springdb"></property>
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
     </bean>  -->

      <!-- 配置spring内置连接池对象 -->
 <!--  <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql:///springdb"></property>
       </bean> -->

</beans>

service

package cn.it.service.impl;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import cn.it.dao.AccountDao;
import cn.it.domain.Account;
import cn.it.service.AccountService;
/**
 * 配置事务
 *      @Transactional
 *          propagation : 传播行为
 *          readOnly    :是否只读
 *  * 可以配置到类上:表明此类当中的所有方法都具有此事务
 *  * 可以配置到方法上:表明此方法具有此事务
 *          (就近原则)
 */
@Service("accountService")
@Transactional( propagation=Propagation.REQUIRED,readOnly=false)
public class AccountServiceImpl implements AccountService {
    @Autowired
    private AccountDao accountDao;

    /**
     * 转账:
     * 从sourceName账户转出 money 元 给 targetName账户
     */
    public void transfer(String sourceName, String targetName, float money) {

        Account sourceAcc = findAccountByName(sourceName);
        Account targetAcc = findAccountByName(targetName);
        sourceAcc.setMoney(sourceAcc.getMoney() + money);
        targetAcc.setMoney(targetAcc.getMoney() - money);
        updateAccount(sourceAcc);
        //用于测试事务
        //int i = 1 / 0;     
        updateAccount(targetAcc);


    }
    /**
     * 根据用户名修改账户金额
     */
    @Override
    public int updateAccount(Account account) {
        return accountDao.updateAccount(account);
    }

    /**
     * 根据用户名查找账户
     */
    @Transactional(propagation=Propagation.REQUIRED,readOnly=true)
    public Account findAccountByName(String name) {
        return accountDao.findAccountByName(name);
    }

}

六、纯anno|注解的事物处理

1.@EnableTransactionManagement:开启对事务管理的注解支持
2.@Bean 创建事物管理器,交给spring管理
3.@Transactional 在service层类及方法上绑定通知类型
* propagation : 传播行为
* readOnly :是否只读

我们需要定义一个配置类

/**
 * @EnableTransactionManagement:开启对事务管理的注解支持
 */
@Configuration
@ComponentScan("cn.it")
@Import(jdbcConfig.class)
@EnableTransactionManagement
public class SpringConfig {
    /**
     * 创建事物管理器,交给spring管理
     * 
     */
    @Bean
    public PlatformTransactionManager TransactionManager(DataSource dataSource) {
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值