Slick Code 中的竞争条件

Posted

技术标签:

【中文标题】Slick Code 中的竞争条件【英文标题】:Race condition in Slick Code 【发布时间】:2015-06-28 07:46:46 【问题描述】:

我已经在 specs2 中编​​写了这个精巧的 DAO 及其单元测试。

我的代码有竞争条件。当我运行相同的测试时,我得到不同的输出。

即使在我执行的两个函数中都存在竞争条件 Await.result(future, Duration.Inf)

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 运行相同的代码时,我在不同的运行中看到 2 种不同类型的输出

    有时代码会出现异常

    插入的行数 100 [信息] HelloSpec [信息] [信息] 这个用例应该 [info] + 应该插入行 [信息] [信息] 这个用例应该 [信息]!返回 100 行 [错误] JdbcSQLException: : Table PEOPLE not found; SQL 语句: [错误] 选择 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)

    有时第一个函数调用返回 0 行,第二个函数调用返回 100 个值

    SLF4J:无法加载类“org.slf4j.impl.StaticLoggerBinder”。 SLF4J:默认为无操作(NOP)记录器实现 SLF4J:有关详细信息,请参阅http://www.slf4j.org/codes.html#StaticLoggerBinder。 插入的行数 100 向量() 0 向量(Person(100,test100,user100), Person(99,test99,user99), Person(98,test98,user98), Person(97,test97,user97), Person(96,test96,user96), Person(95 ,test95,user95), 人(94,test94,user94), 人(93,test93,user93), 人(92,test92,user92), 人(91,test91,user91), 人(90,test90,user90) , 人(89,test89,user89), 人(88,test88,user88), 人(87,test87,user87), 人

我不明白为什么我的代码会出现这些竞争条件,因为我在每个方法中都阻止了未来。

【问题讨论】:

【参考方案1】:

您假设两个测试用例应该连续运行,一个接一个是不正确的。测试用例并行运行。只需使用sequential 来验证情况是否如此。

【讨论】:

以上是关于Slick Code 中的竞争条件的主要内容,如果未能解决你的问题,请参考以下文章

text VS Code Slick Snippets

JavaScript 中的竞争条件与复合赋值

Ruby MongoId:回调中的竞争条件

CUDA内核中的竞争条件

事务是不是会停止 MySQL 中的所有竞争条件问题?

为啥“删除”这个无锁堆栈类中的节点会导致竞争条件?