我有一个使用2 db事务运行的多线程java进程,如下所示:
. . dbop1(); . . . dbop2(); . .
当我终止进程(在linux上使用kill)时,数据库可能会丢失完整性,因为程序可能会在dbop1()和dbop2()之间终止。
如果有办法捕捉杀死信号然后优雅终止?例如,如果kill介于两者之间,我想仍然完成dbop2()然后终止。
try{ beginTransaction(); getSession().save(obj); //sessionFactory.openSession().save(obj); commitTransaction(); } catch(Exception e){ e.printStackTrace(); rollbackTransaction(); throw e; }finally{ closeSession(); }
答案 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的一种机制。