java.lang.OutOfMemoryError при сохранении огромного количества записей - PullRequest
3 голосов
/ 01 июня 2011

У меня проблема с сохранением огромного количества записей в базу данных с использованием 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 ]

5 голосов
/ 01 июня 2011

Зацикливание на нескольких вызовах базы данных, приводящих к 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>

В этой ситуации вы используете поток исключительно для его побочного эффекта, работая в другом контексте, чтобы он не сохранялсякучаТаким образом, немедленное соединение сразу после объявления потока, так что на самом деле ничего не выполняется параллельно.

1 голос
/ 01 июня 2011

Вы можете попробовать запустить сборщик мусора: http://www.beetrootstreet.com/blog/index.cfm/2009/6/25/Clearing-ColdFusion-memory-using-garbage-collection-when-memory-gets-low

0 голосов
/ 02 июня 2011

Здесь происходит несколько довольно неэффективных вещей.Во-первых, он генерирует 1000 user объектов, что не очень хорошая идея сделать в одном запросе в ColdFusion.Во-вторых, он выполняет 1000 запросов к базе данных, что не очень хорошая идея для любого языка программирования.

Я бы прекратил использовать объекты модели для подобного случая и выяснил, как сжать логику водин запрос к базе данных.ORM в Wheels, как правило, очень полезен, но имеет ограничения в таких ситуациях, как эта.

Например, если вы используете 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 или другой механизм базы данных.

...