codecamp

OceanBase XA 组件

XA 组件是 OceanBase Connector/J 指定的标准 XA 接口。

XADatasource 接口和 Oracle 实施

javax.sql.XADataSource 接口概述了 XA 数据源的标准功能,是 XA 连接的工厂。getXAConnection 方法重载返回一个 XA 连接实例,并可以选择使用用户名和密码作为输入,如下所示:

public interface XADataSource
{
   XAConnection getXAConnection() throws SQLException;
   XAConnection getXAConnection(String user, String password)
      throws SQLException;
   ...
}

OceanBase Connector/J 使用 OracleXADataSource 类实现 XADataSource 接口。OracleXADataSource 类还扩展了 OracleConnectionPoolDataSource 类,而 OracleConnectionPoolDataSource 类扩展了 OracleDataSource 类,因此包括所有连接属性。

OracleXADataSource 类的 getXAConnection 方法返回 XA 连接实例的 Oracle 实现,这些实例是 OracleXAConnection 实例。

说明 
您可以使用前面讨论的非池化数据源相同的命名约定在 Java 命名目录和接口(JNDI)中注册 XA 数据源。

XAConnection 接口和 Oracle 实施

XA 连接实例与池连接实例一样,封装了与数据库的物理连接。 这里的数据库是指在产生 XA 连接实例的 XA 数据源实例的连接属性中指定的数据库。

每个 XA 连接实例还具有生成 OracleXAResource 实例的功能,该实例将与之相对应以用于协调分布式事务。

XA 连接实例是实现标准 javax.sql.XAConnection 接口类的实例,如下所示:

public interface XAConnection extends PooledConnection
{
   javax.jta.xa.XAResource getXAResource() throws SQLException;
}

XAConnection 接口扩展了 javax.sql.PooledConnection 接口,因此还包括 getConnectioncloseaddConnectionEventListener 和 removeConnectionEventListener 方法。

JDBC 使用 OracleXAConnection 类实现 XAConnection 接口,OracleXAConnection 类还扩展了 OraclePooledConnection 类。

OracleXAConnection 类的 getXAResource 方法返回 OracleXAResource 实例的 Oracle 实现,该实例是一个OracleXAResource 实例。getConnection 方法返回一个 OracleConnection 实例。

XA 连接实例返回的 OceanBase Connector/J 连接实例充当物理连接的临时句柄,而不是封装物理连接。物理连接由 XA 连接实例封装。与常规连接完全相同,连接从 XAConnection 对象获得连接的行为,直至参与到全局事务为止。这时,自动提交状态设置为 false。全局事务结束后,自动提交状态将返回到其在全局事务之前的值。从 XAConnection 获得的连接的默认自动提交状态均为 true

每次调用 XA 连接实例的 getConnection 方法时,都会返回一个表现出默认行为的新连接实例,并关闭以前存在的并由同一 XA 连接实例返回的所有以前的连接实例。但是,建议在打开新的连接实例之前显式关闭先前的连接实例。

调用 XA 连接实例的 close 方法将关闭与数据库的物理连接,并通常在中间层执行。

XAResource 接口和 Oracle 实施

事务管理器使用 OracleXAResource 实例来协调分布式事务的所有事务分支。

每个 OracleXAResource 实例都提供给事务管理器调用的关键功能,如下:

  • 将分布式事务与产生此 OracleXAResource 实例的 XA 连接实例中运行的事务分支关联和解除关联。本质上,是将分布式事务与 XA 连接实例封装的物理连接或会话相关联。这是通过使用事务 ID 来完成的。

  • 执行分布式事务的两阶段提交功能,以确保在所有事务分支中更改都成功之前,不会在某一个事务分支中提交更改。

注意 
  • 因为 XA 连接实例和 OracleXAResource 实例之间必须始终存在一对一的关联,所以当关联的 XA 连接实例关闭时,隐式关闭 OracleXAResource 实例。
  • 如果事务由指定的 OracleXAResource 实例打开,则它也必须由相同的 OracleXAResource 实例关闭。

OracleXAResource 实例是实现标准 javax.transaction.xa.XAResource 接口类的实例。OceanBase Connector/J 使用OracleXAResource 类实现 XAResource 接口。

每当调用 OracleXAConnection 类的 getXAResource 方法时, OceanBase Connector/J 都会创建并返回一个 OracleXAResource 实例,并且将 OracleXAResource 实例与连接实例和通过该连接运行的事务分支相关联。

这种方法是将 OracleXAResource 实例与特定连接以及在该连接中运行的事务分支相关联的方式。

OracleXAResource 方法功能和输入参数

OracleXAResource 类具有几种方法来协调事务分支和与其关联的分布式事务。此功能通常涉及两阶段提交操作。

从中间层组件(例如应用程序服务器)接收 OracleXAResource 实例的事务管理器通常会调用此功能。

这些方法中的每一个都以 Xid 实例的形式将事务 ID 作为输入,其中包括事务分支 ID 组件和分布式事务 ID 组件。每个事务分支都有唯一的事务 ID,但是属于同一全局事务的事务分支作为其事务 ID 的一部分,所以具有相同的全局事务组件。

Start

代表事务分支开始工作,将事务分支与分布式事务相关联。语法如下:

void start(Xid xid, int flags)

flags 参数必须是以下一个或多个值:

  • XAResource.TMNOFLAGS

    将新事务分支的开始标记为与此 XA 资源实例相关联的会话中的后续操作。该分支将具有事务 ID xid,这是由事务管理器创建的 OracleXid 实例。 这会将事务分支映射到适当的分布式事务。

  • XAResource.TMJOIN

    将与此 XA 资源实例相关联会话的后续操作加入到 xid 指定的现有事务分支中。

  • XAResource.TMRESUME​恢复 xid 指定的事务分支。

说明

 只能恢复之前挂起的事务分支。

  • OracleXAResource.ORATMSERIALIZABLE

    使用事务 ID xid 启动可序列化的事务。

  • OracleXAResource.ORATMREADONLY

    使用事务 ID xid 启动一个只读事务。

  • OracleXAResource.ORATMREADWRITE

    使用事务 ID xid 启动读/写事务。

  • OracleXAResource.ORATRANSLOOSE

    使用事务 ID xid 启动一个松散耦合的事务。

TMNOFLAGSTMJOINTMRESUMEORATMSERIALIZABLEORATMREADONLY 和 ORATMREADWRITE 被定义为 XAResource 接口和 OracleXAResource 类的 static 成员。ORATMSERIALIZABLEORATMREADONLY 和 ORATMREADWRITE 是隔离模式标志。默认的隔离行为是 READ COMMITTED

说明 
  • 代替使用 TMRESUME 的 start 方法,事务管理器可以强制转换为 OracleXAResource 并使用 resume(Xid xid) 方法(Oracle 扩展)。
  • 如果使用 TMRESUME,则还必须使用 TMNOMIGRATE,如 start(xid,XAResource.TMRESUME|OracleXAResource.TMNOMIGRATE) 中所示。这可以防止应用程序收到错误信息 ORA 1002: fetch out of sequence
  • 如果错误地使用了隔离模式标识,则会引发代码为 XAER_INVAL 的异常。此外,因为无法设置现有事务的隔离级别,所以在恢复全局事务时不能使用隔离模式标识。如果在恢复事务时尝试使用隔离模式标识,则会引发代码为 ORA-24790 的外部 Oracle 异常。
  • 为了避免错误 Error ORA 1002: fetch out of sequence,请在启动方法中包括 TMNOMIGRATE 标识。例如:start(xid, XAResource.TMSUSPEND | OracleXAResource.TMNOMIGRATE);
  • 在编写使用这些标识的事务管理器时,请注意 OracleXAResource 中定义的所有标志都是 Oracle 扩展。

请注意,要在启动事务分支时创建适当的事务 ID,事务管理器必须知道该事务分支属于哪个分布式事务。其机制在中间层和事务管理器之间处理。

End

结束工作代表 xid 指定的事务分支,将事务分支与其分布式事务解除关联。语法如下:

void end(Xid xid, int flags)

flags 参数可以具有以下值之一:

  • XAResource.TMSUCCESS

    这表明该事务分支已经成功。

  • XAResource.TMFAIL

    这表明该事务分支已失败。

  • XAResource.TMSUSPEND

    这是为了挂起 xid 指定的事务分支。通过挂起事务分支,您可以在单个会话中拥有多个事务分支。但是,在给定时间只能激活一个。这比进行两次会话要耗费更多的资源。

TMSUCCESSTMFAIL 和 TMSUSPEND 被定义为 XAResource 接口和 OracleXAResource 类的静态成员。

说明 
  • 与使用 TMSUSPEND 的 end 方法不同,事务管理器可以将其强制转换为 OracleXAResource 并使用 suspend(Xid xid) 方法(Oracle 扩展)。
  • 暂停事务的 XA 功能提供了一种在单个 JDBC 连接内的各种事务之间进行切换的方法。您可以使用 XA 类来完成此操作。
  • 如果使用 TMSUSPEND,则还必须使用 TMNOMIGRATE,如 end(xid,XAResource.TMSUSPEND| OracleXAResource.TMNOMIGRATE) 所示。 这样可以防止应用程序收到错误 ORA 1002: fetch out of sequence
  • 为了避免错误 Error ORA 1002: fetch out of sequence,请将 TMNOMIGRATE 标识作为 end 方法的一部分。 例如:end(xid, XAResource.TMSUSPEND | OracleXAResource.TMNOMIGRATE);
  • 在编写使用这些标识的事务管理器时,请注意 OracleXAResource 中定义的所有标志都是 Oracle 扩展。

Prepare

在 xid 指定的事务分支中准备执行的更改。这是两阶段提交操作的第一阶段,以确保可以访问数据库并且可以成功提交更改。语法如下:

int prepare(Xid xid)

此方法返回一个整数值,如下所示:

  • XAResource.XA_RDONLY

    如果事务分支仅运行只读操作(例如 SELECT 语句),则返回此值。

  • XAResource.XA_OK

    如果事务分支运行所有准备就绪且没有错误的更新,则返回此值。

  • NA(不返回任何值)

    如果事务分支运行更新,如果其中任何一个在准备过程中遇到错误,则不返回任何值。在这种情况下,将引发 XA 异常。

XA_RDONLY 和 XA_OK 被定义为 XAResource 接口和 OracleXAResource 类的静态成员。

说明 
  • 在调用 prepare 方法之前始终在分支上调用 end 方法。
  • 如果分布式事务中只有一个事务分支,则无需调用 prepare 方法。无需预先准备就可以调用OracleXAResource 提交方法。

Commit

在 xid 指定的事务分支中提交准备好的更改。这是两阶段提交的第二阶段,仅在成功准备好所有事务分支之后才执行。语法如下:

void commit(Xid xid, boolean onePhase)

设置 onePhase 参数如下:

  • true

    表示在提交事务分支时使用一阶段协议而不是两阶段协议,适用于分布式事务中只有一个事务分支的情况。prepare 步骤将被跳过。

  • false

    表示在提交事务分支时使用两阶段协议。

Rollback

在 xid 指定的事务分支中回滚准备好的更改。语法如下:

void rollback(Xid xid)

Forget

告诉资源管理器忘记启发完成的事务分支。语法如下:

public void forget(Xid xid)

Recover

事务管理器在恢复期间调用此方法,以获取当前处于准备完成或启发完成状态的事务分支的列表。语法如下:

public Xid[] recover(int flag) 
说明 
TMSTARTRSCANTMENDRSCAN 和 TMNOFLAGS 的 flag 值会被忽略,其他的 flag 值会引发异常。
资源管理器为当前处于准备或启发完成状态的事务分支返回零个或多个 Xid。如果在操作过程中发生错误,则资源管理器将引发适当的 XAException
说明 
恢复方法要求在 Oracle 数据库服务器中具有 DBA_PENDING_TRANSACTIONS 的 SELECT 权限和 SYS.DBMS_XA 的 EXECUTE 权限。

isSameRM

要确定两个 OracleXAResource 实例是否对应于同一资源管理器,请从一个 OracleXAResource 实例调用 isSameRM 方法,并指定另一个 OracleXAResource 实例作为输入。

在以下示例中,假定 xares1 和 xares2 是 OracleXAResource 实例:

boolean sameRM = is1.isSameRM(is2);

Xid 接口和 Oracle 实施

事务管理器创建事务 ID 实例,并用于协调分布式事务的分支。每个事务分支都分配有唯一的事务 ID,其中包括以下信息:

  • 格式识别码

    格式标识符指定 Java 事务管理器。例如,可能有一个格式标识符 ORCL。该字段不能为空。格式标识符的大小为 4 个字节。

  • 全局事务标识符

    它也被称为分布式事务 ID 组件。全局事务标识符的大小为 64 个字节。

  • 分支限定符

    也称为事务分支 ID 组件。分支限定符的大小为 64 个字节。

属于同一分布式事务的所有事务分支的事务 ID 具有相同的 64 字节全局事务标识符值。但是,总的事务 ID 对于每个事务分支都是唯一的。

XA 事务 ID 实例是实现标准 javax.transaction.xa.Xid 接口类的实例,该接口是 X/Open 事务的标识符 XID 的结构的 Java 映射。

Oracle 使用 oracle.jdbc.xa 包中的 OracleXid 类实现此接口。OracleXid 实例仅在事务管理器中使用,对应用程序或应用服务器透明。

说明 
Oracle 不需要将 OracleXid 用于 OracleXAResource 调用。相反,请使用实现 javax.transaction.xa.Xid 接口的任何类。

事务管理器在创建 OracleXid 实例时可以使用以下内容:

public OracleXid(int fId, byte gId[], byte bId[]) throws XAException

其中,fId 是格式标识符的整数值,gId [] 是全局事务标识符的字节数组,bId [] 是分支限定符的字节数组。

Xid 接口指定以下 getter 方法:

  • public int getFormatId()

  • public byte[] getGlobalTransactionId()

  • public type[] getBranchQualifier()


OceanBase 分布式事务概述
OceanBase 分布式事务示例
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

OceanBase 控制台指南

OceanBase ODC 使用指南

OceanBase Web 版 ODC

OceanBase 客户端版 ODC

OceanBase Connector/J 开发者指南

OceanBase 什么是OceanBase Connector/J

OceanBase SQL 参考(MySQL 模式)

OceanBase SQL 参考(Oracle 模式)

OceanBase 基本元素

OceanBase 数据库对象

OceanBase 函数

OceanBase 单行函数

OceanBase 返回数字的字符串函数

OceanBase 通用比较函数

OceanBase 编码解码函数

OceanBase SQL 调优指南

OceanBase 相关协议

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }