I've read already this and that but it does not fit me. I have openjpa realization and I need to make batch insert. I have some entity and with Spring I inject my transaction-manager and EntityManager from EntityManagerFactory like
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="persistenceUnitName" value="JpaPersistenceUnit"/>
<property name="jpaPropertyMap">
<map>
<entry key="openjpa.jdbc.DBDictionary" value="org.apache.openjpa.jdbc.sql.OracleDictionary" />
<entry key="openjpa.ConnectionFactoryProperties" value="PrintParameters=true" />
</map>
</property>
</bean>
In class I have
@PersistenceContext
protected EntityManager em;
AtomicInteger size = new AtomicInteger();
@TransactionalRollback
public void saveLogs(Logs log) {
int i = size.incrementAndGet();
int batchSize=100;
em.persist(log);
if(i%batchSize==0){
em.flush();
em.clear();
}
}
And here, I don't know, what should I do. Because, if I use flush() I got error, that I can't do anything with Shared EntityManager. When I do only persist, it's Ok, but every data commit immediately.
Maybe is it possible to make batch insert with SpringBuilder and some of nativeQuery? Like
String insert = "INSERT into SIEBEL_METHOD_LOGS (?1,?2,?3,?4) VALUES ";
StringBuilder builder = new StringBuilder(insert);
builder.append(
"(" + log.getMethod() + "), "
+ "(" + log.getClient() + "), "
+ "(" + log.getStartDate() + "), "
+ "(" + log.getResponseTime() + "), "
+ "(" + log.getIsError() + ")");
Query query = em.createNativeQuery(builder.toString());
query.executeUpdate();
But, I'm not sure about that.
P.S. Also, I don't understand meaning of that org.apache.openjpa.jdbc.sql.OracleDictionary has field
// batch limit
private int defaultBatchLimit = 100;
When does it work? Because whenever I persist and end my method, I get flush into DB and it doesn't depend on 100 or 5 elements I've persisted into DB. They would be there.
I used that solution, but maybe is it possible more elegance
public class LoggerClass {
private static final int batchSize = 100;
private List<MethodsLog> logsList;
private AtomicLong sizeList;
private void initList() {
this.logsList = new ArrayList<>(batchSize);
this.sizeList = new AtomicLong();
}
public void saveLogs(MethodsLog log) {
long i = sizeList.incrementAndGet();
logsList.add(log.toJpa());
if (i % batchSize == 0) {
saveToDBAndClear(logsList);
initList();
}
}
private synchronized void saveToDBAndClear(List<MethodsLog> logs) {
MethodsService.saveLogs(logs);
}
@TransactionalRollback
public void saveLogs(List<MethodLogs> logs) {
for (MethodLogs log : logs) {
em.persist(log);
}
}
}