Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Native List Insert query in Jpa/hibernate + Spring

I want to insert a list of Objects in my db. In a special case I know that they primary key (not auto-generated) is not already there. Since I need to insert a big collection, the save(Iterable<Obj> objects) is to slow.

Therefore I consider using a native query. native insert query in hibernate + spring data

In the previous answer, it does not say how to insert a collection of objects. Is this possible?

@Query("insert into my_table (date, feature1, feature2, quantity) VALUES <I do not know what to add here>", nativeQuery = true)
void insert(List<Obj> objs);

Of course if you have a better solution overall, Its even better.

like image 426
Paul Fournel Avatar asked Oct 26 '16 10:10

Paul Fournel


People also ask

How do I write native sql queries in JPA?

We can use @Query annotation to specify a query within a repository. Following is an example. In this example, we are using native query, and set an attribute nativeQuery=true in Query annotation to mark the query as native. We've added custom methods in Repository in JPA Custom Query chapter.

Can we use native query in JPA repository?

You can implement these operations using JPQL, Criteria, or native queries. You can use the @Query annotation to define such a JPQL or native SQL statement. Because write operations need to be executed differently than read operations, you also need to annotate the repository method with a @Modifying annotation.


1 Answers

I ended up implementing my own repository. The performance of this is really good, 2s instead of 35s before to insert 50000 elements. The problem with this code is that it does not prevent sql injections.

I also tryed to build a query using setParameter(1, ...) but somehow JPA takes a long time to do that.

class ObjectRepositoryImpl implements DemandGroupSalesOfDayCustomRepository {

    private static final int INSERT_BATCH_SIZE = 50000;

    @Autowired
    private EntityManager entityManager;

    @Override
    public void blindInsert(List<SomeObject> objects) {
         partition(objects, INSERT_BATCH_SIZE).forEach(this::insertAll);
    }

    private void insertAll(List<SomeObject> objects) {
         String values = objects.stream().map(this::renderSqlForObj).collect(joining(","));
         String insertSQL = "INSERT INTO mytable (date, feature1, feature2, quantity) VALUES ";
         entityManager.createNativeQuery(insertSQL + values).executeUpdate();
         entityManager.flush();
         entityManager.clear();
    }

    private String renderSqlForObj(Object obj) {
        return "('" + obj.getDate() + "','" +
            obj.getFeature1() + "','" +
            obj.getFeature2() + "'," +
            obj.getQuantity() + ")";
    }
}
like image 103
Paul Fournel Avatar answered Sep 20 '22 11:09

Paul Fournel