我在使用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
请帮我解决这个问题。
答案 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或其他数据库引擎,查询将会有所不同。