事务(Transaction) 简述

本文详细介绍了数据库事务的概念,强调其作为最小不可分的工作单元在确保业务一致性中的关键作用。通过网上购物交易的例子,展示了事务在处理一系列数据库操作时如何保证平稳性和可预测性。同时,通过对比无事务和有事务的代码示例,阐述了事务如何在发生错误时进行回滚,以维护数据的完整性和一致性。
摘要由CSDN通过智能技术生成

一、定义

  • 事务:一个最小的不可再分的工作单元;通常一个事务对应一个完整的业务(例如银行账户转账业务,该业务就是一个最小的工作单元)
  • 一个完整的业务需要批量的DML(insert、update、delete)语句共同联合完成
  • 事务只和DML语句有关,或者说DML语句才有事务。这个和业务逻辑有关,业务逻辑不同,DML语句的个数不同

二、应用场景

设想网上购物的一次交易,其付款过程至少包括以下几步数据库操作:

  • 更新客户所购商品的库存信息
  • 保存客户付款信息–可能包括与银行系统的交互
  • 生成订单并且保存到数据库中
  • 更新用户相关信息,例如购物数量等等

正常的情况下,这些操作将顺利进行,最终交易成功,与交易相关的所有数据库信息也成功地更新。但是,如果在这一系列过程中任何一个环节出了差错,例如在更新商品库存信息时发生异常、该顾客银行帐户存款不足等,都将导致交易失败。一旦交易失败,数据库中所有信息都必须保持交易前的状态不变,比如最后一步更新用户信息时失败而导致交易失败,那么必须保证这笔失败的交易不影响数据库的状态–库存信息没有被更新、用户也没有付款,订单也没有生成。否则,数据库的信息将会一片混乱而不可预测。
数据库事务正是用来保证这种情况下交易的平稳性和可预测性的技术

三、代码形式表示

1、没有事务

向数据库插入三条数据,其中第二条语句错误

/**
 * 没有事务
 * 
 * setAutoCommit(boolean b) : 
 * 			设置是否自动提交
 * 			参数为false则不提交,需要手动提交
 * 			参数为true则提交
 */
public class NoTransaction {
	public static void main(String[] args) {
		Connection connection = null;
		Statement statement = null;
		try {
			// 获取链接对象
			connection = DBUtil.getConnection();
			// 获取执行SQL语句的对象
			statement = connection.createStatement();

			/**
			 * 一次性添加三条记录
			 */
			statement.addBatch("insert into test(id,name) values(101,'无事务测试1')");
			// 故意写错字段,就是想让它出意外
			statement.addBatch("insert into test(id,nam) values(102,'无事务测试2')");
			statement.addBatch("insert into test(id,name) values(103,'无事务测试3')");
			/**
			 * 这种条件下,没有关闭自动提交,除了第二条错误的语句没有添加
			 * 另外两条成功添加
			 * 如果是转账业务的话,这种情况就会出错
			 */
			statement.executeBatch();
			System.out.println("执行成功");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			DBUtil.close(statement);
			DBUtil.close(connection);
		}
	}
}

2、有事务

/**
 * 关闭自动提交事务,手动提交,如果有错误,回滚。
 * 
 * setAutoCommit(boolean b) : 
 * 			设置是否自动提交
 * 			参数为false则不提交,需要手动提交
 * 			参数为true则提交
 */
public class Transaction {
	public static void main(String[] args) {
		Connection connection = null;
		Statement statement = null;
		try {
			// 链接对象
			connection = DBUtil.getConnection();
			/**
			 * 关闭自动提交,即使SQL语句正确,数据库表也不会发生变化
			 */
			connection.setAutoCommit(false);
			// 获取执行SQL语句的对象
			statement = connection.createStatement();
			/**
			 * 执行多条语句
			 */
			statement.addBatch("insert into test(id,name) values(201,'有事务测试1')");
			/**
			 * 错误语句,字段 nam 不正确
			 */
			statement.addBatch("insert into test(id,nam) values(202,'有事务测试2')");
			statement.addBatch("insert into test(id,name) values(203,'有事务测试3')");
			// 执行
			statement.executeBatch();
			System.out.println("执行成功");
			/**
			 * 手动提交事务
			 */
			connection.commit();
			// 打开自动提交
			connection.setAutoCommit(true);
		} catch (Exception e) {
			e.printStackTrace();
			try {
				/**
				 	到这里说明有错误,需要回滚
					如果不回滚,直接打开自动提交的话,那么201和203还是会被添加进去
				 	因为没有提交之前的操作被保存到数据库缓存区,执行commit命令的时候,才会强制刷新到数据库中
					如果不回滚,等于没有使用事务一样,回滚就会跳转到执行操作之前
				 	所以 回滚之后会把对应的缓存区清空,然后再开启自动提交,就不会出现问题了
				 */
				connection.rollback();
				/**
				 * 再次把自动提交打开
				 */
				connection.setAutoCommit(true);
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
		} finally {
			DBUtil.close(statement);
			DBUtil.close(connection);
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring框架的事务传播机制主要负责控制事务的启动、提交、回滚等操作,并根据方法的调用场景自动处理事务的传播行为。以下是Spring事务传播机制的一些关键点: ### 传播行为 Spring支持多种传播行为(Propagation),它们描述了在哪些上下文中开始一个新的事务或继续已有的事务: 1. **PROPAGATION_REQUIRED**:如果事务正在运行,则加入该运行的事务;如果没有事务,创建一个新的事务。这是默认的行为。 2. **PROPAGATION_SUPPORTS**:如果存在事务,则加入它,否则以非事务的方式运行。这类似于PROPAGATION_REQUIRED,只是当存在事务时不抛出异常。 3. **PROPAGATION_MANDATORY**:需要一个现有事务,否则抛出异常。 4. **PROPAGATION_REQUIRES_NEW**:总是开启新的事务,无论是否存在现有的事务。 5. **PROPAGATION_NOT_SUPPORTED**:以非事务方式运行,如果存在事务则忽略之。 6. **PROPAGATION_NEVER**:以非事务方式运行,如果有事务则抛出异常。 7. **PROPAGATION_NESTED**:开启嵌套事务,这个新事务包含在现有的事务内,确保数据一致性。 ### 事务隔离级别 事务隔离级别的选择会影响并发操作时数据库的结果的一致性。常见的隔离级别包括: - **READ_UNCOMMITTED**:读取未提交的数据,可能导致脏读、幻读和不可重复读等问题。 - **READ_COMMITTED**:只读取已经提交的事务产生的数据,避免脏读,但可能遇到不可重复读和幻读。 - **REPEATABLE_READ**:在同一事务期间多次读取相同的记录时,结果保持一致,防止脏读和不可重复读,但可能会遇到幻读。 - **SERIALIZABLE**:完全序列化事务,保证最高级别的隔离性,但效率最低。 ### 示例配置 在Spring中配置事务传播行为通常是在应用上下文的配置中完成的,通过定义`tx:`标签和相应的属性来实现。下面是一个简单的示例: ```xml <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <tx:annotation-driven transaction-manager="transactionManager"/> @Service("myService") @Transactional(propagation = Propagation.REQUIRED) public class MyService { //... } ``` 在这个例子中,我们首先定义了一个`DataSourceTransactionManager` bean作为事务管理器,然后通过`tx:annotation-driven`元素启用了基于注解的事务管理,并指定了事务管理器。服务层的`@Transactional`注解指定了传播行为为`REQUIRED`。 ### 结论 理解Spring的事务传播机制对于编写健壮且高效的分布式应用程序至关重要。它允许开发者基于业务需求灵活地控制事务的生命周期和行为,提高应用的稳定性和可靠性。同时,合理的配置和使用事务隔离级别也是保证数据一致性和性能的关键因素之一。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值