【问题标题】:Batch insert using Native SQL in Hibernate在 Hibernate 中使用 Native SQL 批量插入
【发布时间】:2014-10-14 16:23:17
【问题描述】:

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

上面的代码工作正常。我认为这不是最好的方法。 如果有的话,请给我另一种可能的方法。 谢谢

【问题讨论】:

    标签: java mysql hibernate


    【解决方案1】:

    Hibernate 具有批处理功能。但是在上述情况下,我使用的是 Native SQL,根据我的观察,在 Native SQL 的情况下,hibernate 批处理效果并不大。是的,它肯定避免了内存不足错误,但并没有太大改善表现。 因此我退回到在 Hibernate 中实现 JDBC Batch。Hibernate 提供了方法 doWork() 从 Hibernate Session 中获取连接。

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

    【讨论】:

    • 这仅在使用 ?rewriteBatchedStatements=true 时有效。
    • 我必须在 Temp 表中插入 7 个 Lac LoanNumber(记录)(LoanNumber 是唯一的一列)。我可以提及的批量大小是多少?
    【解决方案2】:

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

    【讨论】:

    • 命名参数是否与setString(position, value)一起使用?
    • 你应该关闭hibernateSession吗?
    【解决方案3】:

    如果您不需要担心 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")....
    

    这样您的查询将只运行一次,而不是针对列表中的每一项。

    【讨论】:

    • 我必须承认这是纯粹的懒惰,但我不想问自己在个别查询中是否存在 SQL 注入的风险,我不想让后面的 coder reviewers 担心,所以我从不这样做。如果您确实强烈添加 cmets 为什么,则在该特定上下文中是可以接受的。
    猜你喜欢
    • 2016-11-20
    • 2011-02-15
    • 1970-01-01
    • 2012-02-16
    • 2015-07-03
    • 2011-07-04
    • 1970-01-01
    • 1970-01-01
    • 2011-11-13
    相关资源
    最近更新 更多