Multithreading 数据库是否可以在Scala线程中阻止并行表访问?

Multithreading 数据库是否可以在Scala线程中阻止并行表访问?,multithreading,postgresql,scala,Multithreading,Postgresql,Scala,在Scala应用程序中,我创建了几个线程。在每个线程中,我将不同的数据从数组写入同一个PostgreSQL表。我注意到一些线程没有将数据写入PostgreSQL表。但是,应用程序日志中没有错误。数据库是否可以阻止并行表访问?这种行为的原因是什么 MainApp.scala: PostgreSQL.scala: 出于您的兴趣,默认情况下,JDBC是同步的。这意味着它会阻塞线程,直到操作在特定连接上完成。这意味着,如果您试图在一个连接上同时执行多个操作,则操作将按顺序执行 关于这方面的更多信息:

在Scala应用程序中,我创建了几个线程。在每个线程中,我将不同的数据从数组写入同一个PostgreSQL表。我注意到一些线程没有将数据写入PostgreSQL表。但是,应用程序日志中没有错误。数据库是否可以阻止并行表访问?这种行为的原因是什么

MainApp.scala:

PostgreSQL.scala:


出于您的兴趣,默认情况下,JDBC是同步的。这意味着它会阻塞线程,直到操作在特定连接上完成。这意味着,如果您试图在一个连接上同时执行多个操作,则操作将按顺序执行

关于这方面的更多信息:

这是第一个也是最可能的原因。第二个可能的原因是,数据库块修改由另一个事务更新的表单元格上的操作,具体方式取决于隔离级别

这是第二个可能的原因

最后,但并非最不重要的一点是,在Scala中没有必要使用裸线程。对于并发/异步编程,开发了许多库(如),并且有使用这些库(如或)访问数据库的特殊库。
由于许多原因,使用它们比使用裸线程更好。

PostgreSQL将使用锁暂停与其他操作不兼容的操作,例如不同的事务试图修改同一表行。一个事务被阻止,直到另一个事务完成。不确定您是否正在经历这种情况。正如Laurenz所写:如果两个事务试图修改同一行,那么第二个事务将等待第一个事务完成。第二个可能会覆盖第一个设置的值。您可以将所有事务更改为使用可序列化隔离级别,那么如果出现这种情况,您至少会得到一个错误同样,如果阻塞需要很长时间,可能是您忘记了结束事务。请注意,Postgres中的隔离级别与SQL Server中的隔离级别差别最大:可序列化在Postgres中比在SQL Server中更有效
val postgreSQL = new PostgreSQL(configurations)

val semaphore = new Semaphore(5)

for (item <- array) {
    semaphore.acquire()

    val thread = new Thread(new CustomThread(postgreSQL, semaphore, item))

    thread.start()
}
import java.util.concurrent.Semaphore
import java.util.UUID.randomUUID
import utils.PostgreSQL

class CustomThread(postgreSQL: PostgreSQL, semaphore: Semaphore, item: Item) extends Runnable {
    override def run(): Unit = {
        try {
            // Create the unique filename.
            val filename: String = randomUUID().toString

            // Write to the database the filename of the item.
            postgreSQL.changeItemFilename(filename, item.id)

            // Change the status type of the item.
            postgreSQL.changeItemStatusType(3, request.id)
        } catch {
            case e: Throwable =>
                e.printStackTrace()
        } finally {
            semaphore.release()
        }
    }
}
package utils

import java.sql.{Connection, DriverManager, PreparedStatement, ResultSet}
import java.util.Properties

class PostgreSQL(configurations: Map[String, String]) {
  val host: String = postgreSQLConfigurations("postgresql.host")
  val port: String = postgreSQLConfigurations("postgresql.port")
  val user: String = postgreSQLConfigurations("postgresql.user")
  val password: String = postgreSQLConfigurations("postgresql.password")
  val db: String = postgreSQLConfigurations("postgresql.db")
  val url: String = "jdbc:postgresql://" + host + ":" + port + "/" + db
  val driver: String = "org.postgresql.Driver"

  val properties = new Properties()

  val connection: Connection = getConnection

  var statement: PreparedStatement = _

  def getConnection: Connection = {
    properties.setProperty("user", user)
    properties.setProperty("password", password)

    var connection: Connection = null

    try {
      Class.forName(driver)
      connection = DriverManager.getConnection(url, properties)
    } catch {
      case e:Exception =>
        e.printStackTrace()
    }

    connection
  }

  def changeItemFilename(filename: String, id: Int): Unit = {
    try {
      statement = connection.prepareStatement("UPDATE REPORTS SET FILE_NAME = ? WHERE ID = ?;", ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY)
      statement.setString(1, filename)
      statement.setInt(2, id)
      statement.execute()
    } catch {
      case e: Exception =>
        e.printStackTrace()
    }
  }
}