Mybatis 映射器接口实现类的方式 运行过程debug分析
查询一张表的所有数据。
环境:
使用工具intellij idea 2018.2版本。
创建maven工程不用骨架
1 <?xml version="1.0" encoding="utf-8"?> 2 <project xmlns="http://maven.apache.org/pom/4.0.0" 3 xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" 4 xsi:schemalocation="http://maven.apache.org/pom/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 <modelversion>4.0.0</modelversion> 6 7 <groupid>com.jxjdemo</groupid> 8 <artifactid>day34_mybatis1_curd_dao</artifactid> 9 <version>1.0-snapshot</version> 10 11 <properties><!--锁定编译版本与字符集--> 12 <project.build.sourceencoding>utf-8</project.build.sourceencoding> 13 <maven.compiler.source>1.8</maven.compiler.source> 14 <maven.compiler.target>1.8</maven.compiler.target> 15 </properties> 16 17 <dependencies> 18 <dependency><!--导入mysql依赖--> 19 <groupid>mysql</groupid> 20 <artifactid>mysql-connector-java</artifactid> 21 <version>5.1.47</version> 22 </dependency> 23 24 <dependency> <!--导入mybatis依赖--> 25 <groupid>org.mybatis</groupid> 26 <artifactid>mybatis</artifactid> 27 <version>3.5.2</version> 28 </dependency> 29 30 <dependency> <!--导入日志依赖--> 31 <groupid>log4j</groupid> 32 <artifactid>log4j</artifactid> 33 <version>1.2.17</version> 34 </dependency> 35 36 <dependency> 37 <groupid>junit</groupid> 38 <artifactid>junit</artifactid> 39 <version>4.12</version> 40 </dependency> 41 </dependencies> 42 </project>
- 表user
1 package com.jxjdemo.domain; 2 import java.util.date; 3 4 public class user { 5 private integer id; 6 private string username; 7 private date birthday; //框架会帮我们自动转 8 private string sex; 9 private string address; 10 11 @override 12 public string tostring() { 13 return "user{" + 14 "id=" + id + 15 ", username='" + username + '\'' + 16 ", birthday=" + birthday + 17 ", sex='" + sex + '\'' + 18 ", address='" + address + '\'' + 19 '}'; 20 } 21 //省略get与set方法
2.映射器xml
1 <?xml version="1.0" encoding="utf-8"?><!--引入约束--> 2 <!doctype mapper 3 public "-//mybatis.org//dtd mapper 3.0//en" 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 <mapper namespace="com.jxjdemo.dao.userdao"><!--mapper:映射器配置/namespace:映射器的全限定类名--> 6 7 <select id="queryall" resulttype="com.jxjdemo.domain.user"><!--查询所有--> 8 select * from user 9 </select>
3.映射器配置文件
<?xml version="1.0" encoding="utf-8"?><!--引入约束--> <!doctype mapper public "-//mybatis.org//dtd mapper 3.0//en" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.jxjdemo.dao.userdao"><!--mapper:映射器配置/namespace:映射器的全限定类名--> <select id="queryall" resulttype="com.jxjdemo.domain.user"> select * from user </select> </mapper>
4.实现类
1 package com.jxjdemo.dao.impl; 2 import com.jxjdemo.dao.userdao; 3 import com.jxjdemo.domain.user; 4 import org.apache.ibatis.session.sqlsession; 5 import org.apache.ibatis.session.sqlsessionfactory; 6 import java.util.list; 7 8 public class userdaoimpl implements userdao {//执行sql语句用实现类做,不用代理对象。 9 //从工厂里面获取sqlsession对象 10 private sqlsessionfactory factory;//以后由sping整合sping创建,现在去测试类里面创建 11 12 public userdaoimpl(sqlsessionfactory factory) { 13 this.factory = factory; 14 } 15 16 @override 17 public list<user> queryall() { 18 sqlsession session = factory.opensession(); 19 list<user> list = session.selectlist("com.jxjdemo.dao.userdao.queryall");//返回的是object但实际得到的是(userdao) 20 session.close();//session关闭流,释放资源 21 return list; 22 }
5.测试类
1 package com.jxjtest.test; 2 3 import com.jxjdemo.dao.userdao; 4 import com.jxjdemo.dao.impl.userdaoimpl; 5 import com.jxjdemo.domain.user; 6 import org.apache.ibatis.io.resources; 7 import org.apache.ibatis.session.sqlsessionfactory; 8 import org.apache.ibatis.session.sqlsessionfactorybuilder; 9 import org.junit.after; 10 import org.junit.before; 11 import org.junit.test; 12 13 import java.io.ioexception; 14 import java.io.inputstream; 15 import java.util.date; 16 import java.util.list; 17 18 public class mybatiscurdtest { 19 private sqlsessionfactory factory; 20 private inputstream is; 21 private userdao userdao; 22 23 @test 24 public void testqueryall(){ //查询全部 25 //读取配置文件,获取sqlsession对象工厂,获取映射器提取 26 list<user> userlist = userdao.queryall(); 27 for (user user : userlist){ 28 system.out.println(user); 29 } 30 } 31 @before 32 public void init() throws ioexception { //重复执行的代码,单独提取出来 33 is = resources.getresourceasstream("sqlmapconfig.xml");//提取成员变量后 34 35 // sqlsessionfactory factory = new sqlsessionfactorybuilder().build(is); //获取sqlsession对象,通过工厂构建一个,提取成员变量 36 factory = new sqlsessionfactorybuilder().build(is); 37 userdao = new userdaoimpl(factory);//提取成员变量 38 } 39 @after 40 public void destroy() throws ioexception { //关流 41 is.close(); 42 } 43 }
6.数据库核心配置文件xml
1 <?xml version="1.0" encoding="utf-8" ?> 2 <!doctype configuration 3 public "-//mybatis.org//dtd config 3.0//en" 4 "http://mybatis.org/dtd/mybatis-3-config.dtd"> 5 <!--mybatis的核心配置文件,主要配置数据库连接信息--> 6 <configuration><!--根标签--> 7 <!--enxironments 可以配置多个数据库环境--> 8 <environments default="mysql"><!--default 默认使用的数据库--> 9 <environment id="mysql"><!--environment每一个数据库连接(配置)信息--> 10 <transactionmanager type="jdbc" /><!--事物管理方式--> 11 <datasource type="pooled"><!--数据源。不使用un连接池pooled,pooled使用连接池,jndi查找数据源配置文件--> 12 <property name="driver" value="com.mysql.jdbc.driver" /> 13 <property name="url" value="jdbc:mysql://localhost:端口号/库名"/> 14 <property name="username" value="账号"/> 15 <property name="password" value="密码"/> 16 </datasource> 17 </environment> 18 </environments> 19 20 <mappers> 21 <mapper resource="com/jxjdemo/dao/userdao.xml" /> 22 </mappers> 23 </configuration>
7.省略log4j日志配置文件,目录结构。
8.在测试类打断点,开始debug跟踪,从这里开始。
相册里面有步骤截图,可以配合一起看。
1 list<user> userlist = userdao.queryall();
9.到实现类,获取session
1 sqlsession session = factory.opensession();
10.跟踪这行代码做了什么事情,进入这个方法。
1 list<user> list = session.selectlist("com.jxjdemo.dao.userdao.queryall");
11.到了defaultsqlsession.java类里面,在selectlist调了selectlist,方法的重载。
1 @override 2 public <e> list<e> selectlist(string statement) { 3 return this.selectlist(statement, null); 4 } 5 6 @override 7 public <e> list<e> selectlist(string statement, object parameter) { 8 return this.selectlist(statement, parameter, rowbounds.default); 9 }
12.到了ms,获取数据库,配置文件信息,与sql类型。关键在于executor.query执行查询。
1 public <e> list<e> selectlist(string statement, object parameter, rowbounds rowbounds) { 2 try { 3 mappedstatement ms = configuration.getmappedstatement(statement); 4 return executor.query(ms, wrapcollection(parameter), rowbounds, executor.no_result_handler); 5 } catch (exception e) { 6 throw exceptionfactory.wrapexception("error querying database. cause: " + e, e); 7 } finally { 8 errorcontext.instance().reset(); 9 } 10 }
13.先对wrspcollection(parameter)包装一下。回到12.
1 if (object instanceof collection) {这里省略}
14.进入cachingexecutor.java.这个类自己不执行。
1 @override 2 public <e> list<e> query(mappedstatement ms, object parameterobject, rowbounds rowbounds, resulthandler resulthandler) throws sqlexception { 3 boundsql boundsql = ms.getboundsql(parameterobject);
15.这里第一步,从ms.getboundsql获取到了绑定的sql语句。
cachekey key = createcachekey(ms, parameterobject, rowbounds, boundsql);//缓存相关忽略
16.继续调query方法重载。
return query(ms, parameterobject, rowbounds, resulthandler, key, boundsql);
17.到了query方法。
1 @override 2 public <e> list<e> query(mappedstatement ms, object parameterobject, rowbounds rowbounds, resulthandler resulthandler, cachekey key, boundsql boundsql) 3 throws sqlexception { 4 cache cache = ms.getcache();
18.找缓存。
1 if (cache != null) {
19.缓存里面没有,cachingexecutor.java.这个类自己不执行,就调了delegate委托者。
return delegate.query(ms, parameterobject, rowbounds, resulthandler, key, boundsql);
20.cachingexecutor.java.这个类是从父类继承的,所以到了baseexecutor.java.
@override public <e> list<e> query(mappedstatement ms, object parameter, rowbounds rowbounds, resulthandler resulthandler, cachekey key, boundsql boundsql) throws sqlexception { errorcontext.instance().resource(ms.getresource()).activity("executing a query").object(ms.getid());
21.往下走。
if (closed) {//1. if (querystack == 0 && ms.isflushcacherequired()) {//2. querystack++;//3. list = resulthandler == null ? (list<e>) localcache.getobject(key) : null;//4. if (list != null) {//5.
22.到了queryfromdatabase开始到库里面查询。
list = queryfromdatabase(ms, parameter, rowbounds, resulthandler, key, boundsql);
23.baseexecutor.java.执行了doquery方法
localcache.putobject(key, execution_placeholder);//1 list = doquery(ms, parameter, rowbounds, resulthandler, boundsql);//2.
24.进入doquery查看,到了simpleexecutor.java
1 public <e> list<e> doquery(mappedstatement ms, object parameter, rowbounds rowbounds, resulthandler resulthandler, boundsql boundsql) throws sqlexception { 2 statement stmt = null;//1 3 configuration configuration = ms.getconfiguration();//2.configuration所有的配置信息 4 statementhandler handler = configuration.newstatementhandler(wrapper, ms, parameter, rowbounds, resulthandler, boundsql);//3. 5 stmt = preparestatement(handler, ms.getstatementlog());//4.准备得到一个 6 return handler.query(stmt, resulthandler);//5.handler.query开始真正执行了
25.进入query到了routingstatementhandler.java
return delegate.query(statement, resulthandler);//调了delegate
26.调了delegate到了preparedstatementhandler.java
1 public <e> list<e> query(statement statement, resulthandler resulthandler) throws sqlexception { 2 preparedstatement ps = (preparedstatement) statement;preparedstatement预编译对象 3 ps.execute();//2.获取预编译对象,执行任意语句 4 return resultsethandler.handleresultsets(ps);// 5 }
到了这里就是最终的结果,剩余处理结果集,封装的事情了。
结果:mybatis封装的再深底层还是jdbc。