It often happens that there is a good library, but something is missing in it, some pearl buttons. So it’s to me with Activiti , a rather popular business process engine with BPMN 2.0 support, valuable for its Java nativeness. Without going into details of the internal structure of this open source product, it is quite obvious that in his work he uses a variety of data: metadata of business process definitions, instance data and historical data. For their storage, Activiti uses a DBMS, allowing you to choose from DB2, H2, Oracle, MySQL, MS SQL and PostgreSQL. This engine is very good, and is used not only for small crafts. Perhaps the question of support for caching database accesses in this product arose not only from me. At least once he asked the developers , who responded to it in the sense that the metadata is cached, but for the rest of the data there is not much point in this and it is not easy. In principle, it is possible to agree about the absence of a big sense - the data of a specific instance or its historical data with a small probability can be reused. But the scenario, when this still happens, is also possible. For example, if we have a cluster of Activiti servers with a common base. In general, a person with an inquisitive mind may well want to have a decent cache in Activiti. For example, use Apache Ignite for this .<select id="selectJob" parameterType="string" resultMap="jobResultMap"> select * from ${prefix}ACT_RU_JOB where ID_ = #{id, jdbcType=VARCHAR} </select> <cache type="org.mybatis.caches.ignite.IgniteCacheAdapter" /> @Configuration @ConditionalOnClass(name = "javax.persistence.EntityManagerFactory") @EnableConfigurationProperties(ActivitiProperties.class) public class CachedJpaConfiguration extends JpaProcessEngineAutoConfiguration.JpaConfiguration { @Bean @ConditionalOnMissingBean public SpringProcessEngineConfiguration springProcessEngineConfiguration( DataSource dataSource, EntityManagerFactory entityManagerFactory, PlatformTransactionManager transactionManager, SpringAsyncExecutor springAsyncExecutor) throws IOException { return getCachedConfig(super.springProcessEngineConfiguration (dataSource, entityManagerFactory, transactionManager, springAsyncExecutor)); } private SpringProcessEngineConfiguration getCachedConfig(final SpringProcessEngineConfiguration parentConfig) { Enhancer enhancer = new Enhancer(); CallbackHelper callbackHelper = new CallbackHelper(SpringProcessEngineConfiguration.class, new Class[0]) { @Override protected Object getCallback(Method method) { if (method.getName().equals("initMybatisConfiguration")) { return (MethodInterceptor) (obj, method1, args, proxy) -> getCachedConfiguration( (org.apache.ibatis.session.Configuration) proxy.invokeSuper(obj, args)); } else { return NoOp.INSTANCE; } } }; enhancer.setSuperclass(SpringProcessEngineConfiguration.class); enhancer.setCallbackFilter(callbackHelper); enhancer.setCallbacks(callbackHelper.getCallbacks()); SpringProcessEngineConfiguration result = (SpringProcessEngineConfiguration) enhancer.create(); result.setDataSource(parentConfig.getDataSource()); result.setTransactionManager(parentConfig.getTransactionManager()); result.setDatabaseSchemaUpdate("create-drop"); return result; } private org.apache.ibatis.session.Configuration getCachedConfiguration(org.apache.ibatis.session.Configuration configuration) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(org.apache.ibatis.session.Configuration.class); enhancer.setCallback(new CachedConfigurationHandler(configuration)); return (org.apache.ibatis.session.Configuration) enhancer.create(); } private class CachedConfigurationHandler implements InvocationHandler { private org.apache.ibatis.session.Configuration configuration; CachedConfigurationHandler(org.apache.ibatis.session.Configuration configuration) { this.configuration = configuration; this.configuration.addCache(IgniteCacheAdapter.INSTANCE); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object originalResult = method.invoke(configuration, args); if (method.getName().equals("getMappedStatement")) { return getCachedMappedStatement((MappedStatement) originalResult); } return originalResult; } } private MappedStatement getCachedMappedStatement(MappedStatement mappedStatement) { return new MappedStatement .Builder(mappedStatement.getConfiguration(), mappedStatement.getId(), mappedStatement.getSqlSource(), mappedStatement.getSqlCommandType()) .databaseId(mappedStatement.getDatabaseId()) .resource(mappedStatement.getResource()) .fetchSize(mappedStatement.getFetchSize()) .timeout(mappedStatement.getTimeout()) .statementType(mappedStatement.getStatementType()) .resultSetType(mappedStatement.getResultSetType()) .parameterMap(mappedStatement.getParameterMap()) .resultMaps(mappedStatement.getResultMaps()) .cache(IgniteCacheAdapter.INSTANCE) .useCache(true) .build(); } } result.setDatabaseSchemaUpdate("create-drop"); IgniteConfiguration igniteCfg = new IgniteConfiguration(); igniteCfg.setGridName("testGrid"); igniteCfg.setClientMode(true); igniteCfg.setIgniteHome("<IGNITE_HOME>"); CacheConfiguration config = new CacheConfiguration(); config.setName("myBatisCache"); config.setCacheMode(CacheMode.LOCAL); config.setStatisticsEnabled(true); config.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC); igniteCfg.setCacheConfiguration(config); TcpDiscoverySpi tcpDiscoverySpi = new TcpDiscoverySpi(); TcpDiscoveryJdbcIpFinder jdbcIpFinder = new TcpDiscoveryJdbcIpFinder(); jdbcIpFinder.setDataSource(dataSource); tcpDiscoverySpi.setIpFinder(jdbcIpFinder); tcpDiscoverySpi.setLocalAddress("localhost"); igniteCfg.setDiscoverySpi(tcpDiscoverySpi); TcpCommunicationSpi tcpCommunicationSpi = new TcpCommunicationSpi(); tcpCommunicationSpi.setLocalAddress("localhost"); igniteCfg.setCommunicationSpi(tcpCommunicationSpi); Ignition.ignite("testGrid").getOrCreateCache("myBatisCache").metrics(); Source: https://habr.com/ru/post/310170/
All Articles