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
接口,因此还包括 getConnection
、close
、addConnectionEventListener
和 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
启动一个松散耦合的事务。
TMNOFLAGS
、TMJOIN
、TMRESUME
、ORATMSERIALIZABLE
、ORATMREADONLY
和 ORATMREADWRITE
被定义为 XAResource
接口和 OracleXAResource
类的 static
成员。ORATMSERIALIZABLE
、ORATMREADONLY
和 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
指定的事务分支。通过挂起事务分支,您可以在单个会话中拥有多个事务分支。但是,在给定时间只能激活一个。这比进行两次会话要耗费更多的资源。
TMSUCCESS
、TMFAIL
和 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)
说明TMSTARTRSCAN
、TMENDRSCAN
和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()