Search code examples
javapersistenceignite

No commit for Ignite CacheStoreAdapter


Mistake with CacheStoreAdapter. When its method sessionEnd is called a connection of CacheStoreSessionResource is always is closed. There are no any exceptions. But indeed transaction is not commited and no any changes in a database. My code is very simple. All is done according to the original Ignite examples.

Client

IgniteCache<String, String> typeCache = ignite.getOrCreateCache("typeCache");
try (Transaction tx = ignite.transactions().txStart(TransactionConcurrency.PESSIMISTIC,
        TransactionIsolation.REPEATABLE_READ)) {
    typeCache.put("code", "name");
    tx.commit();
}
catch (Exception e) {
    log.error("ERROR. Put Type: " + type, e);
}

Server:

public class CacheJdbcTypeStore extends CacheStoreAdapter<String, String> {

    @CacheStoreSessionResource
    private CacheStoreSession ses;

    @Override
    public void write(Cache.Entry<? extends String, ? extends String> entry) {
        String key = entry.getKey();
        String val = entry.getValue();

        try (Connection conn = connection(ses)) {
            try (PreparedStatement st = conn.prepareStatement(
                    "insert into t_type (code, name) values (?, ?)")) {
                st.setString(1, key);
                st.setString(2, val);
                st.executeUpdate();
            }
        }
        catch (Exception e) {
            throw new CacheWriterException("Failed to write Type " + val, e);
        }
    }

    @Override
    public void sessionEnd(boolean commit) {
        try (Connection conn = ses.attachment()) {
            if (conn != null && !conn.isClosed() && ses.isWithinTransaction()) {
                if (commit)
                    conn.commit();
                else
                    conn.rollback();
            }
        }
        catch (SQLException e) {
            throw new CacheWriterException("Failed to end store session of Type cache", e);
        }
    }

    private Connection connection(CacheStoreSession ses) throws Exception {
        if (ses.isWithinTransaction()) {
            Connection conn = ses.attachment();
    /************************************/
    /* Here conn always is closed. WHY???? */
    /* As result transaction is never commited !!!! */
    /************************************/
            if (conn == null || conn.isClosed()) {
                conn = openConnection(false);
                ses.attach(conn);
            }
            return conn;
        }
        else {
            return openConnection(true);
        }
    }

    // Opens JDBC connection.
    private Connection openConnection(boolean autocommit) throws Exception {
        Connection conn = DriverManager.getConnection(url);
        conn.setAutoCommit(autocommit);
        return conn;
    }

    @Override
    public String load(final String key) {
        return null;
    }

    @Override
    public void delete(Object key) {
    }

}

Configuration

<property name="cacheConfiguration">
    <list>
        <bean class="org.apache.ignite.configuration.CacheConfiguration">
            <property name="name" value="typeCache" />
            <property name="cacheMode" value="PARTITIONED" />
            <property name="atomicityMode" value="TRANSACTIONAL" />
            <property name="backups" value="1" />
            <property name="cacheStoreFactory">
                <bean class="javax.cache.configuration.FactoryBuilder"
                    factory-method="factoryOf">
                    <constructor-arg
                    value="ru.raiffeisen.cache.store.jdbc.CacheJdbcTypeStore" />
                </bean>
            </property>
            <property name="readThrough" value="true" />
            <property name="writeThrough" value="true" />
        </bean>
    </list>
</property>

Solution

  • You use try-with-resource for connection, so each time, when you leave this block, a connection will be closed.

    try (Connection conn = ses.attachment()) {}
    

    I think you checked this implementation:https://apacheignite.readme.io/docs/3rd-party-store#section-cachestore-example but, as you can see, it mentioned that it's not a transactional. Please check this cache store implementation as an example of transactional cache store

    Also, to see non null value in conn variable, try to add more than one insert inside transaction.