热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Java中的事务—JDBC事务和JTA事务

网上的博客中有很多关于事务的讨论,事务介绍基本都是数据库层面的事务,本文来介绍一下J2EE中和事务相关的内容,在阅读本文之前,

网上的博客中有很多关于事务的讨论,事务介绍基本都是数据库层面的事务,本文来介绍一下J2EE中和事务相关的内容,在阅读本文之前,希望读者对分布式有一定的了解。

Java事务的类型有三种:JDBC事务、JTA(Java Transaction API)事务、容器事务。 常见的容器事务如Spring事务,容器事务主要是J2EE应用服务器提供的,容器事务大多是基于JTA完成,这是一个基于JNDI的,相当复杂的API实现。所以本文暂不讨论容器事务。本文主要介绍J2EE开发中两个比较基本的事务:JDBC事务和JTA事务。

JDBC事务

JDBC的一切行为包括事务是基于一个Connection的,在JDBC中是通过Connection对象进行事务管理。在JDBC中,常用的和事务相关的方法是: setAutoCommit、commit、rollback等。

Java_jdbc

下面看一个简单的JDBC事务代码:

public void JdbcTransfer() { java.sql.Connection conn = null;try{ conn = conn =DriverManager.getConnection("jdbc:oracle:thin:@host:1521:SID","username","userpwd");// 将自动提交设置为 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'");// 提交事务conn.commit();// 事务提交:转账的两步操作同时成功} catch(SQLException sqle){ try{ // 发生异常,回滚在本事务中的操做conn.rollback();// 事务回滚:转账的两步操作完全撤销stmt.close(); conn.close(); }catch(Exception ignore){ } sqle.printStackTrace(); }
}

上面的代码实现了一个简单的转账功能,通过事务来控制转账操作,要么都提交,要么都回滚。

JDBC事务的优缺点

DBC为使用Java进行数据库的事务操作提供了最基本的支持。通过JDBC事务,我们可以将多个SQL语句放到同一个事务中,保证其ACID特性。JDBC事务的主要优点就是API比较简单,可以实现最基本的事务操作,性能也相对较好。

但是,JDBC事务有一个局限:一个 JDBC 事务不能跨越多个数据库!!!所以,如果涉及到多数据库的操作或者分布式场景,JDBC事务就无能为力了。

JTA事务

为什么需要JTA

通常,JDBC事务就可以解决数据的一致性等问题,鉴于他用法相对简单,所以很多人关于Java中的事务只知道有JDBC事务,或者有人知道框架中的事务(比如Hibernate、Spring)等。但是,由于JDBC无法实现分布式事务,而如今的分布式场景越来越多,所以,JTA事务就应运而生。

如果,你在工作中没有遇到JDBC事务无法解决的场景,那么只能说你做的项目还都太小。拿电商网站来说,我们一般把一个电商网站横向拆分成商品模块、订单模块、购物车模块、消息模块、支付模块等。然后我们把不同的模块部署到不同的机器上,各个模块之间通过远程服务调用(RPC)等方式进行通信。以一个分布式的系统对外提供服务。

一个支付流程就要和多个模块进行交互,每个模块都部署在不同的机器中,并且每个模块操作的数据库都不一致,这时候就无法使用JDBC来管理事务。我们看一段代码:

/** 支付订单处理 **/
@Transactional(rollbackFor = Exception.class)
public void completeOrder() {orderDao.update(); // 订单服务本地更新订单状态accountService.update(); // 调用资金账户服务给资金帐户加款pointService.update(); // 调用积分服务给积分帐户增加积分accountingService.insert(); // 调用会计服务向会计系统写入会计原始凭证merchantNotifyService.notify(); // 调用商户通知服务向商户发送支付结果通知
}

上面的代码是一个简单的支付流程的操作,其中调用了五个服务,这五个服务都通过RPC的方式调用,请问使用JDBC如何保证事务一致性?我在方法中增加了@Transactional注解,但是由于采用调用了分布式服务,该事务并不能达到ACID的效果。

JTA事务比JDBC事务更强大。一个JTA事务可以有多个参与者,而一个JDBC事务则被限定在一个单一的数据库连接。下列任一个Java平台的组件都可以参与到一个JTA事务中:JDBC连接、JDO PersistenceManager 对象、JMS 队列、JMS 主题、企业JavaBeans(EJB)、一个用J2EE Connector Architecture 规范编译的资源分配器。

JTA的定义

Java事务API(Java Transaction API,简称JTA ) 是一个Java企业版 的应用程序接口,在Java环境中,允许完成跨越多个XA资源的分布式事务。

JTA

JTA和它的同胞Java事务服务(JTS;Java TransactionService),为J2EE平台提供了分布式事务服务。不过JTA只是提供了一个接口,并没有提供具体的实现,而是由j2ee服务器提供商 根据JTS规范提供的,常见的JTA实现有以下几种:

1.J2EE容器所提供的JTA实现(JBoss)
2.独立的JTA实现:如JOTM,Atomikos.这些实现可以应用在那些不使用J2EE应用服务器的环境里用以提供分布事事务保证。如Tomcat,Jetty以及普通的java应用。

JTA里面提供了 java.transaction.UserTransaction ,里面定义了下面几个方法

begin:开启一个事务commit:提交当前事务rollback:回滚当前事务setRollbackOnly:把当前事务标记为回滚setTransactionTimeout:设置事务的事件,超过这个事件,就抛出异常,回滚事务

这里,值得注意的是,不是使用了UserTransaction就能把普通的JDBC操作直接转成JTA操作,JTA对DataSource、Connection和Resource 都是有要求的,只有符合XA规范,并且实现了XA规范的相关接口的类才能参与到JTA事务中来,关于XA规范,请看我的另外一篇文章中有相关介绍。这里,提一句,目前主流的数据库都支持XA规范。

要想使用用 JTA 事务,那么就需要有一个实现 javax.sql.XADataSource 、 javax.sql.XAConnection 和 javax.sql.XAResource 接口的 JDBC 驱动程序。一个实现了这些接口的驱动程序将可以参与 JTA 事务。一个 XADataSource 对象就是一个 XAConnection 对象的工厂。XAConnection 是参与 JTA 事务的 JDBC 连接。

要使用JTA事务,必须使用XADataSource来产生数据库连接,产生的连接为一个XA连接。

XA连接(javax.sql.XAConnection)和非XA(java.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事务的转账操作,该操作相对依赖于J2EE容器,并且需要通过JNDI的方式获取UserTransaction和Connection。

标准的分布式事务

一个分布式事务(Distributed Transaction)包括一个事务管理器(transaction manager)和一个或多个资源管理器(resource manager)。一个资源管理器(resource manager)是任意类型的持久化数据存储。事务管理器(transaction manager)承担着所有事务参与单元者的相互通讯的责任

JTA的实现方式也是基于以上这些分布式事务参与者实现的,具体的关于JTA的实现细节不是本文的重点,感兴趣的同学可以阅读JTA 深度历险 – 原理与实现

JTA的优缺点

JTA的优点很明显,就是提供了分布式事务的解决方案,严格的ACID。但是,标准的JTA方式的事务管理在日常开发中并不常用,因为他有很多缺点:

实现复杂
通常情况下,JTA UserTransaction需要从JNDI获取。这意味着,如果我们使用JTA,就需要同时使用JTA和JNDI。
JTA本身就是个笨重的API
通常JTA只能在应用服务器环境下使用,因此使用JTA会限制代码的复用性。

总结

Java事务的类型有三种:JDBC事务、JTA(Java Transaction API)事务、容器事务,其中JDBC的事务操作用法比较简单,适合于处理同一个数据源的操作。JTA事务相对复杂,可以用于处理跨多个数据库的事务,是分布式事务的一种解决方案。

这里还要简单说一下,虽然JTA事务是Java提供的可用于分布式事务的一套API,但是不同的J2EE平台的实现都不一样,并且都不是很方便使用,所以,一般在项目中不太使用这种较为负责的API。现在业内比较常用的分布式事务解决方案主要有异步消息确保型、TCC、最大努力通知等。关于这几种分布式事务解决方案,我会在后面的文章中介绍。欢迎关注与交流。

 


转:https://my.oschina.net/wugong/blog/1649929



推荐阅读
  • 分布式开源任务调度框架 TBSchedule 深度解析与应用实践
    本文深入解析了分布式开源任务调度框架 TBSchedule 的核心原理与应用场景,并通过实际案例详细介绍了其部署与使用方法。首先,从源码下载开始,详细阐述了 TBSchedule 的安装步骤和配置要点。接着,探讨了该框架在大规模分布式环境中的性能优化策略,以及如何通过灵活的任务调度机制提升系统效率。最后,结合具体实例,展示了 TBSchedule 在实际项目中的应用效果,为开发者提供了宝贵的实践经验。 ... [详细]
  • Java Web开发中的JSP:三大指令、九大隐式对象与动作标签详解
    在Java Web开发中,JSP(Java Server Pages)是一种重要的技术,用于构建动态网页。本文详细介绍了JSP的三大指令、九大隐式对象以及动作标签。三大指令包括页面指令、包含指令和标签库指令,它们分别用于设置页面属性、引入其他文件和定义自定义标签。九大隐式对象则涵盖了请求、响应、会话、应用上下文等关键组件,为开发者提供了便捷的操作接口。动作标签则通过预定义的动作来简化页面逻辑,提高开发效率。这些内容对于理解和掌握JSP技术具有重要意义。 ... [详细]
  • FastDFS Nginx 扩展模块的源代码解析与技术剖析
    FastDFS Nginx 扩展模块的源代码解析与技术剖析 ... [详细]
  • Spring框架中的面向切面编程(AOP)技术详解
    面向切面编程(AOP)是Spring框架中的关键技术之一,它通过将横切关注点从业务逻辑中分离出来,实现了代码的模块化和重用。AOP的核心思想是将程序运行过程中需要多次处理的功能(如日志记录、事务管理等)封装成独立的模块,即切面,并在特定的连接点(如方法调用)动态地应用这些切面。这种方式不仅提高了代码的可维护性和可读性,还简化了业务逻辑的实现。Spring AOP利用代理机制,在不修改原有代码的基础上,实现了对目标对象的增强。 ... [详细]
  • 深入解析Spring Boot启动过程中Netty异步架构的工作原理与应用
    深入解析Spring Boot启动过程中Netty异步架构的工作原理与应用 ... [详细]
  • Node.js 教程第五讲:深入解析 EventEmitter(事件监听与发射机制)
    本文将深入探讨 Node.js 中的 EventEmitter 模块,详细介绍其在事件监听与发射机制中的应用。内容涵盖事件驱动的基本概念、如何在 Node.js 中注册和触发自定义事件,以及 EventEmitter 的核心 API 和使用方法。通过本教程,读者将能够全面理解并熟练运用 EventEmitter 进行高效的事件处理。 ... [详细]
  • Ceph API微服务实现RBD块设备的高效创建与安全删除
    本文旨在实现Ceph块存储中RBD块设备的高效创建与安全删除功能。开发环境为CentOS 7,使用 IntelliJ IDEA 进行开发。首先介绍了 librbd 的基本概念及其在 Ceph 中的作用,随后详细描述了项目 Gradle 配置的优化过程,确保了开发环境的稳定性和兼容性。通过这一系列步骤,我们成功实现了 RBD 块设备的快速创建与安全删除,提升了系统的整体性能和可靠性。 ... [详细]
  • Spring框架入门指南:专为新手打造的详细学习笔记
    Spring框架是Java Web开发中广泛应用的轻量级应用框架,以其卓越的功能和出色的性能赢得了广大开发者的青睐。本文为初学者提供了详尽的学习指南,涵盖基础概念、核心组件及实际应用案例,帮助新手快速掌握Spring框架的核心技术与实践技巧。 ... [详细]
  • 2016-2017学年《网络安全实战》第三次作业
    2016-2017学年《网络安全实战》第三次作业总结了教材中关于网络信息收集技术的内容。本章主要探讨了网络踩点、网络扫描和网络查点三个关键步骤。其中,网络踩点旨在通过公开渠道收集目标信息,为后续的安全测试奠定基础,而不涉及实际的入侵行为。 ... [详细]
  • TypeScript 实战分享:Google 工程师深度解析 TypeScript 开发经验与心得
    TypeScript 实战分享:Google 工程师深度解析 TypeScript 开发经验与心得 ... [详细]
  • Spring Boot 实战(一):基础的CRUD操作详解
    在《Spring Boot 实战(一)》中,详细介绍了基础的CRUD操作,涵盖创建、读取、更新和删除等核心功能,适合初学者快速掌握Spring Boot框架的应用开发技巧。 ... [详细]
  • 深入解析JWT的实现与应用
    本文深入探讨了JSON Web Token (JWT) 的实现机制及其应用场景。JWT 是一种基于 RFC 7519 标准的开放性认证协议,用于在各方之间安全地传输信息。文章详细分析了 JWT 的结构、生成和验证过程,并讨论了其在现代 Web 应用中的实际应用案例,为开发者提供了全面的理解和实践指导。 ... [详细]
  • 本文详细解析了如何使用 jQuery 实现一个在浏览器地址栏运行的射击游戏。通过源代码分析,展示了关键的 JavaScript 技术和实现方法,并提供了在线演示链接供读者参考。此外,还介绍了如何在 Visual Studio Code 中进行开发和调试,为开发者提供了实用的技巧和建议。 ... [详细]
  • 在Spring Boot项目中,通过YAML配置文件为静态变量设置值的方法与实践涉及以下几个步骤:首先,创建一个新的配置类。需要注意的是,自动生成的setter方法默认是非静态的,因此需要手动将其修改为静态方法,以确保静态变量能够正确初始化。此外,建议使用`@Value`注解或`@ConfigurationProperties`注解来注入配置属性,以提高代码的可读性和维护性。 ... [详细]
  • 如何使用Python高效绘制矩形图形
    本文详细介绍了如何利用Python的Turtle库高效绘制矩形图形,适合初学者快速上手。通过具体示例代码,帮助读者理解Turtle库的基本绘图方法和技巧,同时探讨了在不同应用场景中绘制矩形的实际操作,为后续复杂图形的绘制打下坚实基础。 ... [详细]
author-avatar
nashiyizhiyu_847_695
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有