本文将详细讲解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中设好,传入。
不管什么方式,最终效果一样就可进入下一步。
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 <?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)类
普通方式(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方式(存储过程)的主函数
三种方式的控制台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