在此筆記里,我們將看到我們?nèi)绾慰梢允褂孟馭tatement和PreparedStatement JDBC API來批量在任何數(shù)據(jù)庫中插入數(shù)據(jù)。此外,我們將努力探索一些場景,如在內(nèi)存不足時正常運(yùn)行,以及如何優(yōu)化批量操作。 想想一下下面的代碼: Bad Code String [] queries = { "insert into employee (name, city, phone) values ('A', 'X', '123')", "insert into employee (name, city, phone) values ('B', 'Y', '234')", "insert into employee (name, city, phone) values ('C', 'Z', '345')", }; Connection connection = new getConnection(); Statement statemenet = connection.createStatement(); for (String query : queries) { statemenet.execute(query); } statemenet.close(); connection.close(); 這是糟糕的代碼。它單獨(dú)執(zhí)行每個查詢,每個INSERT語句的都提交一次數(shù)據(jù)庫??紤]一下,如果你要插入1000條記錄呢?這是不是一個好主意。 下面是執(zhí)行批量插入的基本代碼。來看看: Good Code Connection connection = new getConnection(); Statement statemenet = connection.createStatement(); for (String query : queries) { statemenet.addBatch(query); } statemenet.executeBatch(); statemenet.close(); connection.close();
請注意我們?nèi)绾问褂胊ddBatch()方法,而不是直接執(zhí)行查詢。然后,加入所有的查詢,我們使用statement.executeBatch()方法一次執(zhí)行他們。沒有什么花哨,只是一個簡單的批量插入。 請注意,我們已經(jīng)從一個String數(shù)組構(gòu)建了查詢?,F(xiàn)在,你可能會想,使其動態(tài)化。例如: import java.sql.Connection; import java.sql.Statement; //... Connection connection = new getConnection(); Statement statemenet = connection.createStatement(); for (Employee employee: employees) { String query = "insert into employee (name, city) values('" + employee.getName() + "','" + employee.getCity + "')"; statemenet.addBatch(query); } statemenet.executeBatch(); statemenet.close(); connection.close(); 請注意我們是如何從Employee對象中的數(shù)據(jù)動態(tài)創(chuàng)建查詢并在批處理中添加,插入一氣呵成。完美!是不是? 等等......你必須思考什么關(guān)于SQL注入?這樣動態(tài)創(chuàng)建的查詢SQL注入是很容易的。并且每個插入查詢每次都被編譯。 為什么不使用PreparedStatement而不是簡單的聲明。是的,這是個解決方案。下面是SQL注入安全批處理。 SQL Injection Safe Batch - SQL注入安全批處理 import java.sql.Connection; import java.sql.PreparedStatement; //... String sql = "insert into employee (name, city, phone) values (?, ?, ?)"; Connection connection = new getConnection(); PreparedStatement ps = connection.prepareStatement(sql); for (Employee employee: employees) { ps.setString(1, employee.getName()); ps.setString(2, employee.getCity()); ps.setString(3, employee.getPhone()); ps.addBatch(); } ps.executeBatch(); ps.close(); connection.close(); 看看上面的代碼。漂亮。我們使用的java.sql.PreparedStatement和在批處理中添加INSERT查詢。這是你必須實(shí)現(xiàn)批量插入邏輯的解決方案,而不是上述Statement那個。 java.lang.OutOfMemoryError: Java heap space 這是因?yàn)槟阍噲D在一個批次添加所有語句,并一次插入。最好的辦法是將執(zhí)行分批次??纯聪旅娴慕鉀Q方案 String sql = "insert into employee (name, city, phone) values (?, ?, ?)"; Connection connection = new getConnection(); PreparedStatement ps = connection.prepareStatement(sql); final int batchSize = 1000; int count = 0; for (Employee employee: employees) { ps.setString(1, employee.getName()); ps.setString(2, employee.getCity()); ps.setString(3, employee.getPhone()); ps.addBatch(); if(++count % batchSize == 0) { ps.executeBatch(); } } ps.executeBatch(); // insert remaining records ps.close(); connection.close(); 這才是理想的解決方案,它避免了SQL注入和內(nèi)存不足的問題。看看我們?nèi)绾芜f增計(jì)數(shù)器計(jì)數(shù),一旦BATCHSIZE 達(dá)到 1000,我們調(diào)用executeBatch()提交。 來源: http://itindex.blog.51cto.com/3619105/801447 |
|