Java 如何在ApacheIgnite中隔离事务
我试图使用事务同步对Ignite中存储的对象的访问,发现一个事务的结果常常覆盖另一个事务的结果。为了便于测试,我编写了一个更简单的JUnit测试版本:Java 如何在ApacheIgnite中隔离事务,java,multithreading,transactions,isolation-level,ignite,Java,Multithreading,Transactions,Isolation Level,Ignite,我试图使用事务同步对Ignite中存储的对象的访问,发现一个事务的结果常常覆盖另一个事务的结果。为了便于测试,我编写了一个更简单的JUnit测试版本: import junit.framework.TestCase; import org.apache.ignite.Ignite; import org.apache.ignite.IgniteCache; import org.apache.ignite.Ignition; import org.apache.ignite.configurat
import junit.framework.TestCase;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteCache;
import org.apache.ignite.Ignition;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.transactions.Transaction;
import org.apache.ignite.transactions.TransactionConcurrency;
import org.apache.ignite.transactions.TransactionIsolation;
public class IgniteTransactionTest extends TestCase {
private Ignite ignite;
@Override
protected void setUp() throws Exception {
// Start up a non-client Ignite for tests
IgniteConfiguration config = new IgniteConfiguration();
ignite = Ignition.getOrStart(config);
}
public void testTransaction() throws InterruptedException {
IgniteCache cache = ignite.getOrCreateCache("cache");
cache.put("counter", 0);
Runnable r = () -> {
for (int i = 0; i < 1000; i++) {
Transaction tx = ignite.transactions().txStart(
TransactionConcurrency.PESSIMISTIC, TransactionIsolation.SERIALIZABLE);
int counter = (int) cache.get("counter");
counter += 1;
cache.put("counter", counter);
try {
tx.commit();
} catch (Exception ex) {
System.out.println("Commit failed");
i--;
}
}
};
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
t1.start();
t2.start();
t1.join();
t2.join();
assertEquals((int) cache.get("counter"), 2000);
}
@Override
protected void tearDown() throws Exception {
ignite.close();
}
}
导入junit.framework.TestCase;
导入org.apache.ignite.ignite;
导入org.apache.ignite.IgniteCache;
导入org.apache.ignite.Ignition;
导入org.apache.ignite.configuration.ignite配置;
导入org.apache.ignite.transactions.Transaction;
导入org.apache.ignite.transactions.TransactionConcurrency;
导入org.apache.ignite.transactions.TransactionIsolation;
公共类IgniteTransactionTest扩展了TestCase{
私人点火;
@凌驾
受保护的void setUp()引发异常{
//启动非客户端Ignite进行测试
IgniteConfiguration config=新的IgniteConfiguration();
ignite=Ignition.getOrStart(配置);
}
public void testTransaction()引发InterruptedException{
IgniteCache cache=ignite.getOrCreateCache(“缓存”);
cache.put(“计数器”,0);
可运行r=()->{
对于(int i=0;i<1000;i++){
事务tx=ignite.transactions().txStart(
TransactionConcurrency.悲观、TransactionIsolation.SERIALIZABLE);
int计数器=(int)cache.get(“计数器”);
计数器+=1;
cache.put(“counter”,counter);
试一试{
tx.commit();
}捕获(例外情况除外){
System.out.println(“提交失败”);
我--;
}
}
};
螺纹t1=新螺纹(r);
螺纹t2=新螺纹(r);
t1.start();
t2.start();
t1.join();
t2.连接();
assertEquals((int)cache.get(“计数器”),2000年);
}
@凌驾
受保护的void tearDown()引发异常{
点燃。关闭();
}
}
基本上,它运行两个独立的线程,尝试递增Ignite缓存中存储的计数器(隔离级别可序列化),然后检查计数器是否具有正确的值。根据Ignite交易的规则:
TransactionIsolation.SERIALIZABLE隔离级别意味着所有事务都以完全隔离的方式发生,就好像系统中的所有事务都是连续执行的一样。此级别的读取访问与TransactionIsolation.REPEATABLE_读取级别的读取访问方式相同。但是,在TransactionConcurrency.Optimization模式下,如果某些事务不能相互串行隔离,则将选择一个获胜者,而冲突的其他事务将导致抛出TransactionOptimisticeException
但是运行这个测试会产生
junit.framework.AssertionFailedError:应为:但为:
指示一个线程中的写入可以在另一个线程中的读取和写入之间交错。此外,文档建议失败的事务在尝试提交时应引发异常,但这种情况从未发生
我是否一开始就不理解如何使用事务?如何使它们保持隔离?您在没有提供缓存配置的情况下创建缓存。默认情况下,已创建原子缓存,此缓存不支持任何事务性功能 您需要这样的smth:
ignite.getOrCreateCache(new CacheConfiguration<>("cache")
.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL));
ignite.getOrCreateCache(新缓存配置(“缓存”)
.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL));
创建缓存时未提供缓存配置。默认情况下,已创建原子缓存,此缓存不支持任何事务性功能
您需要这样的smth:
ignite.getOrCreateCache(new CacheConfiguration<>("cache")
.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL));
ignite.getOrCreateCache(新缓存配置(“缓存”)
.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL));