一. 为什么要传递Connection?
在前面的概述中我们知道, JDBC事务处理的作用对象为Connection, 因此要想控制操作在同一个事务里面,
我们必须要传递Connection, 确保使用的是同一个Connection.
二. 如何传递Connection?
本实例使用转账的例子: 即从A账户转100元到B账户, 这需要做两次update表操作
1. 代码结构图:
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污染.
源码下载: http://download.csdn.net/detail/zdp072/7908249
本文探讨了在JDBC事务处理中,为何需要传递Connection以确保操作在同一事务内。通过一个转账实例,展示了如何在Service层和Dao层之间传递Connection来实现事务。然而,这种做法被指出是API污染,因为它需要Dao层方法接收并使用底层的Connection对象。
362

被折叠的 条评论
为什么被折叠?



