Jpa/hibernate + Spring 中的本地列表插入查询

12

我想将对象列表插入数据库。在特殊情况下,我知道它们的主键(非自动生成)不存在。由于需要插入大量数据,save(Iterable<Obj> objects) 方法速度太慢。

因此,考虑使用原生查询。 hibernate + spring data 中的原生插入查询

在之前的答案中,并没有说明如何插入对象集合。这是否可能?

@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);

当然,如果你有更好的综合解决方案,那就更好了。


1
尝试实现Spring Data JPA的批量插入功能。 - Kushan
2个回答

8

最终,我自己实现了我的代码库。这个的性能非常好,在插入50000个元素时,只需要2s就可以完成,而以前需要35s。但是这段代码存在防止SQL注入的问题。

我也尝试使用setParameter(1, ...)来构建查询语句,但是JPA处理起来时间较长。

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() + ")";
    }
}

3

我知道这是7年前的事情,但为了防止有人需要一个安全的SQL注入方法,使用JdbcTemplate并具有与被接受答案相同的速度,我还是发表一下。

public class MyBatchRepository {

    private static final int INSERT_BATCH_SIZE = 20000;
    private static final String INSERT_QUERY_BASE = "INSERT INTO table_name(column1, column2, column3) VALUES ";
    private static final String INSERT_PARAM_BASE = "(?,?,?)";
    private static final String DELIMITER = ",";

    private JdbcTemplate jdbcTemplate;

    public MyBatchRepository(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public void performBatchInsert(List<Object> objects) {
        ListUtils.partition(objects, INSERT_BATCH_SIZE).forEach(this::batchInsert);
    }

    private void batchInsert(List<Object> objects) {
        String insertQuery = buildInsertQuery(objects.size());
        Object[] insertParameters = buildParameters(objects);

        jdbcTemplate.update(insertQuery, insertParameters);
    }

    protected String buildInsertQuery(int size) {
        String parameters = String.join(DELIMITER, Collections.nCopies(size, INSERT_PARAM_BASE));
        return INSERT_QUERY_BASE + parameters;
    }

    protected Object[] buildParameters(List<Object> objects) {
        return objects.stream()
                .map(this::toObjectArray)
                .flatMap(Stream::of)
                .toArray(Object[]::new);
    }

    private Object[] toObjectArray(Object object) {
        return new Object[]{
            object.column1(),
            object.column2(),
            object.column3()
        };
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接