简体   繁体   English

Java中的非阻塞ODBC调用

[英]Non-blocking ODBC calls in Java

I use pretty standard Java ODBC functionality - grab a Connection from the pool, create a Statement and execute it. 我使用了非常标准的Java ODBC功能-从池中获取一个Connection ,创建一个Statement并执行它。

Our use-case is a game, logging game progress - ODBC calls are largely calls to stored procedures and in most cases there are no return values. 我们的用例是一个游戏,记录游戏进度-ODBC调用主要是对存储过程的调用,并且在大多数情况下,没有返回值。 So the fact the ODBC call blocks is annoying - the game is already turn based but users can see longer pauses if the DB is slow. 因此,ODBC调用块很烦人-游戏已经基于回合制,但是如果数据库运行缓慢,用户可以看到更长的暂停时间。

If I don't need to check the result of an ODBC call, is there any built-in functionality to execute the statement asyncronously? 如果我不需要检查ODBC调用的结果,是否有任何内置功能可以异步执行该语句? If not, what is a good way to do this without writing lots of code? 如果不是,那么在不编写大量代码的情况下执行此操作的好方法是什么? I DO still need to catch ODBC exceptions when and if they occur. 我仍然需要捕获ODBC异常,只要它们发生就可以了。

This question looks related although not identical... Is asynchronous jdbc call possible? 尽管不完全相同,但这个问题看起来很相关... 可以进行异步jdbc调用吗?

Let's assume you have a OdbcCaller : 假设您有一个OdbcCaller

public class OdbcCaller {

public void callODBC() {
    // call ODBC directly
    // ...
}

You can wrap it in a runnable task and submit the task to a thread pool to make it executes asyncronously: 您可以将其包装在一个可运行的任务中,然后将该任务提交给线程池以使其异步执行:

public void asyncCallODBC() {
    // wrap the call with a runnable task
    executor.execute(new Runnable() {

        @Override
        public void run() {
            callODBC();
        }
    });
    // the above line would return immediately.
}

The executor is a thread pool implementation provided by JDK, it could be defined as follows: executor是JDK提供的线程池实现,可以定义如下:

Executor executor = new ThreadPoolExecutor(/* core pool size */5,
        /* maximum pool size */10,
        /* keepAliveTime */1,
        /* time unit of keepAliveTime */TimeUnit.MINUTES,
        /* work queue */new ArrayBlockingQueue<Runnable>(10000),
        /* custom thread factory */new ThreadFactory() {
            private AtomicInteger counter = new AtomicInteger(0);

            @Override
            public Thread newThread(Runnable r) {
                Thread t = new Thread(r, "asyncCaller-" + (counter.incrementAndGet()));
                return t;
            }
        },
        /*
         * policy applied when all tasks are occupied and task
         * queue is full.
         */new ThreadPoolExecutor.CallerRunsPolicy());

The ThreadPoolExecutor is highly configurable and is welled documented in JavaDoc , you might want read it first. ThreadPoolExecutor是高度可配置的,并且在JavaDoc中有详细记录 ,您可能需要首先阅读它。

Following are some sugguestion of thread pool configurations based on my experiences: 以下是根据我的经验提出的线程池配置的一些建议:

  • The proper thread pool size is depending on the scenario, you may need run some tests to tune it. 适当的线程池大小取决于方案,您可能需要运行一些测试以对其进行调整。
  • The work queue is used to cache the tasks when there are no available worker threads. 当没有可用的工作线程时,工作队列用于缓存任务。 A unbounded queue is not a good idea as you might run out your memory. 无限队列不是一个好主意,因为您可能会耗尽内存。
  • It is a good practice to provide a ThreadFactory and give the threads a meaningful name. 最好提供一个ThreadFactory并为线程指定一个有意义的名称。 It will be very useful when you need to inspect threads states(using jstack or other tools). 当您需要检查线程状态(使用jstack或其他工具)时,它将非常有用。
  • The reject policy is applied when no resources is available. 当没有可用资源时,将应用拒绝策略。 You can choose one of the build-in policy(reject, discard, caller-run, discardOldest), or implement your own policy. 您可以选择一种内置策略(“拒绝”,“丢弃”,“调用者运行”,“ discardOldest”)或实施自己的策略。
public class Snippet
{
    static int i = 0;



    public static void main(String[] args) throws SQLException
    {
        ExecutorService eventExecutor = Executors.newSingleThreadExecutor();
        final Connection c = DriverManager.getConnection("jdbc:url", "user",
                "password");
        Runnable r = new Runnable()
        {

            public void run()
            {
                try
                {
                    CallableStatement s = c
                            .prepareCall("{ call your_procedure(?) }");
                    s.setInt(1, i);
                    s.execute();
                } catch (SQLException e)
                {
                    e.printStackTrace();
                }
            }
        };
        for (; i < 100; i++)
            eventExecutor.submit(r);
    }
}

Runs the call to your_procedure 100 times with 100 different parameters. 使用100个不同的参数将对your_procedure的调用运行100次。

If you are using EJB 3.1, you can create a @Stateless EJB, and mark one of the methods @Asynchronous . 如果使用的是EJB 3.1,则可以创建@Stateless EJB,并标记方法之一@Asynchronous This is an out-of-the-box solution for Enterprise Java environment ( There the external management of Thread resources are not recommended). 这是企业Java环境一个彻头彻尾的现成解决方案( 外部管理Thread资源不推荐)。

Not sure about this but maybe you can use an aynsctask? 不确定,但是也许可以使用aynsctask? That handles db stuff in a different thread 在不同的线程中处理数据库的东西

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM