Java 事务介绍

Java 事务
概念:
通常观念认为,事务仅与数据库相关。
事务必须服从 ISO/IEC 所制定的 ACID 原则。
事务特性: 1. 原子性:事务执行过程中的任何失败都将导致事务所做的修改失效。 2. 一致性:当事务执行失败时,所有被该事务影响的数据都应该恢复到事务执行前的状态。
3. 隔离性:在事务执行过程中对数据的修改,在事务提交之前对其他事务不可见。 4. 持久性:事务处理结束,其效果在数据库中持久化。
通俗理解,事务是一组原子操作单元,从数据库角度说,就是一组 SQL 指令。
事务是为了解决数据安全操作提出的,事务控制实际上就是控制数据的安全访问。
事务的类型:
JDBC 事务
用 Connection 对象控制,JDBC 的 Connection 接口提供了两种事务模式:自动提交、手工提交。
JDBC 为使用 Java 进行数据库的事务操作提供了最基本的支持。可以将多个 SQL 语句放到同一个事务
中,保证其 ACID 特性。
优点: API 比较简单,可以实现最基本的事务操作,性能也相对较好。
缺点:事务的范围局限于一个数据库连接。一个 JDBC 事务不能跨越多个数据库。
涉及到多数据库的操作或者分布式场景,JDBC事务就无能为力了
简单代码实现: 对于数据修改,要么全部执行,要么全部不执行 事务执行前后,数据状态保持一致性(例如转账,转账之后两人总金额不变) 一个事务的处理不能影响另一个事务的处理 即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作 Connection : java.sql.Connection public void JdbcTransfer() { java.sql.Connection conn = null; try{
JTA (Java Transaction API)事务
JTA 是一种高层的,与实现无关的,与协议无关的 API,应用程序和应用服务器可以使用 JTA来访问事
务。
可以理解为 JTA 是我们使用事务必要的工具,可以帮我们解决分布式事务的问题。
如果计划用 JTA 界定事务,需要有一个实现 javax.sql.XADataSource 、 javax.sql.XAConnection 和 javax.sql.XAResource 接口的 JDBC 驱动程序。
这个实现这些接口的驱动程序可以参与 JTA 事务。
一个 XADataSource 对象就是一个 XAConnection 对象的工厂, XAConnection 是参与 JTA 事务的
JDBC 连接。
J2EE 应用程序使用 JNDI 查询数据源。
JNDI:是 J2EE 里面一个重要的规范,使用 JNDI 不用代码写一长串去连接数据库,只需要引入使
用数据库的配置文件,便于解耦合。
使用 JTA 事务必须使用 XADataSource 来产生数据库连接,产生的连接为 XA 连接。
符合 XA 规范的相关接口类才能使用 JTA 事务。
String url = “jdbc:mysql://localhost:3306/test?user=root& password=root”; //定义连接数据库的url conn = DriverManager.getConnection(url); // 将自动提交设置为 false, //若设置为 true 则数据库将会把每一次数据更新认定为一个事务并自动提交 conn.setAutoCommit(false); // 获取一个执行、发送 SQL 语句的对象 stmt = conn.createStatement(); // 将 A 账户中的金额减少 500 stmt.execute("\ update t_account set amount = amount - 500 where account_id = ‘A’"); // 将 B 账户中的金额增加 500 stmt.execute("\ update t_account set amount = amount + 500 where account_id = ‘B’"); // 提交事务 conn.commit(); // 事务提交:转账的两步操作同时成功 } catch(SQLException sqle){ try{// 发生异常,回滚在本事务中的操作 conn.rollback(); // 事务回滚:转账的两步操作完全撤销 stmt.close(); conn.close(); }catch(Exception ignore){ ignore.printStackTrace(); }sqle.printStackTrace(); } }
XA(javax.sql.XAConnection)和非XA(javax.sql.Connection)连接的区别在于:XA可以参与JTA事 务,而且不支持自动提交 相关代码引用: public void JtaTransfer() { javax.transaction.UserTransaction tx = null; java.sql.Connection conn = null; try{tx = (javax.transaction.UserTransaction) context.lookup(“java:comp/UserTransaction”); //取得JTA事务,本例中是由Jboss容器管理 javax.sql.DataSource ds = (javax.sql.DataSource) context.lookup(“java:/XAOracleDS”); //取得数据库连接池,必须有支持XA的数据库、驱动程序 tx.begin(); conn = ds.getConnection(); // 将自动提交设置为 false, //若设置为 true 则数据库将会把每一次数据更新认定为一个事务并自动提交 conn.setAutoCommit(false); stmt = conn.createStatement(); // 将 A 账户中的金额减少 500 stmt.execute("\ update t_account set amount = amount - 500 where account_id = ‘A’"); // 将 B 账户中的金额增加 500 stmt.execute("\ update t_account set amount = amount + 500 where account_id = ‘B’"); // 提交事务 tx.commit(); // 事务提交:转账的两步操作同时成功 } catch(SQLException sqle){ try{// 发生异常,回滚在本事务中的操做 tx.rollback(); // 事务回滚:转账的两步操作完全撤销 stmt.close(); conn.close(); }catch(Exception ignore){ }sqle.printStackTrace(); } }
JTA 提供了 UserTransaction 用来处理事务,不过不光依靠这个类就能将 JDBC 操作转换为 JTA
操作,还是需要符合 XA 协议的接口。
JTA 优点很明显,可以解决分布式事务,可是有很多缺点,实现复杂、笨重、限制代码复用性。
容器事务
容器事务主要是 J2EE 应用服务器提供的,容器事务大多是基于 JTA 完成,这是一个基于 JNDI 的,相当
复杂的 API 实现。
通过 EJB 容器提供的容器事务管理机制(CMT)完成功能。
ETJ: 将Java Beans的运行正式从客户端领域扩展到服务器领域
声明式事务
通过 AOP(面向切面)方式在方法前使用编程式事务的方法开启事务,在方法后提交或回滚。用配置文
件的方法或注解方法(如:@Transactional)控制事务。
注解在方法上是方法自动启动事务,在类上是整个类中的方法都使用事务
Spring 开启事务注解
SpringBoot 事务处理
只需要简单的 @Transactional 注解可实现
简单代码实现:
编程式事务
手动开启、提交、回滚事务。
Spring 编程式事务实现需要在配置文件中配置相应的事务处理器,用 AOP、事务标签、注解方式实现事
务。
例如 JDBC 事务处理器
<tx:annotation-driven transaction-manager=“transactionManager”/> @Service public class PersonService { @Resource private PersonMapper personMapper; @Resource private CompanyMapper companyMapper; //rollbackFor:触发回滚的异常,默认是RuntimeException和Error //isolation: 事务的隔离级别,默认是Isolation.DEFAULT也就是数据库自身的默认隔离级别 @Transactional(rollbackFor = {RuntimeException.class, Error.class}) public void saveOne(Person person) { Company company = new Company(); company.setName(“tenmao:” + person.getName()); companyMapper.insertOne(company); personMapper.insertOne(person); } }
由于我们使用较多的是 SpringBoot 开发,这里就不多对 Spring 配置文件进行更多的阐述了。
无论是 Spring 还是 SpringBoot 实现编程式事务都需要在实体类中获取事务处理器对象,手动进
行开启事务和提交事务各种操作。
SpringBoot 简单代码实现:
事务的属性
事务的隔离级别 (Transaction Isolation Levels)
JDBC 对事务的支持
JDBC 提供了5种不同的事务隔离级别,在 Connection 中进行了定义。
Connection 提供了一个 auto-commit 的属性来指定事务何时结束。
当 auto-commit 为 true 时,当每个独立 SQL 操作的执行完毕,事务立即自动提交,也就是说
每个 SQL 操作都是一个事务。
当 auto-commit 为 false 时,每个事务都必须显示调用 commit 方法进行提交,或者显示调用
rollback 方法进行回滚。auto-commit 默认为 true。
保存点( SavePoint ):JDBC 定义了 SavePoint 接口,提供在一个更细粒度的事务控制机制。当
设置了一个保存点后,可以 rollback 到该保存点处的状态,而不是 rollback 整个事务。
TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition()); try {for (int i = 0; i < 10; i++) { Post post = new Post(); if (i == 5) { post.setContent(“dddddddddddddddddddddddddddddddddddddddddddd”); } else post.setContent(“post” + i); post.setWeight(i); postService.save(post); }transactionManager.commit(status); } catch (Exception e) { transactionManager.rollback(status); e.printStackTrace(); } TRANSACTION_NONE JDBC 驱动不支持事务 TRANSACTION_READ_UNCOMMITTED 允许脏读、不可重复读和幻读。 TRANSACTION_READ_COMMITTED 禁止脏读,但允许不可重复读和幻读。 TRANSACTION_REPEATABLE_READ 禁止脏读和不可重复读,单运行幻读。 TRANSACTION_SERIALIZABLE 禁止脏读、不可重复读和幻读。
Connection接口的 setSavepoint 和 releaseSavepoint 方法可以设置和释放保存点。
JDBC 规范虽然定义了事务的以上支持行为,但是各个 JDBC 驱动,数据库厂商对事务的支持程度
可能各不相同。
事务的传播行为
事务并发处理可能引起的问题
脏读(dirty read):一个事务读取了另一个事务尚未提交的数据
不可重复读(non-repeatable read):一个事务的操作导致另一个事务前后两次读取到不同的数据
幻读(phantom read):一个事务的操作导致另一个事务前后两次查询的结果数据量不同
不可重复读是同一数据不一样,幻读是数据量不一样
PROPAGATION_REQUIRED: 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这 个事务中。这是最常见的选择。 PROPAGATION_SUPPORTS: 支持当前事务,如果当前没有事务,就以非事务方式执行。 PROPAGATION_MANDATORY: 支持当前事务,如果当前没有事务,就抛出异常。 PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。 PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 PROPAGATION_NEVER: 以非事务方式执行,如果当前存在事务,则抛出异常。 虽然有7种,但是常用的就第一种REQUIRED和第四种REQUIRES_NEW

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值