如何在Apache Ignite中隔离事务

时间:2017-02-03 04:46:24

标签: 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.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();
    }
}

基本上,它运行两个单独的线程,尝试递增存储在Ignite缓存中的计数器,隔离级别为SERIALIZABLE,然后检查计数器是否具有正确的值。根据Ignite交易的documentation

  

TransactionIsolation.SERIALIZABLE隔离级别意味着所有事务都以完全隔离的方式发生,就好像系统中的所有事务都是一个接一个地串行执行一样。具有此级别的读取访问权限与TransactionIsolation.REPEATABLE_READ级别相同。但是,在TransactionConcurrency.OPTIMISTIC模式下,如果某些事务无法彼此串行隔离,则会选择一个获胜者,而其他冲突事务将导致抛出TransactionOptimisticException。

但是运行此测试会产生

  

junit.framework.AssertionFailedError:expected:&lt; 1613&gt;但是:&lt; 2000&gt;

表示一个线程中的写入可以在另一个线程中的读取和写入之间进行交错。此外,文档建议失败的事务在尝试提交时应该抛出异常,但这种情况永远不会发生。

我是否想知道如何首先使用交易?我如何让他们孤立?

1 个答案:

答案 0 :(得分:3)

您在没有提供CacheConfiguration的情况下创建缓存。默认情况下,创建了Atomic缓存,此缓存不支持任何事务功能。

你需要像这样的人:

ignite.getOrCreateCache(new CacheConfiguration<>("cache")
    .setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL));