好記憶不如爛筆頭,能記下點東西,就記下點,有時間拿出來看看,也會發覺不一樣的感受.
業務背景:接一個徵信公司的api,然後快速解析,批量入庫的操作!記錄一下流水賬,主要是記錄關於Statement執行批處理操作,sql後邊不允許加";"的異常 !!!
目錄
梳理
1. api 返回的是 json 串;
2.快速解析json,生成建表語句,並且批量插入(個別接口,返回解析,拼裝後的sql語句達到:5w+)
3.使用DruidDataSource 構建jdbc連接池,使用 Statement 的批處理操作.
執行:
1.Jdbc連接池代碼 :
private Logger logger = LoggerFactory.getLogger(getClass().getName()); /** * 數據庫集合. */ final ConcurrentHashMap<String, DataSource> dataSourceMap = new ConcurrentHashMap(); /** * 初始化池子 * @param destDbInfo */ public boolean initPool(DestDbInfo destDbInfo){ try { //通過直接創建連接池對象的方式創建連接池對象 DruidDataSource druidDataSource = new DruidDataSource(); druidDataSource.setUsername(destDbInfo.getUsername()); druidDataSource.setPassword(destDbInfo.getPassword()); druidDataSource.setUrl(destDbInfo.getUrl()); druidDataSource.setDriverClassName(destDbInfo.getDriver()); druidDataSource.setMinIdle(10); druidDataSource.setMaxActive(300); DataSource druidPool = druidDataSource; String key = JsonUtils.bean2JsonStr(destDbInfo); dataSourceMap.put(key,druidPool); return true; }catch (Exception e){ e.printStackTrace(); } return false; } /** * 得到數據庫連接 */ public Connection getConn(DestDbInfo destDbInfo){ if (destDbInfo==null){ logger.error("傳遞的對象爲空!"); return null; } String key = JsonUtils.bean2JsonStr(destDbInfo); DataSource druidPool = dataSourceMap.get(key); try { if (druidPool!=null){ return druidPool.getConnection(); } }catch (Exception e){ e.printStackTrace(); } return null; } /** * 執行入庫操作. * @param destDbInfo * @param sqls * @return */ public boolean executeSql(DestDbInfo destDbInfo,List<String> sqls) throws SQLException { if (sqls.isEmpty()){ return false; } Connection connection = getConn(destDbInfo); Statement statement = connection.createStatement(); int count = sqls.size(); for (int i = 0; i < count ; i++) { System.out.println(sqls.get(i)); statement.addBatch(sqls.get(i)); if (i>0 && i % 10000 ==0){ statement.executeBatch(); statement.clearBatch(); } } int[] nums = statement.executeBatch(); System.out.println("執行成功的條數是:"+nums); statement.clearBatch(); statement.close(); connection.close(); return true; } /** * 執行單條件語句 * @param destDbInfo * @param sql * @return * @throws SQLException */ public boolean executeSql(DestDbInfo destDbInfo,String sql) throws SQLException { if (StringUtils.isBlank(sql)){ return false; } Connection connection = getConn(destDbInfo); PreparedStatement statement = connection.prepareStatement(sql); int count = statement.executeUpdate(); statement.close(); connection.close(); return count>0 ? true : false; } /** * 使用PreparedStatement查詢數據 * @param destDbInfo * @param sql * @return 結果集 不要關閉連接 */ public Integer selectSql(DestDbInfo destDbInfo,String sql){ try { Connection connection = getConn(destDbInfo); PreparedStatement pstmt=connection.prepareStatement(sql); ResultSet rs = pstmt.executeQuery(); Integer value =null; while (rs.next()){ value=rs.getInt(1); } rs.close(); pstmt.close(); connection.close(); return value; } catch (SQLException e1) { logger.error(e1.getMessage()); } return null; }
2. jdbc url 配置
jdbc:mysql://192.168.10.186:3306/data_sync?autoReconnect=true&rewriteBatchedStatements=true&useUnicode=true&characterEncoding=utf-8&useSSL=false
mysql中,如果不加上rewriteBatchedStatements=true,你的批處理是假的批處理,只是寫了批處理,但是jdbc去執行的時候,卻不是按照批處理來執行的。
3. 執行異常,要執行的 sql 如:
可以看見,所有的sql後邊都是加上";"的,這就會報上面的錯誤,讓人哭笑不得、因爲在oracle中,sql語句後邊要是不加";",那執行是要報錯的。
4.結論
哎,真的是一個坑爹的潛藏的異常信息,一般人誰會想到:正常的sql都會寫";",可是在mysql的批處理上,就會報錯,而且這種錯誤很難定位的到是因爲分號的問題。
5.總結
使用rewriteBatchedStatements 是有限制的,即爲執行的總條數>3,如果小於這個數,那麼還是走的是逐條執行!真的是坑!!!