3.7. 热 Rod Java 客户端事务
您可以在 JTA Transactions 中配置和使用 Hot Rod 客户端。
要参与事务,Hot Rod 客户端需要与之交互的 TransactionManager,以及它是否通过同步或 XAResource 接口参与事务。https://docs.oracle.com/javaee/7/api/javax/transaction/Synchronization.html
事务在准备阶段获取条目的写锁是最佳的。为了避免数据不一致,请务必阅读有关 使用 Transactions 的冲突。
3.7.1. 配置服务器
服务器中的缓存还必须是事务处理,客户端才会参与 JTA 事务。
需要以下服务器配置,否则只进行事务回滚:
-
隔离级别必须是
REPEATABLE_READ
。 -
建议使用
PESSIMISTIC
锁定模式,但可以使用OPTIMISTIC
。 -
事务模式应该是
NON_XA
或NON_DURABLE_XA
。热 Rod 事务不应使用FULL_XA
,因为它会降低性能。
例如:
<replicated-cache name="hotrodReplTx"> <locking isolation="REPEATABLE_READ"/> <transaction mode="NON_XA" locking="PESSIMISTIC"/> </replicated-cache>
热 Rod 事务有自己的恢复机制。
3.7.2. 配置 Hot Rod 客户端
事务的 RemoteCache 会根据缓存进行配置。例外是事务的超时,它是全局的,因为单个事务可以与多个 RemoteCaches 交互。
以下示例演示了如何为缓存 my-cache
配置事务 RemoteCache :
org.infinispan.client.hotrod.configuration.ConfigurationBuilder cb = new org.infinispan.client.hotrod.configuration.ConfigurationBuilder(); //other client configuration parameters cb.transactionTimeout(1, TimeUnit.MINUTES); cb.remoteCache("my-cache") .transactionManagerLookup(GenericTransactionManagerLookup.getInstance()) .transactionMode(TransactionMode.NON_XA);
有关配置参数的文档,请参阅配置 Builder 和 RemoteCache ConfigurationBuilder Javadoc。
您还可以使用属性文件配置 Java Hot Rod 客户端,如下例所示:
infinispan.client.hotrod.cache.my-cache.transaction.transaction_manager_lookup = org.infinispan.client.hotrod.transaction.lookup.GenericTransactionManagerLookup infinispan.client.hotrod.cache.my-cache.transaction.transaction_mode = NON_XA infinispan.client.hotrod.transaction.timeout = 60000
3.7.2.1. TransactionManagerLookup Interface
TransactionManagerLookup
提供了一个入口点,用于获取 TransactionManager。
TransactionManagerLookup
的可用实现:
- GenericTransactionManagerLookup
- 查找类,用于查找在 Java EE 应用服务器中运行的 TransactionManager。如果无法找到 TransactionManager,则默认为 RemoteTransactionManager。这是 Hot Rod Java 客户端的默认设置。
在大多数情况下,GenericTransactionManagerLookup 是合适的。但是,如果您需要集成自定义 TransactionManagerLookup
接口,您可以实现 TransactionManager Lookup 接口。
- RemoteTransactionManagerLookup
- 如果没有其他实施,则基本和易失性 TransactionManager。请注意,这个实现在处理并发事务和恢复时有很大的限制。
3.7.3. 事务模式
TransactionMode 控制 RemoteCache 如何与 TransactionManager 交互。
在 Data Grid 服务器和您的客户端应用程序上配置事务模式。如果客户端试图对非事务缓存执行事务操作,则可能会出现运行时异常。
在 Data Grid 配置和客户端设置中,事务模式都相同。将以下模式与客户端搭配使用,请参阅服务器的 Data Grid 配置模式:
NONE
- RemoteCache 不与 TransactionManager 交互。这是默认模式,不是事务处理模式。
NON_XA
- RemoteCache 通过 同步 与 TransactionManager 交互。
NON_DURABLE_XA
- RemoteCache 通过 XAResource 与 TransactionManager 交互。恢复功能被禁用。
FULL_XA
-
RemoteCache 通过 XAResource 与 TransactionManager 交互。启用恢复功能。调用
XaResource.recover ()
方法,以检索要恢复的事务。
3.7.4. 使用事务检测冲突
事务使用键的初始值来检测冲突。
例如,当事务开始时,"k" 的值为 "v"。在准备阶段,事务从服务器获取"k"以读取值。如果值已更改,事务会回滚以避免冲突。
事务使用版本来检测更改,而不是检查值相等。
forceReturnValue
参数控制 RemoteCache 的写入操作,并帮助避免冲突。它有以下值:
-
如果为
true
,则 TransactionManager 在执行写入操作前从服务器获取最新的值。但是,forceReturnValue
参数仅适用于首次访问密钥的操作。 -
如果为
false
,则 TransactionManager 在执行写入操作前不会从服务器获取最新的值。
此参数不会影响 替换
或放置 if Absent
等 条件 写入操作,因为它们需要最新的值。
以下事务提供了一个示例,其中 forceReturnValue
参数可以防止出现冲突的写入操作:
事务 1 (TX1)
RemoteCache<String, String> cache = ... TransactionManager tm = ... tm.begin(); cache.put("k", "v1"); tm.commit();
事务 2 (TX2)
RemoteCache<String, String> cache = ... TransactionManager tm = ... tm.begin(); cache.put("k", "v2"); tm.commit();
在这个示例中,TX1 和 TX2 并行执行。"k"的初始值为 "v"。
-
如果
forceReturnValue = true
,则cache.put ()
操作从 TX1 和 TX2 的服务器获取"k"的值。首先获取"k"锁定的事务,然后提交。其他事务会在提交阶段回滚,因为事务可以检测到 "k" 的值为 "v"。 -
如果
forceReturnValue = false
,则cache.put ()
操作不会从服务器获取"k"的值并返回 null。TX1 和 TX2 都可以成功提交,这会导致冲突。这是因为事务都无法检测到初始值为 "k" 已更改。
以下事务包括 cache.get ()
操作,以便在执行 cache.put ()
操作前读取 "k" 的值:
事务 1 (TX1)
RemoteCache<String, String> cache = ... TransactionManager tm = ... tm.begin(); cache.get("k"); cache.put("k", "v1"); tm.commit();
事务 2 (TX2)
RemoteCache<String, String> cache = ... TransactionManager tm = ... tm.begin(); cache.get("k"); cache.put("k", "v2"); tm.commit();
在前面的示例中,TX1 和 TX2 都是读取密钥,因此 forceReturnValue
参数不会生效。一个事务提交,另一个回滚。但是 cache.get ()
操作需要额外的服务器请求。如果您不要求服务器请求的 cache.put ()
操作返回值效率低下。
3.7.5. 使用 Configured Transaction Manager 和 Transaction Mode
以下示例演示了如何使用在 RemoteCacheManager
中配置的 TransactionManager
和 TransactionMode
:
//Configure the transaction manager and transaction mode. org.infinispan.client.hotrod.configuration.ConfigurationBuilder cb = new org.infinispan.client.hotrod.configuration.ConfigurationBuilder(); cb.remoteCache("my-cache") .transactionManagerLookup(RemoteTransactionManagerLookup.getInstance()) .transactionMode(TransactionMode.NON_XA); RemoteCacheManager rcm = new RemoteCacheManager(cb.build()); //The my-cache instance uses the RemoteCacheManager configuration. RemoteCache<String, String> cache = rcm.getCache("my-cache"); //Return the transaction manager that the cache uses. TransactionManager tm = cache.getTransactionManager(); //Perform a simple transaction. tm.begin(); cache.put("k1", "v1"); System.out.println("K1 value is " + cache.get("k1")); tm.commit();