首先,我对SpringBoot、RESTAPI非常陌生,尤其是ApacheIgnite,所以这可能是一个小问题,但目前还不能解决。
我有一个Oracle12c数据库,其中包含一些表,问题中的两个表是:
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键,此外还有一个check约束和一个唯一索引。
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键,此外还有一个check约束和一个unique约束。
读取和更新此表需要基于Spring引导的RESTAPI。ApacheIgnite缓存层需要在RESTAPI和数据库之间。执行如下。整个解决方案基于本指南:
https://dzone.com/articles/in-memory-data-grid-with-apache-ignite
,根据其他stackoverflow和各种论坛文章在不工作时进行了一些更改。
数据库bean(自定义,因为密码在日志中以自定义方式加密)。数据源本身工作良好,通过使用自动连线的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);
}
点燃豆子:
@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常量的注释,这部分内容会改变,这段代码只是为了看看我是否能读写数据库。到目前为止,getallocatedllicenses()函数似乎正在工作(没有异常发生),我在响应中成功地接收到一个空的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 db一样?有可能吗?我为Ignite显式地设置了oracleDialect,OracleJDBC驱动程序在pom.xml文件中。或者点火无法连接到数据库?(我没有在日志中找到任何表明这一点的信息。)
我这里缺什么?