本文地址,轉載注明出處:http://www.cnblogs.com/sunwufan/archive/2012/04/27/2473308.html
本文將詳細講解Mybatis訪問MySQL數據庫的三種方式及測試效果。
三種方式:simple方式(基本數據庫逐條訪問)、batch方式(批量操作)、procedure方式(存儲過程)。
文章主要內容:
- 准備工作:數據庫建立、存儲過程建立等。
- Eclipse中的項目搭建。
- 所得數據分析,工作原理淺析。
1.准備工作:
命令行還是圖形界面?這個隨意,總之建完就這么個東西。
建表主要有兩點注意:
- 主鍵要自增(再插入數據是時,省去很多麻煩)
- 表要建成UTF8格式(否則插入中文可能報錯,或亂碼。當然在安裝MySQL進行配置時也要選GBK之類的)
為MySQL建存儲過程

1 CREATE DEFINER = `root`@`localhost` PROCEDURE `NewProc`(IN `name_in` varchar(255),IN `age_in` int,IN `sex_in` varchar(255),IN `password_in` varchar(255),IN `num_in` int) 2 BEGIN 3 SET @a=0; 4 Label:LOOP 5 SET @a=@a+1; 6 INSERT INTO person ( name, age, sex, password) VALUES (name_in,age_in,sex_in,password_in); 7 IF @a=num_in THEN 8 LEAVE Label; 9 END IF; 10 END LOOP Label; 11 END;
num_in為執行插入操作的次數,在java中設好,傳入。
不管什么方式,最終效果一樣就可進入下一步。
本文地址,轉載注明出處:Mybatis 批量插入、存儲過程
2.Eclipse中的項目搭建。
建立javaProject,最終目錄結構。
簡單說下建立時的邏輯順序:1導入三個jar包-->2建立log4j.properties -->3建立Configuration.xml-->4建立Person.java-->5 建立InsertSimple.java-->6建立person.xml-->7在Configuration.xml中注冊person.xml-->此時InsertSimple.java就可以運行了。
剩下的兩個Insert**.java建立好后在person.xml中注入即可。
ok講完流程了,下面開始狂貼代碼:
配置文件

1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> 3 <configuration> 4 <environments default="myexample"> 5 <environment id="myexample"> 6 <transactionManager type="JDBC" /> 7 <dataSource type="POOLED"> 8 <property name="driver" value="com.mysql.jdbc.Driver" /> 9 <property name="url" value="jdbc:mysql://localhost:3306/javaweb" /> 10 <property name="username" value="root" /> 11 <property name="password" value="admin"/> 12 </dataSource> 13 </environment> 14 </environments> 15 <mappers> 16 <mapper resource="person.xml"/> 17 </mappers> 18 </configuration>

1 log4j.rootLogger=DEBUG, Console 2 3 #Console 4 log4j.appender.Console=org.apache.log4j.ConsoleAppender 5 log4j.appender.Console.layout=org.apache.log4j.PatternLayout 6 log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n 7 8 log4j.logger.java.sql.ResultSet=INFO 9 log4j.logger.org.apache=INFO 10 log4j.logger.java.sql.Connection=DEBUG 11 log4j.logger.java.sql.Statement=DEBUG 12 log4j.logger.java.sql.PreparedStatement=DEBUG

1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 3 <mapper namespace="org.wufan.dao.PersonDao"> 4 5 6 <insert id="insert" parameterType="org.wufan.vo.Person" 7 keyProperty="id" keyColumn="GENERATED_KEY" useGeneratedKeys="true"> 8 INSERT INTO person ( name, age, sex, password) 9 VALUES ( 10 #{name},#{age},#{sex},#{password} ) 11 </insert> 12 13 14 <insert id="insertBatch" parameterType="org.wufan.vo.Person" 15 keyProperty="id" keyColumn="GENERATED_KEY" useGeneratedKeys="true"> 16 INSERT INTO person ( name, age, sex, password) 17 VALUES 18 <foreach collection="persons" item="item" index="index" 19 separator=","> 20 (#{item.name},#{item.age},#{item.sex},#{item.password}) 21 </foreach> 22 </insert> 23 24 25 <insert id="insertByProc" statementType="CALLABLE"> 26 {call insertPro(#{name},#{age},#{sex},#{password},#{num})} 27 </insert> 28 29 </mapper>
Java代碼
pojo(vo)類

1 package org.wufan.vo; 2 3 4 public class Person { 5 private int id; 6 private String name; 7 private int age; 8 private String sex; 9 private String password; 10 public int getId() { 11 return id; 12 } 13 public void setId(int id) { 14 this.id = id; 15 } 16 public String getName() { 17 return name; 18 } 19 public void setName(String name) { 20 this.name = name; 21 } 22 public int getAge() { 23 return age; 24 } 25 public void setAge(int age) { 26 this.age = age; 27 } 28 public String getSex() { 29 return sex; 30 } 31 public void setSex(String sex) { 32 this.sex = sex; 33 } 34 public String getPassword() { 35 return password; 36 } 37 public void setPassword(String password) { 38 this.password = password; 39 } 40 }
普通方式(for循環逐條插入)的主函數

1 package org.wufan.test; 2 3 import java.io.IOException; 4 import org.apache.ibatis.io.Resources; 5 import org.apache.ibatis.session.SqlSession; 6 import org.apache.ibatis.session.SqlSessionFactory; 7 import org.apache.ibatis.session.SqlSessionFactoryBuilder; 8 import org.wufan.vo.Person; 9 10 public class InsertSimple { 11 12 /** 13 * @param args 14 */ 15 public static void main(String[] args) { 16 17 int num = 10000;// 插入數據量 18 SqlSessionFactory factory = null; 19 try { 20 factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("Configuration.xml")); 21 } catch (IOException e) { 22 e.printStackTrace(); 23 } 24 System.out.println("進入MySQL"); 25 double begin = System.currentTimeMillis(); 26 SqlSession sqlSession = factory.openSession(); 27 Person per = new Person(); 28 for (int i = 1; i <= num; i++) { 29 30 per.setName("InsertSimple" + i); 31 per.setAge(i); 32 per.setSex("男"); 33 per.setPassword("密碼" + i); 34 35 sqlSession.insert("org.wufan.dao.PersonDao.insert", per); 36 sqlSession.commit(); 37 // sqlSession.clearCache(); 38 } 39 double time = (System.currentTimeMillis() - begin) / 1000; 40 System.out.println("插入共花費時間" + time + "s"); 41 } 42 43 }
batch方式(批量操作)的主函數

1 package org.wufan.test; 2 3 import java.io.IOException; 4 import java.util.ArrayList; 5 import java.util.HashMap; 6 import java.util.List; 7 import java.util.Map; 8 9 import org.apache.ibatis.io.Resources; 10 import org.apache.ibatis.session.ExecutorType; 11 import org.apache.ibatis.session.SqlSession; 12 import org.apache.ibatis.session.SqlSessionFactory; 13 import org.apache.ibatis.session.SqlSessionFactoryBuilder; 14 import org.wufan.vo.Person; 15 16 public class InsertBatch { 17 18 /** 19 * @param args 20 */ 21 public static void main(String[] args) { 22 23 int num = 10000;// 插入數據量 24 SqlSessionFactory factory = null; 25 List<Person> list = new ArrayList<Person>(); 26 try { 27 factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("Configuration.xml")); 28 } catch (IOException e) { 29 e.printStackTrace(); 30 } 31 Person per = new Person(); 32 for (int i = 1; i <= num; i++) { 33 // per.setId(null); 34 per.setName("InsertBatchName" + i); 35 per.setAge(i); 36 per.setSex("男"); 37 per.setPassword("密碼" + i); 38 list.add(per); 39 } 40 double begin = System.currentTimeMillis(); 41 SqlSession sqlSession = factory.openSession(ExecutorType.BATCH, false); 42 43 Map<String, List<Person>> tmp = new HashMap<String, List<Person>>(); 44 tmp.put("persons", list); 45 46 sqlSession.insert("org.wufan.dao.PersonDao.insertBatch", tmp); 47 sqlSession.commit(); 48 49 sqlSession.close(); 50 double time = (System.currentTimeMillis() - begin) / 1000; 51 System.out.println("插入共花費時間" + time + "s"); 52 53 } 54 }
procedure方式(存儲過程)的主函數

1 package org.wufan.test; 2 3 import java.io.IOException; 4 import java.util.HashMap; 5 import java.util.Map; 6 7 import org.apache.ibatis.io.Resources; 8 import org.apache.ibatis.session.SqlSession; 9 import org.apache.ibatis.session.SqlSessionFactory; 10 import org.apache.ibatis.session.SqlSessionFactoryBuilder; 11 12 public class InsertProcedure { 13 14 /** 15 * @param args 16 */ 17 public static void main(String[] args) { 18 int num=10000;//插入數據量 19 SqlSessionFactory factory = null; 20 ; 21 try { 22 factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("Configuration.xml")); 23 } catch (IOException e) { 24 e.printStackTrace(); 25 } 26 SqlSession sqlSession = factory.openSession(); 27 Map map = new HashMap(); 28 map.put("name", "InsertProcName"); 29 map.put("age", 11); 30 map.put("sex", "男"); 31 map.put("password", "1234"); 32 map.put("num", num); 33 double begin = System.currentTimeMillis(); 34 sqlSession.insert("org.wufan.dao.PersonDao.insertByProc", map); 35 sqlSession.commit(); 36 sqlSession.close(); 37 double time = (System.currentTimeMillis() - begin) / 1000; 38 System.out.println("插入共花費時間" + time + "s"); 39 } 40 }
三種方式的控制台log
普通方式InsertSimple.java
batch方式(批量操作)
procedure方式(存儲過程)
如果出現以上三圖,恭喜,哥們你成功了!!
3.所得數據分析。
1 1--num = 1000 ; 2 普通處理:3.527s 3 批量處理:0.628s 4 存儲過程處理:0.144s 5 6 2--num = 1w; 7 普通處理:27.465s 8 批量處理:1.528s 9 存儲過程處理:0.585s 10 11 3--num = 10w; 12 普通處理: 335.18s 13 批量處理: 11.944s 14 存儲過程處理:5.146s 15 16 4--num = 30w; 17 普通處理: 885.335s 18 批量處理:34.767s 19 存儲過程處理:15.875s
小筆記本扛不住了,測試就到這里了。
注意:在這里由於存儲數據過大,批量處理時內存會吃不消。
- 我的筆記本到達10W條數據時,會超過MySQL默認內存設置。Eclipse會報錯。
解決辦法:http://www.cnblogs.com/chy710/archive/2008/03/06/1093680.html
當插入30w條數據時會報“Java heap space” java虛擬機內存錯誤
解決辦法:http://developer.51cto.com/art/200906/128572.htm
工作原理淺析(其實上面的DEBUG截圖,已經很能說明問題了):
- 普通方式,就是一條一條往里插。
優點:對計算機基本沒什么要求,插入方式靈活。
缺點:重復插入大量數據時,很慢。
- 批量處理:是把插入請求放入內存,一起提交給數據庫。
優點:比普通方式快,比存儲過程靈活。
缺點:吃內存,海量數據壓力略大。
- 存儲過程:只需在程序中調用存儲過程,向數據庫傳參,。數據庫根據你建好的存儲過程來跑。
優點:最快,飛起啊!!
缺點:較為死板,換數據庫工具,還要在新的數據庫中建立存儲過程。改需求時維護,較為麻煩。
從數據報告可看出,普通插入理論上就是一次函數,二階導數為零(就尼瑪直線啊!);批量處理和存儲過程應該都是會有一個性價比最好的值。一階導數恆大於零,二階導數先正后負。
PS:
- Mybatis和Ibatis還是有些不同的(雖然沒用過Ibatis),網上的文章比較少,官網的用戶報告下不下來,靠網友經驗和自己摸索做的。本人也是被趕鴨子上架頭一次做,之前都怎么敲過java代碼,更別說框架了,如有錯誤請指正!!
- 請不要管我要源碼了,這些寫的比較清楚了(基本上這就算源碼了==!),用源碼一點成就感都沒得。
- 別問我其他操作怎么搞,我估計也不會的,如果針對此教程調試不通過可以盡管問。
最后是查到的一些對我有幫助的資料:
ibatis 學習筆記(一) 批量處理 存儲過程 (行文方式直接抄他的,但具體技術就不一樣了,他的測試結果有點怪)
Mybatis調用存儲過程 ibatis3調用存儲過程 mybatis 3.0.5 --batch insert后如何獲取返回的值
MyBatis的關於批量數據操作的體會 Java:MyBatis簡單入門 MyBatis簡介與配置MyBatis+Spring+MySql