zoukankan      html  css  js  c++  java
  • 【从零开始学Spring笔记】Spring的事务管理

    大家可以关注作者的账号,关注从零开始学Spring笔记文集。也可以根据目录前往作者的博客园博客进行学习。本片文件将基于黑马程序员就业班视频进行学习以及资料的分享,并记录笔记和自己的看法。欢迎大家一起学习和讨论。

    【从零开始学Spring笔记】Spring学习路线

    什么事务

    事务:逻辑上的一组操作,组成这组操作的各个单元,要么全都成功,要么全都失败。

    事务的特性

    原子性:事务不可分割
    一致性:事务执行前后数据完整性保持一致
    隔离性:一个事务的执行不应该受到其他事务的干扰
    持久性:一旦事务结束,数据就持久化到数据库

    如果不考虑隔离性引发安全性问题

    • 读问题
      脏读 :一个事务读到另一个事务未提交的数据
      不可重复读 :一个事务读到另一个事务已经提交的update的数据,导致一个事务中多次查询结果不一致
      虚读、幻读 :一个事务读到另一个事务已经提交的insert的数据,导致一个事务中多次查询结果不一致。
    • 写问题
      丢失更新

    解决读问题

    设置事务的隔离级别

    • Read uncommitted :未提交读,任何读问题解决不了。(效率最高,但是安全性最低)
      Read committed :已提交读,解决脏读,但是不可重复读和虚读有可能发生。
      Repeatable read :重复读,解决脏读和不可重复读,但是虚读有可能发生。
      Serializable :解决所有读问题。

    Spring的事务管理的API

    PlatformTransactionManager:平台事务管理器

    平台事务管理器:接口,是Spring用于管理事务的真正的对象。

    • DataSourceTransactionManager :底层使用JDBC管理事务
      HibernateTransactionManager :底层使用Hibernate管理事务

    TransactionDefinition :事务定义信息

    事务定义:用于定义事务的相关的信息,隔离级别、超时信息、传播行为、是否只读

    TransactionStatus:事务的状态

    事务状态:用于记录在事务管理过程中,事务的状态的对象。

    事务管理的API的关系:
    Spring进行事务管理的时候,首先平台事务管理器根据事务定义信息进行事务的管理,在事务管理过程中,产生各种状态,将这些状态的信息记录到事务状态的对象中。

    Spring的传播行为

    在实际开发中,可能会遇到特别复杂的业务逻辑层,里面事务繁多,还可能会相互调用。这时候就需要事务的传播行为来进行管理。
    Spring中提供了七种事务的传播行为:
    保证多个操作在同一个事务中
    $color{red}{**}$PROPAGATION_REQUIRED :默认值,如果A中有事务,使用A中的事务,将操作包含进来。如果A没有,创建一个新的事务,将操作包含进来
    PROPAGATION_SUPPORTS :支持事务,如果A中有事务,使用A中的事务。如果A没有事务,不使用事务。
    PROPAGATION_MANDATORY :如果A中有事务,使用A中的事务。如果A没有事务,抛出异常。

    保证多个操作不在同一个事务中
    $color{red}{**}$PROPAGATION_REQUIRES_NEW :如果A中有事务,将A的事务挂起(暂停),创建新事务,只包含自身操作。如果A中没有事务,创建一个新事务,包含自身操作。
    PROPAGATION_NOT_SUPPORTED :如果A中有事务,将A的事务挂起。不使用事务管理。
    PROPAGATION_NEVER :如果A中有事务,报异常。

    嵌套式事务
    $color{red}{**}$PROPAGATION_NESTED :嵌套事务,如果A中有事务,按照A的事务执行,执行完成后,设置一个保存点,执行B中的操作,如果没有异常,执行通过,如果有异常,可以选择回滚到最初始位置,也可以回滚到保存点。

    搭建Spring的事务管理的环境

    第一步:创建 Senvice的接口和实现类

    package com.tyust.tx.demo1;
    
    public interface AccountService {
    		
    	public void transfer(String form, String to ,Double money);
    
    }
    
    package com.tyust.tx.demo1;
    
    public class AccountServiceImpl implements AccountService {
    	
    	private AccountDao accountDao; 
    
    	@Override
    	/**
    	 * from:传出账户
    	 * to:转入账户
    	 * money:金额
    	 */
    	public void transfer(String form, String to, Double money) {
    		accountDao.outMoney(form, money);
    		accountDao.inMoney(to, money);
    		
    	}
    
    	public void setAccountDao(AccountDao accountDao) {
    		this.accountDao = accountDao;
    	}
    
    	
    
    }
    

    第二步:创建 DAO的接口和实现类

    package com.tyust.tx.demo1;
    
    import org.springframework.jdbc.core.JdbcTemplate;
    
    public interface AccountDao {
    
    	public void outMoney(String from, double money);
    
    	public void inMoney(String to, double money);
    
    }
    package com.tyust.tx.demo1;
    
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.core.support.JdbcDaoSupport;
    
    public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
    
    	@Override
    	public void outMoney(String from, double money) {
    		this.getJdbcTemplate().update("update account set money = money - ? where name = ?", money, from);
    
    	}
    
    	@Override
    	public void inMoney(String to, double money) {
    		this.getJdbcTemplate().update("update account set money = money + ? where name = ?", money, to);
    
    	}
    
    }
    

    第三步:配置Senvice和DAO: 交给Spring管理

    <bean id = "accountDao" class="com.tyust.tx.demo1.AccountDaoImpl">
    	<property name="dataSource" ref="ds"></property>
    	</bean>
    	<bean id = "accountService" class="com.tyust.tx.demo1.AccountServiceImpl">
    	<property name="accountDao" ref="accountDao"></property>
    	</bean>
    

    第四步:配置连接池和JDBC的模板

     <context:property-placeholder location="classpath:jdbc.properties"/>
    	
    	<!-- 配置C3p0连接池 -->
    	<bean id="ds" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    		<property name="driverClass" value="${jdbc.driverClass}"></property>
    		<property name="jdbcUrl" value="${jdbc.url}"/>
    		<property name="user" value="${jdbc.username}"/>
    		<property name="password" value="${jdbc.password}"></property>
    	</bean>
    

    第五步:测试

    package com.tyust.tx.demo1;
    
    import javax.annotation.Resource;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:tx.xml")
    public class SpringDemo {
    	
    	@Resource(name = "accountService")
    	private AccountService accountService;
    	
    
    	@Test
    	public void demo() {
    		accountService.transfer("关羽", "张飞", 1000d);
    	}
    }
    

    输出结果

    为什么引入事务

    上例就是没有事务的实现方法,如果在transfer()方法中转出和转入之间存在异常,就会出现转出实现了,转入却没有实现,这在现实生活中是不允许的。所以需要事务的保障

    Spring的事务管理——编程式事务(需要手动编写代码)

    第一步:配置平台事务管理器

    
    	<!-- 配置事务平台管理器 -->
    	<bean id="transactionManager"
    		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    		<property name="dataSource" ref="dataSource"></property>
    	</bean>
    

    第二步:Spring 提供了事务管理的模板类

    <bean id="transactionTemplate"
    		class="org.springframework.transaction.support.TransactionTemplate">
    		<property name="transactionManager" ref="transactionManager"></property>
    	</bean>
    

    第三步:在业务层注入事务管理的模板

    //注入事务管理的模板
    	private TransactionTemplate transactionTemplate;
    
    </bean>
    	<bean id="accountService"
    		class="com.tyust.tx.demo1.AccountServiceImpl">
    		<property name="accountDao" ref="accountDao"></property>
    		<property name="transactionTemplate"
    			ref="transactionTemplate"></property>
    	</bean>
    

    第四步:编写事务管理的代码

    public void transfer(final String form,final String to, final Double money) {
    		
    		transactionTemplate.execute(new TransactionCallbackWithoutResult() {
    			
    			@Override
    			protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
    				accountDao.outMoney(form, money);
    				int i =1/0;
    				accountDao.inMoney(to, money);
    			}
    		});
    }
    

    第五步:测试
    发现并没有出现转出实现了,转入却没有实现的情况

    Spring的事务管理——声明式事务管理(通过配置实现)---AOP

    XML方式的声明式事务管理

    第一步:引入aop的开发包

    第二步:恢复转账环境
    把上一个例子添加的编辑事务代码全部删除
    第三步:配置事务管理器

    <bean id ="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    		<property name="dataSource" ref="dataSource"></property>
    	</bean>
    

    第四步:配置增强

            <!-- 配置事务的增强 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
    	<tx:attributes>
    	 <tx:method name="*" propagation="REQUIRED"/>
    	</tx:attributes>
    </tx:advice>
    

    事务管理规范
    <tx:method name="save" propagation="REQUIRED" isolation="DEFAULT"/>
    <tx:method name="update
    " propagation="REQUIRED" />
    <tx:method name="delete" propagation="REQUIRED" />
    <tx:method name="find
    " read-only="true"/>

    read-only:只读,不能增删改,只能查
    timeout:-1 ->一直有效

    第五步:AOP的配置

        <aop:config>
    	<aop:pointcut expression="execution(* com.tyust.tx.demo2.AccountServiceImpl.*(..) )" id="pointcut1"/>
    	<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
    </aop:config>
    

    第六步:测试
    发现并没有出现转出实现了,转入却没有实现的情况

    注解方式的声明式事务管理

    第一步:引入aop的开发包
    第二步:恢复转账环境
    第三步:配置事务管理器
    前三步和之前一样
    第四步:开启注解事务

    <tx:annotation-driven transaction-manager="transactionManager"/>
    

    第五步:在业务层添加注解

    只需要在AccountServiceImpl类上面加@Transaction注解即可
    第六步:测试
    发现并没有出现转出实现了,转入却没有实现的情况

  • 相关阅读:
    How To Build CyanogenMod Android for smartphone
    CentOS安装Code::Blocks
    How to Dual boot Multiple ROMs on Your Android SmartPhone (Upto Five Roms)?
    Audacious——Linux音乐播放器
    How to Dual Boot Multiple ROMs on Your Android Phone
    Everything You Need to Know About Rooting Your Android Phone
    How to Flash a ROM to Your Android Phone
    什么是NANDroid,如何加载NANDroid备份?
    Have you considered compiled a batman-adv.ko for android?
    BATMAN—Better Approach To Mobile Adhoc Networking (B.A.T.M.A.N.)
  • 原文地址:https://www.cnblogs.com/zllk/p/12663901.html
Copyright © 2011-2022 走看看