使用JDBC中的PreparedStatement批量插入

工具类

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

import org.apache.log4j.Logger;


/**
 * 
 * @Title: J
 * @ClassName:JdbcUtil.java
 * @Description:
 *
 * @Copyright 2016-2017 新开普 - Powered By 研发中心
 * @author: FLY
 * @date:2017年9月27日 下午5:01:29
 * @version V1.0
 */
public class JdbcUtil {

   // 定义数据库的链接 
   private static Connection conn;

   // 定义sql语句的执行对象 
   private static PreparedStatement pstmt;

   // 定义查询返回的结果集合  
   private static ResultSet rs;
   
   static Logger jdbcLog = LoggerUtil.getLogger("gateway", "jdbc");// 数据库连接日志

   /**
    * 
    * @Title:  获取数据库连接
    * @Description:
    *
    * @author: FLY
    * @date:2017年9月27日 下午5:11:01
    */
   public static void getConnection() {
       try {
               Context ic = new InitialContext();
               //此处要添加的是查找数据源的名字  但是要加前缀java:comp/env
               DataSource source = (DataSource)ic.lookup("java:comp/env/jdbc/数据库名");         
               conn = source.getConnection();       
           } catch (NamingException e) {
              jdbcLog.error("【数据源没找到!】,异常信息:"+e);
               e.printStackTrace();
           } catch (SQLException e) {
              jdbcLog.error("【获取数连接对象失败!】,异常信息:"+e);
               e.printStackTrace();
           }

   }

   
   public static boolean executeBatch(String sql, Object... objs) {
      int n = 0;
      try {
         getConnection();
         jdbcLog.info("【进入批量处理】,sql:" + sql+",参数:"+objs);
         // 那么对于每一条insert语句,都会产生一条log写入磁盘
         conn.setAutoCommit(false);
         pstmt = conn.prepareStatement(sql);
         for (int i = 0; i < objs.length; i++) {
            pstmt.setObject(i + 1, objs[i]);
            
            // 1w条记录插入一次
             if (i % 10000 == 0){
                pstmt.executeBatch();
                conn.commit();
              }
         }
         
          
         // 最后插入不足1w条的数据
         int[] executeBatch = pstmt.executeBatch();
         conn.commit();
         //更新条数 
         n= executeBatch.length;
         jdbcLog.warn("【批量处理】,更新条数:"+n);
      } catch (SQLException e) {
         e.printStackTrace();
         jdbcLog.warn("【批量处理异常】,异常信息:"+e);
      } finally {
         close(conn, pstmt, rs);
      }

      return n > 0 ? true : false;
   }
   
   
    /**
     * 执行数据库插入操作
     *
     * @param datas     插入数据表中key为列名和value为列对应的值的Map对象的List集合
     * @param tableName 要插入的数据库的表名
     * @return 影响的行数
     * @throws SQLException SQL异常
     */
    public static int executeBatchInsert(String tableName, List<Map<String, Object>> datas) throws SQLException {
       
       long startTime=System.currentTimeMillis();//记录开始时间
        jdbcLog.info("【批量插入】,数据表:" + tableName+" ,要插入的数据:"+datas);
        /**影响的行数**/
        int affectRowCount = -1;
        try {
           /**从数据库连接池中获取数据库连接**/
           getConnection();
           /**设置不自动提交,以便于在出现异常的时候数据库回滚**/
           conn.setAutoCommit(false);
            Map<String, Object> valueMap = datas.get(0);
            /**获取数据库插入的Map的键值对的值**/
            Set<String> keySet = valueMap.keySet();
            Iterator<String> iterator = keySet.iterator();
            /**要插入的字段sql,其实就是用key拼起来的**/
            StringBuilder columnSql = new StringBuilder();
            /**要插入的字段值,其实就是?**/
            StringBuilder unknownMarkSql = new StringBuilder();
            Object[] keys = new Object[valueMap.size()];
            // 要执行到数据库的SQL
            String sqlStr = "";
            int i = 0;
            while (iterator.hasNext()) {
                String key = iterator.next();
                keys[i] = key;
                columnSql.append(i == 0 ? "" : ",");
                columnSql.append(key);

                unknownMarkSql.append(i == 0 ? "" : ",");
                unknownMarkSql.append("?");
                i++;
            }
            /**开始拼插入的sql语句**/
            StringBuilder sql = new StringBuilder();
            sql.append("INSERT INTO ");
            sql.append(tableName);
            sql.append(" (");
            sql.append(columnSql);
            sql.append(" )  VALUES ");
            /*sql.append(" )  VALUES (");
            sql.append(unknownMarkSql);
            sql.append(" )");*/
           
            
            // jdbcLog.info("【批量插入】,数据表:" + tableName+" ,SQL:"+sql.toString());
            // StringBuffer sql = new StringBuffer();
            int dataCount = datas.size();
            for (int j = 0; j < dataCount; j++) {
                for (int k = 0; k < keys.length; k++) {
                    // pstmt.setObject(k + 1, datas.get(j).get(keys[k]));
                   /*sql.append(" (");
                    sql.append(datas.get(j).get(keys[k]));*/
                    
                    if(k == 0){
                       sql.append(" (");
                       sql.append("'").append(datas.get(j).get(keys[k])).append("'");
                        sql.append(" ,");
                    }else if(k == keys.length-1){
                        sql.append("'").append(datas.get(j).get(keys[k])).append("'");
                        sql.append(" ),");
                    }else{
                       sql.append("'").append(datas.get(j).get(keys[k])).append("'");
                       sql.append(" ,");
                    }
                }
                
                
                // 每1000个提交一次
            if ((j != 0 && j % 1000 == 0) || j == dataCount - 1) {
               
               sqlStr = sql.substring(0, sql.length() - 1);
               // jdbcLog.info("【批量插入】,数据表:" + tableName+" ,最终SQL:"+sqlStr);
               
               /**执行SQL预编译**/
               pstmt = conn.prepareStatement("");
               pstmt.addBatch(sqlStr);
            }
            
            
            }
            int[] arr = pstmt.executeBatch();
            conn.commit();
            long endTime=System.currentTimeMillis();//记录结束时间
            float excTime=(float)(endTime-startTime)/1000;
            affectRowCount = arr.length;
            
            jdbcLog.info("【批量插入】,数据表:" + tableName+" ,最终SQL:"+sql.toString()+" ,返回:["+ affectRowCount + "] 行"+" ,执行时间:["+excTime+"]s");
        } catch (Exception e) {
           e.printStackTrace();
           jdbcLog.error("【批量插入异常】,数据表:" + tableName+" ,异常信息:"+e);
            if (conn != null) {
                conn.rollback();
            }
            // throw e;
        } finally {
           close(conn, pstmt, rs);
        }
        return affectRowCount;
    }
   
    /**
     * 执行数据库插入操作
     *
     * @param datas     插入数据表中key为列名和value为列对应的值的Map对象的List集合
     * @param tableName 要插入的数据库的表名
     * @return 影响的行数
     * @throws SQLException SQL异常
     */
    public static int batchInsert(String tableName, List<Map<String, Object>> datas) throws SQLException {
       
        jdbcLog.info("【批量插入】,数据表:" + tableName+" ,要插入的数据:"+datas);
        /**影响的行数**/
        int affectRowCount = -1;
        try {
           /**从数据库连接池中获取数据库连接**/
           getConnection();
           conn.setAutoCommit(false);
            Map<String, Object> valueMap = datas.get(0);
            /**获取数据库插入的Map的键值对的值**/
            Set<String> keySet = valueMap.keySet();
            Iterator<String> iterator = keySet.iterator();
            /**要插入的字段sql,其实就是用key拼起来的**/
            StringBuilder columnSql = new StringBuilder();
            /**要插入的字段值,其实就是?**/
            StringBuilder unknownMarkSql = new StringBuilder();
            Object[] keys = new Object[valueMap.size()];
            int i = 0;
            while (iterator.hasNext()) {
                String key = iterator.next();
                keys[i] = key;
                columnSql.append(i == 0 ? "" : ",");
                columnSql.append(key);

                unknownMarkSql.append(i == 0 ? "" : ",");
                unknownMarkSql.append("?");
                i++;
            }
            /**开始拼插入的sql语句**/
            StringBuilder sql = new StringBuilder();
            sql.append("INSERT INTO ");
            sql.append(tableName);
            sql.append(" (");
            sql.append(columnSql);
            sql.append(" )  VALUES (");
            sql.append(unknownMarkSql);
            sql.append(" )");

            /**执行SQL预编译**/
            pstmt = conn.prepareStatement(sql.toString());
            /**设置不自动提交,以便于在出现异常的时候数据库回滚**/
            // conn.setAutoCommit(false);
            jdbcLog.info("【批量插入】,数据表:" + tableName+" ,SQL:"+sql.toString());
            for (int j = 0; j < datas.size(); j++) {
                for (int k = 0; k < keys.length; k++) {
                    pstmt.setObject(k + 1, datas.get(j).get(keys[k]));
                }
                pstmt.addBatch();
            }
            int[] arr = pstmt.executeBatch();
            jdbcLog.info("【批量插入】,数据表:" + tableName+" ,最终SQL:["+ pstmt.toString() + "] ");
            
            conn.commit();
            affectRowCount = arr.length;
            jdbcLog.info("【批量插入】,数据表:" + tableName+" ,成功了插入了:["+ affectRowCount + "] 行");
        } catch (Exception e) {
           e.printStackTrace();
           jdbcLog.error("【批量插入异常】,数据表:" + tableName+" ,异常信息:"+e);
            if (conn != null) {
                conn.rollback();
            }
            // throw e;
        } finally {
           close(conn, pstmt, rs);
        }
        return affectRowCount;
    }
    
   /**
    * 
    * @Title: 批量更新
    * @param sql
    * @param objs
    * @return boolean
    * @Description:
    *
    * @author: FLY
    * @date:2017年9月27日 下午4:40:38
    */
   public static boolean executeUpdate(String sql, Object... objs) {
      int n = 0;
      try {
         getConnection();
         jdbcLog.info("【进入批量更新】,sql:" + sql+",参数:"+objs);
         pstmt = conn.prepareStatement(sql);
         for (int i = 0; i < objs.length; i++) {
            pstmt.setObject(i + 1, objs[i]);
         }
         n = pstmt.executeUpdate();
         jdbcLog.warn("【批量更新】,更新条数:"+n);
      } catch (SQLException e) {
         e.printStackTrace();
         jdbcLog.warn("【批量更新异常】,异常信息:"+e);
      } finally {
         close(conn, pstmt, rs);
      }

      return n > 0 ? true : false;
   }

   

   /**
    * 
    * @Title: 查询
    * @param sql
    * @param objs
    * @return int
    * @Description:
    *
    * @author: FLY
    * @date:2017年9月27日 下午4:44:57
    */
   public static int queryForInt(String sql, Object... objs) {
      try {
         getConnection();
         pstmt = conn.prepareStatement(sql);
         for (int i = 0; i < objs.length; i++) {
            pstmt.setObject(i + 1, objs[i]);
         }

         rs = pstmt.executeQuery();

         if (rs.next())
            return rs.getInt(1);
      } catch (SQLException e) {
         e.printStackTrace();
      } finally {
         close(conn, pstmt, rs);
      }

      return 0;
   }

   /**
    * 
    * @Title: 释放数据库连接
    * @param conn
    * @param stmt
    * @param rs void
    * @Description:
    *
    * @author: FLY
    * @date:2017年9月27日 下午4:44:31
    */
   public static void close(Connection conn, Statement stmt, ResultSet rs) {
      if (rs != null){
         try {
            rs.close();
         } catch (Exception e) {
            e.printStackTrace(); 
            jdbcLog.error("【释放返回结果集异常】,异常信息:"+e);
         }
      }
      if (stmt != null){
         try {
            stmt.close();
         } catch (Exception e) {
            e.printStackTrace();
            jdbcLog.error("【释放sql语句的执行对象异常】,异常信息:"+e);
         }
      }
      if (conn != null){
         try {
            conn.close();
         } catch (Exception e) {
            e.printStackTrace();
            jdbcLog.error("【释放数据库连接异常】,异常信息:"+e);
         }
      }
   }

}

rewriteBatchedStatements

在数据库连接语句上少了启用rewriteBatchedStatements参数,可以再提高插入速度

如果不开启rewriteBatchedStatements=true,那么jdbc会把批量插入当做一行行的单条处理,也即没有达到批量插入的效果 

jdbc:mysql://IP:PORT/database?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&rewriteBatchedStatements=true

 

 

 

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
你可以使用JDBC批量插入数据到ClickHouse数据库。下面是一个简单的示例代码来演示如何使用JDBC批量插入数据: ```java import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; public class ClickHouseBatchInsert { public static void main(String[] args) { // JDBC连接信息 String url = "jdbc:clickhouse://localhost:8123/default"; String username = "your_username"; String password = "your_password"; // SQL插入语句 String sql = "INSERT INTO your_table (column1, column2, column3) VALUES (?, ?, ?)"; // 数据集 Object[][] data = { {"value1_1", "value1_2", "value1_3"}, {"value2_1", "value2_2", "value2_3"}, {"value3_1", "value3_2", "value3_3"} }; try (Connection conn = DriverManager.getConnection(url, username, password); PreparedStatement pstmt = conn.prepareStatement(sql)) { // 关闭自动提交 conn.setAutoCommit(false); // 批量插入数据 for (Object[] row : data) { for (int i = 0; i < row.length; i++) { pstmt.setObject(i + 1, row[i]); } pstmt.addBatch(); } // 执行批量插入 int[] result = pstmt.executeBatch(); // 提交事务 conn.commit(); System.out.println("成功插入 " + result.length + " 条数据"); } catch (SQLException e) { e.printStackTrace(); } } } ``` 在这个示例,你需要将`url`、`username`和`password`替换为你实际的ClickHouse连接信息,将`your_table`替换为你要插入数据的目标表名。然后,根据你的数据集,调整`data`数组的值和列数。 这个示例使用了`PreparedStatement`来执行预编译的SQL语句,并使用`addBatch()`方法将批量插入的每一行添加到批处理。最后,通过调用`executeBatch()`方法执行批处理操作,并使用`commit()`方法提交事务。 这样,你就可以使用JDBC批量插入数据到ClickHouse数据库了。希望对你有所帮助!如果有任何问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

琦彦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值