Slick 中的线程安全
Thread safety in Slick
我有一个关于 Slick/the 数据库如何管理异步操作的一般理解问题。当我撰写查询或操作时,说
(for {
users <- UserDAO.findUsersAction(usersInput.map(_.email))
addToInventoriesResult <- insertOrUpdate(inventoryInput, user)
deleteInventoryToUsersResult <- inventoresToUsers.filter(_.inventoryUuid === inventoryInput.uuid).delete if addToInventoriesResult == 1
addToInventoryToUsersResult <- inventoresToUsers ++= users.map(u => DBInventoryToUser(inventoryInput.uuid, u.uuid)) if addToInventoriesResult == 1
} yield(addToInventoriesResult)).transactionally
是否有可能另一个用户可以例如在第一个操作 UserDAO.findUsersAction(usersInput.map(_.email))
执行后但在其余操作之前删除用户,从而导致插入失败(由于外键错误)?或者可能导致更新丢失的场景,例如:事务 A 读取数据,然后事务 B 更新此数据,然后事务 A 根据它读取的内容进行更新,它将看不到 B 的更新并覆盖它
我认为这可能取决于数据库的实现或者 JDBC,因为这是作为 SQL 的一个块发送到数据库的,但也许 Slick 在其中发挥了作用。我正在使用 MySQL。
如果此处存在同步问题,解决此问题的最佳方法是什么?。我已经阅读了诸如按顺序处理操作(作为语义单元)的后台队列之类的方法,但这不会部分消除能够异步访问数据库的好处 -> 性能不佳吗?
首先,如果底层数据库驱动程序是阻塞的(基于 JDBC 的驱动程序的情况),那么 Slick 无法提供真正非阻塞意义上的异步性能(即线程将被无论完成给定查询需要多长时间,都会被消耗和阻塞。
有人在谈论为 Oracle 和 SQL Server(在付费的 Typesafe 订阅下)实施非阻塞驱动程序,但这不会很快发生 AFAICT。有一个 couple of projects 确实为 Postegres 和 MySQL 提供非阻塞驱动程序,但是 YMMV,仍处于早期阶段。
除此之外,当您调用 transactionally
时,Slick 会执行一批查询并将它们包装在一个 try-catch 块中,并将基础连接的 autocommit
标志设置为 false。查询成功执行后,通过将 autocommit
设置回默认值 true 来提交事务。如果抛出异常,则调用连接的 rollback
方法。只是 Slick 方便地抽象出来的标准 JDBC 会话样板文件。
至于你的用户在交易中被删除并正确处理的场景,那是底层 database/driver 的工作。
我有一个关于 Slick/the 数据库如何管理异步操作的一般理解问题。当我撰写查询或操作时,说
(for {
users <- UserDAO.findUsersAction(usersInput.map(_.email))
addToInventoriesResult <- insertOrUpdate(inventoryInput, user)
deleteInventoryToUsersResult <- inventoresToUsers.filter(_.inventoryUuid === inventoryInput.uuid).delete if addToInventoriesResult == 1
addToInventoryToUsersResult <- inventoresToUsers ++= users.map(u => DBInventoryToUser(inventoryInput.uuid, u.uuid)) if addToInventoriesResult == 1
} yield(addToInventoriesResult)).transactionally
是否有可能另一个用户可以例如在第一个操作 UserDAO.findUsersAction(usersInput.map(_.email))
执行后但在其余操作之前删除用户,从而导致插入失败(由于外键错误)?或者可能导致更新丢失的场景,例如:事务 A 读取数据,然后事务 B 更新此数据,然后事务 A 根据它读取的内容进行更新,它将看不到 B 的更新并覆盖它
我认为这可能取决于数据库的实现或者 JDBC,因为这是作为 SQL 的一个块发送到数据库的,但也许 Slick 在其中发挥了作用。我正在使用 MySQL。
如果此处存在同步问题,解决此问题的最佳方法是什么?。我已经阅读了诸如按顺序处理操作(作为语义单元)的后台队列之类的方法,但这不会部分消除能够异步访问数据库的好处 -> 性能不佳吗?
首先,如果底层数据库驱动程序是阻塞的(基于 JDBC 的驱动程序的情况),那么 Slick 无法提供真正非阻塞意义上的异步性能(即线程将被无论完成给定查询需要多长时间,都会被消耗和阻塞。
有人在谈论为 Oracle 和 SQL Server(在付费的 Typesafe 订阅下)实施非阻塞驱动程序,但这不会很快发生 AFAICT。有一个 couple of projects 确实为 Postegres 和 MySQL 提供非阻塞驱动程序,但是 YMMV,仍处于早期阶段。
除此之外,当您调用 transactionally
时,Slick 会执行一批查询并将它们包装在一个 try-catch 块中,并将基础连接的 autocommit
标志设置为 false。查询成功执行后,通过将 autocommit
设置回默认值 true 来提交事务。如果抛出异常,则调用连接的 rollback
方法。只是 Slick 方便地抽象出来的标准 JDBC 会话样板文件。
至于你的用户在交易中被删除并正确处理的场景,那是底层 database/driver 的工作。