前言:有人问了我一个问题,就是说在网络中断的时候,JTA的全局事务管理,会不会回滚?当时说会回滚,但没给对方说清楚理由,也不太认同我的观点。现在总结一下。

今天一天都在看文档(也查了一些博客和网站),主要看EJB、JTA、JDBC、Mysql,来分享一下地址(全是官方网址,可能更具有权威):

http://docs.oracle.com/javaee/6/tutorial/doc/  备注:虽然是java EE 6的文档,但基本上不会差太多,主要看的是EJB、JTA

https://docs.oracle.com/javase/tutorial/jdbc/basics/transactions.html   这个是J2SE 8的文档,主要看的关于事务的处理

https://dev.mysql.com/doc/refman/5.6/en/xa.html  Mysql中的XA事务(分布式事务,必须实现XA协议,JTA多数据源全局事务管理中提到的两段式事务提交引擎,JTA的分布式事务必须使用支持XA协议的数据源,也叫作:nonemulated data source

https://dev.mysql.com/doc/refman/5.7/en/binary-log.html  Mysql中的binary-log,一个可以记录整个Mysql Server端的日志,redo log或者undo log,都只是记录InnoDB引擎的日志。

其他:

1,维基百科:https://en.wikipedia.org/wiki/Java_Transaction_API

2,Spring官方文档:36. Distributed Transactions with JTA

3,Oracle官方文档:7 Java Transaction API

看完之后,本宝宝坚持,会回滚!只是,有关于一些配置,尤其是不同数据源的事务配置,不管是代码层级,还是数据库服务配置,都不能错,缺一不可!

一、对问题的看法

在总结具体代码实施之前,我先总结一下对这个事儿的看法:

1,为什么我的回答,得不到明显认同,尽管我自己很确认这个答案!

第一点:可能是当时的语气表达太温和或者不太自信,尽管后来我再次确认,但似乎依然没有得到认可。第二点:对方可能在实际应用过程中,确实遇到了分布式事务没有回滚的情况。第三点:对方可能并不知道我在说什么,比如说我告诉他先获取一个上下文SessionContext ,再用UserTransaction接口,再去显示的开始事务,提交事务等,这样就就可以处理分布式事务(这是EJB实现分布式事务的方式,来源维基百科,Oracle相应的官方文档也有说明)第四点:可能真的是我理解错了

2,为什么我无法将我的观点表达清楚!

第一点:我看的是java EE规范中对于JTA、EJB中关于分布式事务处理的说明(纯英文官方文档),但我目前为止可能缺乏一个宏观的总结,我的表达可能缺乏条理,不够清晰、不够生动,所以,我现在进行总结。 第二点:对方一直问我最底层的实现,我都写出具体的代码了,但他问我JTA到底是怎么做到分布式事务处理的。对于那个层次上的具体机制,我确实目前还没有深入了解。  

3,怎么去看待他问的关于网络中断,分布式事务会不会回滚的问题

第一点:EJB实现了java EE多个规范,其中一个很重要的功能就是实现JTA进行分布式事务处理,不可能只有他想到网络中断吧??? 那人家想到了,就一定会有解决方案,不管目前为止是否完善!

二、JTA事务管理

备注:对于一般的事务,不多说。主要说明一下分布式事务!

1,首先是EJB中对于分布式事务的实现

EJB支持两种形式的分布式事务,一种是基于Bean管理的,一种是基于容器管理的。简单说来,它们的主要区别就是编程式和声明式的区别。因为如果使用基于Bean管理的事务,那么代码会像这样:

begin transaction
...
	update table-a
...
	if (condition-x)
   commit transaction
	else if (condition-y)
   update table-b
   commit transaction
	else
   rollback transaction
   begin transaction
   update table-c
   commit transaction
但如果是基于容器管理的事务,那么代码就会像这样:

@TransactionAttribute(NOT_SUPPORTED)
@Stateful
public class TransactionBean implements Transaction {
...
    @TransactionAttribute(REQUIRES_NEW)
    public void firstMethod() {...}

    @TransactionAttribute(REQUIRED)
    public void secondMethod() {...}

    public void thirdMethod() {...}

    public void fourthMethod() {...}
}
只是不管哪一种,都是通过JTA提供的UserTransaction接口而做的。它最基本的流程是:获取上下文—拿到UserTransaction接口—连接数据源—开启事务—提交事务—回滚事务!简单实例:

Context ic = new InitialContext();
DataSource ds = (DataSource) ic.lookup("jdbc/OracleDS");
Connection conn = ds.getConnection();
2,关于数据库的配置

前面也说到,分布式的事务,必须实现XA协议,而JTA的分布式事务,一定要使用XA协议的数据源。那么我们常用的mysql数据库,在处理分布式事务的时候,应该怎么配置???

两种情况,第一种:尽管我们从业务上划分了多个服务,但仍然在同一数据库;第二种:各个服务,并不在同一个数据库,但在同一个数据库服务器。PS:别问我连数据库服务器都不同怎么办,宝宝还没研究到那儿。

第一种情况:这个不需要对数据库有额外的配置,因为它还涉及不到多个数据源。这时候事务执行的简单过程如下:

1,先记录 undo/redo log,确保日志刷到磁盘上持久存储。
2,更新数据记录,缓存操作并异步刷盘。
3,提交事务,在 redo log 中写入 commit 记录。

注意点:undo/redo log ,只是记录InnoDB引擎的日志。另外一个也支持事务的引擎NDB,有一个ndb-log的配置。所以,尽管是一个数据库,但要保证事务,需要确认涉及到事务的表都是InnoDB引擎。另外:InnoDB支持128个回滚段,每个回滚段最多支持1023个并发数据修改事务,总共限制大约128K并发数据修改事务(只读事务不计入最大限制)。

第二种情况:需要额外的配置Mysql server的binary log和数据库隔离级别

简单说来,binary log是能够完整记录整个服务器操作的日志,当涉及到多数据源的时候,必须开启binary log。 第二点,处理分布式事务,必须选用可串行化隔离级别。

https://dev.mysql.com/doc/refman/5.6/en/xa.html

我目前对于以上所涉及到的文档,得出的理解是目前的样子。如果有不一致的,还望指导一二!

三、总结

我有那么瞬间都在怀疑我看的官方文档到底是不是真的! 还有一个就是SpringMVC注解的实现,我告诉他我实现的自定义注解,是通过反射去做的,所以我认为是反射。但我看他那意思好像是我又错了,因为让我再次确认了一下。 我好疑惑,其实,如果我说的不对,那就告诉我正确的是什么,或者就说我答的不对也行,我问他吧,又不跟我说。      

唉,说来说去,还是自己总结的不够深入,知识体系、宏观体系上的逻辑关联性,还需要进一步加强,加油啦!

posted on 2017-09-16 11:30  何红霞  阅读(647)  评论(0编辑  收藏  举报