摘要:本文主要向大家介绍了JAVA语言之MyBatis源码解读,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。
本文主要向大家介绍了JAVA语言之MyBatis源码解读,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。
之前我们通过图片讲解了Mybatis底层原理,今天我们就从源码入手去解读下Mybatis这个持久化框架是如何执行SQL的这个完整过程。
老样子,我们在看源码之前先写下demo,参考官方文档进行编写即可。
mysql5.7\mybatis1.3.9\springboot项目
User表的model类
package com.ckmike.mybatisdemo.model;
import java.util.Date;
/**
* User 简要描述
* <p> TODO:描述该类职责 </p>
*
* @author ckmike
* @version 1.0
* @date 18-12-16 下午3:14
* @copyright ckmike
**/
public class User {
private int id;
private String name;
private int age;
private String address;
private Date ctime;
public User() { }
public User(int id, String name, int age, String address, Date ctime) {
this.id = id;
this.name = name;
this.age = age;
this.address = address;
this.ctime = ctime;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setAddress(String address) {
this.address = address;
}
public void setCtime(Date ctime) {
this.ctime = ctime;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public String getAddress() {
return address;
}
public Date getCtime() {
return ctime;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
", ctime=" + ctime +
'}';
}
}
UserMapper接口
package com.ckmike.mybatisdemo.mapper;
import com.ckmike.mybatisdemo.model.User;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* @ClassName UserMapper
* @Description TODO:描述该接口职责
* @Author ckmike
* @Date 18-12-16 下午3:18
* @Version 1.0
* @Copyright ckmike
**/
@Mapper
public interface UserMapper {
List<User> getUser();
}
UserMapper.xml接口映射SQL文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "//mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ckmike.mybatisdemo.mapper.UserMapper">
<select id="getUser" resultType="com.ckmike.mybatisdemo.model.User">
SELECT * FROM user;
</select>
</mapper>
mybatis-config.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "//mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="false"/>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<typeAliases>
<typeAlias type="com.ckmike.mybatisdemo.model.User" alias="User"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" /> <!-- 声明使用那种事务管理机制 JDBC/MANAGED -->
<!-- 配置数据库连接信息 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver" />
<property name="url" value="jdbc:mysql://127.0.0.1:3306/ckmike?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&useSSL=false&verifyServerCertificate=false&autoReconnct=true&autoReconnectForPools=true&allowMultiQueries=true" />
<property name="username" value="root" />
<property name="password" value="******" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mybatis/UserMapper.xml"/>
</mappers>
</configuration>
这里开启了mybatis日志执行输出。
接下来就是看测试代码:
package com.ckmike.mybatisdemo;
import com.ckmike.mybatisdemo.mapper.UserMapper;
import com.ckmike.mybatisdemo.model.User;
import com.ckmike.mybatisdemo.service.UserService;
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 org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
public class MybatisDemoApplicationTests {
@Autowired
private UserService userService;
@Test
public void contextLoads() {
// 1. 通过服务调用,获取users
List<User> userList = this.userService.getUser();
System.out.println(userList.get(0).toString());
try {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
// 2.通过执行sql获取
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = sqlSessionFactory.openSession();
String sql = "com.ckmike.mybatisdemo.mapper.UserMapper.getUser";
List<User> list = session.selectList(sql);
System.out.println(list.get(0).toString());
// 3.通过获取Mapper
UserMapper userMapper = session.getMapper(UserMapper.class);
List<User> users = userMapper.getUser();
System.out.println(users.get(0).toString());
session.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
分析:
上面我们总共用来三种方式去调用mybatis执行sql语句,返回结果。
1.通过SpringBoot初始化项目,注入UserService调用UserMapper接口代理实例返回mybatis执行结果。
2.通过mybatis配置文件,构建一个SqlSessionFactory,开启一个SqlSession,通过执行UserMapper接口映射的方法返回结果。
3.通过SqlSession获取到UserMapper接口的代理实例,直接调用接口执行SQL返回结果。
其实上面1和3是同一种方式。只是前者通过application配置初始化了SqlSessionFactory,后续跟3是一致的。
那么我们就通过2和3两种方式开始解读这个mybatis源码,看看底层代码的设计实现是怎么样。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.apache.ibatis.session;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.Properties;
import org.apache.ibatis.builder.xml.XMLConfigBuilder;
import org.apache.ibatis.exceptions.ExceptionFactory;
import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.session.defaults.DefaultSqlSessionFactory;
public class SqlSessionFactoryBuilder {
public SqlSessionFactoryBuilder() {
}
public SqlSessionFactory build(Reader reader) {
return this.build((Reader)reader, (String)null, (Properties)null);
}
public SqlSessionFactory build(Reader reader, String environment) {
return this.build((Reader)reader, environment, (Properties)null);
}
public SqlSessionFactory build(Reader reader, Properties properties) {
return this.build((Reader)reader, (String)null, properties);
}
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
SqlSessionFactory var5;
try {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
var5 = this.build(parser.parse());
} catch (Exception var14) {
throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException var13) {
;
}
}
return var5;
}
public SqlSessionFactory build(InputStream inputStream) {
return this.build((InputStream)inputStream, (String)null, (Properties)null);
}
public SqlSessionFactory build(InputStream inputStream, String environment) {
return this.build((InputStream)inputStream, environment, (Properties)null);
}
public SqlSessionFactory build(InputStream inputStream, Properties properties) {
return this.build((InputStream)inputStream, (String)null, properties);
}
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
SqlSessionFactory var5;
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
var5 = this.build(parser.parse());
} catch (Exception var14) {
throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException var13) {
;
}
}
return var5;
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
}
上面这个SqlSessionFactoryBuilder类非常的简单,就是构建SqlSessionFactory的工具类。可以通过Configuration类初始化一个SqlSessionFactory,也可以通过文件流的形式加载XML配置文件初始化SqlSessionFactory,不管Configuration也好、文件流也好,都是通过XML文件去构造Configuration或者文件流,核心就是Mybatis-config配置构造SqlSessionFactory.最终都是得到一个DefaultSqlSessionFactory(实现了SqlSessionFactory接口)。
package org.apache.ibatis.session.defaults;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.ibatis.exceptions.ExceptionFactory;
import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.TransactionIsolationLevel;
import org.apache.ibatis.transaction.Transaction;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.managed.ManagedTransactionFactory;
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private final Configuration configuration;
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
public SqlSession openSession() {
return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false);
}
public SqlSession openSession(boolean autoCommit) {
return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, autoCommit);
}
public SqlSession openSession(ExecutorType execType) {
return this.openSessionFromDataSource(execType, (TransactionIsolationLevel)null, false);
}
public SqlSession openSession(TransactionIsolationLevel level) {
return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), level, false);
}
public SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) {
return this.openSessionFromDataSource(execType, level, false);
}
public SqlSession openSession(ExecutorType execType, boolean autoCommit) {
return this.openSessionFromDataSource(execType, (TransactionIsolationLevel)null, autoCommit);
}
public SqlSession openSession(Connection connection) {
return this.openSessionFromConnection(this.configuration.getDefaultExecutorType(), connection);
}
public SqlSession openSession(ExecutorType execType, Connection connection) {
return this.openSessionFromConnection(execType, connection);
}
public Configuration getConfiguration() {
return this.configuration;
}
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
DefaultSqlSession var8;
try {
Environment environment = this.configuration.getEnvironment();
TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
Executor executor = this.configuration.newExecutor(tx, execType);
var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
} catch (Exception var12) {
this.closeTransaction(tx);
throw ExceptionFactory.wrapException("Error opening session. Cause: " + var12, var12);
} finally {
ErrorContext.instance().reset();
}
return var8;
}
private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {
DefaultSqlSession var8;
try {
boolean autoCommit;
try {
autoCommit = connection.getAutoCommit();
} catch (SQLException var13) {
autoCommit = true;
}
Environment environment = this.configuration.getEnvironment();
TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
Transaction tx = transactionFactory.newTransaction(connection);
Executor executor = this.configuration.newExecutor(tx, execType);
var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
} catch (Exception var14) {
throw ExceptionFactory.wrapException("Error opening session. Cause: " + var14, var14);
} finally {
ErrorContext.instance().reset();
}
return var8;
}
private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
return
本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注编程语言JAVA频道!
您输入的评论内容中包含违禁敏感词
我知道了
请输入正确的手机号码
请输入正确的验证码
您今天的短信下发次数太多了,明天再试试吧!
我们会在第一时间安排职业规划师联系您!
您也可以联系我们的职业规划师咨询:
版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
沪公网安备 31011502005948号