Java事务(二) - 传递Connection

一. 为什么要传递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污染.

时间: 2024-10-29 19:10:04

Java事务(二) - 传递Connection的相关文章

Mybaits 源码解析 (十二)----- Mybatis的事务如何被Spring管理?Mybatis和Spring事务中用的Connection是同一个吗?

不知道一些同学有没有这种疑问,为什么Mybtis中要配置dataSource,Spring的事务中也要配置dataSource?那么Mybatis和Spring事务中用的Connection是同一个吗?我们常用配置如下 <!--会话工厂 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name=&qu

Java事务与JTA

一.什么是JAVA事务 通俗的理解,事务是一组原子操作单元,从数据库角度说,就是一组SQL指令,要么全部执行成功,若因为某个原因其中一条指令执行有错误,则撤销先前执行过的所有指令.更简答的说就是:要么全部执行成功,要么撤销不执行. 事务必须服从ISO/IEC所制定的ACID原则. 原子性(atomicity) 一致性(consistency) 隔离性(isolation) 持久性(durability) 原子性表示事务执行过程中的任何失败都将导致事务所做的任何修改失效. 一致性表示当事务执行失败

Java事务(三) - 使用ThreadLocal

一. 为什么使用ThreadLocal: 在上一篇博文中, 我们通过传递Connection的方式来控制事务, 这种方法可以达到目的, 但让人看的不爽, 如果涉及到调用多个service, 那我是不是还得从controller层传递Connection? ThreadLocal的用法见上一篇博客, 该类保证一个类的实例变量在各个线程中都有一份单独的拷贝, 从而不会影响其他线程中的实例变量 二. 如何使用ThreadLocal: 1. 写一个TransactionManager类: /** * 管

温故而知新java事务

一.什么是Java事务 通常的观念认为,事务仅与数据库相关. 事务必须服从ISO/IEC所制定的ACID原则.ACID是原子性(atomicity).一致性(consistency).隔离性 (isolation)和持久性(durability)的缩写. 原子性:表示事务执行过程中的任何失败都将导致事务所做的任何修改失效. 一致性:表示 当事务执行失败时,所有被该事务影响的数据都应该恢复到事务执行前的状态. 隔离性:表示在事务执行过程中对数据的修改,在事务提交之前对其他事务不可见. 持 久性:表

java事务(三)——自己实现分布式事务

在上一篇<java事务(二)——本地事务>中已经提到了事务的类型,并对本地事务做了说明.而分布式事务是跨越多个数据源来对数据来进行访问和更新,在JAVA中是使用JTA(Java Transaction API)来实现分布式的事务管理的.但是在本篇中并不会说明如何使用JTA,而是在不依赖其他框架以及jar包的情况下自己来实现分布式事务,作为对分布式事务的一个理解. 假设现在有两个数据库,可以是在一台机器上也可以是在不同机器上,现在要向其中一个数据库更新用户账户信息,另外一个数据库新增用户的消费信

什么是Java事务

一.什么是Java事务 通常的观念认为,事务仅与数据库相关. 事务必须服从ISO/IEC所制定的ACID原则.ACID是原子性(atomicity).一致性(consistency).隔离性(isolation)和持久性(durability)的缩写.事务的原子性表示事务执行过程中的任何失败都将导致事务所做的任何修改失效.一致性表示当事务执行失败时,所有被该事务影响的数据都应该恢复到事务执行前的状态.隔离性表示在事务执行过程中对数据的修改,在事务提交之前对其他事务不可见.持久性表示已提交的数据在

java事务 深入Java事务的原理与应用

java事务 深入Java事务的原理与应用 一.什么是JAVA事务 通常的观念认为,事务仅与数据库相关. 事务必须服从ISO/IEC所制定的ACID原则.ACID是原子性(atomicity).一致性(consistency).隔离性 (isolation)和持久性(durability)的缩写.事务的原子性表示事务执行过程中的任何失败都将导致事务所做的任何修改失效.一致性表示 当事务执行失败时,所有被该事务影响的数据都应该恢复到事务执行前的状态.隔离性表示在事务执行过程中对数据的修改,在事务提

java事务学习笔记总结

通过这段时间的对java事务机制的学习,用这篇文章做个阶段性的总结,后续如果有时间,还可以深入学习和研究下分布式事务的补偿机制(目前中国只有阿里巴巴在这方面有成熟的研究成果),后续的学习成果,我也会补充到该系列文章中 一.什么是JAVA事务 通常的观念认为,事务仅与数据库相关. 事务必须服从ISO/IEC所制定的ACID原则.ACID是原子性(atomicity).一致性(consistency).隔离性 (isolation)和持久性(durability)的缩写.事务的原子性表示事务执行过程

java事务学习笔记(九)--深度剖析JTA原理与实现

通过本系列对java事务的学习,对事务的概念有了初步的了解,但是互联网的发展一日千里,数据量更是爆炸性增长,而普 通数据库也越来越成为应用系统的性能瓶颈,分布式数据库应运而生,相应的,java分布式事务JTA(Java Transaction API)也在这 种背景下产生了.有幸拜读了IBM developersWorks深度好文,加上自己的一些理解分享给各位看官,仅供大家互相交流学习. 原文地址:http://www.ibm.com/developerworks/cn/java/j-lo-jt