加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – Squeryl:显式运行查询

发布时间:2020-12-16 18:15:30 所属栏目:安全 来源:网络整理
导读:当我在squeryl中创建一个查询时,它返回一个Query [T]对象.查询尚未执行,并且当我遍历Query对象时(Query [T]扩展Iterable [T]). 在执行查询时,必须有一个事务{}或一个inTransaction {}块. 我只是谈论SELECT查询而不需要交易,但是squeryl框架需要它们. 我想在
当我在squeryl中创建一个查询时,它返回一个Query [T]对象.查询尚未执行,并且当我遍历Query对象时(Query [T]扩展Iterable [T]).

在执行查询时,必须有一个事务{}或一个inTransaction {}块.

我只是谈论SELECT查询而不需要交易,但是squeryl框架需要它们.

我想在我的应用程序模型中创建一个查询,并将其直接传递给视图,其中模板中的视图助手迭代它并呈现数据.
这只有在将事务{}块放在控制器中时才有可能(控制器包含模板的调用,因此进行迭代的模板也在内部).将事务{}块放在模型中是不可能的,因为模型并不真正执行查询.

但据我了解,交易与控制器无关.这是模型的决定,使用哪个数据库框架,如何使用它以及在何处使用事务.所以我希望transaction {}块在模型中.

我知道我可以 – 而不是返回Query [T]实例 – 在此Query [T]对象上调用Iterable [T] .toList,然后返回创建的列表.然后整个查询在模型中执行,一切都很好.但我不喜欢这种方法,因为数据库中请求的所有数据都必须缓存在此列表中.我更喜欢这种数据直接传递给视图的方式.我喜欢在结果集很大的时候流式传输结果集的MySql功能.

有可能吗?也许类似函数Query [T] .executeNow()将请求发送到数据库,能够关闭事务,但仍然使用MySQL流功能并接收剩余的(选定的,因此固定的)结果集它被访问了吗?因为结果集在查询时刻是固定的,所以关闭事务应该不是问题.

解决方法

我在这里看到的一般问题是你试图结合以下两个想法:

>懒惰的数据计算;这里:数据库结果
>隐藏在计算完成时必须触发的后处理操作的需要;这里:从控制器中隐藏或查看必须关闭数据库会话

由于你的计算是懒惰的,并且因为你没有义务将它执行到最后(这里:迭代整个结果集),所以没有明显的钩子可以触发后处理步骤.

您调用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()

在创建对象时,即在IterableQuery的构造函数内,或者在将对象传递给控制器??之前,可以完成对manualIt.start()的调用.

但是,以这种方式处理资源(文件,数据库连接等)非常脆弱,因为在异常的情况下不会触发后处理.如果你看一下org.squeryl.dsl.QueryDsl._using的实现,你会看到IterableQuery中缺少的几个try … finally块.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读