简体   繁体   English

在 Hibernate 中使用 Native SQL 批量插入

[英]Batch insert using Native SQL in Hibernate

I want to insert records in database using Hibernate Native SQL.The code is like below我想使用 Hibernate Native SQL 在数据库中插入记录。代码如下

 Session session = sessionFactory.openSession();
 Transaction tx = session.beginTransaction();

String sqlInsert = "insert into sampletbl (name) values (?) ";
for(String name : list){
   session.createSQLQuery( sqlInsert )
          .setParameter(1,name)
          .executeUpdate();
} 
tx.commit();
session.close();

Above code is working fine.I think it is not the best way.上面的代码工作正常。我认为这不是最好的方法。 Please give me another possible ways to do this if any.如果有的话,请给我另一种可能的方法。 Thank you谢谢

Hibernate have a Batch functionality.But in above case I am using Native SQL,as per my observation hibernate batch is not much effective in case of Native SQL.Yes,surely it avoids the out of memory error but does not improves much performance. Hibernate有一个批处理功能。但在上面的例子中,我使用的是Native SQL,根据我的观察,hibernate批处理对于Native SQL来说效果不是很好。是的,它确实避免了内存不足错误,但没有提高性能。 Hence I retreated to implemented JDBC Batch in Hibernate.Hibernate provides method doWork() to get Connection from Hibernate Session. 因此我退回到在Hibernate中实现了JDBC doWork()提供了方法doWork()来从Hibernate Session获取Connection。

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
//get Connction from Session
session.doWork(new Work() {
       @Override
       public void execute(Connection conn) throws SQLException {
          PreparedStatement pstmt = null;
          try{
           String sqlInsert = "insert into sampletbl (name) values (?) ";
           pstmt = conn.prepareStatement(sqlInsert );
           int i=0;
           for(String name : list){
               pstmt .setString(1, name);
               pstmt .addBatch();

               //20 : JDBC batch size
             if ( i % 20 == 0 ) { 
                pstmt .executeBatch();
              }
              i++;
           }
           pstmt .executeBatch();
         }
         finally{
           pstmt .close();
         }                                
     }
});
tx.commit();
session.close();

Here is the same example for Java 8, Hibernate-JPA 2.1: 以下是Java 8,Hibernate-JPA 2.1的相同示例:

@Repository
public class SampleNativeQueryRepository {
    private final Logger log = LoggerFactory.getLogger(SampleNativeQueryRepository.class);
    @PersistenceContext
    private EntityManager em;

    public void bulkInsertName(List<String> list){
        Session hibernateSession = em.unwrap(Session.class);
        String sql = "insert into sampletbl (name) values (:name) ";
        hibernateSession.doWork(connection -> {
            try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
                int i = 1;
                for(String name : list) {
                    preparedStatement.setString(1, name);
                    preparedStatement.addBatch();
                    //Batch size: 20
                    if (i % 20 == 0) {
                        preparedStatement.executeBatch();
                    }
                    i++;
                }
                preparedStatement.executeBatch();
            } catch (SQLException e) {
                log.error("An exception occurred in SampleNativeQueryRepository.bulkInsertName: {}", e);
            }
        });
    }
}

If you don't need to worry about SQL injection. 如果您不需要担心SQL注入。 ie you are not getting data from user side then you can do this. 即,您没有从用户端获取数据,那么您可以这样做。

StringBuilder sqlInsert = new StringBuilder("insert into sampletbl (name) values ");
for(String name : list){   
    sqlInsert.append("("+name++"),");
}
sqlInsert.setLength(sqlInsert.length() - 1);
session.createSQLQuery( sqlInsert.toString()).executeUpdate();

It will create a query like this. 它会创建一个这样的查询。

insert into sampletbl (name) values ("name1"), ("name2")....

This way your query will run only once and not for each and every item in the list. 这样,您的查询将只运行一次,而不是列表中的每个项目。

A slight variation leveraging the Named Parameter features of Hibernate Native Query without the Spring JDBC or Spring JPA: A slight variation leveraging the Named Parameter features of Hibernate Native Query without the Spring JDBC or Spring JPA:

@Transactional(propagation = Propagation.REQUIRED)
public int[] updateInBatch(List<Entity> entities) {
    int[] resultsRef = null;
    try {
        Session session = entityManager.unwrap(Session.class);
        int[] results = new int[entities.size()];
        IntStream.range(0, entities.size())
                .forEach(idx -> {
                    Entity entity = entities.get(idx);
                    Query q = session
                            .createNativeQuery("UPDATE Entity " +
                                    " WHERE " +
                                    " ID = :Id  ")
                            .unwrap(SQLQuery.class)
                            .setString("Id", entity.getId());
                    results[idx] = q.executeUpdate();
                });
        session.flush();
        session.clear();
        resultsRef = results;
    } catch (Exception ex) {
        resultsRef = null;
    }
    return resultsRef;
} 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM