Spring事务管理之编程式事务场景及使用详解

问题引出:

当我在进行某一个业务开发时,需要先在主表存入一条数据逻辑上上是在主表存入一条数据以后从表再存入主表的附属信息。但是再出现运行过程 中出现了异常导致主表的数据存入进去了从表却没有信息。举个例子在进行转账的时候往往会从一个账户转出一定金额到另一个 账户,不允许一个人的
账户的余额已经减少了钱而另一个人的账户却没有收到转账的情况,那么再这种时候在业务层对 数据库进行操作的 时候就必须保证要么转成功(甲转出
了500元,乙的账户多了500元)要么全部失败(甲没有转出乙也没有收到),
这种保证了数据的完整性和一致性的特性正好符合事务的特性。下面就模拟一个转账的例子来看一看Spring中的事务带来的效果。
 首先描述一下业务:我在数据库中建立了一张账户表account里面有Id,balance两个字段。有一个操作account的Dao层 AccountDao具有转入
rollIn(int id,double money)和转出rollOut(int id,double money)两个方法。业务层AccountService封装 了一个转账的方法。
 AccountDao层代码:
public interface AccountDao {
	void rollIn(int id,double money);
	void rollOut(int id,double money);
}
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
	@Override
	public void rollIn(int id, double money) {
		String sql = "update account set balance = balance + ? where id = ?";
		this.getJdbcTemplate().update(sql,money,id);
	}
	@Override
	public void rollOut(int id, double money) {
		String sql = "update account set balance = balance - ? where id = ?";
		this.getJdbcTemplate().update(sql,money,id);
	}
}
 AccountService层代码:
public interface AccountService {
	void transfer(int in,int out,double money);
}
public class AccountServiceImpl implements AccountService {
	private AccountDao accountDao;
	public void setAccountDao(AccountDao accountDao) {
		this.accountDao = accountDao;
	}
	@Override
	public void transfer(int in, int out, double money) {
		accountDao.rollOut(out, money);
		accountDao.rollIn(in, money);
	}
}
 测试层代码:
public class SpringTest {
	public static void main(String[] args) {
		ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
		if(ac != null){
			AccountService accountService = (AccountService) ac.getBean("accountService");
			if(accountService != null){
				accountService.transfer(1, 2, 500d);
			}
		}
	}
}
 上述代码是在没有异常的情况下进行的,没有出现转丢的情况。现在人为的修改业务层的代码,模拟出现的异常。
public void transfer(int in, int out, double money) {
		accountDao.rollOut(out, money);
		String temp = null;
		temp.toCharArray();
		accountDao.rollIn(in, money);
	}
当代码执行到temp.toCharArray()的时候将会出现NullPointerExceprion异常,下面的账户转入操作将不会被执行,就出现了转丢钱的情况。
首先来看看Spring事务相关的三个关键类:
  • PlatformTransactionManager:事务管理器接口,对于实现者,Spring提供了众多根据持久层框架而适配的派生类,如 HibernateTransactionManagerDataSourceTransactionManager、JtaTransactionManager等众多的派生类,具体参考官方API。
  • TransactionDefintion:事务定义信息,包括事务的隔离级别、传播行为、超时、只读等。
  • TransactionStatus:事务具体运行状态。

事务管理器接口PlatformTransactionManager

Spring事务管理之编程式事务场景及使用详解_第1张图片 事务定义信息TansactionDefintion

 事务隔离级别
Spring事务管理之编程式事务场景及使用详解_第2张图片
传播行为
Spring事务管理之编程式事务场景及使用详解_第3张图片

编程式事务:

  • 在AccountService中注入TransactionTemplate来简化事务管理的操作
  • 在TransactionTemplate中注入TransactionManager(真正的事务管理类)
  • 在TransactionManager中注入数据源(拿到连接对象)
 改造后的配置文件:

   
    
	
	
		
		
		
		
		
		
		
		
		
		
		
		
		
		
 
	
	
		
				
	
	
	
		
		
	
	
	
		
		
		
	
	
		
	
  
 改造后的service代码
public class AccountServiceImpl implements AccountService {
	private AccountDao accountDao;
	
	public void setAccountDao(AccountDao accountDao) {
		this.accountDao = accountDao;
	}
	
	/*提供set方法供属性注入*/
	private TransactionTemplate transactionTemplate;
	public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
		this.transactionTemplate = transactionTemplate;
	}

	@Override
	public void transfer(final int in, final int out, final double money) {
		transactionTemplate.execute(new TransactionCallbackWithoutResult() {		
			@Override
			protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
				accountDao.rollOut(out, money);
				String temp = null;
				temp.toCharArray();
				accountDao.rollIn(in, money);
			}
		});
		
	}
}
 执行结果发现异常抛出,数据库里面的数据无仍和变化,既没有转出也没有转入。

Spring事务管理之编程式事务场景及使用详解_第4张图片
 但是基于编程的事务不仅需要在使用事务管理的地方去进行注入,还需要自己对事物管理的代码进行编程,没有声明式事务来的那么方便。声明式事务请见下篇Spring事务管理之
声明式事务。








你可能感兴趣的:(Spring)