zoukankan      html  css  js  c++  java
  • Spring 事情具体详尽的解释

    一、Spring事务管理 
    1、 Spring事务管理机制 三个核心部分 
    1) PlatformTransactionManager  平台的事务管理器  commit 提交事务、rollback 回滚事务 、 TransactionStatus getTransaction(TransactionDefinition definition) 
    2) TransactionDefinition  事务定义信息(和事务管理相关一些參数)  隔离级别、传播级别、超时 、事务是否仅仅读  (静态信息) 

    3) TransactionStatus 事务状态  (事务执行过程中 一些动态信息 ) 

    关系: 事务管理參数信息由 TransactionDefinition 载入, Spring事务管理由PlatformTransactionManager  完毕, PlatformTransactionManager 管理事务过程中依据 TransactionDefinition 定义事务管理信息来管理事务  。在事务执行过程中不同一时候刻 事务状态信息不同, TransactionStatus 就表示不同一时候刻事务状态信息 


    第一个组件 事务管理器 PlatformTransactionManager  接口 
    org.springframework.jdbc.datasource.DataSourceTransactionManager ------- 针对jdbc开发或者 iBatis开发 进行事务管理 
    org.springframework.orm.hibernate3.HibernateTransactionManager  -------  针对Hibernate3开发 进行事务管理 


    第二个组件 事务定义信息 TransactionDefinition 
    隔离级别: 
    1) read_uncommitted 读未提交   引发全部事务隔离问题(脏读、不可反复读、虚读)
    2) read_committed 读已提交  不会发生脏读,会导致不可反复读和虚读 
    3) repeatable_read 反复读  不会发生 脏读和不可反复读。会导致虚读 
    4) serializable  序列化 採用串行方式管理事务,同一时间,仅仅能有一个事务在操作 ,阻止全部隔离问题发生 


    DEFAULT 採取数据库默认隔离级别  Oracle read_committed、 Mysql repeatable_read 

    事务传播行为:(七种)
    1) PROPAGATION_REQUIRED : 支持当前事务。假设不存在 就新建一个  , 将 deleteUser 和 removeAllOrders 放入同一个事务  (Spring默认提供事务传播级别)
    2) PROPAGATION_SUPPORTS : 支持当前事务。假设不存在。就不使用事务  
    3) PROPAGATION_MANDATORY : 支持当前事务,假设不存在,抛出异常 
    4) PROPAGATION_REQUIRES_NEW : 假设有事务存在。挂起当前事务,创建一个新的事务  , deleteUser和removeAllOrder 两个事务运行。无不论什么关系 
    5) PROPAGATION_NOT_SUPPORTED : 以非事务方式执行。假设有事务存在,挂起当前事务
    6) PROPAGATION_NEVER  :  以非事务方式执行,假设有事务存在,抛出异常
    7) PROPAGATION_NESTED : 假设当前事务存在,则嵌套事务运行


    事物传播行为的须要性:


    二、 Spring事务管理案例  转账案例(转出金额和转入金额)
    Spring事务管理 分为编程式事务管理和 声明式事务管理 
    编程式事务管理:在程序中通过编码来管理事务。事务代码侵入,开发中极少应用
    声明式事务管理:无需侵入事务管理代码,开发维护及其方便,底层应用Spring AOP来完毕 



    1、编程式 完毕事务管理


    CREATE TABLE `account` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(20) NOT NULL,
      `money` double DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
    INSERT INTO `account` VALUES ('1', 'aaa', '1000');
    INSERT INTO `account` VALUES ('2', 'bbb', '1000');


    导入jar包 spring基本6个 aop4个 jdbc2个 c3p01个 驱动1个 

    导入jdbc.properties和log4j.properties

    jdbc.driverClass= com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql:///springtx
    jdbc.user= root
    jdbc.password=abc
    ### direct log messages to stdout ###
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.Target=System.err
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
    
    ### direct messages to file mylog.log ###
    log4j.appender.file=org.apache.log4j.FileAppender
    log4j.appender.file.File=c:/mylog.log
    log4j.appender.file.layout=org.apache.log4j.PatternLayout
    log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
    
    ### set log levels - for more verbose logging change 'info' to 'debug' ###
    
    log4j.rootLogger=info, stdout

    业务层 IAccountServive  AccountServiceImpl 

    package service;
    
    /**
     * 以字母I開始 通常表示一个接口
     * @author 
     *
     */
    public interface IAccountService {
    	/**
    	 * 转账操作
    	 * @param outAccount  转出账户
    	 * @param inAccount  转入账户
    	 * @param money 转账金额 
    	 */
    	public void transfer(String outAccount, String inAccount , double money);
    }
    
    package service;
    
    import org.springframework.transaction.TransactionStatus;
    import org.springframework.transaction.support.TransactionCallbackWithoutResult;
    import org.springframework.transaction.support.TransactionTemplate;
    
    import dao.IAccountDAO;
    /**
     * 编程式事务管理
     * @author 
     *
     */
    public class AccountServiceImpl implements IAccountService {
    	private IAccountDAO accountDAO;
    	// 事务模板。编程式事务。是通过该模板进行管理
    	private TransactionTemplate transactionTemplate;
    	
    	@Override
    	public void transfer(final String outAccount, final String inAccount, final double money) {
    		transactionTemplate.execute(new TransactionCallbackWithoutResult() {
    			@Override
    			protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
    				// 转账 分为转入和转出
    				accountDAO.out(outAccount, money);
    //				int d= 1/0;
    				accountDAO.in(inAccount, money);
    				System.out.println("转账成功!

    "); } }); } public void setAccountDAO(IAccountDAO accountDAO) { this.accountDAO = accountDAO; } public void setTransactionTemplate(TransactionTemplate transactionTemplate) { this.transactionTemplate = transactionTemplate; } }


    DAO层 IAccountDAO  AccountDAOImpl

    package dao;
    
    /**
     * Account 操作
     * @author 
     *
     */
    public interface IAccountDAO {
    	// 转出
    	public void out(String outAccount, double money);
    	// 转入
    	public void in(String inAccount, double money);
    }
    
    package dao;
    
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    import org.springframework.jdbc.core.RowMapper;
    import org.springframework.jdbc.core.support.JdbcDaoSupport;
    
    import domain.Account;
    
    public class AccountDAOImpl extends JdbcDaoSupport implements IAccountDAO {
    
    	@Override
    	public void out(String outAccount, double money) {
    		// 推断金额是否满足
    		Account account = this.getJdbcTemplate().queryForObject("select * from account where name = ?

    " , new RowMapper<Account>(){ @Override public Account mapRow(ResultSet rs, int rowNum) throws SQLException { Account account = new Account(); account.setId(rs.getInt("id")); account.setName(rs.getString("name")); account.setMoney(rs.getDouble("money")); return account; } },outAccount); if(account.getMoney() < money){ // 转账金额大于余额 throw new RuntimeException("余额不足无法转账!"); } // 转账 this.getJdbcTemplate().update("update account set money=money-? where name=?

    ", money ,outAccount); } @Override public void in(String inAccount, double money) { // 转入 this.getJdbcTemplate().update("update account set money=money + ? where name=?

    ", money ,inAccount); } }

    在业务层中事务 TransactionTemplate 模板工具类。进行事务管理 
    * 将TransactionTemplate对象注入到Service中 
    * 将相应事务管理器 注入个 TransactionTemplate  
    applicationContext.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:context="http://www.springframework.org/schema/context" 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"> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 配置数据源 --> <!-- c3p0数据源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driverClass}"></property> <property name="jdbcUrl" value="${jdbc.url}"></property> <property name="user" value="${jdbc.user}"></property> <property name="password" value="${jdbc.password}"></property> </bean> <!-- 配置JdbcTemplate , 将数据源注入到jdbcTemplate --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 将jdbcTemplate 注入DAO --> <bean id="accountDAO" class="dao.AccountDAOImpl"> <property name="jdbcTemplate" ref="jdbcTemplate"></property> </bean> <!-- 编程式事务管理 --> <!-- 1、配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 2、将事务管理器 注入给 事务模板 --> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager" ref="transactionManager"></property> </bean> <!-- 3、将模板 给Service --> <!-- 将DAO注入Service --> <bean id="accountService" class="service.AccountServiceImpl"> <property name="accountDAO" ref="accountDAO"></property> <property name="transactionTemplate" ref="transactionTemplate"></property> </bean> </beans>

    2、 声明式事务管理 (原始方式)
    TransactionProxyFactoryBean  事务代理工厂Bean为目标类生成代理。进行事务管理 

    上面的其它部分不变。仅仅须要修改AccountServiceImpl,创建新的AccountServiceImpl2

    package service;
    
    import org.springframework.transaction.annotation.Isolation;
    import org.springframework.transaction.annotation.Propagation;
    import org.springframework.transaction.annotation.Transactional;
    
    import dao.IAccountDAO;
    
    /**
     * 声明式事务管理
     * 
     * @author seawind
     * 
     */
    @Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.DEFAULT,readOnly=false,rollbackFor=ArithmeticException.class) // 进行事务管理
    public class AccountServiceImpl2 implements IAccountService {
    	private IAccountDAO accountDAO;
    
    	@Override
    	public void transfer(final String outAccount, final String inAccount,
    			final double money) {
    		// 转账 分为转入和转出
    		accountDAO.out(outAccount, money);
    		//int d= 1/0;
    		accountDAO.in(inAccount, money);
    		System.out.println("转账成功!");
    
    	}
    
    	public void setAccountDAO(IAccountDAO accountDAO) {
    		this.accountDAO = accountDAO;
    	}
    
    }
    
    applicationContext2.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:context="http://www.springframework.org/schema/context" 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"> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 配置数据源 --> <!-- c3p0数据源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driverClass}"></property> <property name="jdbcUrl" value="${jdbc.url}"></property> <property name="user" value="${jdbc.user}"></property> <property name="password" value="${jdbc.password}"></property> </bean> <!-- 配置JdbcTemplate , 将数据源注入到jdbcTemplate --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 将jdbcTemplate 注入DAO --> <bean id="accountDAO" class="dao.AccountDAOImpl"> <property name="jdbcTemplate" ref="jdbcTemplate"></property> </bean> <!-- 将DAO注入Service --> <bean id="accountService" class="service.AccountServiceImpl2"> <property name="accountDAO" ref="accountDAO"></property> </bean> <!-- 事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 为accountService 生成代理对象,进行事务管理 --> <bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <!-- 须要事务管理器 --> <property name="transactionManager" ref="transactionManager"></property> <!-- 被代理目标对象 --> <property name="target" ref="accountService"></property> <!-- 对目标业务接口生成代理 --> <property name="proxyInterfaces" value="service.IAccountService"></property> <!-- 事务定义參数 --> <property name="transactionAttributes"> <!-- 为事务管理方法 配置 隔离级别、传播级别、仅仅读 --> <props> <!-- 代理方法名 --> <prop key="*">PROPAGATION_REQUIRED,+java.lang.ArithmeticException</prop> </props> </property> </bean> </beans>

    transactionAttributes 事务属性配置格式 
    prop格式:PROPAGATION,ISOLATION,readOnly,-Exception,+Exception
    1) PROPAGATION 传播行为
    2) ISOLATION 隔离级别 
    3) readOnly : 仅仅读事务。不能进行改动操作
    4) -Exception : 发生这些异常回滚事务 
    5) +Exception : 发生这些异常仍然提交事务 
    <prop key="*">PROPAGATION_REQUIRED,+java.lang.ArithmeticException</prop>  发生java.lang.ArithmeticException 事务也会提交
    <prop key="*">PROPAGATION_REQUIRED,readOnly</prop> 事务是仅仅读,不能进行改动操作  


    3、 声明式事务管理 (使用XML配置声明式事务 基于tx/aop)
    导入tx 和 aop schema 名称空间 

    applicationContext3.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: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"> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 配置数据源 --> <!-- c3p0数据源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driverClass}"></property> <property name="jdbcUrl" value="${jdbc.url}"></property> <property name="user" value="${jdbc.user}"></property> <property name="password" value="${jdbc.password}"></property> </bean> <!-- 配置JdbcTemplate , 将数据源注入到jdbcTemplate --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 将jdbcTemplate 注入DAO --> <bean id="accountDAO" class="dao.AccountDAOImpl"> <property name="jdbcTemplate" ref="jdbcTemplate"></property> </bean> <!-- 将DAO注入Service --> <bean id="accountService" class="service.AccountServiceImpl2"> <property name="accountDAO" ref="accountDAO"></property> </bean> <!-- 事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 通过tx:advice 配置事务管理增强 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!-- 配置事务属性 --> <tx:attributes> <!-- 对哪个方法用事务管理 --> <tx:method name="transfer" propagation="REQUIRED" isolation="DEFAULT" read-only="false" /> </tx:attributes> </tx:advice> <!-- 配置aop --> <aop:config proxy-target-class="false"> <!-- 配置切点 --> <aop:pointcut expression="execution(* service.AccountServiceImpl2.*(..))" id="mytransactionpointcut"/> <!-- 将一个Advice作为 一个切面 Advisor --> <!-- 对 mytransactionpointcut 切点 进行 txAdvice 增强 --> <aop:advisor advice-ref="txAdvice" pointcut-ref="mytransactionpointcut"/> </aop:config> </beans>


    4、声明式事务管理 (使用注解配置 )
    对须要管理事务的方法,加入注解@Transactionnal 
    * @Transactionnal 能够载入类上面 或者 方法名上面 


    在applicationContext.xml中加入 <tx:annotation-driven transaction-manager="transactionManager"/> 


    @Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.DEFAULT,readOnly=false,rollbackFor=ArithmeticException.class)
    propagation=Propagation.REQUIRED 传播行为
    isolation=Isolation.DEFAULT 隔离级别
    readOnly=false 是否仅仅读
    rollbackFor=ArithmeticException.class 发生异常回滚 
    noRollbackFor=xxx.class 发生异常 仍然提交事务 

    applicationContext4.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: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">
    	<context:property-placeholder location="classpath:jdbc.properties"/>
    
    	<!-- 配置数据源 -->
    	<!-- c3p0数据源  -->
    	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    		<property name="driverClass" value="${jdbc.driverClass}"></property>
    		<property name="jdbcUrl" value="${jdbc.url}"></property>
    		<property name="user" value="${jdbc.user}"></property>
    		<property name="password" value="${jdbc.password}"></property>
    	</bean>			
    	
    	<!-- 配置JdbcTemplate , 将数据源注入到jdbcTemplate -->
    	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    		<property name="dataSource" ref="dataSource"></property>
    	</bean>
    	
    	<!-- 将jdbcTemplate 注入DAO -->
    	<bean id="accountDAO" class="dao.AccountDAOImpl">
    		<property name="jdbcTemplate" ref="jdbcTemplate"></property>
    	</bean>
    	
    	<!-- 将DAO注入Service -->
    	<bean id="accountService" class="service.AccountServiceImpl2">
    		<property name="accountDAO" ref="accountDAO"></property>
    	</bean>
    	
    	<!-- 事务管理器 -->
    	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    		<property name="dataSource" ref="dataSource"></property>
    	</bean>
    	
    	<!-- 注解驱动事务管理 -->
    	<tx:annotation-driven transaction-manager="transactionManager"/>
    	
    </beans>
    创建測试类

    package test;
    
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import service.IAccountService;
    
    public class AccountTest {
    	@Test
    	// 測试用例   声明式事务管理 (使用注解配置 )
    	public void demo4(){
    		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext4.xml");
    		IAccountService accountService = (IAccountService) applicationContext.getBean("accountService");
    		accountService.transfer("aaa", "bbb", 200);
    	}
    	
    	@Test
    	// 測试用例 声明式事务管理 (使用XML配置声明式事务 基于tx/aop)
    	public void demo3(){
    		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext3.xml");
    		IAccountService accountService = (IAccountService) applicationContext.getBean("accountService");
    		accountService.transfer("aaa", "bbb", 200);
    	}
    	
    	@Test
    	// 測试用例  声明式事务管理 (原始方式)
    	public void demo2(){
    		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext2.xml");
    		// 原始方式进行声明事务管理,必须获得代理对象
    		IAccountService accountService = (IAccountService) applicationContext.getBean("accountServiceProxy");
    		accountService.transfer("aaa", "bbb", 200);
    	}
    	
    	@Test
    	// 測试用例  编程式
    	public void demo1(){
    		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    		IAccountService accountService = (IAccountService) applicationContext.getBean("accountService");
    		accountService.transfer("aaa", "bbb", 200);
    	}
    }
    
    **************************************** 注解进行事务管理是最方便, 还需要掌握 tx/aop事务管理

    版权声明:本文博主原创文章。博客,未经同意不得转载。

  • 相关阅读:
    HDU1013 Digital Roots
    DP---背包问题
    新生代与老年代
    JVM常见问题(二)
    JVM常见问题 一(转载)
    JVM内存模型及分区
    (转载)JVM知识小集
    类加载机制:全盘负责和双亲委托
    mysql 函数GROUP_CONCAT(temp.amount SEPARATOR ',')的用法
    mysql优化--explain关键字
  • 原文地址:https://www.cnblogs.com/blfshiye/p/4872944.html
Copyright © 2011-2022 走看看