Java 关系数据库锁定

Java 关系数据库锁定,java,database,multithreading,Java,Database,Multithreading,在面试期间,我一直在问以下问题: 有以下情况 大约有10个线程从队列中获取信息(作为消息对象放入),对其进行解析并将其传递到同一个数据库表。虽然将数据传递到数据库的过程很复杂,包含大量操作,包括插入、删除和更新,但整个过程是原子的,受事务打开和事务关闭操作的限制。当队列开始获得重复消息时,DB开始面临许多问题,如锁、死锁、回滚和e.t.c 伪代码说明: function void doWork(Message msg){ int msgId = msg.getId(); Timestam

在面试期间,我一直在问以下问题: 有以下情况 大约有10个线程从队列中获取信息(作为消息对象放入),对其进行解析并将其传递到同一个数据库表。虽然将数据传递到数据库的过程很复杂,包含大量操作,包括插入、删除和更新,但整个过程是原子的,受事务打开和事务关闭操作的限制。当队列开始获得重复消息时,DB开始面临许多问题,如锁、死锁、回滚和e.t.c 伪代码说明:

function void doWork(Message msg){
  int msgId = msg.getId();
  Timestamp msgTime = msg.getTime();
  Data data = msg.getData();
  OpenTransaction;
     // manipulate db 
     parseIntoDB(msgId, msgTime,data);
  CloseTransaction; 
}
值得注意的是,表没有约束。我问了两个问题:

  • 为什么它(锁定)只发生在重复数据中

  • 如何快速解决问题而不考虑 表演

  • 过了一段时间,当我无法解释为什么会发生锁定时,她说这是由于同一行上的锁造成的。所以我认为我们应该在处理数据库时对函数执行一些同步,从而在parseIntoDB上放置synchronized块

    function void doWork(Message msg){
      int msgId = msg.getId();
      Timestamp msgTime = msg.getTime();
      Data data = msg.getData();
      OpenTransaction;
         synchronized(someObject){
            // manipulate db 
            parseIntoDB(msgId, msgTime,data);
         }
      CloseTransaction; 
    }
    

    根据她的回答,我的方向是正确的,但我仍然不知道是只锁定parseIntoDB函数还是同时锁定事务活动,应该对哪个对象进行第二次监视?

    这个问题测试理论事务隔离级别的知识,可能还有MVCC之类的实现细节(Oracle)与行和页锁定(MSSQL)的对比


    我不会在这里详细讨论,因为这是书中的主题,但我怀疑面试官想向她介绍访问序列化、幂等操作、最小化工作量、可伸缩性、一致性模型,可能是乐观锁定或A/B死锁。

    如果不知道事务是如何实现的,我们就无法真正回答这个问题nd处理的作用。我们还必须知道我们被允许和/或被要求对重复的消息做什么:我们必须处理它们,或者不处理它们,或者我们必须只部分处理它们,或者我们不能处理它们?同样,为了使并发处理变得可靠,我们必须解决系统状态的许多方面。但是我们可以在概括性

    我将假定msgId标识一条消息

    如果没有重复消息,则每个事务都在不同的msgId上。由于以前没有问题,但现在有问题,我们可以预期DBMS已设置为允许不同msgId上的事务同时进行

    但是,随着消息的多个副本到达(即使它们不在同一时间的队列中),多个线程可以同时尝试影响数据库中是否存在重叠的行集。这导致了问题

    粗略地说,如果线程使用的msgId中没有重复的msgId,我们的问题就不会出现。因此,解决方案是每个msgId都有一个锁管理器。线程从队列中获取一个msgId。它尝试获取该msgId上的锁。如果失败,则根据策略,它要么丢弃消息并请求另一个,要么等待。当线程是用msgId完成的,它会解锁它。等待必须根据锁管理器实现的某种协议来执行活动性

    但是,更好的解决方案是,线程只需查看一个队列,该队列为线程提供了一个msgId,但它们也会在何时使用该msId通知队列。这样的队列是使用这样的锁管理器和旧队列实现的

    我再说一遍,这是粗糙和一般的。合理的并发编程是复杂的