一 分析mybatis的工作原理:
如上图所示是mybatis的工作原理
1 首先程序加载全局的配置文件,形成配置文件类
2 通过Mapper的接口形成一个mapper的代理
3 通过调用mapper的代理执行对应的方法,此时代理中会发现,method.getdeclareClass并不是一个类,而是一个接口
4 此时通过执行mapperMethod,也就是接口的方法,因为mepperproxy是组合了sqlsession的,当调用mapper接口的方法时,它通过方法的映射,最终还是调用的sqlsession的接口方法。
5 sqlsession本身不带有接口的实现类,所以此时sqlsession类就组合进来Excutor执行器。通过executor来完成实现。
6 excutor执行的时候需要通过原始jdbc对sql 生成不同的statement比如预编译的prepareStatement,这个时候会借助statementHandler来完成构建Statement
7 可以看到执行到达数据库的过程中,还要经过一个parameterHandler,通过这个类来设置参数。
8 最后查询结果包装结果集通过resultSethandler进行结果集处理,并返回.
二 手写mybaties分析
如上图所示是对编写一个mybatis的具体思想和步奏的分析,首先我们要有一个使用的方式就是编写一个持久层的jar包并且把它集成到系统里面。其次是具体框架的一些实现步奏与实现思路。参考右半部分的代码实现流程。
三 手写Mybatis
3.1 使用侧
步奏
1.引入自定义的pom.xml依赖
<dependency>
<groupId>cn.lalaframework.boot</groupId>
<artifactId>worn-persist</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
2.编辑自定义的配置文件 mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<dataSource>
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://192.168.189.3:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
<mappers>
<mapper resource="mybatis/UserMapper.xml"/>
</mappers>
</configuration>
UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<mapper namespace="user">
<select id="selectOne" parameterType="worn.xiao.huolala.persist.User" resultType="worn.xiao.huolala.persist.User">
select * from user where age=#{age}
</select>
<select id="selectList" parameterType="worn.xiao.huolala.persist.User" resultType="worn.xiao.huolala.persist.User">
select * from user where age=#{age}
</select>
</mapper>
3.编写掉用代码
public class PersistTest {
public static void main(String[] args) throws IOException, JDOMException {
String resource = "mybatis/mybatis-config.xml";
InputStream resourceAsStream = Resources.class.getClassLoader().getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryBuilder.build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
User userparameter=new User();
userparameter.setAge(10);
List<User> user = sqlSession.selectList("user.selectList",userparameter);
System.out.println(JSONObject.toJSONString(user));
}
}
4.执行结果
3.2 核心代码实现
1.解析xml生成配置类
public static SqlSessionFactory build(InputStream inputStream) throws IOException, JDOMException {
XMLConfigBuilder xmlConfigBuilder=new XMLConfigBuilder(inputStream);
return new DefaultSqlSessionFactory(xmlConfigBuilder.parse());
}
public class XMLConfigBuilder {
private InputStream inputStream;
public XMLConfigBuilder() {
}
public XMLConfigBuilder(InputStream inputStream) {
this.inputStream = inputStream;
}
public Configuration parse() throws IOException, JDOMException {
SAXBuilder builder = new SAXBuilder();
Document document = builder.build(inputStream, "");
Element configration = document.getRootElement();
Configuration configuration = new Configuration();
configuration.setDataSource(parseDataSource(configration, "dataSource"));
parseMappedStatementMap(configuration, configration, "mappers");
return configuration;
}
private void parseMappedStatementMap(Configuration configuration, Element configration, String mappers) throws IOException, JDOMException {
Element child = configration.getChild(mappers);
List<Element> children = child.getChildren();
if (children.size() <= 0) {
return;
}
for (int i = 0; i < children.size(); i++) {
Element element = children.get(i);
Attribute resource = element.getAttribute("resource");
parseMapper(configuration, resource.getValue());
}
}
private void parseMapper(Configuration configuration, String value) throws IOException, JDOMException {
SAXBuilder builder = new SAXBuilder();
InputStream resourceAsStream = XMLConfigBuilder.class.getClassLoader().getResourceAsStream(value);
Document document = builder.build(resourceAsStream, "");
Element configration = document.getRootElement();
List<Element> children = configration.getChildren();
Attribute namespace = configration.getAttribute("namespace");
for (int i = 0; i < children.size(); i++) {
Element element = children.get(i);
Attribute id = element.getAttribute("id");
Attribute parameterType = element.getAttribute("parameterType");
Attribute resultType = element.getAttribute("resultType");
String statementId = namespace.getValue().concat(".").concat(id.getValue());
String name = element.getName();
String originSql = element.getText();
SqlSource sqlSource = getSqlSource(configuration, originSql);
MappedStatement mappedStatement = new MappedStatement
.MappedStatementBuidler()
.statementId(statementId)
.sqlSource(sqlSource)
.parameterType(parameterType.getValue())
.sqlCommond(SqlCommond.valueOf(name.toUpperCase(Locale.ROOT)))
.resultType(resultType.getValue())
.build();
configuration.getMappedStatementMap().put(statementId, mappedStatement);
}
}
private SqlSource getSqlSource(Configuration configuration, String originSql) {
ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler();
GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);
String finalSql = parser.parse(originSql);
return new StaticSqlSource(configuration, finalSql, handler.getParameterMappings());
}
public DataSource parseDataSource(Element configration, String development) {
Properties properties = new Properties();
Element elements = configration.getChild(development);
List<Element> children =elements.getChildren();
if (children.size() > 0) {
for (int i = 0; i < children.size(); i++) {
Element element = children.get(i);
Attribute name = element.getAttribute("name");
Attribute value = element.getAttribute("value");
properties.setProperty(name.getValue(), value.getValue());
}
}
JdbcDataSource jdbcDataSource = new JdbcDataSource();
jdbcDataSource.setDriver(properties.getProperty("driver"));
jdbcDataSource.setUrl(properties.getProperty("url"));
jdbcDataSource.setUsername(properties.getProperty("username"));
jdbcDataSource.setPassword(properties.getProperty("password"));
return jdbcDataSource;
}
}
2.sqlsession执行器
public class DefaultSqlSession implements SqlSession {
private Configuration configuration;
private Executor executor;
public DefaultSqlSession(){
}
public DefaultSqlSession(Configuration configuration,Executor executor){
this.configuration=configuration;
this.executor=executor;
}
@Override
public <E> E selectOne(String statementId, Object parameterObj) {
MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
return executor.selectOne(statementId,mappedStatement,parameterObj);
}
@Override
public <E> List<E> selectList(String statementId, Object parameterObj) {
MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
return executor.selectList(statementId,mappedStatement,parameterObj);
}
}
3 executor 执行器
public class SimpleExecutor implements Executor {
private Configuration configuration;
public SimpleExecutor(Configuration configuration) {
this.configuration = configuration;
}
@Override
public <E> E selectOne(String statementId, MappedStatement mappedStatement, Object parameterObj) {
List<E> selectList = this.selectList(statementId, mappedStatement, parameterObj);
if (selectList.size() > 1) {
throw new RuntimeException("selectOne but has more than one");
}
if (selectList.size() == 1) {
return selectList.get(0);
}
return null;
}
@Override
public <E> List<E> selectList(String statementId, MappedStatement mappedStatement, Object parameterObj) {
try {
Connection connection = configuration.getDataSource().getConnection();
SqlSource sqlSource = mappedStatement.getSqlSource();
BoundSql boundSql = sqlSource.getBoundSql(parameterObj);
ParameterHandler parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObj, boundSql);
ResultSetHandler resultHandler = configuration.newResultHandler(mappedStatement);
StatementHandler statementHandler = configuration.newStatementHandler(this,
mappedStatement, parameterObj, resultHandler, boundSql, parameterHandler);
Statement statement = statementHandler.prepare(connection, 1000);
statementHandler.parameterize(statement);
return statementHandler.<E>query(statement, resultHandler);
} catch (Exception exception) {
throw new RuntimeException(exception);
}
}
}
4 statementhandler 查库
package cn.lalaframework.boot.handler;
import cn.lalaframework.boot.config.MappedStatement;
import cn.lalaframework.boot.executor.Executor;
import cn.lalaframework.boot.sql.BoundSql;
import java.sql.*;
import java.util.List;
public class PreparedStatementHandler implements StatementHandler {
private Executor executor;
private MappedStatement mappedStatement;
private Object parameter;
private ResultSetHandler resultHandler;
private BoundSql boundSql;
private ParameterHandler parameterHandler;
public PreparedStatementHandler() {
}
public PreparedStatementHandler(Executor executor,
MappedStatement mappedStatement,
Object parameter,
ResultSetHandler resultHandler,
BoundSql boundSql,
ParameterHandler parameterHandler) {
this.executor = executor;
this.mappedStatement = mappedStatement;
this.parameter = parameter;
this.resultHandler = resultHandler;
this.boundSql = boundSql;
this.parameterHandler = parameterHandler;
}
@Override
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSql());
return preparedStatement;
}
@Override
public void parameterize(Statement statement) {
parameterHandler.setParameters((PreparedStatement) statement);
}
@Override
public int update(Statement statement) throws SQLException {
PreparedStatement preparedStatement = (PreparedStatement) statement;
return preparedStatement.executeUpdate();
}
@Override
public <E> List<E> query(Statement statement, ResultSetHandler resultHandler) {
try {
PreparedStatement preparedStatement = (PreparedStatement) statement;
ResultSet resultSet = preparedStatement.executeQuery();
return resultHandler.<E> handleResult(resultSet);
} catch (Exception exception) {
throw new RuntimeException(exception);
}
}
@Override
public BoundSql getBoundSql() {
return boundSql;
}
@Override
public ParameterHandler getParameterHandler() {
return parameterHandler;
}
}
5 结果集处理 ResultSetWapper
public class ResultSetWapper {
private ResultSet resultSet;
private MappedStatement mappedStatement;
public ResultSetWapper() {
}
public ResultSetWapper(ResultSet resultSet, MappedStatement mappedStatement) {
this.resultSet = resultSet;
this.mappedStatement = mappedStatement;
}
public List<Object> getResult() {
// 1 获取数据库中的结果集
// 2 从mappedStatement 获取到结果集的映射
// 3 封装并返回结果集
List<Object> resutl = new ArrayList<>();
try {
while (resultSet.next()) {
String resultType = mappedStatement.getResultType();
Class<?> obj = Class.forName(resultType);
Object newInstance = obj.newInstance();
ResultSetMetaData metaData = resultSet.getMetaData();
int columnCount = metaData.getColumnCount();
for (int i = 0; i < columnCount; i++) {
String columnName = metaData.getColumnName(i+1);
Object val = resultSet.getObject(columnName);
Field field = obj.getDeclaredField(columnName);
field.setAccessible(true);
field.set(newInstance, val);
}
resutl.add(newInstance);
}
} catch (Exception exception) {
throw new RuntimeException(exception);
}
return resutl;
}
}
以上就是自定义编写一个mybatis的具体步骤。