码迷,mamicode.com
首页 > 编程语言 > 详细

Java事务(二) - 传递Connection

时间:2014-09-11 23:52:32      阅读:280      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   io   使用   java   ar   strong   2014   

一. 为什么要传递Connection?

在前面的概述中我们知道, JDBC事务处理的作用对象为Connection, 因此要想控制操作在同一个事务里面, 

我们必须要传递Connection, 确保使用的是同一个Connection.


二. 如何传递Connection?

本实例使用转账的例子: 即从A账户转100元到B账户, 这需要做两次update表操作

1. 代码结构图:

bubuko.com,布布扣

2. 建表语句:

DROP TABLE IF EXISTS `account`;
CREATE TABLE `account` (
  `id` int(10) NOT NULL,
  `name` varchar(20) NOT NULL,
  `money` int(20) NOT NULL,
  PRIMARY KEY  (`id`)
) 

INSERT INTO `account` VALUES ('1', 'lucy', '1000');
INSERT INTO `account` VALUES ('2', 'lili', '1000');

3. 实体类:

public class Account {
	private int id;
	private String name;
	private int money;

	// getter and setter
}

4. C3P0连接池配置:

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
	<default-config>
		<property name="driverClass">com.mysql.jdbc.Driver</property>
		<property name="jdbcUrl">jdbc:mysql:///test</property>
		<property name="user">root</property>
		<property name="password">root</property>

		<property name="acquireIncrement">50</property>
		<property name="initialPoolSize">100</property>
		<property name="minPoolSize">50</property>
		<property name="maxPoolSize">1000</property>
	</default-config> 
</c3p0-config> 

5. JDBC工具类:

public class JDBCUtils {
	private static DataSource dataSource;
	static {
		// 加载C3P0连接池
		dataSource = new ComboPooledDataSource();
	}

	public static DataSource getDataSource() {
		return dataSource;
	}

	public static Connection getConnection() throws SQLException {
		return dataSource.getConnection();
	}

}

6. 业务逻辑类:

/**
 * 业务逻辑层
 */
public class AccountService {
	
	public void transfer(Account outAccount, Account inAccount, int money) throws SQLException {
		
		// 开启 事务 
		Connection conn = JDBCUtils.getConnection();
		conn.setAutoCommit(false);

		// 查询两个账户
		AccountDAO accountDAO = new AccountDAO();
		outAccount = accountDAO.findAccountById(outAccount.getId());
		inAccount = accountDAO.findAccountById(inAccount.getId());

		// 转账 - 修改原账户金额 
		outAccount.setMoney(outAccount.getMoney() - money);
		inAccount.setMoney(inAccount.getMoney() + money);

		try {
			// 更新账户金额, 注意: 这里往Dao层传递连接
			accountDAO.update(outAccount, conn);
			// int x = 1 / 0; 
			accountDAO.update(inAccount, conn);
			
			// 转账成功, 提交事务
			conn.commit();
		} catch (Exception e) {
			// 转账失败, 回滚事务
			conn.rollback();
			e.printStackTrace();
		}
	}
}

7. Dao类:

/**
 * DAO层: CRUD
 */
public class AccountDAO {
	
	// 查询账户
	public Account findAccountById(int id) throws SQLException {
		String sql = "select * from account where id = ?";
		Object[] params = {id};
		QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource());
		return queryRunner.query(sql, new BeanHandler<Account>(Account.class), params);
	}
	
	// 更新账户: 接受传递的连接
	public void update(Account account, Connection conn) throws SQLException {
		String sql = "update account set name = ?, money = ? where id = ?";
		Object[] params = {account.getName(), account.getMoney(), account.getId()};
		QueryRunner queryRunner = new QueryRunner();
		queryRunner.update(conn, sql, params);
	}
}

8. 测试类:

public class TransferTest {
	
	@Test
	public void transferTest() throws SQLException {
		Account out = new Account();
		out.setId(1);
		
		Account in = new Account();
		in.setId(2);
		AccountService accountService = new AccountService();
		accountService.transfer(out, in, 100);
	}
}


三. 总结:

上面传递Connection对象的方法虽然可以完成事务处理的目的, 但是这样的做法是丑陋的, 原因在于: 为了完成事务处理的目的, 

我们需要将一个底层Connection类在service层和Dao层之间进行传递, Dao层的方法需要接受这个Connection对象, 这种做法是典型的API污染.




Java事务(二) - 传递Connection

标签:style   blog   http   io   使用   java   ar   strong   2014   

原文地址:http://blog.csdn.net/zdp072/article/details/39214073

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!