繁体   English   中英

如何让两个相同的读写+并发事务相互等待?

[英]How can I make two identical read+write concurrent transactions wait for each other?

我有一个从数据库中读取的Spring事务,如果找不到它,则会创建它。 例:

@Transactional
public int getUserIdCreateIfNotExistent(String email) throws Exception {
  try {
    return jdbcTemplate.queryForObject("SELECT id FROM users WHERE email = ?", Integer.class, email);
  } catch (IncorrectResultSizeDataAccessException e) {
    Thread.sleep(10000);
    return jdbcTemplate.queryForObject("INSERT INTO users (email) values(?) RETURNING id", Integer.class, email);
  }
}

当同时调用此方法两次时,将导致两个不同的用户在数据库中具有相同的电子邮件(对于唯一的电子邮件没有约束,这仅用于说明目的)。

我希望第二个事务等待第一个事务,以便只创建一个用户。 我已经尝试将事务隔离级别更改为Isolation.SERIALIZABLE但它所做的只是使提交最后一次回滚的事务。

编辑:在任何人建议使用synchronized或类似的东西在java中锁定解决方案之前,重要的是要了解此方法是Web应用程序的一部分,并在特定端点被命中时调用。 Web应用程序在几台不同的计算机上运行,​​并且负载均衡,并且在同时调用两次端点时会出现问题。 这意味着代码可以在两台不同的机器上并行执行,与另一台机器上的同一个DB通信

解决了咨询锁:

@Transactional
public int getUserIdCreateIfNotExistent(String email) throws Exception {
  try {
    jdbcTemplate.queryForRowSet("SELECT pg_advisory_xact_lock(hashtext('users'), hashtext(?))", email);
    return jdbcTemplate.queryForObject("SELECT id FROM users WHERE email = ?", Integer.class, email);
  } catch (IncorrectResultSizeDataAccessException e) {
    Thread.sleep(10000);
    return jdbcTemplate.queryForObject("INSERT INTO users (email) values(?) RETURNING id", Integer.class, email);
  }
}

您可以使用“锁”表。 它将包含您需要锁定的所有内容,即表名(例如“用户”)和行键(例如“email”)。

如果您需要更快的东西,那么您可以在服务器上使用memcached和复制。 如果你的插入不多,那么db解决方案可能没问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM