簡體   English   中英

在 Hibernate 中使用 Native SQL 批量插入

[英]Batch insert using Native SQL in Hibernate

我想使用 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();

上面的代碼工作正常。我認為這不是最好的方法。 如果有的話,請給我另一種可能的方法。 謝謝

Hibernate有一個批處理功能。但在上面的例子中,我使用的是Native SQL,根據我的觀察,hibernate批處理對於Native SQL來說效果不是很好。是的,它確實避免了內存不足錯誤,但沒有提高性能。 因此我退回到在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();

以下是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);
            }
        });
    }
}

如果您不需要擔心SQL注入。 即,您沒有從用戶端獲取數據,那么您可以這樣做。

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

它會創建一個這樣的查詢。

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

這樣,您的查詢將只運行一次,而不是列表中的每個項目。

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