Estou precisando persistir diversos registros e queria saber a melhor forma de se fazer isso, hoje estou fazendo da forma abaixo e gostaria de saber se tem alguma maneira melhor pois vai ser processado diversos registros (1000).
Realmente queria a opinião de vocês de como melhorar esse código lembrando que está apenas com alguns campos pois é bem maior que isso a classe.
public Boolean processar(JSONObject json) throws Exception {
this.em = EntityManagerUtil.build().createEntityManager();
EntityTransaction tx = em.getTransaction();
ContasReceberEntity entity = new ContasReceberEntity();
try {
for (int i = 0; i < json.getJSONArray("dtParcela").length(); i++) {
try {
em.clear();
tx.begin();
entity.setIdExcecao(0); //Eu precisei zerar o campo pois como é auto-incremento a entidade sempre mantinha o ultimo gerado.
entity.setIdEmpresa(json.isNull("idEmpresa") ? null : json.getInt("idEmpresa"));
entity.setTpExcecao(json.isNull("tpConta") ? null : json.getString("tpConta"));
entity.setDtExcecao(DateUtil.parse(json.getJSONArray("dtParcela").getString(i), "yyyy-MM-dd'T'HH:mm:ss"));
entity.setDtUltalt(new Date());
em.persist(entity);
tx.commit();
} catch (Exception ex) {
tx.rollback();
return false;
}
}
return true;
} catch (Exception ex) {
return false;
} finally {
if (em != null && em.isOpen()) {
em.close();
}
}
}
Não usar JPA já seria um bom início, por padrão a cada objeto persistido ele vai acumulando em cache. Por que está precisando usar um recurso pesado pra fazer um simples comando de INSERT na base? Eu usaria JDBC puro.
Até onde conheço, pelo menos com Hibernate sem seguir JPA tem como não usar cache, através do StatelessSession. Com JPA teria que pesquisar se é possível.
Dependendo de qual SGDB estiver usando, ele próprio já tem recursos otimizados pra isso. SQL Server por exemplo tem o BCP.
Na verdade usei JPA porque essa tabela possui +20 campos e controlar isso via insert simples está sujeito a falhas fora simplicidade do código que com JPA fica mais legível. Enfim vou pesquisar mais um pouco sobre o assunto.
Isso é uma decisão pessoal sua por temer errar lidando com SQL diretamente. Pois seria mais eficiente para o resultado, é o que importa pro usuário. Achei que estivesse buscando isso. Sobre quantidade de campos, basta copiar e colar o script de insert da tabela, que ferramentas de banco disponibilizam. Os parâmetros você vai ter que passar de uma forma ou de outra. Um meio termo seria usar o JdbcTemplate.
Fora isso, dependendo do caso trabalhar com várias threads pode ajudar, ou ainda, enviar para o banco pacotes de inserts ao invés de 1 por vez, o que diminui a quantidade de acesso.
Você tá fazendo abrindo uma transaction para cada item dentro loop, o desempenho fica horrivel quando vc faz isso em uma batch, você deve chamar esse trecho antes de iniciar o for.
Esse cara tem que ser criado dentro do for, assim você não precisa fazer entity.setIdExcecao(0); dentro do loop, pois o objeto da entidade vai ser recriado toda vez.[quote=“mpissolato, post:1, topic:354660”]
tx.commit();
[/quote]
Esse cara tem que ser chamado no antes do return true; , assim você só faz um commit no banco de dados de 1 só vez.
Operações em batch tem que ser feito com cuidado, pois tendem a consumir muita memória da aplicação caso não estejam bem otimizadas.
Concordo com você no final das contas o mais importante é usuário é exatamente isso que eu to buscando, e realmente via SQL a performance é outra coisa.
Sim eu tentei da forma que você me disse, criando a entity dentro do loop e apenas commit antes do return true o problema que nesse caso grava apenas um registro é como se a entidade estivesse sendo limpa enfim vou testar mais uma vez.
Obrigado pela resposta e artigos já me ajudou bastante.