代码之家  ›  专栏  ›  技术社区  ›  Gábor Major

未找到弹簧靴Apache点火表

  •  0
  • Gábor Major  · 技术社区  · 8 年前

    首先,我对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文件中。或者点火无法连接到数据库?(我没有在日志中找到任何表明这一点的信息。)

    我这里缺什么?

    1 回复  |  直到 8 年前
        1
  •  3
  •   alamar    8 年前

    如果您正在对ApacheIgnite执行查询,那么应该是 update "LALicenseCountCache".LALicenseCount set active_count = ?, temporary_count = ? where id = ?

    点燃表名和模式!=Oracle表名和架构。Ignite不实现SQL查询的透明代理。您不通过Ignite查询Oracle,而是查询Ignite自己的SQL。

    注意你也应该这样做 loadCache() 首先将所有数据从Oracle拉到ApacheIgnite的缓存中。否则,您的更新将无法工作,因为Ignite的SQL只对缓存中的内容进行操作。

    推荐文章