java - 使用java和mysql服务器的读/写模式

标签 java sql sql-server concurrency read-write

我在使用 SQL Server 和 java 时遇到了并发问题。 我已经设置了一个消息队列,并有一个系统可以从该队列中读取数据。对于每条消息,都会发生以下情况:

  1. 消息包含“数量属性”。读取此属性并用该数字更新 table1 中的一行。
  2. 另一个表,table2 包含“总计”属性,并读取一行以获取总计值。 table1 和 table2 行可以使用 Id 进行映射。
  3. 通过添加消息中的数量属性来更新表 2 行。

这里的问题是,当我有多个服务实例并且两个实例都收到处理同一行的消息时,它们会向 table2 写入不同的值。这是一种读/写模式。

示例:

我在 table2 上得到了这个:

+------+-------+
| id   | total |
+------+-------+
| 1    | 100   |
+------+-------+
| 2    | 100   |
+------+-------+

并收到两条消息,要求在 table1 上插入两行:

+------+-------+
| id   | qty   |
+------+-------+
| 1    | 10    |
+------+-------+

+------+-------+
| id   | qty   |
+------+-------+
| 1    | 50    |
+------+-------+

a) 消息 1 到达并尝试更新表 2 中的总计,它读取 100 并将总计更新为 110 b) 消息 2 到达并尝试更新总计,因为第一条消息尚未完成,所以它读取的总计为 100,并将其更新为 150。 c) 我们预计总数为 160 (100+10+50),但我们得到了 150,所以状态不正确。

有什么可以用来解决这个并发问题吗?

最佳答案

所以,在行上加锁是有必要的。我建议使用数据库锁来实现双重检查锁 - https://en.wikipedia.org/wiki/Double-checked_locking )。

1 - 启动事务(例如服务方法上的 @Transactional 注释)

2 - 使用 PESSIMISTIC_WRITE 锁定模式从数据库检索实体(确保指示 hibernate 应读取新副本而不是存储在 session 缓存中的副本)

3 - 在字段上执行更改/更新

4 - 保存实体(如果您不想等待自动刷新,请确保将值刷新到数据库)

5 - 提交事务(使用@Transactional时自动完成)

当您的事务在目标实体/数据库行上持有锁时,防止其他事务在您的更新正在进行时读取它。

实现如下:

    @Transactional
    public void updateValue(int id) {
        final Session session = this.sessionFactory.getCurrentSession();
        final Table1 table = session.get(Table1.class, id,LockMode.PESSIMISTIC_WRITE);
        session.refresh(table);
        table.setCount(table.getNoteCount()+1);
        session.saveOrUpdate(table);
        session.flush();
    }

希望这有帮助。

关于java - 使用java和mysql服务器的读/写模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60554676/

相关文章:

java - Java 10 中的 Collectors.toUnmodifiableList 与 Collections.unmodifiableList

Java 枚举到字符串映射保持一致性

java - Spring + JDBC 连接不上数据库

mysql - Web 应用程序中的数据库连接

mysql - 通过在 MySQL 中搜索多列和多个值来选择行

java - Velocity 无法使用 webApp 找到资源

mysql - 将两个案例查询合并为一个

c# - System.Data.Entity.ModelConfiguration.ModelValidationException

sql - 如何从 NULL 列中获取值?

SQL 过程 : Removing duplicates, 重新分配外键引用