Spring事务开发(附代码链接)

最后附有网盘链接(程序打包+数据库)

Spring 事务开发

^
^

1、Spring事务的概念与定义

Spring事务和数据库中的事务其实是一样的,也是回滚
Spring事务其实就是Spring AOP,底层创建动态代理对象,在代码的开头结尾封装了开启事务和事务回滚操作。用过JDBC原生代码的更应该清楚了,都是显示在代理里commit和rollback的。然后一大堆try catch…

Spring事务一般是针对Service的,回滚service的操作。

^
^

2、Spring事务的特性ACID

①原子性(atomicity):确保动作要么全部完成要么完全不起作用。
②一致性(consistency):数据和资源就处于一种满足业务规则的一致性状态中。
③隔离性(isolation): 用户的操作不能混淆。
④持久性(durability): 一旦事务完成, 无论发生什么系统错误, 它的结果都不应该受到影响。
^
^

3、事务的传播行为

Spring事务开发(附代码链接)_第1张图片
^
^

4、事务隔离级别

事务的隔离级别要得到底层数据库引擎的支持, 而不是应用程序或者框架的支持。事务的隔离级别有以下几种:

ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是。
ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读和不可重复读,因此很少使用该隔离级别。
ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。
ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。即使在多次查询之间有新增的数据满足该查询,这些新增的记录也会被忽略。该级别可以防止脏读和不可重复读。
ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

Oracle 支持的 2 种事务隔离级别:READ_COMMITED , SERIALIZABLE
Mysql 支持 4 中事务隔离级别。
^
^

5、Spring事务三大接口介绍

1.PlatformTransactionManager(平台)事务管理器
spring并不直接管理事务,而是提供了很多事务管理器,将事务管理职责委托给hibernate或者JTA等持久化机制所提供的相关平台框架事务来实现。

spring事务管理器的接口是org.springframework.transaction.PlatformTransactionManager

通过这个接口,spring为各个平台如hibernate,jdbc等提供了对应的事务管理器,怎么实现是各个平台自己的事情了。

public interface PlatformTransactionManager extends TransactionManager {
    //获取事务状态
    TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;
	//事务提交
    void commit(TransactionStatus var1) throws TransactionException;
	//事务回滚
    void rollback(TransactionStatus var1) throws TransactionException;
}

2.TransactionDefinition事务定义信息(事务传播行为,隔离级别,超时,只读,回滚原则)

public interface TransactionDefinition {
    //支持当前事务,若没有事务则创建一个事务
    int PROPAGATION_REQUIRED = 0;
    //如果存在当前事务,则加入事务,如果没有,则以非事务方式运行
    int PROPAGATION_SUPPORTS = 1;
     //如果存在当前事务,则加入事务,如果没有,则抛出异常
    int PROPAGATION_MANDATORY = 2;
    //创建一个新的事务,如果存在当前事务,则当前事务挂起
    int PROPAGATION_REQUIRES_NEW = 3;
    //以非事务方式运行,如果存在当前事务,则当前事务挂起
    int PROPAGATION_NOT_SUPPORTED = 4;
     //以非事务方式运行,如果存在当前事务,则抛出异常
    int PROPAGATION_NEVER = 5;
    /**表示如果当前有一个事务正在运行中,则该方法应用运行在一个嵌套的事务中
    *被嵌套的事务可以独立运行于封装的事务进行提交或者回滚(保存点)
    *如果封装事务不存在则 PROPAGATION_REQUIRES_NEW 
    **/
    int PROPAGATION_NESTED = 6;
    //使用后端数据库默认的隔离级别,oracle默认读已提交,mysql可重复度
    int ISOLATION_DEFAULT = -1;
    //最低的隔离级别,允许读取尚未提交的数据变更,可能会导致幻读、脏读或者不可重复读
    int ISOLATION_READ_UNCOMMITTED = 1;
    //允许读取并发事务已经提交的数据,避免脏读,但是不可避免幻读或者不可重复读
    int ISOLATION_READ_COMMITTED = 2;
    //对于多次读取同一条记录的结果是一致的,除非数据是被本身事务所修改,可以避免脏读和不可重复度,幻读可能发生
    int ISOLATION_REPEATABLE_READ = 4;
    //最高的隔离级别,完全服从ACID的隔离级别,所有的事务依次逐个执行,事务之间完全不可能产生干扰,避免脏读,幻读,不可重复度,但是性能最低
    int ISOLATION_SERIALIZABLE = 8;
    //使用默认的超时时间,事务进行时间大于设置时间就会抛异常,进行回滚
    int TIMEOUT_DEFAULT = -1;
	//获取事务的传播行为
    default int getPropagationBehavior() {
        return 0;
    }
	//获取事务的隔离级别
    default int getIsolationLevel() {
        return -1;
    }
	//获取事务的超时时间
    default int getTimeout() {
        return -1;
    }
	//获取事务的是否只读
    default boolean isReadOnly() {
        return false;
    }
	//获取事务的名称
    @Nullable
    default String getName() {
        return null;
    }
 
    static TransactionDefinition withDefaults() {
        return StaticTransactionDefinition.INSTANCE;
    }
}
final class StaticTransactionDefinition implements TransactionDefinition {
    static final StaticTransactionDefinition INSTANCE = new StaticTransactionDefinition();
 
    private StaticTransactionDefinition() {
    }
}

3.TransactionStatus:事务运行状态
用来记录事务的状态,该接口定义了一组方法,用来获取或者判断事务的状态信息。

PlatformTransactionManager. getTransaction(…)返回一个TransactionStatus对象,返回的TransactionStatus对象可能代表一个新的或者已经存在的事务

public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable {
    boolean hasSavepoint();
 
    void flush();
}

^
^

6、Spring代理方式灵活

Spring事务开发(附代码链接)_第2张图片
^
^

7、实现方式两个:编程式(XML配置和)、声明注解式

7.1编程式
1、xml文件配置,
文件名/springtx/src/main/resources/config/applicationContext-program.xml
代码

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:util="http://www.springframework.org/schema/util"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util.xsd
        ">
   
   <!-- 
   	通过import 标签引入其他上下文配置文件
    -->     
    <import resource="applicationContext-jdbc.xml"/>    
        
    <bean id="stuCardDao" class="init.wuji.springboot.tx.program.StuCardDaoImpl">
    	<property name="jt" ref="jdbcTemplate"></property>
    </bean>


	<bean id="stuCardService" class="init.wuji.springboot.tx.program.StuCardServiceImpl">
		<property name="scDao" ref="stuCardDao"></property>
		<property name="transactionTemplate" ref="transactionTemplate"></property>
	</bean>
</beans>

config文件还有其他部署文件,一会会上传供大家测试。

另外一个文件呢是原来的springJDBC也做了更改
文件名:/springtx/src/main/resources/config/applicationContext-jdbc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:util="http://www.springframework.org/schema/util"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util.xsd
        ">
   
   <!-- 
   	通过import 标签引入其他上下文配置文件
    -->     
    <import resource="applicationContext-jdbc.xml"/>    
        
    <bean id="stuCardDao" class="init.wuji.springboot.tx.program.StuCardDaoImpl">
    	<property name="jt" ref="jdbcTemplate"></property>
    </bean>


	<bean id="stuCardService" class="init.wuji.springboot.tx.program.StuCardServiceImpl">
		<property name="scDao" ref="stuCardDao"></property>
		<property name="transactionTemplate" ref="transactionTemplate"></property>
	</bean>
</beans>

^
^

2、示例的类和接口的文件代码
/springtx/src/main/java/init/wuji/springboot/tx/program/StuCardServiceImpl.java

package init.wuji.springboot.tx.program;

import java.math.BigDecimal;

import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

import init.wuji.springboot.tx.exception.NoEnoughMoneyException;




public class StuCardServiceImpl implements StuCardService{

	private StuCardDao scDao;
	
	private TransactionTemplate transactionTemplate;
	
	/**
	 * 	转账支付,当金额不足时,抛出异常。
	 * @param targetCardNo 目标账号
	 * @param sourceCardNo 源账号
	 * @param money 转账金额
	 */
	public void transaferMoney(final String targetCardNo, final String sourceCardNo, final String money) {
		
		transactionTemplate.execute(new TransactionCallback() {

			public Object doInTransaction(TransactionStatus status) {
				
				StuCard sourceCard = scDao.getStuCardInfoById(sourceCardNo);
				StuCard targetCard = scDao.getStuCardInfoById(targetCardNo);
				//修改后勤人员信息
				sourceCard.setMoney(sourceCard.getMoney().subtract(new BigDecimal(money)));
				
				targetCard.setMoney(targetCard.getMoney().add(new BigDecimal(money)));
				scDao.updateStuCardByCardNo(targetCard);
				if(sourceCard.getMoney().compareTo(new BigDecimal("0")) < 0){
					throw new NoEnoughMoneyException("账户余额不足,请充值。。。。");
				}
				scDao.updateStuCardByCardNo(sourceCard);
				System.out.println("支付完成!商品购买成功!!!!!");
				
				return null;
			}
			
		});
		
		
	}

	/**
	 * @return the scDao
	 */
	public StuCardDao getScDao() {
		return scDao;
	}

	/**
	 * @param scDao the scDao to set
	 */
	public void setScDao(StuCardDao scDao) {
		this.scDao = scDao;
	}

	/**
	 * @return the transactionTemplate
	 */
	public TransactionTemplate getTransactionTemplate() {
		return transactionTemplate;
	}

	/**
	 * @param transactionTemplate the transactionTemplate to set
	 */
	public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
		this.transactionTemplate = transactionTemplate;
	}
}

/springtx/src/main/java/init/wuji/springboot/tx/program/StuCardService.java

package init.wuji.springboot.tx.program;

public interface StuCardService {

	/**
	 * 
	 * @param targetCardNo
	 * @param sourceCardNo
	 * @param money
	 */
	public void transaferMoney(String targetCardNo, String sourceCardNo, String money);
	
}

MAIN方法(后台的数据库以及工程我给链接)
/springtx/src/main/java/init/wuji/springboot/tx/program/Main.java

package init.wuji.springboot.tx.program;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {

	public static void main(String[] args) {
		ApplicationContext ioc = new ClassPathXmlApplicationContext("config/applicationContext-program.xml");
		
		StuCardService stuCardService = ioc.getBean(StuCardService.class);
		stuCardService.transaferMoney("111", "222", "30");
	}
}

7.2声明注解式
类似于AOP操作
这个很省事,简单的说一下,xml配置好了就ok。
applicationContext-anno-tx.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:util="http://www.springframework.org/schema/util"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util.xsd
        ">
   
   <!-- 
   	通过import 标签引入其他上下文配置文件
    -->     
    <import resource="applicationContext-jdbc.xml"/>    
        
    <context:component-scan base-package="com.zzxtit.springboot.*.anno"></context:component-scan>    
	
	<tx:annotation-driven transaction-manager="transactionManager"/>
	
</beans>

applicationContext-xml-tx.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:util="http://www.springframework.org/schema/util"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util.xsd
        ">
   
   <!-- 
   	通过import 标签引入其他上下文配置文件
    -->     
    <import resource="applicationContext-jdbc.xml"/>    
        
    <bean id="stuCardDao" class="com.zzxtit.springboot.tx.xml.StuCardDaoImpl">
    	<property name="jt" ref="jdbcTemplate"></property>
    </bean>


	<bean id="stuCardService" class="com.zzxtit.springboot.tx.xml.StuCardServiceImpl">
		<property name="scDao" ref="stuCardDao"></property>
	</bean>
	
	<!-- 
		事务传播属性的配置
	 -->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="insert*" propagation="REQUIRED"/>
			<tx:method name="add*" propagation="REQUIRED"/>
			<tx:method name="update*" propagation="REQUIRED"/>
			<tx:method name="modify*" propagation="REQUIRED"/>
			<tx:method name="edit*" propagation="REQUIRED"/>
			<tx:method name="delet*" propagation="REQUIRED"/>
			
			<tx:method name="transafer*" propagation="REQUIRED"/>
			
			<tx:method name="query*" propagation="REQUIRED" read-only="true"/>
			<tx:method name="select*" propagation="REQUIRED" read-only="true"/>
			<tx:method name="find*" propagation="REQUIRED" read-only="true"/>
		</tx:attributes>
	</tx:advice>
	
	<!-- 
		事务的切入点配置
	 -->
	<aop:config>
		<aop:pointcut expression="execution(* com.zzxtit.springboot.*.xml.*.*(..))" id="txPointCut"/>
		<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
	</aop:config>
	
</beans>

主方法不变,StuCard.java不变
StuCardDao.java不变
剩下的加上注解@Repository和@Autowired
代码打包下面给链接了
博主主页已经上传了资源。

链接

链接:https://pan.baidu.com/s/1_8Hs6V06GdX7ia5fYV4MlQ
提取码:7s8u

你可能感兴趣的:(java)