3

我在使用 CFWheels 将大量记录保存到数据库时遇到问题。这是一个例子:

<cfloop from="1" to="10000" index="i">
 <cfset var newUser = model("user").new()>
 <cfset newUser.name = "Test"&i>
 <cfset newUser.save()>
</cfloop>

这会导致 java.lang.OutOfMemoryError

请帮助我如何解决这个问题。

4

3 回答 3

5

循环导致 OOM 的多个数据库调用是一个已知的 ColdFusion 错误。幸运的是,有一个解决方法,使用<cfthread/>. 您应该能够像这样更改您的代码:

<cfloop from="1" to="10000" index="i">
 <cfset threadName = "thread" & createUuid()>
 <cfthread name="#threadName#">
  <cfset var newUser = model("user").new()>
  <cfset newUser.name = "Test"&i>
  <cfset newUser.save()>
 </cfthread>
 <cfthread action="join" name="#threadName#">
</cfloop>

在这种情况下,您使用线程只是为了它的副作用,在不同的上下文中运行,这样它就不会保留在堆上。因此,在声明线程后立即加入,因此它实际上并没有并行运行任何东西。

于 2011-06-01T12:07:26.223 回答
1

您可以尝试运行垃圾收集器: http ://www.beetrootstreet.com/blog/index.cfm/2009/6/25/Clearing-ColdFusion-memory-using-garbage-collection-when-memory-gets-low

于 2011-06-01T12:41:15.550 回答
0

这里发生了一些相当低效的事情。首先,它会生成 1,000 个user对象,这在 ColdFusion 中的单个请求中并不是一个好主意。其次,它运行 1,000 个数据库查询,这在任何编程语言中都不是一个好主意。

在这种情况下,我会停止使用模型对象,并弄清楚如何将逻辑压缩到单个数据库查询中。Wheels 中的 ORM 东西通常非常有用,但在这种情况下它有其局限性。

例如,如果您使用的是 SQL Server 2008,则可以在user模型中执行此操作,以使所有内容都在一次调用下cfquery

<cffunction name="batchCreate">
    <cfquery datasource="#get('dataSourceName')#">
        INSERT INTO
            #this.tableName()# (#this.columnNameForProperty("name")#)
        VALUES
            <cfloop from="1" to="10000" index="i">
                (<cfqueryparam cfsqltype="cf_sql_varchar" value="Test#i#">)
                <cfif i lt 10000>,</cfif>
            </cfloop>
    </cfquery>
</cffunction>

当然,如果您使用 MySQL 或其他数据库引擎,查询看起来会有所不同。

于 2011-06-02T12:30:16.840 回答