title: Batch insert using JPA/Toplink
body: <p>I have a web application that receives messages through an HTTP interface, e.g.:</p>
  
  <pre><code>http://server/application?source=123&amp;destination=234&amp;text=hello
  </code></pre>
  
  <p>This request contains the ID of the sender, the ID of the recipient and the text of the message.</p>
  
  <p>This message should be processed like:</p>
  
  <ul>
  <li>finding the matching User object for both the source and the destination from the database</li>
  <li>creating a tree of objects: a Message that contains a field for the message text and two User objects for the source and the destination</li>
  <li>persisting this tree to a database.</li>
  </ul>
  
  <p>The tree will be loaded by other applications that I can't touch.</p>
  
  <p>I use Oracle as the backing database and JPA with Toplink for the database handling tasks. If possible, I'd stay with these.</p>
  
  <p>Without much optimization I can achieve ~30 requests/sec throughput in my environment. That's not much, I'd require ~300 requests/sec. So I measured where the performance bottleneck is and found that the calls to <code>em.persist()</code> takes most of the time. If I simply comment out that line, the throughput go well over 1000 requests/sec.</p>
  
  <p>I tried to write a small test application that used simple JDBC calls to persist 1 million messages to the same database. I used batching, meaning I did 100 inserts then a commit, and repeated until all the records was in the database. I measured ~500 requests/sec throughput in this scenario, that would meet my needs.</p>
  
  <p>It is clear that I need to optimize insert performance here. However as I mentioned earlier I would like to keep using JPA and Toplink for this, not pure JDBC.</p>
  
  <p>Do you know a way to create batch inserts with JPA and Toplink? Can you recommend any other technique for improving JPA persist performance?</p>
  
  <p><strong>ADDITIONAL INFO:</strong></p>
  
  <p>"requests/sec" means here: total number of requests / total time from beginning of test to last record written to database.</p>
  
  <p>I tried to make the calls to <code>em.persist()</code> asynchronous by creating an in-memory queue between the servlet stuff and the persister. It helped the performance greatly. However the queue did grow really fast and as the application will receive ~200 requests/second continuously, It is not an acceptable solution for me.</p>
  
  <p>In this decoupled approach I collected requests for 100 msec and called <code>em.persist()</code> on all collected items before commiting the transaction. The EntityManagerFactory is cached between each transaction.</p>