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