【问题标题】:JMS MessageDriven bean - how to synchronize threads?JMS MessageDriven bean - 如何同步线程?
【发布时间】:2015-09-26 19:22:57
【问题描述】:

尽管messagedriven bean是基于异步逻辑的,但我有以下场景:

  1. 2 个包含用户凭据的领域(jdbc 和 ldap)
  2. 当用户在表单中输入用户名和密码时,它会尝试在两个领域(jdbc 和 ldap)中进行身份验证
  3. 对于每个领域的登录尝试,我都会使用 JMS 发送一条消息以记录它

我的问题在于 onMessage(Message message) 覆盖方法。

考虑下面的 JMS 消息 Bean 的 Java 伪代码:

public void onMessage(Message message){
    String username = (cast message to Map and get username);
    Login login = (Login)loginDAO.filter( queryByUsername, username );
    if( login == null ){
        Creates a new entry at database for 'username'
    }else{
        Uses 'username' already created
    }
}

现在我的问题场景:

  1. 我在表单中输入了我的用户名和密码,然后按登录
  2. 尝试登录 JDBC 并触发 JMS 以记录它
  3. 尝试在 LDAP 上登录并触发 JMS 来记录它
  4. onMessage 几乎同时收到 2 条消息(第 2 项和第 3 项)
  5. 消息 1 创建一个新用户,因为它在数据库中不存在
  6. 消息 2 还会创建一个具有相同用户名的新用户

我需要消息 2 在消息 1(如果逻辑)上使用创建的用户(其他逻辑),但我认为它(消息 2)是如此之快,以至于条目尚未在 DB 中持久化,并且两条消息都被捕获“如果逻辑”。

如果我的主题令人困惑且不合适,请提出建议。

[编辑] 到目前为止我所拥有的:

服务器中有一个 MessageDriven Beans (MDB) 的 POOL,对于 2 条消息到达,您将获得 2 个 MDB 同时运行,因此您将保留相同的信息 2 次。

我在 Annotation Message Driven Bean 中使用了一个名为 maxSession 的属性

@ActivationConfigProperty(propertyName = "maxSession", propertyValue = "1")

现在我在池中只有一个 MDB,我在负责检查“用户名”登录审核的所有逻辑的方法中放置了一个 SYNCHRONIZED。

[编辑 2] 如下尼古拉斯所观察到的:

删除了池限制,我创建了一个静态方法来检查数据库(检查用户名是否存在或需要创建和持久化)。

静态,因为它需要与 MDB 的所有实例共享,并且还需要同步以避免在 DB 上重复条目。

谢谢

【问题讨论】:

  • 您的数据库没有存储用户详细信息的表的 PK 吗?第二次插入肯定会抛出异常。
  • 是的。我正在使用 JPA,所以休眠会在持久实体管理器中增加 ID

标签: java multithreading jpa jms


【解决方案1】:

在不知道这段代码实际上应该做什么的情况下,MDB 似乎仍然是实现同步的错误位置。据推测,您将拥有有限数量的用户,并且您将为每个用户处理多条消息。通过将 MDB 池限制为一个实例,您严重限制了 MDB 处理器的吞吐量。

与其尝试在 MDB 中同步,我建议您考虑在用户名持久性机制中实现同步,或者如您在代码中描述的那样:

Creates a new entry at database for 'username'

这样,可以同时处理多条消息,但它们会在命运决定哪个线程保存用户名时短暂阻塞,(一个会保存它,然后获取它,其他人将等待然后获取它)。之后,您将不会多次阻止单个用户名,并且可以运行完整的 MDB 池。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-11
    • 2013-09-23
    • 1970-01-01
    • 2014-12-13
    • 1970-01-01
    • 1970-01-01
    • 2012-06-02
    • 2020-09-07
    相关资源
    最近更新 更多