2

我已经阅读了很多关于在应用程序范围内存储 CFC 的帖子,并且我知道如果 CFC 存储数据,那么它不应该在应用程序范围内。所有执行非实用程序的 CFC 都会存储数据 - 当您传入用户名或电子邮件地址等参数时 - 所以我不知道何时以及何时不使用非实用程序 cfc 的应用程序范围。

我的问题是我有一个posthandler.cfc包含大约 500 行代码的组件来处理来自用户的帖子(就像 SO 会处理发布在此站点上的每个问题一样)。posthandler.cfc组件:

  • “清理”用户提交的任何图像和文本
  • 将图像放在正确的文件夹中
  • 将所有文本写入数据库
  • 返回可以查看帖子的 URL

返回的 URL 由一个简单的 Jquery ajax 调用接收,该调用将用户重定向到 URL。

这种情况在网站上经常发生,目前正在为每个帖子创建一个新的 CFC 实例。将它放在应用程序范围内并且不会导致竞争/锁定条件是否安全?

4

1 回答 1

2

仅仅传入参数并不会“保存”任何东西。从概念上讲,每个线程都有自己的arguments作用域local,它们对任何其他线程都不可见,并且在函数退出时不再存在。所以从这个角度来看,没有冲突。

此外,存储数据并不意味着将其保存到数据库表中。它指的是通过将数据存储在共享范围/对象/等中来维护状态的组件。“共享”意味着资源可以被其他线程访问,并且可能被多个线程同时修改,从而导致竞争条件.

例如,采用这个(人为的)组件函数,它在variables作用域中“保存”信息。如果您每次都创建该组件的新实例,则该函数是安全的,因为每个请求都会获得它自己的实例和variables要使用的范围的单独副本。

 public numeric function doStuff( numeric num1, numeric num2 ) {
    variables.firstNum = arguments.num1 * 12;
    variables.secondNum = arguments.num2 * 10;

    return variables.firstNum / variables.secondNum;
 }

现在将相同的组件放入应用程序范围。它不再安全了。一旦您将其存储在application范围内,该实例 - 及其variables- 也将成为应用程序范围。因此,当函数将数据“保存”到variables作用域时,它本质上是在更新一个application变量。显然,这些不是线程安全的,因为所有请求都可以访问它们。因此,多个线程可以轻松地同时读取/修改相同的变量,从而导致竞争条件。

// "Essentially" becomes this .... 
public numeric function doStuff( numeric num1, numeric num2 ) {
    application.firstNum = arguments.num1 * 12;
    application.secondNum = arguments.num2 * 10;

    return application.firstNum / application.secondNum;
}

此外,正如James A Mohler 指出的那样,当您省略范围时,也会出现同样的问题。声明没有范围的函数变量不会使其成为函数的本地变量。它使其成为默认范围的一部分:-(variables创建上述相同的线程安全问题)。当开发人员忘记限定单个查询变量甚至循环索引时,这种行为导致了许多线程错误。因此,请务必明确定义每个函数变量的范围。

 // Implicitly creates "variables.firstNum" and "variables.secondNum"
 public numeric function doStuff( numeric num1, numeric num2 ) {
    firstNum = arguments.num1 * 12;
    secondNum = arguments.num2 * 10;

    return firstNum / secondNum;
 }

除了添加锁定之外,这两个示例都可以通过显式使用local范围来实现线程安全。通过将数据存储在瞬态local范围内,它对其他线程不可见,并且一旦函数退出就不再存在。

 public numeric function doStuff( numeric num1, numeric num2 ) {
    local.firstNum = arguments.num1 * 12;
    local.secondNum = arguments.num2 * 10;

    return local.firstNum / local.secondNum;
 }

显然还有其他情况需要考虑,例如通过引用传递的复杂对象或结构,以及这些对象是否在函数内被修改。但希望这能阐明“保存数据”的含义以及作用域如何在无状态组件(对application范围安全)和有状态组件(不是)之间产生差异。

TL;博士;

在您的情况下,听起来大部分信息都没有共享,并且是请求级别的(用户信息、上传的图像等),因此存储在应用程序范围内可能是安全的。

于 2019-06-04T01:24:43.140 回答