mybatis-config.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">
<configuration>
<properties resource="jdbc.properties"></properties>
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
<!-- 为包下面的类 指定别名 name 包名 包下面类 默认别名就是类名 -->
<typeAliases>
<package name="com.wxz.domain"></package>
</typeAliases>
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
UserMapper.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.wxz.mapper.UserMapper">
<select id="selectOne" resultType="com.wxz.domain.User" >
select id as id,name as name , address as address ,age as age from user where id = 4
</select>
<select id="selectAll" resultType="com.wxz.domain.User" >
select id as id,name as name , address as address ,age as age from user
</select>
</mapper>
UserMapper
package com.wxz.mapper;
import com.wxz.domain.User;
import java.util.List;
public interface UserMapper {
public User selectOne();
public List<User> selectAll();
}
测试类
package com.wxz;
import com.wxz.domain.User;
import com.wxz.mapper.UserMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
/**
* TODO
*
* @author wxz
* @date 2022/1/9 16:35
*/
public class Test {
public static void main(String[] args) {
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = sqlSession.selectOne("com.wxz.mapper.UserMapper.selectOne");
// UserMapper userDao = sqlSession.getMapper(UserMapper.class);
// User user = userDao.selectOne();
System.out.println(user);
} catch (IOException e) {
e.printStackTrace();
}
}
}
第一步,解析mybatis-config.xml文件
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
?找到mybatis-config.xml中的根节点configuration
?解析配置文件中所有的节点
?找到mappers节点中resource再去解析UserMapper.xml文件
?开始解析UserMapper.xml文件中的mapper节点
?namespace==boundType,并且将namespace放进configration类loadedResources中
将接口放入
将接口(namespace)放进configration 类mapperRegistry中? knownMappers
Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap();
?
为接口创建代理类,(com.wxz.mapper.UserMapper)放入map容器中,使用接口的class对象作为key(UserMapper.class),value值为 MapperProxyFactory<?>
查询的时候,UserMapper.class作为参数,如果namespace和接口的全路径不一致,则抛出绑定异常
?
??Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap()
在MapperProxyFactory<?>中又创建一个map,将方法名称作为key,value值为MapperMethodInvoker,包含sql的标签,包含sql命令的类型,id值
<select id="selectOne" resultType="com.wxz.domain.User" >
select id as id,name as name , address as address ,age as age from user where id = 4
</select>
总之,将接口的代理类放入mapperRegistry中,
?同时将namespace+id? 作为key,valueMappedStatement?放入mappedStatements中
Map<String, MappedStatement> mappedStatements;
?第二步:将xml信息转化为Configuration类对象
?第三步:将Configuration类对象作为参数传入,创建一个SqlSessionFactory对象
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
?第四步:实际上 new DefaultSqlSessionFactory(config)
?第五步:根据sqlSessionFactory获取sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
?第六步:具体的数据库操作
第一种:使用(namespace+id)作为key,去mappedStatements中查询
public <T> T selectOne(String statement, Object parameter) {
List<T> list = this.selectList(statement, parameter);
if (list.size() == 1) {
return list.get(0);
} else if (list.size() > 1) {
throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
} else {
return null;
}
}
statement就是namespace+id 在前面就将namespace+id 作为key放入map中,value是mappedStatent根据key查询mappedStatent
第七步:根据statement找到对应的MappedStatement MappedStatement ms = this.configuration.getMappedStatement(statement);
第八步:调用executor去查询,从MappedStatement获取到sql语句
var6 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, handler);?
BoundSql boundSql = ms.getBoundSql(parameterObject);
第九步:查询缓存,从缓存中获取,若缓存没有,则查询数据库,再放入缓存中
?第十步:根据结果映射关系将查询的结果转化为具体的指定的类 ,此处将查询到的结果转化为User对象
第二种:使用代理(UserMapper.class)作为key,去mapperRegistry中查询
?
?上面已经说明了代理的实现,mybatis源码分析到此结束
根据接口创建代理类(com.wxz.mapper.UserMapper)放入容器中,使用接口的class对象作为key(UserMapper.class),value值为 MapperProxyFactory<?>
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap();
Mabatis中?sql语句的构建
?
public String parse(String text) {
if (text != null && !text.isEmpty()) {
int start = text.indexOf(this.openToken);
if (start == -1) {
return text;
} else {
char[] src = text.toCharArray();
int offset = 0;
StringBuilder builder = new StringBuilder();
StringBuilder expression = null;
do {
if (start > 0 && src[start - 1] == '\\') {
builder.append(src, offset, start - offset - 1).append(this.openToken);
offset = start + this.openToken.length();
} else {
if (expression == null) {
expression = new StringBuilder();
} else {
expression.setLength(0);
}
builder.append(src, offset, start - offset);
offset = start + this.openToken.length();
int end;
for(end = text.indexOf(this.closeToken, offset); end > -1; end = text.indexOf(this.closeToken, offset)) {
if (end <= offset || src[end - 1] != '\\') {
expression.append(src, offset, end - offset);
break;
}
expression.append(src, offset, end - offset - 1).append(this.closeToken);
offset = end + this.closeToken.length();
}
if (end == -1) {
builder.append(src, start, src.length - start);
offset = src.length;
} else {
builder.append(this.handler.handleToken(expression.toString()));
offset = end + this.closeToken.length();
}
}
start = text.indexOf(this.openToken, offset);
} while(start > -1);
if (offset < src.length) {
builder.append(src, offset, src.length - offset);
}
return builder.toString();
}
} else {
return "";
}
}
|