進行處理操作的時候,又可能進行批量操作的時候,有可能產生錯誤,原因是因為有些數據庫默認允許傳遞的數據量是有限制的,
mysql默認是1M,如果是這種情況,需要在mysql的配置文件(my.ini)中的mysqld這個組里面添加max_allowed_packet=10M
我們先來看下批量增加操作:
當然我這里只是說明在mapper映射文件的配置,至於dao層就要簡單的多:
mapper.xml
<insert id="insertBatch">
insert into dept(deptname) values
<foreach collection="list" item="dept" separator=","> (#{deptname}) </foreach> </insert>
當然dao層的參數應該是一個List<dept>集合。
批量刪除操作:
同樣的刪除操作是根據id來刪除的,所以在dao層只需要傳入一個List<Integer>的參數就好。
mapper.xml
<delete id="deleteBatch"> delete from dept where <foreach collection="list" item="key" separator="or"> id=#{key} </foreach> </delete>
下面來說說怎么在mybatis中批量修改操作的。這里有三種方法:
第一種:
利用分號分割多個sql語句來實現,需要在jdbc的連接url中添加 allowMultiQueries=true這個選項即可。但是這個操作,mysql和sqlserver是支持的,
oracle數據庫好像不支持;
mapper.xml
<update id="updateBatch"> <foreach collection="list" item="dept" separator=";"> update dept set deptname=#{dept.deptname} where id=#{dept.id} </foreach> </update>
第二種,這種批量更新方式不需要設置jdbc的url的allowMultiQueries=true
因為它只有一條update語句。這也是比較推薦大家使用的。
先來個簡單點的,數據庫只有一個列(字段)的mapper.xml配置
mapper.xml
<update id="updateBatch"> update dept set <trim prefix="deptname=case" suffix="end"> <foreach collection="list" item="dept"> when id=#{dept.id} then #{dept.deptname} </foreach> </trim> <where> <foreach collection="list" item="dept" separator="or"> id=#{dept.id} </foreach> </where> </update>
下面這個就是對數據多個列(多個字段)的處理以及判斷是否為空
<update id="updateBatch"> update employee <trim prefix="set" prefixOverride=";"> <trim prefix="user_name=case" suffix="end,"> <foreach collection="list" item="emp"> <if test="emp.username != null and emp.username != '''> when id=#{emp.id} then #{emp.username} </if> </foreach> </trim> <trim prefix="salary=case" suffix="end,"> <foreach collection="list" item="emp"> <if test="emp.salary!= null and emp.salary != '''> when id=#{emp.id} then #{emp.salary} </if> </foreach> </trim> <trim prefix="gender=case" suffix="end,"> <foreach collection="list" item="emp"> <if test="emp.gender!= null and emp.gender!= '''> when id=#{emp.id} then #{emp.gender} </if> </foreach> </trim> </trim> <where> <foreach collection="list" item="emp" separator="or"> id=#{emp.id} </foreach> </where> </update>
上面這兩種批量操作的方式性能比較高,但是不是純粹意義上jdbc的批處理,大家都可能了解jdbc的批處理是利用prepareStatement的
addBatch() ,executeBatch()這兩個方法來完成的。
所以下面這個種就是利用mybatis對jdbc的批處理來完成的
先來看看映射文件的寫法:
這里說下,因為這個批處理要用到java代碼,所以說在xml配置方面會變得簡單多。不像上面兩種進行語句的拼接
mapper.xml
<update id="update"> update employee <set> <if test="username !=null and username != ''"> user_name = #{username} </if> <if test="salary!=null and salary != ''"> salary= #{salary} </if> <if test="gender!=null and gender != ''"> gender= #{gender} </if> </set> </update>
以上代碼的dao層都需要一個用到interface下的方法,這里我就舉例第三種的寫法
public interface EmployeeDao{ //注意這個接口是不需要實現的 void update(Employee employee); }
然后utils層的寫法
public class SqlSessionFactoryUtil { private static final String CONFIG_FILE_PATH = "mybatis-config.xml"; private static SqlSessionFactory factory = null; static { try { InputStream inputStream = Resources.getResourceAsStream(CONFIG_FILE_PATH); factory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException("讀取文件失敗"); } } public static SqlSessionFactory getFactory(){ return factory; } public static SqlSession getSession(){ return factory.openSession(true); } }
然后是service層的寫法
public class EmployeeService{ public void update(List<Employee> employees>{ SqlSessionFactory factory = SqlSessionFactoryUtil.getFactory(); SqlSession session = factory.openSession(ExecutorType.BATCH); EmployeeDao employeeDao = session.getMapper(EmployeeDao.class); try{ int size = employees.size(); for(int i = 0; i< size ;i++){ Employee employee = employees.get(i); //這下面這里調用這個方法的時候,在批處理的操作語境下等價於調用 prepareStatement.addBatch() employeeDao.update(employee); //這個if判斷是避免積累太多的更新數據造成堆棧溢出的現象 if(i>0 && i%2 ==0 || i ==size-1){ //等價於調用prepareStatement的executeBatch方法 session.commit(); //調用commit的時候,其內部真正完成批量操作的方法其實是 flushStatement();這個方法的返回值可以獲取 //每個更新語句影響的行數,這個數據 flushStatements()方法不會自動調用clearCache()方法來清理一級緩存 //但是調用commit這個方法的時候,會自動調用清空內部一級緩存的方法 } } }catch(Exception e){ session.rollback(); }finally{ session.close(); } } }