【问题标题】:UniObjects for Java how to open sessions to emulate connection poolingUniObjects for Java 如何打开会话以模拟连接池
【发布时间】:2022-01-16 23:22:02
【问题描述】:

我正在开发一个将 UniVerse 数据库连接到 REST 端点的 API。 问题是我们没有使用 UniVerse Java 库进行本地连接池的许可。

这个软件是用 Java 开发的,使用 Spring Boot,以及我打开会话到 Universe 的方式

uniSession = uniJava.openSession();
 uniSession.setHostName(server);
 uniSession.setUserName(userName);
 uniSession.setPassword(password);
 uniSession.setAccountPath(accountPath);
 uniSession.connect(); 

我对其进行迭代并将会话保存在列表“freeSession”中,当我收到请求时,我从该列表中弹出一个会话,将其移动到“occupiedSession”,使用它并返回到“freeSession”。

但问题是 sessios 列表中的所有内容都是“相同的”。我的意思是,我无法接收并发请求,因为我的 API 只有“一个会话”来与 UniVerse 服务器交互。

【问题讨论】:

  • 你用 UniObjects 做什么?查询数据库还是调用 BASIC 子程序?
  • 该文档仅用于付费客户的注册(不是支持采用您的产品的好模型),因此这里的任何人都不太可能提供帮助。您使用的底层 API 是否支持打开多个会话?如果这需要许可证,那么您不太可能破解它,这可能违反了许可条款。
  • @webthaumaturge 仅用于调用子程序
  • Universe 服务器有多少用户/普通许可证?您可以通过在 Universe 服务器上的命令行运行 uv/bin/uvlictool 来确定这一点。您只有一个普通/用户许可证吗?这就是“API 只有一个会话”的意思吗?老实说,您的技术似乎最终会得到多个并行可用的连接。
  • @webthaumaturge 服务器有大约 300 个许可证。但我的 api 可以使用 5 和 30 之间。我无权访问服务器,因为它是我们的客户端的。我的软件必须连接到 Universe 服务器,调用子例程,然后通过 REST 端点返回响应。但问题是如何管理和解决并发请愿。我只有一组凭据可以从我的 API 连接到 Universe。但现在我一次无法解决多个请求

标签: java spring universe unidata uniobjects


【解决方案1】:

尝试在 UniDK 5.2.1 中升级到最新版本的 UniObjects for Java。我猜想使用 UniJava 可能在旧版本中表现出这种行为。只要你只是运行 BASIC 程序,我猜你不会遇到 10.1.21 的任何兼容性问题:

  1. 访问 https://rbc.rocketsoftware.com/u2bcesdinternal.asp?pid=100000047043&product=U2CL 并下载 U2 Current Clients 安装程序

OR(长期)

  1. 访问https://rbc.rocketsoftware.com/buildmatrix.asp
  2. 为产品选择 U2 客户端,为平台选择 Windows
  3. 使用下载列中的产品链接下载安装程序

老实说,我正在使用 UniObjects for Java(在 UniDK 5.2.1 中)从 Spring Boot 应用程序连接到 Universe,并且我能够使用与您类似的代码创建和维护多个并行连接。如果我同时收到十个 Web 请求,我可以在 Universe 中看到十个独立的 uvcs/defcs 连接。我唯一不同的是使用最新的 jars,我只是创建一个新的 UniSession 实例(然后像你一样调用 connect):

UniSession uniSession = new UniSession();

而不是

UniSession uniSession = uniJava.openSession();

然而,最新版本的 UniJava 似乎与创建新实例基本相同,但有一些额外的日志记录和跟踪。

Rocket 中确实有人告诉我,正常的 Universe 许可协议禁止重新创建连接池,从而迫使您购买连接池许可。我没有方便确认的许可证。但是,我不建议在与 Rocket 会面的情况下购买连接池许可证,以讨论您的应用程序在扩展时的具体要求。根据负载、持久性和性能要求,您可能需要将读取操作分散到多个 Universe 复制中,已发布的连接池许可模型无法很好地/成本有效地支持此操作。

【讨论】:

  • 感谢您的回答!我昨天已经解决了这个问题...我会尝试你分享给我的最新版本!我之前没有找到这些资源
  • 我还有一个问题:如何控制会话,以免它们因超时而死?我希望连接始终可用,并且在调用子例程时不会出现“RPC 失败”错误。
【解决方案2】:

已经有一段时间了,我无法再访问代码了,但几年前我处理过类似的问题。该解决方案使用semaphore 来帮助实现并发。创建一个可以全局共享的连接池类。当调用代码需要一个 unisession 时,如果可用,连接池会抓取一个,否则它会阻塞调用线程,直到有一个可用。当然,您不想像本例中那样硬编码计数或连接参数(其中大部分是从信号量 javadocs 复制的)。

import java.util.concurrent.Semaphore;

public class ConnectionPool
{
    private static final int COUNT = 5;
    private static final ConnectionPool INSTANCE = new ConnectionPool();

    private final Semaphore available = new Semaphore(COUNT, true);
    protected UniSession[] items =  new UniSession[COUNT];

    protected boolean[] used = new boolean[COUNT];
    protected UniJava uniJava = new UniJava();

    private ConnectionPool() {
        for (int i = 0; i < COUNT; i++) {
            items[i] = uniJava.openSession();
            items[i].setHostName("server name");
            items[i].setUserName("user name");
            items[i].setPassword("password");
            items[i].setAccountPath("account path");
            items[i].connect();
        }
    }

    public static ConnectionPool getInstance() {
        return INSTANCE;
    }

    public UniSession borrow() throws InterruptedException {
        available.acquire();
        return getNextAvailableItem();
    }

    public void release(UniSession session) {
        if (markAsUnused(session))
            available.release();
    }

    protected synchronized UniSession getNextAvailableItem() {
        for (int i = 0; i < COUNT; ++i) {
            if (!used[i]) {
                used[i] = true;
                return items[i];
            }
        }
        return null;
    }

    protected synchronized boolean markAsUnused(Object item) {
        for (int i = 0; i < COUNT; ++i) {
            if (item == items[i]) {
                if (used[i]) {
                    used[i] = false;
                    return true;
                } else
                    return false;
            }
        }
        return false;
    }

}

然后在您的 API 代码中,当您需要一个 unisession 时,您会从池中借用一个,并确保在完成后释放它。像这样的:

UniSession uniSession = null;

try {
    uniSession = ConnectionPool.getInstance().borrow();
    
    // do work
    
} finally {
    ConnectionPool.getInstance().release(uniSession);
}

这使您的应用程序可以重复使用会话池,并且会话数永远不会超过您指定的计数。

【讨论】:

    猜你喜欢
    • 2010-12-12
    • 1970-01-01
    • 2016-12-25
    • 2012-07-03
    • 2015-01-03
    • 2017-07-17
    • 1970-01-01
    • 1970-01-01
    • 2021-01-22
    相关资源
    最近更新 更多