Native List在Jpa/hibernate + Spring中插入查询

Pau*_*nel 7 java spring hibernate jpa

我想在我的数据库中插入一个对象列表.在特殊情况下,我知道他们的主键(不是自动生成的)不存在.因为我需要插入一个大集合,所以save(Iterable<Obj> objects)要慢.

因此,我考虑使用本机查询.hibernate + spring数据中的本机插入查询

在上一个答案中,它没有说明如何插入对象集合.这可能吗?

@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);
Run Code Online (Sandbox Code Playgroud)

当然,如果你有一个更好的整体解决方案,它甚至更好.

Pau*_*nel 5

我最终实现了自己的存储库。这个的性能真的很好,插入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() + ")";
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 3

我知道这是 7 年前的事,但发布此内容只是为了以防万一有人需要使用 JdbcTemplate 的 SQL 注入安全方法,但速度与接受的答案相同。

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()
        };
    }
}
Run Code Online (Sandbox Code Playgroud)