始终在方法的开头和结尾执行代码

时间:2015-12-30 21:49:32

标签: scala implicit

我使用以下代码连接到MongoDb:

   def insert() = {

    val mc = new com.mongodb.MongoClient("localhost", 27017);
    val db = mc.getDatabase("MyDb");

    //My insert code

    mc.close();

  }                                               //> insert: ()Unit

我有各种方法可以打开和关闭连接。   行可以:

  val mc = new com.mongodb.MongoClient("localhost", 27017);
val db = mc.getDatabase("MyDb");
mc.close();

被提取,以便在方法的开头和结尾隐式调用它们。   Scala是否暗示是为了满足这种情况还是需要反思?

3 个答案:

答案 0 :(得分:2)

您可以定义一个执行某些“工作”功能的方法,例如

def withMongoDb[T](work: DB => T): T = {
  val mc = new com.mongodb.MongoClient("localhost", 27017)
  // I don't actually know what type `db` is so I'm calling it `DB`
  val db: DB = mc.getDatabase("MyDb")

  try { work(db) }
  finally { mc.close() }
}

然后你就可以使用它:

withMongoDb { db =>
  db.insert(...)
  db.query(...)
}

这与Slick, pre-3.0中使用的方法类似,即withSessionwithTransaction

现在,如果你实现了一些便利方法,例如

def insertStuff(values: Seq[Int])(implicit db: DB) = {
  db.insert(values)
}

然后,您可以在db来电中将withMongoDb标记为隐含,有效地确保您不会在该区块之外不小心拨打insertStuff

withMongoDb { implicit db =>
  insertStuff(Seq(1,2,3,4))
}

insertStuff(Seq(1,2,3,4)) // compile error

答案 1 :(得分:2)

一种常见的模式是使用按名称调用方法,您可以传递一个接受DB的函数并对其执行某些操作。 call-by-name方法可以促进客户端等的创建,并在其中执行代码。

def withDB[A](block: DB => A): A = {
  val mc = new com.mongodb.MongoClient("localhost", 27017);
  val db = mc.getDatabase("MyDb");
  try block(db) finally mc.close()
}

并使用它:

def insert() = withDB { db =>
   // do something with `db`
}

但是,看看documentation说:

  

具有内部连接池的MongoDB客户端。对于大多数应用程序,您应该为整个JVM安装一个MongoClient实例。

这使得上述方法看起来不错,假设这是您正在使用的版本。我确实可以看到一些并发问题试图这样做,并打开太多连接。

但是,您可以遵循相同的模式,将连接创建填充到单个对象中。但是,当您的应用程序关闭时,您需要管理客户端的关闭。

object Mongo {
  lazy val mc = new com.mongodb.MongoClient("localhost", 27017);
  lazy val db = mc.getDatabase("MyDb");

  def withDB[A](block: DB => A): A = block(db)

  def close(): Unit = mc.close()
}

答案 2 :(得分:0)

而不是暗示你可以做这样的事情:

  def mongoConn(ip:String, port:Int, dbName:String):(Database => Unit) => Unit  = {
    f => {
      val mc = new com.mongodb.MongoClient(ip, port)
      val db = mc.getDatabase(dbName)

      f(db)

      mc.close()
    }
  }

  val conn =  mongoConn("localhost", 27017, "MyDb")

  conn(db => {
    //insert code
  })