1

我使用非常标准的 Java ODBC 功能——Connection从池中获取一个,创建一个Statement并执行它。

我们的用例是一个游戏,记录游戏进度 - ODBC 调用主要是对存储过程的调用,并且在大多数情况下没有返回值。所以 ODBC 调用阻塞的事实很烦人 - 游戏已经是基于回合的,但如果 DB 很慢,用户可以看到更长的暂停。

如果我不需要检查 ODBC 调用的结果,是否有任何内置功能可以异步执行语句?如果不是,那么在不编写大量代码的情况下,有什么好方法可以做到这一点?我仍然需要在 ODBC 异常发生时捕获它们。

这个问题看起来相关,但不完全相同……异步 jdbc 调用可能吗?

4

4 回答 4

10

假设您有一个OdbcCaller

public class OdbcCaller {

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

您可以将其包装在一个可运行的任务中并将该任务提交到线程池以使其异步执行:

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.
}

是JDK提供的executor线程池实现,可以定义如下:

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());

ThreadPoolExecutor是高度可配置的,并且在JavaDoc中有很好的记录,您可能需要先阅读它。

以下是根据我的经验对线程池配置的一些建议:

  • 正确的线程池大小取决于场景,您可能需要运行一些测试来调整它。
  • 当没有可用的工作线程时,工作队列用于缓存任务。无界队列不是一个好主意,因为您可能会耗尽内存。
  • ThreadFactory为线程提供一个有意义的名称是一种很好的做法。jstack当您需要检查线程状态(使用或其他工具)时,它将非常有用。
  • 当没有可用资源时应用拒绝策略。您可以选择一种内置策略(reject、discard、caller-run、discardOldest),或实施您自己的策略。
于 2013-02-23T16:31:56.827 回答
0
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);
    }
}

使用 100 个不同的参数运行对 your_procedure 的调用 100 次。

于 2013-02-27T13:45:38.503 回答
0

如果您使用的是 EJB 3.1,您可以创建一个@StatelessEJB,并标记其中一种方法@Asynchronous。这是企业 Java 环境的开箱即用解决方案(建议外部管理Thread资源)。

于 2013-02-27T16:41:52.087 回答
-2

对此不确定,但也许您可以使用 aynsctask?在不同的线程中处理数据库的东西

于 2013-02-19T18:36:09.727 回答