版权声明:本文为博主原创文章,未经博主允许不得转载。 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();
}
}
}
}