查询一张表的所有数据。

环境:

使用工具IntelliJ IDEA 2018.2版本。

创建Maven工程不用骨架

 <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>com.jxjdemo</groupId>
<artifactId>day34_mybatis1_curd_dao</artifactId>
<version>1.0-SNAPSHOT</version> <properties><!--锁定编译版本与字符集-->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties> <dependencies>
<dependency><!--导入mysql依赖-->
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency> <dependency> <!--导入mybatis依赖-->
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency> <dependency> <!--导入日志依赖-->
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency> <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
</project>
  1. 表User
 package com.jxjdemo.domain;
import java.util.Date; public class User {
private Integer id;
private String username;
private Date birthday; //框架会帮我们自动转
private String sex;
private String address; @Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", birthday=" + birthday +
", sex='" + sex + '\'' +
", address='" + address + '\'' +
'}';
}
//省略Get与Set方法

2.映射器XML

 <?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>

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.实现类

 package com.jxjdemo.dao.impl;
import com.jxjdemo.dao.UserDao;
import com.jxjdemo.domain.User;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import java.util.List; public class UserDaoImpl implements UserDao {//执行SQL语句用实现类做,不用代理对象。
//从工厂里面获取sqlsession对象
private SqlSessionFactory factory;//以后由sping整合sping创建,现在去测试类里面创建 public UserDaoImpl(SqlSessionFactory factory) {
this.factory = factory;
} @Override
public List<User> queryAll() {
SqlSession session = factory.openSession();
List<User> list = session.selectList("com.jxjdemo.dao.UserDao.queryAll");//返回的是Object但实际得到的是(UserDao)
session.close();//session关闭流,释放资源
return list;
}

5.测试类

 package com.jxjtest.test;

 import com.jxjdemo.dao.UserDao;
import com.jxjdemo.dao.impl.UserDaoImpl;
import com.jxjdemo.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test; import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List; public class MybatisCurdTest {
private SqlSessionFactory factory;
private InputStream is;
private UserDao userDao; @Test
public void testQueryAll(){ //查询全部
//读取配置文件,获取sqlsession对象工厂,获取映射器提取
List<User> userList = userDao.queryAll();
for (User user : userList){
System.out.println(user);
}
}
@Before
public void init() throws IOException { //重复执行的代码,单独提取出来
is = Resources.getResourceAsStream("sqlMapConfig.xml");//提取成员变量后 // SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is); //获取sqlsession对象,通过工厂构建一个,提取成员变量
factory = new SqlSessionFactoryBuilder().build(is);
userDao = new UserDaoImpl(factory);//提取成员变量
}
@After
public void destroy() throws IOException { //关流
is.close();
}
}

6.数据库核心配置文件XML

 <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--mybatis的核心配置文件,主要配置数据库连接信息-->
<configuration><!--根标签-->
<!--enxironments 可以配置多个数据库环境-->
<environments default="mysql"><!--default 默认使用的数据库-->
<environment id="mysql"><!--environment每一个数据库连接(配置)信息-->
<transactionManager type="JDBC" /><!--事物管理方式-->
<dataSource type="POOLED"><!--数据源。不使用UN连接池POOLED,POOLED使用连接池,JNDI查找数据源配置文件-->
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:端口号/库名"/>
<property name="username" value="账号"/>
<property name="password" value="密码"/>
</dataSource>
</environment>
</environments> <mappers>
<mapper resource="com/jxjdemo/dao/UserDao.xml" />
</mappers>
</configuration>

  7.省略log4j日志配置文件,目录结构。

Mybatis 映射器接口实现类的方式 运行过程debug分析-LMLPHP

8.在测试类打断点,开始deBug跟踪,从这里开始。

相册里面有步骤截图,可以配合一起看。

 List<User> userList = userDao.queryAll();

9.到实现类,获取session

 SqlSession session = factory.openSession();

10.跟踪这行代码做了什么事情,进入这个方法。

 List<User> list = session.selectList("com.jxjdemo.dao.UserDao.queryAll");

11.到了DefaultSqlSession.java类里面,在selectList调了selectList,方法的重载。

 @Override
public <E> List<E> selectList(String statement) {
return this.selectList(statement, null);
} @Override
public <E> List<E> selectList(String statement, Object parameter) {
return this.selectList(statement, parameter, RowBounds.DEFAULT);
}

12.到了ms,获取数据库,配置文件信息,与SQL类型。关键在于executor.query执行查询。

 public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}

13.先对wrspCollection(parameter)包装一下。回到12.

 if (object instanceof Collection) {这里省略}

14.进入CachingExecutor.java.这个类自己不执行。

  @Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
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方法。

 @Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
Cache cache = ms.getCache();

18.找缓存。

 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);//
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);//2.

24.进入doQuery查看,到了SimpleExecutor.java

 public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;//
Configuration configuration = ms.getConfiguration();//2.configuration所有的配置信息
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);//3.
stmt = prepareStatement(handler, ms.getStatementLog());//4.准备得到一个
return handler.query(stmt, resultHandler);//5.handler.query开始真正执行了

25.进入query到了RoutingStatementHandler.java

return delegate.query(statement, resultHandler);//调了delegate

26.调了delegate到了PreparedStatementHandler.java

 public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;PreparedStatement预编译对象
ps.execute();//2.获取预编译对象,执行任意语句
return resultSetHandler.handleResultSets(ps);//
}

到了这里就是最终的结果,剩余处理结果集,封装的事情了。

结果:Mybatis封装的再深底层还是JDBC。

05-11 10:48