Squeryl:运行查询明确(Squeryl: Run query explicitly)

2019-09-18 04:44发布

当我在创建一个squeryl查询,它返回一个查询[T]的对象。 查询还没有执行,并且将是,当我遍历查询对象(查询[T]延伸的Iterable [T])。

一个查询的执行周围必须有任一事务{}或在inTransaction {}块。

我只是说SELECT查询和交易的不会是必要的,但squeryl框架需要他们。

我想创建我的应用程序的模型查询并将其直接传递到超过它的模板迭代视图助手和展示的数据视图。 在控制器把当事务{}块(该控制器包括模板的呼叫,所以它执行迭代的模板也里面),这是唯一可能的。 这是不可能把交易{}块模型,因为模型并没有真正执行查询。

但是,在我的理解交易无关与控制器。 这是模型数据库架构使用哪个,如何使用它以及在何处使用数据的决定。 所以我想交易{}块是在模型中。

我知道我可以 - 而不是返回查询[T]实例 - 调用此查询[T]对象的Iterable [T] .toList,然后返回所创建的列表。 然后,整个查询模型执行,一切都很好。 但是,我不喜欢这种做法,因为从数据库中请求的所有数据必须在此列表中进行缓存。 我宁愿在那里该数据被直接传递到视图的方式。 我喜欢流的结果集时,它的大的MySQL的功能。

是否有可能? 也许类似的功能的查询[T] .executeNow(),其将请求发送到数据库中,能够关闭交易,但仍使用MySQL流功能和接收的其余部分(选择并因此固定)结果集时它的访问? 由于结果集是固定在查询的时刻,结束交易不应该是一个问题。

Answer 1:

我在这里看到的普遍的问题是您尝试以下两种思路结合起来:

  • 数据的懒惰计算; 在这里:数据库结果

  • 躲藏在计算完必须被触发后处理措施的需求; 位置:从您的控制器隐藏或查看数据库会话必须被关闭

由于您的计算是懒惰,因为你不一定要它执行到最后(这里:遍历整个结果集),有没有可能引发的后处理步骤明显挂钩。

您调用的建议Query[T].toList不会出现此问题,因为计算是进行到了最后,并要求在结果集的最后一个元素可以被用作会议结束时触发。

这就是说,我可以拿出最好的是下面的,这是内部的代码适应org.squeryl.dsl.QueryDsl._using

class IterableQuery[T](val q: Query[T]) extends Iterable[T] {
  private var lifeCycleState: Int = 0
  private var session: Session = null
  private var prevSession: Option[Session] = None

  def start() {
    assert(lifeCycleState == 0, "Queries may not be restarted.")
    lifeCycleState = 1

    /* Create a new session for this query. */
    session = SessionFactory.newSession

    /* Store and unbind a possibly existing session. */
    val prevSession = Session.currentSessionOption
    if(prevSession != None) prevSession.get.unbindFromCurrentThread

    /* Bind newly created session. */
    session.bindToCurrentThread
  }

  def iterator = {
    assert(lifeCycleState == 1, "Query is not active.")
    q.toStream.iterator
  }

  def stop() {
    assert(lifeCycleState == 1, "Query is not active.")
    lifeCycleState = 2

    /* Unbind session and close it. */
    session.unbindFromCurrentThread
    session.close

    /* Re-bind previous session, if it existed. */
    if(prevSession != None) prevSession.get.bindToCurrentThread
  }
}

客户端可以使用查询包装如下:

var manualIt = new IterableQuery(booksQuery)
manualIt.start()
manualIt.foreach(println)
manualIt.stop()
//      manualIt.foreach(println) /* Fails, as expected */

manualIt = new IterableQuery(booksQuery) /* Queries can be reused */
manualIt.start()
manualIt.foreach(b => println("Book: " + b))
manualIt.stop()

的调用manualIt.start()已经可以在创建对象时完成的,即,在构造函数中IterableQuery对象被传递到控制器之前,或。

然而,以这样的方式资源(文件,数据库连接等)的工作是非常脆弱的,因为后处理不例外的情况下触发。 如果你看的实施org.squeryl.dsl.QueryDsl._using你会看到一对夫妇的try ... finally被从缺失块IterableQuery



文章来源: Squeryl: Run query explicitly