过去几天我一直在面对一个关于储蓄和问题的问题。处理Scala期货的数据。我对这两种语言和概念都很陌生。 Lagom关于Cassandra的文档表示要实现大约9个代码文件,我希望确保我的数据库代码能够在将代码扩展到那么多代码之前。
具体来说,我目前正在尝试实施概念验证,以便向/从cassandra数据库发送数据,这些数据库是为您实现的。到目前为止,我能够向数据库发送数据或从数据库中检索数据,但我无法返回该数据,因为这一切都是异步运行,并且还返回数据成功返回。
我已经玩了一会儿;检索代码如下所示:
override def getBucket(logicalBucket: String) = ServiceCall[NotUsed, String] {
request => {
val returnList = ListBuffer[String]()
println("Retrieving Bucket " + logicalBucket)
val readingFromTable = "SELECT * FROM data_access_service_impl.s3buckets;"
//DB query
var rowsFuture: Future[Seq[Row]] = cassandraSession.selectAll(readingFromTable)
println(rowsFuture)
Await.result(rowsFuture, 10 seconds)
rowsFuture onSuccess {
case rows => {
println(rows)
for (row <- rows) println(row.getString("name"))
for (row <- rows) returnList += row.getString("name")
println("ReturnList: " + returnList.mkString)
}
}
rowsFuture onFailure {
case e => println("An error has occured: " + e.getMessage)
Future {"An error has occured: " + e.getMessage}
}
Future.successful("ReturnList: " + returnList.mkString)
}
}
当这个运行时,我得到了预期的数据库值到&#39; println&#39;在onSuccess回调中。但是,我在return语句中使用的同一个变量在回调之外打印为空(并返回空数据)。这也发生在插入&#39;我使用的函数,它并不总是返回我在回调函数中设置的变量。
如果我尝试将该语句放在回调函数中,我会给出错误&#39;返回Unit,期望Future [String]&#39;。所以我已经陷入了无法从回调函数中返回的地方,所以我无法保证我会返回数据。
我的目标是将一个字符串返回给API,以便显示数据库中所有s3存储桶名称的列表。这意味着迭代Future [Seq [Row]]数据类型,并将数据保存为连接字符串。如果有人可以提供帮助,他们将解决我通过Lagom,Akka,Datastax和Cassandra文档阅读的2周问题。我此时大吃一惊(信息过载),而且我没有找到明确指南。
供参考,这里是cassandraSession文档:
LagomTutorial/Documentation Style Information with their only cassandra-query example CassandraSession.scala code
答案 0 :(得分:7)
了解Future
,(和Option
,Either
和Try
)的关键是你(通常)不会获得值 out ,将计算带入。最常见的方法是使用map
和flatMap
方法。
在您的情况下,您想要Seq[Row]
并将其转换为String
。但是,您的Seq[Row]
已包含在名为Future
的此不透明数据结构中,因此您不能像{em>实际那样<{1}}那样只是rows.mkString
Seq[Row]
。因此,不是获取值并对其执行计算,而是将计算rows.mkString
带到数据:
//DB query
val rowsFuture: Future[Seq[Row]] = cassandraSession.selectAll(readingFromTable)
val rowToString = (row: Row) => row.getString("name")
val computation = (rows: Seq[Row]) => rows.map(rowToString).mkString
// Computation to the data, rather than the other way around
val resultFuture = rowsFuture.map(computation)
现在,当rowsFuture
完成后,您通过调用rowsFuture.map
创建的新未来将会实现,并在computation
上调用Seq[Row]
的结果您实际关心。
此时您可以return
resultFuture
,一切都会按预期工作,因为调用getBucket
的代码需要Future
并按原样处理合适的。
Future
不透明?原因很简单,因为它代表了当前可能不存在的值。您只能在价值出现时获得价值,但是当您开始通话时,它就不存在。代码不是让您自己轮询某个isComplete
字段,而是让您注册计算(回调,如onSuccess
和onFailure
),或使用map
和{创建新的派生未来值{1}}。
更深层次的原因是因为flatMap
是Monad而monad包含计算,但是do not have an operation to extract that computation out of them
答案 1 :(得分:0)
替换特定选择的选择以及要为特定字段获取的字段。示例仅用于测试,不是架构建议。
package ldg.com.dbmodule.model
/**
* Created by ldipotet on 05/11/17.
*/
import com.datastax.driver.core.{Cluster, ResultSet, ResultSetFuture}
import scala.util.{Failure, Success, Try}
import java.util.concurrent.TimeUnit
import scala.collection.JavaConversions._
//Use Implicit Global Context is strongly discouraged! we must create
//our OWN execution CONTEXT !
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.{Future, _}
import scala.concurrent.duration._
object CassandraDataStaxClient {
//We create here a CallBack in Scala with the DataStax api
implicit def resultSetFutureToScala(rf: ResultSetFuture):
Future[ResultSet] = {
val promiseResult = Promise[ResultSet]()
val producer = Future {
getResultSet(rf) match {
//we write a promise with an specific value
case Success(resultset) => promiseResult success resultset
case Failure(e) => promiseResult failure (new
IllegalStateException)
}
}
promiseResult.future
}
def getResultSet: ResultSetFuture => Try[ResultSet] = rsetFuture => {
Try(
// Other choice can be:
// getUninterruptibly(long timeout, TimeUnit unit) throws
TimeoutException
// for an specific time
//can deal an IOException
rsetFuture.getUninterruptibly
)
}
def main(args: Array[String]) {
def defaultFutureUnit() = TimeUnit.SECONDS
val time = 20 seconds
//Better use addContactPoints and adds more tha one contact point
val cluster = Cluster.builder().addContactPoint("127.0.0.1").build()
val session = cluster.connect("myOwnKeySpace")
//session.executeAsync es asyncronous so we'll have here a
//ResultSetFuture
//converted to a resulset due to Implicitconversion
val future: Future[ResultSet] = session.executeAsync("SELECT * FROM
myOwnTable")
//blocking on a future is strongly discouraged!! next is an specific
//case
//to make sure that all of the futures have been completed
val results = Await.result(future,time).all()
results.foreach(row=>println(row.getString("any_String_Field"))
session.close()
cluster.close()
}
}