spring5.0学习笔记7

转账事务控制分析
在这里插入图片描述

<?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:tx="http://www.springframework.org/schema/tx"
		xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
				http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
				http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">	

<context:component-scan base-package="com.test"></context:component-scan>
<!-- 配置QueryRunner -->
<bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
	<!-- 注入数据源 -->
<!--  <constructor-arg index="0" ref="dataSource"></constructor-arg> -->	
</bean>

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
	<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
	<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/xiaonei"></property>
	<property name="user" value="root"></property>
	<property name="password" value="tingwei"></property>
</bean>

<!-- 配置Connection的工具类 -->
<bean id="connectionUtil" class="com.test.ConnectionUtil">
	<!-- 注入数据源 -->
	<property name="dataSource" ref="dataSource"></property>
</bean>

<!-- 配置事物管理器 -->
<bean id="txManager" class="com.test.TransactionManager">
	<property name="connectionUtil" ref="connectionUtil"></property>
</bean>
</beans>

package com.test;

import java.io.Serializable;

public class Stu implements Serializable{
	private String name;
	private Float score;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Float getScore() {
		return score;
	}
	public void setScore(Float score) {
		this.score = score;
	}
}
package com.test;

import java.sql.Connection;
import javax.sql.DataSource;

import com.sun.java.swing.plaf.windows.WindowsBorders.DashedBorder;

/**
 * 连接工具类,用于从数据源中获取一个连接,并实现线程的绑定
 */
public class ConnectionUtil {
	
	private ThreadLocal<Connection> tl =new ThreadLocal<Connection>();
	
	private DataSource dataSource;
	
	public void setDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}
	public void setTl(ThreadLocal<Connection> tl) {
		this.tl = tl;
	}
	/**
	 * 获取当前线程上的连接
	 * @return Connection
	 */
	public Connection getThreadConnetion(){
		
		try {
//			1.先从ThreadLocal上获取
			Connection conn = tl.get();
			//2.判断当前线程是否有连接
			if(conn == null){
				//3.从数据源中获取一个连接,并且存入ThreadLocal中
				conn = dataSource.getConnection();
				tl.set(conn);
			}
			//4.返回当前线程上的连接
			return conn;
		} catch (Exception e) {
			// TODO: handle exception
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * 把连接和线程解绑
	 *
	 */
	public void removeConnection(){
		tl.remove();
	}

}
package com.test;
/**
 * 和事物管理相关的工具类,包含开启事务、提交事务、回滚事物、释放连接
 * @author Administrator
 *
 */
public class TransactionManager {
	
	private ConnectionUtil connectionUtil;
	
	/**
	 * 开启事物
	 *
	 */
	public void begainTransaction(){
		try {
			connectionUtil.getThreadConnetion().setAutoCommit(false);
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}
	
	/**
	 * 提交事务
	 *
	 */
	public void commit(){
		try {
			connectionUtil.getThreadConnetion().commit();
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}
	
	/**
	 * 回滚事物
	 *
	 */
	public void rollback(){
		try {
			connectionUtil.getThreadConnetion().rollback();
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}

	/**
	 * 释放连接
	 *
	 */
	public void release(){
		try {
			connectionUtil.getThreadConnetion().close(); //没关闭,而是还给连接池
			connectionUtil.removeConnection();
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}

	public void setConnectionUtil(ConnectionUtil connectionUtil) {
		this.connectionUtil = connectionUtil;
	}
	
}
package com.test;

import java.util.List;

public interface IStuService{
	/**
	 * 查询所有
	 */
	List<Stu> findAllStu();
	
	Stu findStuByName(String name);
	void saveStu(Stu stu);
	void updateStu(Stu stu);
	void deleteStu(String name);
	/**
	 * 转账
	 * @param sourceName
	 * @param targetName
	 * @param money
	 */
	void transfer(String sourceName,String targetName,Float money);
}
package com.test;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service("stuService")
public class StuServiceImp implements IStuService{
	@Autowired
	private IStuDao stuDao;
	@Autowired
	private TransactionManager txManager;
	
	public void setStuDao(IStuDao stuDao) {
		this.stuDao = stuDao;
	}

	public void setTxManager(TransactionManager txManager) {
		this.txManager = txManager;
	}

	public void transfer(String sourceName, String targetName, Float money) {
		// TODO Auto-generated method stub
		try {
			txManager.begainTransaction();
			//1.根据名称查出要转账的账户
			Stu source = stuDao.findStuByName(sourceName);
			//2.根据名称查出转入的账户
			Stu target = stuDao.findStuByName(targetName);
			//3.转出账户减钱
			source.setScore(source.getScore()-money);
			//4.转入账户加钱
			target.setScore(target.getScore()+money);
			//5.更新转出账户
			stuDao.updateStu(source);
			//6.更新转入账户
			//会导致事物的一致性,转账会失败,针对这个问题怎么解决呢?
			int i=1/0;  
			stuDao.updateStu(target);
			
			txManager.commit();
			
			System.out.println("转账成功,转账后双方余额");
			System.out.println(source.getScore());
			System.out.println(target.getScore());
		} catch (Exception e) {
			// TODO: handle exception
			txManager.rollback();
			throw new RuntimeException(e);
		}
		txManager.release();
	}

	@Override
	public void deleteStu(String name) {
		// TODO Auto-generated method stub
		
		try {
			//1.开启事务
			txManager.begainTransaction();
			//2.执行操作
			stuDao.deleteStu(name);
			//3.提交事务
			txManager.commit();
			//4.返回结果
			
		} catch (Exception e) {
			// TODO: handle exception
			//5.回滚操作
			txManager.rollback();
			throw new RuntimeException(e); //产生错误后程序不再执行
		}finally{
			//6.释放连接
			txManager.release();
		}
	}

	@Override
	public List<Stu> findAllStu() {
		List<Stu> stus = null;
		// TODO Auto-generated method stub
		try {
			//1.开启事务
			txManager.begainTransaction();
			//2.执行操作
			stus = stuDao.findAllStu();
			//3.提交事务
			txManager.commit();
			//4.返回结果
			
		} catch (Exception e) {
			// TODO: handle exception
			//5.回滚操作
			txManager.rollback();
			throw new RuntimeException(e); //产生错误后程序不再执行
		}finally{
			//6.释放连接
			txManager.release();
		}
		return stus;
	}

	@Override
	public Stu findStuByName(String name) {
		// TODO Auto-generated method stub
		// TODO Auto-generated method stub
		Stu stu=null;
		try {
			//1.开启事务
			txManager.begainTransaction();
			//2.执行操作
			stu = stuDao.findStuByName(name);
			//3.提交事务
			txManager.commit();
			//4.返回结果
			
		} catch (Exception e) {
			// TODO: handle exception
			//5.回滚操作
			txManager.rollback();
			throw new RuntimeException(e); //产生错误后程序不再执行
		}finally{
			//6.释放连接
			txManager.release();
		}
		return stu;
	}

	@Override
	public void saveStu(Stu stu) {
		// TODO Auto-generated method stub
		stuDao.saveStu(stu);
		try {
			//1.开启事务
			txManager.begainTransaction();
			//2.执行操作
			stuDao.saveStu(stu);
			//3.提交事务
			txManager.commit();
			//4.返回结果
		} catch (Exception e) {
			// TODO: handle exception
			//5.回滚操作
			txManager.rollback();
			throw new RuntimeException(e); //产生错误后程序不再执行
		}finally{
			//6.释放连接
			txManager.release();
		}
	}

	@Override
	public void updateStu(Stu stu) {
		// TODO Auto-generated method stub
		try {
			//1.开启事务
			txManager.begainTransaction();
			//2.执行操作
			stuDao.updateStu(stu);
			//3.提交事务
			txManager.commit();
			//4.返回结果
		} catch (Exception e) {
			// TODO: handle exception
			//5.回滚操作
			txManager.rollback();
			throw new RuntimeException(e); //产生错误后程序不再执行
		}finally{
			//6.释放连接
			txManager.release();
		}
	}

}
package com.test;

import java.util.List;

public interface IStuDao{
	List<Stu> findAllStu();
	
	Stu findStuByName(String name);
	void saveStu(Stu stu);
	void updateStu(Stu stu);
	void deleteStu(String name);
}
package com.test;

import java.sql.Connection;
import java.util.List;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository("stuDao")
public class StuDaoImp implements IStuDao{
	@Autowired
	private QueryRunner runner;
	@Autowired
	private ConnectionUtil connectionUtil;
	public void setConnectionUtil(ConnectionUtil connectionUtil) {
		this.connectionUtil = connectionUtil;
	}

	public StuDaoImp(QueryRunner runner){
		this.runner = runner;
	}

	public StuDaoImp(){

	}
	@Override
	public void deleteStu(String name) {
		// TODO Auto-generated method stub
		try {
			runner.update(connectionUtil.getThreadConnetion(),"delete from stu where id=?", name);
		} catch (Exception e) {
			// TODO: handle exception
			throw new RuntimeException(e);
		}
	}

	@Override
	public List<Stu> findAllStu() {
		// TODO Auto-generated method stub
		try {
			return runner.query(connectionUtil.getThreadConnetion(),"select * from stu", new BeanListHandler<Stu>(Stu.class));
		} catch (Exception e) {
			// TODO: handle exception
			throw new RuntimeException(e);
		}
	}

	@Override
	public Stu findStuByName(String name) {
		// TODO Auto-generated method stub
		try {
			List<Stu> stus = runner.query(connectionUtil.getThreadConnetion(),"select * from stu where sname = ?", new BeanListHandler<Stu>(Stu.class),name);
			if(stus == null || stus.size() == 0){
				return null;
			}
			if(stus.size()>1){
				throw new RuntimeException("结果集 不唯一,数据有问题");
			}
			System.out.println(stus.get(0).getName());
			return stus.get(0);
		} catch (Exception e) {
			// TODO: handle exception
			throw new RuntimeException(e);
		}
	}

	@Override
	public void saveStu(Stu stu) {
		// TODO Auto-generated method stub
		try {
			runner.update(connectionUtil.getThreadConnetion(),"insert into stu(sname,score)values(?,?)",stu.getName(),stu.getScore());
		} catch (Exception e) {
			// TODO: handle exception
			throw new RuntimeException(e);
		}
	}

	@Override
	public void updateStu(Stu stu) {
		// TODO Auto-generated method stub
		try {
			runner.update(connectionUtil.getThreadConnetion(),"update stu set sname=?,score=? where sname=?",stu.getName(),stu.getScore(),stu.getName());
		} catch (Exception e) {
			// TODO: handle exception
			throw new RuntimeException(e);
		}
	}

	public void setRunner(QueryRunner runner) {
		this.runner = runner;
	}

}
/**
 * 转账事务控制分析
 */
package com.test;
import java.util.List;

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

import sun.print.resources.serviceui;

public class Test{
	public static void main(String[] args){
		//1.获取核心容器对象
		ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
		//2.根据id获取bean对象
		IStuService stuService = (IStuService)ac.getBean("stuService",IStuService.class);
		//	List<Stu> stus= stuService.findAllStu();
		//	for(Stu stu:stus){
		//		System.out.println(stu.getName()+" "+stu.getScore());
		//	}

	//	Stu stu = (Stu)stuService.findStuByName("aaa"); 为什么得到的stu name为null
	//	Stu stu = new Stu();
	//	stu.setName("bbb");stu.setScore(98f);
	//	stuService.saveStu(stu);       亲测有效
	//	stuService.updateStu(stu);	    亲测有效
	//	System.out.println(stu.getName()+" "+stu.getScore());
		stuService.transfer("aaa", "bbb", 10f); //后台测试转账能成功,只是存不进去,原因在于取得的名字是null,update的时候存不进去		
	}
}

三月 26, 2020 9:52:12 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@12922f6: display name [org.springframework.context.support.ClassPathXmlApplicationContext@12922f6]; startup date [Thu Mar 26 21:52:12 CST 2020]; root of context hierarchy 三月 26, 2020 9:52:12 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions INFO: Loading XML bean definitions from class path resource [bean.xml] 三月 26, 2020 9:52:12 下午 org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory INFO: Bean factory for application context [org.springframework.context.support.ClassPathXmlApplicationContext@12922f6]: org.springframework.beans.factory.support.DefaultListableBeanFactory@1383eb 三月 26, 2020 9:52:12 下午 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1383eb: defining beans [stuDao,stuService,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,runner,dataSource,connectionUtil,txManager]; root of factory hierarchy 三月 26, 2020 9:52:12 下午 com.mchange.v2.log.MLog INFO: MLog clients using java 1.4+ standard logging. 三月 26, 2020 9:52:13 下午 com.mchange.v2.c3p0.C3P0Registry banner INFO: Initializing c3p0-0.9.2.1 [built 20-March-2013 11:16:28 +0000; debug? true; trace: 10] 三月 26, 2020 9:52:13 下午 com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource getPoolManager INFO: Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, dataSourceName -> 1hge161a96evwyt15tul8v|5b784b, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, identityToken -> 1hge161a96evwyt15tul8v|5b784b, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://localhost:3306/xiaonei, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 15, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 3, numHelperThreads -> 3, preferredTestQuery -> null, properties -> {user=******, password=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ] null Exception in thread "main" java.lang.RuntimeException: java.lang.ArithmeticException: / by zero at com.test.StuServiceImp.transfer(StuServiceImp.java:50) at com.test.Test.main(Test.java:29) Caused by: java.lang.ArithmeticException: / by zero at com.test.StuServiceImp.transfer(StuServiceImp.java:39) ... 1 more null

这样做虽然控制了事务,但是代码显得非常冗余,如何解决请看下回分解。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值