Slick Code 中的竞态条件
Race condition in Slick Code
我已经在 specs2 中编写了这个漂亮的 DAO 及其单元测试。
我的代码存在竞争条件。当我 运行 相同的测试时,我得到不同的输出。
即使在我执行的两个函数中都存在竞争条件 Await.result(future, Duration.Inf)
DAO
package com.example
import slick.backend.DatabasePublisher
import slick.driver.H2Driver.api._
import scala.concurrent.ExecutionContext.Implicits.global
import slick.jdbc.meta._
import scala.concurrent._
import ExecutionContext.Implicits.global
import scala.concurrent.duration._
case class Person(id: Int, firstname: String, lastname: String)
class People(tag: Tag) extends Table[Person](tag, "PEOPLE") {
def id = column[Int]("PERSON_ID", O.PrimaryKey)
def firstname = column[String]("PERSON_FIRST_NAME")
def lastname = column[String]("PERSON_LAST_NAME")
def * = (id, firstname, lastname) <> (Person.tupled, Person.unapply _)
}
object PersonDAO {
private def createList(numRows: Int) : List[Person] = {
def recFunc(counter: Int, result: List[Person]) : List[Person] = {
counter match {
case x if x <= numRows => recFunc(counter + 1, Person(counter, "test" + counter, "user" + counter) :: result)
case _ => result
}
}
recFunc(1, List[Person]())
}
val db = Database.forConfig("test1")
val people = TableQuery[People]
def createAndPopulate(numRows: Int) = {
val action1 = people.schema.create
val action2 = people ++= Seq(createList(numRows) : _* )
val combined = db.run(action1 andThen action2)
val future1 = combined.map { result =>
result map {x =>
println(s"number of rows inserted $x")
x
}
}
Await.result(future1, Duration.Inf).getOrElse(0)
}
def printAll() = {
val a = people.result
val b = db.run(a)
val y = b map { result =>
result map {x => x}
}
val z = Await.result(y, Duration.Inf)
println(z)
println(z.length)
z
}
}
单元测试
import org.specs2.mutable._
import com.example._
class HelloSpec extends Specification {
"This usecase " should {
"should insert rows " in {
val x = PersonDAO.createAndPopulate(100)
x === 100
}
}
"This usecase " should {
"return 100 rows" in {
val x = PersonDAO.printAll()
val y = PersonDAO.printAll()
y.length === 100
}
}
}
当我 运行 使用 activator test
相同的代码时,我在不同的 运行s
上看到 2 种不同类型的输出
有时代码会出现异常
插入的行数 100
[信息] HelloSpec
[信息]
[信息] 这个用例应该
[信息] + 应该插入行
[信息]
[信息] 这个用例应该
[信息]! return 100 行
[错误] JdbcSQL异常::Table 未找到人员; SQL声明:
[错误] select x2."PERSON_ID", x2."PERSON_FIRST_NAME", x2."PERSON_LAST_NAME" from "PEOPLE" x2 [42S02-60] (Message.java: 84)
[错误] org.h2.message.Message.getSQLException(Message.java:84)
[错误] org.h2.message.Message.getSQLException(Message.java:88)
[错误] org.h2.message.Message.getSQLException(Message.java:66)
有时第一个函数调用 returns 0 行和第二个函数调用 returns 100 个值
SLF4J:无法加载 class "org.slf4j.impl.StaticLoggerBinder"。
SLF4J:默认为无操作 (NOP) 记录器实现
SLF4J:有关详细信息,请参阅 http://www.slf4j.org/codes.html#StaticLoggerBinder。
插入的行数 100
向量()
0
矢量(人(100,test100,user100),人(99,test99,user99),人(98,test98,user98),人(97,test97,user97),人(96,test96,user96),人(95 ,test95,user95), Person(94,test94,user94), Person(93,test93,user93), Person(92,test92,user92), Person(91,test91,user91), Person(90,test90,user90) , 人(89,test89,user89), 人(88,test88,user88), 人(87,test87,user87), 人
我不明白为什么我的代码有这些竞争条件,因为我在每个方法中都阻塞了 future。
您假设两个测试用例应该运行 串行,一个接一个是不对的。测试用例是 运行ning 并行的。只需使用 sequential 来验证情况是否如此。
我已经在 specs2 中编写了这个漂亮的 DAO 及其单元测试。
我的代码存在竞争条件。当我 运行 相同的测试时,我得到不同的输出。
即使在我执行的两个函数中都存在竞争条件 Await.result(future, Duration.Inf)
DAO
package com.example
import slick.backend.DatabasePublisher
import slick.driver.H2Driver.api._
import scala.concurrent.ExecutionContext.Implicits.global
import slick.jdbc.meta._
import scala.concurrent._
import ExecutionContext.Implicits.global
import scala.concurrent.duration._
case class Person(id: Int, firstname: String, lastname: String)
class People(tag: Tag) extends Table[Person](tag, "PEOPLE") {
def id = column[Int]("PERSON_ID", O.PrimaryKey)
def firstname = column[String]("PERSON_FIRST_NAME")
def lastname = column[String]("PERSON_LAST_NAME")
def * = (id, firstname, lastname) <> (Person.tupled, Person.unapply _)
}
object PersonDAO {
private def createList(numRows: Int) : List[Person] = {
def recFunc(counter: Int, result: List[Person]) : List[Person] = {
counter match {
case x if x <= numRows => recFunc(counter + 1, Person(counter, "test" + counter, "user" + counter) :: result)
case _ => result
}
}
recFunc(1, List[Person]())
}
val db = Database.forConfig("test1")
val people = TableQuery[People]
def createAndPopulate(numRows: Int) = {
val action1 = people.schema.create
val action2 = people ++= Seq(createList(numRows) : _* )
val combined = db.run(action1 andThen action2)
val future1 = combined.map { result =>
result map {x =>
println(s"number of rows inserted $x")
x
}
}
Await.result(future1, Duration.Inf).getOrElse(0)
}
def printAll() = {
val a = people.result
val b = db.run(a)
val y = b map { result =>
result map {x => x}
}
val z = Await.result(y, Duration.Inf)
println(z)
println(z.length)
z
}
}
单元测试
import org.specs2.mutable._
import com.example._
class HelloSpec extends Specification {
"This usecase " should {
"should insert rows " in {
val x = PersonDAO.createAndPopulate(100)
x === 100
}
}
"This usecase " should {
"return 100 rows" in {
val x = PersonDAO.printAll()
val y = PersonDAO.printAll()
y.length === 100
}
}
}
当我 运行 使用 activator test
相同的代码时,我在不同的 运行s
有时代码会出现异常
插入的行数 100 [信息] HelloSpec [信息] [信息] 这个用例应该 [信息] + 应该插入行 [信息] [信息] 这个用例应该 [信息]! return 100 行 [错误] JdbcSQL异常::Table 未找到人员; SQL声明: [错误] select x2."PERSON_ID", x2."PERSON_FIRST_NAME", x2."PERSON_LAST_NAME" from "PEOPLE" x2 [42S02-60] (Message.java: 84) [错误] org.h2.message.Message.getSQLException(Message.java:84) [错误] org.h2.message.Message.getSQLException(Message.java:88) [错误] org.h2.message.Message.getSQLException(Message.java:66)
有时第一个函数调用 returns 0 行和第二个函数调用 returns 100 个值
SLF4J:无法加载 class "org.slf4j.impl.StaticLoggerBinder"。 SLF4J:默认为无操作 (NOP) 记录器实现 SLF4J:有关详细信息,请参阅 http://www.slf4j.org/codes.html#StaticLoggerBinder。 插入的行数 100 向量() 0 矢量(人(100,test100,user100),人(99,test99,user99),人(98,test98,user98),人(97,test97,user97),人(96,test96,user96),人(95 ,test95,user95), Person(94,test94,user94), Person(93,test93,user93), Person(92,test92,user92), Person(91,test91,user91), Person(90,test90,user90) , 人(89,test89,user89), 人(88,test88,user88), 人(87,test87,user87), 人
我不明白为什么我的代码有这些竞争条件,因为我在每个方法中都阻塞了 future。
您假设两个测试用例应该运行 串行,一个接一个是不对的。测试用例是 运行ning 并行的。只需使用 sequential 来验证情况是否如此。