首先,我对Spring Boot,REST API都很陌生,尤其是apache点燃,所以这可能是一个微不足道的问题,但我暂时无法解决它 .
我有一个包含几个表的Oracle 12c数据库,问题中的两个是:
create table la_license_count (
total_count number not null default 100,
active_count number not null default 0,
temporary_count number not null default 0,
id number not null
);
列'id'是pimary键,除此之外还有一个检查约束和一个唯一索引 .
create table la_license_mapping (
client_id varchar2(200 byte) not null,
license_count number not null default 0,
license_type chat(1 byte) not null default 'F',
registered_at date not null default sysdate,
keepalive_time number,
id number not null;
);
列'id'是pimary键,除此之外还有一个检查约束和一个唯一约束 .
需要基于Spring Boot的REST API来读取和更新此表 . Apache Ignite缓存层需要位于REST API和数据库之间 . 这实现如下 . 整个解决方案基于本指南:https://dzone.com/articles/in-memory-data-grid-with-apache-ignite,基于其他StackOverflow和各种论坛文章的一些更改,当它不工作时 .
数据库bean(自定义,因为密码是以自定义方式在日志中加密的) . DataSource本身工作正常,通过使用自动装配的JdbcTemplate执行CallableStatement进行测试;
@Configuration
public class DatabaseBean {
@Autowired
private ConfigReader configReader;
@Bean(destroyMethod = "")
public DataSource dataSource() {
DatabaseSettings db = configReader.getDatabaseSettings();
return DataSourceBuilder
.create()
.url(db.getConnectionString())
.username(db.getUserName())
.password(db.isPasswordEncrypted() ? Encryptor.decrypt(db.getPassword()) : db.getPassword())
.driverClassName(db.getDriverClassName())
.build();
}
}
实体类:
public class LALicenseCount implements Serializable {
private static final long serialVersionUID = -1L;
private final AtomicLong ID_GEN = new AtomicLong();
private Long id;
private Long totalCount;
private Long activeCount;
private Long temporaryCount;
// getters, setters
public void init() {
this.id = ID_GEN.getAndIncrement();
}
// Various methods for business logic
}
public class LALicenseMapping implements Serializable {
private static final long serialVersionUID = -1L;
private final AtomicLong ID_GEN = new AtomicLong();
private Long id;
@QuerySqlField(index = false)
private String clientID;
private Long licenseCount;
@QuerySqlField(index = false)
private String licenseType;
private Date registeredAt;
private Long keepaliveTime;
// getters, setters
public void init() {
this.id = ID_GEN.getAndIncrement();
}
// Various methods for business logic
}
库:
@Repository
@RepositoryConfig(cacheName = "LALicenseCountCache")
public interface LALicenseCountRepository extends IgniteRepository<LALicenseCount, Long> {
}
@Repository
@RepositoryConfig(cacheName = "LALicenseMappingCache")
public interface LALicenseMappingRepository extends IgniteRepository<LALicenseMapping, Long> {
List<LALicenseMapping> findByClientID(String clientID);
List<LALicenseMapping> findByClientIDAndLicenseType(String clientID, String licenseType);
}
点燃 beans 子:
@Component
public class IgniteConfigurationBean {
@Autowired
private ConfigReader configReader;
@Autowired
private ApplicationContext applicationContext;
@Bean
public Ignite igniteInstance() {
IgniteConfiguration cfg = new IgniteConfiguration();
cfg.setIgniteInstanceName("ignite-1");
cfg.setPeerClassLoadingEnabled(true);
CacheConfiguration<Long, LALicenseCount> ccfg = new CacheConfiguration<>("LALicenseCountCache");
ccfg.setIndexedTyped(Long.class, LALicenseCount.class);
ccfg.setWriteBehind(true);
ccfg.setReadThrough(true);
ccfg.setWriteThrough(true);
CacheJdbcPojoStoreFactory<Long, LALicenseCount> f = new CacheJdbcPojoStoreFactory<>();
f.setDataSourceBean("dataSource");
f.setDialect(new OracleDialect());
JdbcType t = new JdbcType();
t.setCacheName("LALicenseCountCache");
t.setKeyType(Long.class);
t.setValueType(LALicenseCount.class);
t.setDatabaseTable("la_license_count");
t.setDatabaseSchema(configReader.getDatabaseSettings().getUserName());
t.setKeyFields(new JdbcTypeField(Types.INTEGER, "id", Long.class, "id"));
t.setValueFields(
new JdbcTypeField(Types.INTEGER, "total_count", Long.class, "totalCount"),
new JdbcTypeField(Types.INTEGER, "active_count", Long.class, "activeCount"),
new JdbcTypeField(Types.INTEGER, "temporary_count", Long.class, "temporaryCount"));
f.setTypes(t);
ccfg.setCacheStoreFactory(f);
CacheConfiguration<Long, LALicenseMapping> ccfg2 = new CacheConfiguration<>("LALicenseMappingCache");
ccfg2.setIndexedTyped(Long.class, LALicenseMapping.class);
ccfg2.setWriteBehind(true);
ccfg2.setReadThrough(true);
ccfg2.setWriteThrough(true);
CacheJdbcPojoStoreFactory<Long, LALicenseMapping> f2 = new CacheJdbcPojoStoreFactory<>();
f2.setDataSourceBean("dataSource");
f2.setDialect(new OracleDialect());
JdbcType t2 = new JdbcType();
t2.setCacheName("LALicenseMappingCache");
t2.setKeyType(Long.class);
t2.setValueType(LALicenseCount.class);
t2.setDatabaseTable("la_license_mapping");
t2.setDatabaseSchema(configReader.getDatabaseSettings().getUserName());
t2.setKeyFields(new JdbcTypeField(Types.INTEGER, "id", Long.class, "id"));
t2.setValueFields(
new JdbcTypeField(Types.VARCHAR, "client_id", String.class, "clientID"),
new JdbcTypeField(Types.INTEGER, "license_count", Long.class, "licenseCount"),
new JdbcTypeField(Types.VARCHAR, "license_type", String.class, "licenseType"),
new JdbcTypeField(Types.DATE, "registered_at", java.sql.Date.class, "registeredAt"),
new JdbcTypeField(Types.INTEGER, "keepalive_time", Long.class, "keepaliveTime"));
f2.setTypes(t2);
ccfg2.setCacheStoreFactory(f2);
cfg.setCacheConfiguration(ccfg, ccfg2);
return IgniteSpring.start(cfg, applicationContext);
}
}
主要应用类:
@SpringBootApplication
@EnableSwagger2
@ComponentScan(basePackages = {...})
@EnableIgniteRepositories("...")
public class Swagger2SpringBoot extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Swagger2SpringBoot.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(Swagger2SpringBoot.class, args);
}
}
使用此配置,应用程序至少启动 . 我花了很长时间来计算如何设置bean,注释,依赖项等 . 现在我使用这些方式:
@Service
public class LicenseManager {
@Autowired
private LALicenseCountRepository laLicenseCountRepository;
@Autowired
private LALicenseMappingRepository laLicenseMappingRepository;
@Autowired
private Ignite ignite;
private LALicenseCount licenseCount;
private IgniteCache<Long, LALicenseCount> laLicenseCountCache;
@PostConstruct
public void init() {
// There is only one LA_LICENSE_COUNT record always in the DB, and the ID is 1
licenseCount = laLicenseCountRepository.findOne(1L);
laLicenseCountCache = ignite.getOrCreateCache("LALicenseCountCache");
}
public Iterable<LALicenseMapping> getAllAllocatedLicenses() {
return laLicenseMappingRepository.findAll();
}
public void allocateNewLicense(String clientID) {
// prechecks
laLicenseCountCache.query(
new SqlFieldsQuery(
sqlReader.getLicense().getUpdateAllocatedCounts()
).setArgs(
licenseCount.getActiveCount(),
licenseCount.getTemporaryCount(),
1L
)
);
// remaining logic
}
}
请在代码中备用关于1L常量的注释,这部分会改变,这段代码只是为了看看我是否可以读/写数据库 . 到目前为止,getAllAllocatedLicenses()函数似乎正在工作(没有异常发生),我在响应中成功接收到一个空的JSON数组 . 问题是我手动将记录输入数据库表后也收到一个空的JSON数组(不确定Ignite是否应该找到此记录,但我认为是) .
更大的问题是写操作失败 . 应该执行的SQL来自属性文件,如下所示:
update la_license_count set active_count = ?, temporary_count = ? where id = ?
我收到以下stacktraces(仅在laLicenseCountCache.query行之前显示):
2018-07-11 17:40:33.211 [http-nio-9080-exec-8] INFO h.t.c.e.service.LicenseManager - 123456 - Processing new license allocation for client
2018-07-11 17:40:33.506 [http-nio-9080-exec-8] DEBUG h.t.c.e.service.LicenseManager - 123456 - Checks done, allocating new final license
2018-07-11 17:40:33.515 [http-nio-9080-exec-8] ERROR h.t.c.e.a.LAMiddlewareApiController - Unknown exception
javax.cache.CacheException: Failed to parse query. Table "LA_LICENSE_COUNT" not found; SQL statement:
update la_license_count set active_count = ?, temporary_count = ? where id = ? [42102-196]
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 h.t.c.e.s.LicenseManager.allocateLicenseForCid(LicenseManager.java:127)
at h.t.c.e.s.a.LAMiddlewareApiController.lAMiddlewareLicensesCidGet(LAMiddlewareApiController.java:147)
...
Caused by: org.apache.ignite.internal.processors.query.IgniteSQLException: Failed to parse query. Table "LA_LICENSE_COUNT" not found; SQL statement:
update la_license_count set active_count = ?, temporary_count = ? where id = ? [42102-196]
...
Caused by: org.h2.jdbc.JdbcSQLException: Table "LA_LICENSE_COUNT" not found; SQL statement:
update la_license_count set active_count = ?, temporary_count = ? where id = ? [42102-196]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
at org.h2.message.DbException.get(DbException.java:179)
at org.h2.message.DbException.get(DbException.java:155)
at org.h2.command.Parser.readTableOrView(Parser.java:5552)
at org.h2.command.Parser.readTableOrView(Parser.java:5529)
at org.h2.command.Parser.readSimpleTableFilter(Parser.java:796)
at org.h2.command.Parser.parseUpdate(Parser.java:739)
at org.h2.command.Parser.parsePrepared(Parser.java:471)
at org.h2.command.Parser.parse(Parser.java:321)
at org.h2.command.Parser.parse(Parser.java:293)
at org.h2.command.Parser.prepareCommand(Parser.java:258)
at org.h2.engine.Session.prepareLocal(Session.java:578)
at org.h2.engine.Session.prepareCommand(Session.java:519)
at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1204)
at org.h2.jdbc.JdbcPreparedStatement.<init>(JdbcPreparedStatement.java:73)
at org.h2.jdbc.JdbcConnection.prepareStatement(JdbcConnection.java:288)
at org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing.prepare0(IgniteH2Indexing.java:484)
at org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing.prepareStatement(IgniteH2Indexing.java:452)
at org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing.prepareStatement(IgniteH2Indexing.java:419)
at org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing.prepareStatementAndCaches(IgniteH2Indexing.java:2008)
... 85 common frames omitted
根据最后一个异常,它看起来像是在尝试访问Oracle数据库,就好像它是H2数据库一样?那可能吗?我为Ignite显式设置了OracleDialect,而Oracle JDBC驱动程序在pom.xml文件中 . 或者Ignite无法连接到DB? (我没有在日志中找到任何可以表明这一点的内容 . )
我在这里想念的是什么?
1 回答
如果你正在对Apache Ignite执行查询,它可能应该是
update "LALicenseCountCache".LALicenseCount set active_count = ?, temporary_count = ? where id = ?
Ignite表名和模式!= Oracle表名和模式 . Ignite不实现SQL查询的透明代理 . 您不通过Ignite查询Oracle,而是查询Ignite自己的SQL .
请注意,您应该执行
loadCache()
,以便最初将所有数据从Oracle提取到Apache Ignite 's cache. Otherwise your update won' t,因为缓存中的Ignite 's SQL only operates on what'已经存在 .