JDBC编程----借助TreadLocal类解决事务问题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/nrsc272420199/article/details/86033735

1、web层

package com.nrsc.web;

import com.nrsc.service.AccountService;

public class AccountWeb {
	public static void main(String[] args) {
		// 模拟从键盘录入:源账户,目标账户,转账金额
		// 调用Service层方法
		AccountService service = new AccountService();
		boolean result = service.transAccount("jack", "rose", 100);
		if(result){
			System.out.println("转账成功");
		}else{
			System.out.println("转账失败");
		}
	}
}

2、Service层

package com.nrsc.service;

import java.sql.SQLException;

import comc.nrsc.dao.AccountDao;
import comd.nrsc.utils.ConnectionManager;

public class AccountService {
	//Service层只需要调用Dao层的方法进行转账
	//转账:transAccount
	public boolean  transAccount(String fromName, String toName, double money) {
		boolean flag = false;
		try {
			
			//2:执行sql:调用Dao层的方法
			AccountDao dao = new AccountDao();
			//开启事物
			ConnectionManager.begin();
			int i = dao.fromAccount(fromName, money);
			int j = dao.toAccount(toName, money);
			if(i >0 && j > 0){
				System.out.println("转账成功,事务提交");
				//提交事物
				ConnectionManager.commit();
				flag = true;
			}
			
		} catch (Exception e) {
			try {
				System.out.println("转账失败,事务回滚");
				ConnectionManager.rollBack();
				flag =  false;
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
		}
		return flag;
		
	}
}

3、Dao层

package com.nrsc.dao;

import java.sql.SQLException;
import org.apache.commons.dbutils.QueryRunner;
import comd.nrsc.utils.ConnectionManager;

//T1
//getConnection()
//CPU被抢占
///getConnection()

//两年之后

//T2
//getConnection()
///getConnection()

//ThreadLocal<Connection>
//优化的目的是不要让Service层给dao层传Connection,这样增加了dao层和Service的耦合性
public class AccountDao {
	public int fromAccount(String name, double money) throws SQLException {
		QueryRunner qr = new QueryRunner();
		int i = qr.update(ConnectionManager.getConnection(), "update account set money = money - ? where name = ?",
				money, name);

		return i;
	}

	// i > 0
	// 模拟异常
	// 转账: rose + 100
	public int toAccount(String name, double money) throws SQLException {
		QueryRunner qr = new QueryRunner();
		int j = qr.update(ConnectionManager.getConnection(), "update account set money = money + ? where name = ?", 100,
				"rose");
		return j;
	}

}

4、ConnectionManager

  • ThreadLocal保证同一线程获得同一个Connection
  • 事务的开启提交和回滚
package comd.nrsc.utils;

import java.sql.Connection;
import java.sql.SQLException;

public class ConnectionManager {
	// Map<Thread,Connection> map = new HashMap<Thread,Connection>;
	private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();

	public static Connection getConnection() throws SQLException {
		// 1:第一次获取的时候判断集合中是否为NULL
		// 如果为空,在集合中存储一个Connection对象
		Connection conn = tl.get();
		if (conn == null) {
			conn = C3P0Utils.getConnection();
			tl.set(conn);
		}
		// 2:如果第二次获取的时候,集合不为空,则直接获取
		return conn;
	}

	// 开启事物
	public static void begin() throws SQLException {
		getConnection().setAutoCommit(false);
	}

	// 提交事物
	public static void commit() throws SQLException {
		getConnection().commit();
	}

	// 回滚事物
	public static void rollBack() throws SQLException {
		getConnection().rollback();
	}
}

5、C3P0Utils

package comd.nrsc.utils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.sql.DataSource;

import com.mchange.v2.c3p0.comoPooledDataSource;

public class C3P0Utils {
	//DataSource是java提供的连接池接口,里面有获取数据库连接的方法
	
	//自动读取c3p0-config.xml配置文件,并生成C3P0实现的DataSource--comoPooledDataSource
	private static comoPooledDataSource dataSource = new comoPooledDataSource();
	
	//获取连接
	public static Connection getConnection() throws SQLException{
		return dataSource.getConnection();
	}
	
	//获取连接池---或者叫数据源
	public static DataSource getDataSource(){
		return dataSource;
	}
	//4:释放资源
	public static void close(ResultSet rs, Statement stat, Connection conn) {
		if (rs != null) {
			try {
				rs.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		if (stat != null) {
			try {
				stat.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		if (conn != null) {
			try {
				conn.close(); //这里的close不是把连接断开,而是把连接重新放回连接池
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

猜你喜欢

转载自blog.csdn.net/nrsc272420199/article/details/86033735