【问题标题】:Preventing concurrent access to a method in servlet防止同时访问 servlet 中的方法
【发布时间】:2019-05-25 21:31:18
【问题描述】:

我在 servlet 中有一个方法,可以在数据库中插入辅导预约。此方法有一个业务规则,用于检查该会话的导师在该日期和时间是否已经忙。代码看起来像这样:

class BookingService {
    public void insert(Booking t) {
        if(available(t.getTutor(), t.getDate(), t.getTime())) {
            bookingDao.insert(t);
        } else {
            // reject
        }
    }
}

问题是多个用户可能同时尝试在相同的日期和时间预订同一个导师,并且没有什么可以阻止他们通过测试并插入他们的预订。我尝试过使insert() 同步并使用锁,但它不起作用。如何防止并发访问此方法?

【问题讨论】:

  • 你接受了一些不好的建议。当应用程序有多个实例时,同步会失败(例如,这是在云中扩展的一种正常方式)。交易边界在哪里?
  • 有很多方法可以解决这个问题。我同意 synchronized 块并不适用于所有情况,但是 OP 没有指定多应用程序或云情况。
  • @Jason:如果您也描述解决问题的其他方法,您的答案将会大大改善。
  • 有很多方法可以解决这个问题,以至于问题可能会进入too broadprimarily opinion based 的领域。我只是根据当时可用的信息描述了最简单的方法。

标签: java multithreading servlets concurrency


【解决方案1】:

使用 synchronized 是尝试解决此问题的不充分方法:

首先,您将编写应用程序代码,以便一次只能部署一个实例。这不仅仅是在云中扩展。 IT 部门想要支持一个应用程序的多个实例是正常的,这样它就不会出现单点故障(因此,如果托管一个实例的机器出现故障,应用程序仍然可用)。使用静态同步意味着锁不会扩展到一个应用程序类加载器之外,因此多个实例仍然可以以一种容易出错的方式交错工作。

如果您在某个时候离开项目,以后的维护人员可能不会意识到这个问题,并且可能会尝试以您不希望的方式部署应用程序。使用同步意味着您将留下一个地雷让他们偶然发现。

其次,使用同步块会阻碍应用程序的并发性,因为一次只能进行一个线程。

因此,您引入了瓶颈,同时通过部署第二个实例切断了操作解决瓶颈的能力。不是一个好的解决方案。

由于发布的代码没有显示交易在哪里的迹象,我猜是每个 DAO 创建自己的交易,或者您正在以自动提交模式连接。数据库提供事务来帮助解决这个问题,并且由于该功能是在数据库中实现的,因此无论有多少应用程序实例正在运行,它都可以工作。

解决上述问题的一种简单方法是将事务置于服务层,以便所有 DAO 调用都在同一个事务中执行。您可以让服务层从池中检索数据库连接,启动事务,将连接传递给每个 DAO 方法调用,提交事务,然后将连接返回到池。

【讨论】:

  • 谢谢,因为这只是一个大学项目,我们没有学到任何这些东西,我认为无论如何同步都会起作用。但我会调查一下,看看我能不能用这种方式解决它。
  • @Sepfins:很酷,我认为这是一个学校项目。如果您使用的是关系数据库,我会鼓励您了解事务。在工作面试中知道这些东西会让你脱颖而出。
【解决方案2】:

解决问题的一种方法是使用synchronized 块。您可以选择许多东西作为锁定对象 - 目前this 应该没问题:

class BookingService {
    public void insert(Booking t) {
        synchronized(this) {
            if(available(t.getTutor(), t.getDate(), t.getTime())) {
                bookingDao.insert(t);
            } else {
                // reject
            }
        }
    }
}

如果您有多个 servlet 实例,则应使用静态对象作为锁。

【讨论】:

  • 谢谢,用静态对象同步解决了
猜你喜欢
  • 2012-01-25
  • 2016-09-13
  • 2012-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-09-24
相关资源
最近更新 更多