I'm not sure that this case is valid at all right now, since as for now, Ignite doesn't support transactions for SQL.
Evgenii 2018-07-24 13:36 GMT+03:00 Maxim Malygin <[email protected]>: > Hi Evgenii, > > Thanks for the answer. > Unfortunately it seems it does matter. If I do a query inside a > transaction and use an instance of a cache that differs of a cache inside > the query, I will get the following exception (note I do it on client node): > > Exception in thread "main" javax.cache.CacheException: Cannot start/stop > cache within lock or transaction. > at org.apache.ignite.internal.processors.cache. > IgniteCacheProxyImpl.query(IgniteCacheProxyImpl.java:676) > at org.apache.ignite.internal.processors.cache. > IgniteCacheProxyImpl.query(IgniteCacheProxyImpl.java:615) > at org.apache.ignite.internal.processors.cache. > GatewayProtectedCacheProxy.query(GatewayProtectedCacheProxy.java:356) > at simax.test.Startup.main(Startup.java:39) > Caused by: class org.apache.ignite.IgniteException: Cannot start/stop > cache within lock or transaction. > at org.apache.ignite.internal.processors.cache.GridCacheProcessor. > checkEmptyTransactions(GridCacheProcessor.java:4251) > at org.apache.ignite.internal.processors.cache.GridCacheProcessor. > dynamicStartCache(GridCacheProcessor.java:2942) > at org.apache.ignite.internal.processors.cache.GridCacheProcessor. > dynamicStartCache(GridCacheProcessor.java:2884) > at org.apache.ignite.internal.processors.cache.GridCacheProcessor. > createMissingQueryCaches(GridCacheProcessor.java:4114) > at org.apache.ignite.internal.processors.query.h2. > IgniteH2Indexing.prepareStatementAndCaches(IgniteH2Indexing.java:2017) > at org.apache.ignite.internal.processors.query.h2. > IgniteH2Indexing.parseAndSplit(IgniteH2Indexing.java:1796) > at org.apache.ignite.internal.processors.query.h2. > IgniteH2Indexing.querySqlFields(IgniteH2Indexing.java:1652) > at org.apache.ignite.internal.processors.query. > GridQueryProcessor$4.applyx(GridQueryProcessor.java:2035) > at org.apache.ignite.internal.processors.query. > GridQueryProcessor$4.applyx(GridQueryProcessor.java:2030) > at org.apache.ignite.internal.util.lang.IgniteOutClosureX. > apply(IgniteOutClosureX.java:36) > at org.apache.ignite.internal.processors.query.GridQueryProcessor. > executeQuery(GridQueryProcessor.java:2578) > at org.apache.ignite.internal.processors.query.GridQueryProcessor. > querySqlFields(GridQueryProcessor.java:2044) > at org.apache.ignite.internal.processors.cache. > IgniteCacheProxyImpl.query(IgniteCacheProxyImpl.java:664) > > It seems the issue is in starting cache used in the query. If I get > IgniteCache instance for that cache, it will be started before the > transaction. But if it's never used in Ignite.cache(..) or > ignite.getOrCreateCache(..), the cache will be started inside query(..) > method which is executed in the transaction and I will get the above listed > exception. As workaround, I need to pre-initialize all caches used in > queries using either Ignite.cache(..) or ignite.getOrCreateCache(..). Note > that all caches are configured in XML configuration on server nodes only > but the queries is executed on a client node. > > The code is very simple: > > public class Startup { > private static final Logger log = LogManager.getLogger(Startup.class); > > public static void main(String[] args) { > boolean client = args.length >= 1 && "client".equalsIgnoreCase( > args[0]); > Ignite ignite; > if (client) { > log.info("Starting client node..."); > ignite = Ignition.start("client.xml"); > } else { > log.info("Starting server node..."); > ignite = Ignition.start("server.xml"); > } > log.info("Cache names: " + ignite.cacheNames()); > IgniteCache<?, ?> cache1 = ignite.cache("Cache1"); > > try (Transaction tx = ignite.transactions().txStart()) { > // query from cache1 using instance of cache1 > List<List<?>> r1 = cache1.query(new SqlFieldsQuery("SELECT * > FROM Cache1")).getAll(); // No exception here because Cache1 is already > initialized by ignite.cache("Cache1") > log.info("Result from cache1: " + r1); > } > > try (Transaction tx = ignite.transactions().txStart()) { > // query from cache2 using instance of cache1 > List<List<?>> r2 = cache1.query(new SqlFieldsQuery("SELECT * > FROM Cache2")).getAll(); // <<< Got exception here if invoked on client > node (clientMode=true) > log.info("Result from cache2: " + r2); > } > } > } > > client.xml: > > <?xml version="1.0" encoding="UTF-8"?> > <beans xmlns="http://www.springframework.org/schema/beans" > xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" > xmlns:context="http://www.springframework.org/schema/context" > xsi:schemaLocation="http://www.springframework.org/schema/beans > http://www.springframework.org/schema/beans/spring-beans-4.3.xsd"> > <bean class="org.apache.ignite.configuration.IgniteConfiguration"> > <property name="clientMode" value="true"/> > </bean> > </beans> > > server.xml: > > <?xml version="1.0" encoding="UTF-8"?> > <beans xmlns="http://www.springframework.org/schema/beans" > xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" > xmlns:context="http://www.springframework.org/schema/context" > xsi:schemaLocation="http://www.springframework.org/schema/beans > http://www.springframework.org/schema/beans/spring-beans-4.3.xsd"> > <bean class="org.apache.ignite.configuration.IgniteConfiguration"> > <property name="clientMode" value="false"/> > <property name="cacheConfiguration"> > <list> > <bean class="org.apache.ignite.configuration. > CacheConfiguration"> > <property name="name" value="Cache1"/> > <property name="sqlSchema" value="PUBLIC"/> > <property name="queryEntities"> > <list> > <bean class="org.apache.ignite. > cache.QueryEntity"> > <property name="keyType" > value="Cache1Key"/> > <property name="keyFields"> > <set> > <value>id1</value> > <value>id2</value> > </set> > </property> > <property name="valueType" value="Cache1"/> > <property name="fields"> > <map> > <entry key="id1" > value="java.lang.String"/> > <entry key="id2" > value="java.lang.String"/> > <entry key="aaa" > value="java.lang.String"/> > <entry key="bbb" > value="java.lang.String"/> > <entry key="ccc" > value="java.lang.String"/> > </map> > </property> > </bean> > </list> > </property> > </bean> > <bean class="org.apache.ignite.configuration. > CacheConfiguration"> > <property name="name" value="Cache2"/> > <property name="sqlSchema" value="PUBLIC"/> > <property name="queryEntities"> > <list> > <bean class="org.apache.ignite. > cache.QueryEntity"> > <property name="keyType" > value="Cache2Key"/> > <property name="keyFields"> > <set> > <value>id3</value> > <value>id4</value> > </set> > </property> > <property name="valueType" value="Cache2"/> > <property name="fields"> > <map> > <entry key="id3" > value="java.lang.String"/> > <entry key="id4" > value="java.lang.String"/> > <entry key="xxx" > value="java.lang.String"/> > <entry key="yyy" > value="java.lang.String"/> > <entry key="zzz" > value="java.lang.String"/> > </map> > </property> > </bean> > </list> > </property> > </bean> > </list> > </property> > </bean> > </beans> > > Maybe I do something incorrectly? > > Thanks, > Maxim > > пн, 23 июл. 2018 г. в 17:51, Evgenii Zhuravlev <[email protected]>: > >> Hi Maxim, >> >> It doesn't matter, which cache you will use for SQL queries here, so, >> yes, you can use some dummy cache. In future, afaik, there are plans to >> change this API, the method will be placed in Ignite class instead of >> IgniteCache. >> >> Regards, >> Evgenii >> >> 2018-07-23 17:41 GMT+03:00 Maxim Malygin <[email protected]>: >> >>> Hi, >>> >>> I have the question regarding Java API for SQL queries. >>> As I understand from the documentation, API for SQL queries is placed in >>> IgniteCache interface ("query" method). This means that I need to get or >>> create a cache to do a SQL query. What cache name I should use to get >>> instance of IgniteCache? Some dummy cache? >>> >>> Thanks, >>> Maxim >>> >> >>
