保存大量记录时的java.lang.OutOfMemoryError

时间:2011-06-01 11:40:41

标签: exception coldfusion cfwheels

我在使用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

请帮我解决这个问题。

3 个答案:

答案 0 :(得分:5)

Looping over multiple database calls leading to OOM is a known ColdFusion bug。幸运的是,有一种解决方法,使用<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>

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

答案 1 :(得分:1)

答案 2 :(得分:0)

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

我会停止对这样的情况使用模型对象,并弄清楚如何将逻辑压缩到单个数据库查询中。车轮上的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或其他数据库引擎,查询将会有所不同。