使用数据库读取和写入来杀死多线程操作

时间:2014-07-22 23:51:00

标签: java linux multithreading hibernate exception

我有一个使用2 db事务运行的多线程java进程,如下所示:

.
.
dbop1();
.
.
.
dbop2();
.
.

当我终止进程(在linux上使用kill)时,数据库可能会丢失完整性,因为程序可能会在dbop1()和dbop2()之间终止。
如果有办法捕捉杀死信号然后优雅终止?例如,如果kill介于两者之间,我想仍然完成dbop2()然后终止。

由于性能问题,我对在单个事务中进行2 db事务犹豫不决。 而且我假设如果在数据库事务期间发生了杀死,数据就不会被破坏,这是真的吗? 更多dbop1()和dbop2()是hibernate包装器,如下所示:

    try{
            beginTransaction();
            getSession().save(obj);
            //sessionFactory.openSession().save(obj);
            commitTransaction();

        }
        catch(Exception e){
            e.printStackTrace();

            rollbackTransaction();
            throw e;
        }finally{
            closeSession(); 
        }

1 个答案:

答案 0 :(得分:1)

正如您已经提到的,这里的正确方法是将两个db语句放在一个事务中,因为其他任何事情很可能都存在完整性问题。这可能取决于您的特定用例,但完整性问题通常比您在此处遇到的任何性能问题更为重要。

这种情况的原因超出了通过kill被杀死的应用程序,因为第二个db语句可能有异常,应用程序可能在它们之间崩溃,或者服务器/网络可能有问题,等等。所以最好的做法肯定是将两个陈述都放在一个交易中。

现在,说完所有这些,可以根据kill级别来阻止kill语句,可能是通过注册一个等待(或阻塞)的关闭钩子,直到两个语句都完成为止。但是,我不建议这样做,因为kill -9会完全跳过这个,就像上面提到的其他可能性一样。

E.g。 (仅为完整性,因为我根本不建议使用以下代码)。 使用ReentrantReadWriteLock以某种方式通过sharedState共享(可能设置为下面的关闭挂钩,或者如果你真的想要它可能是单身)。

Runtime.getRuntime.addShutdownHook(new Thread() {
    public void run()
    {
        sharedState.rwl.writeLock().lock();
        System.out.println("We are shutting down!");
        // Hopefully holding this lock does not prevent our shutdown
        // I.e. no other thread needs it to complete gracefully
    }
}

try
{
    sharedState.rwl.readLock().lock();
    dbOp1;
    dbOp2;
} finally
{
    sharedState.rwl.readLock().unlock();
}

其中sharedState表示您在关闭钩子和运行数据库操作的代码之间共享rwl的一种机制。