前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >mybatis教程之原理剖析

mybatis教程之原理剖析

作者头像
用户4919348
发布2019-04-02 11:35:12
4620
发布2019-04-02 11:35:12
举报
文章被收录于专栏:波波烤鸭波波烤鸭

  MyBatis是目前非常流行的ORM框架,功能很强大,然而其实现却比较简单、优雅。本文通过代理的方式来看下其实现

方式一:传统API方式

代码语言:javascript
复制
@Test
public void add() throws IOException {
	// 1.通过Resources对象加载配置文件
	InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
	// 2.获取SqlSessionFactory对象
	SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream );
	// 3.通过SqlSessionFactory对象获取SQLSession对象
	SqlSession session = factory.openSession();
	User user = new User();
	user.setName("dpb");
	user.setAge(22);
	// dpb.addUser  是映射文件中 namespace的内容加 id的内容,定位要执行的SQL
	int count = session.insert("dpb.addUser", user);
	System.out.println("影响的行数:"+count);
	// 需要显示的提交
	session.commit();
	session.close();
}

1.怎么加载配置文件的

代码语言:javascript
复制
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");

进入getResourceAsStream方法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

小结:   Resources.getResourceAsStream(“mybatis-config.xml”);这行代码其实很简单,就是通过类加载器加载我们的配置文件,获取到一个InputSream。

扩展知识

getResourceAsStream方法的使用:

  1. Class.getResourceAsStream(String path) : path 不以’/'开头时默认是从此类所在的包下取资源,以’/'开头则是从ClassPath根下获取。其只是通过path构造一个绝对路径,最终还是由ClassLoader获取资源
  2. Class.getClassLoader.getResourceAsStream(String path) :默认则是从ClassPath根下获取,path不能以’/'开头,最终是由ClassLoader获取资源。

2.怎么获取SqlSessionFactory对象的

代码语言:javascript
复制
// 2.获取SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder()
										.build(inputStream );

源码分析

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

小结:   通过SqlSessionFactoryBuilder的builder方法获取SqlSessionFactory对象,实际是获取的是DefaultSqlSessionFactory对象,且同时解析了配置文件,并将信息封装到了Configuration对象中。加载配置文件的方式在项目中肯定只需要加载一次。所以在整个项目生命周期中SqlSessionFactory的实例只需要一个,所以此处可以将SqlSessionFactory设计为单例模式。

3.获取SqlSession对象

代码语言:javascript
复制
SqlSession session = factory.openSession();
在这里插入图片描述
在这里插入图片描述
默认的执行器是SIMPLE
默认的执行器是SIMPLE
在这里插入图片描述
在这里插入图片描述

处理器

说明

SimpleExecutor

就是普通的执行器

ReuseExecutor

执行器会重用预处理语句(prepared statements)

BatchExecutor

批量执行器

在这里插入图片描述
在这里插入图片描述

  同时创建了Transaction对象,该对象有数据库连接对象Connection

在这里插入图片描述
在这里插入图片描述

创建执行器的过程

在这里插入图片描述
在这里插入图片描述

小结:   通过openSession()方法获取SqlSession对象,我们获取到了一个DefaultSqlSession实例,不会自动提交事务。实例化了一个执行器,如果我们没有专门指定执行器的类型,那么默认的执行器是SimpleExecutor。且获取了Transaction对象。

4.insert方法执行的过程

代码语言:javascript
复制
int i = session.insert("aaa.addUser", user);
代码语言:javascript
复制
<?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="aaa">
	<insert id="addUser" parameterType="com.sxt.bean.User">
		insert into t_user(name,age)values(#{name},#{age})		
	</insert>
</mapper>

代码跟踪:

在这里插入图片描述
在这里插入图片描述

添加数据进入DefaultSqlSession方法后调用的还是update方法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

回到此处

在这里插入图片描述
在这里插入图片描述

进入update方法

在这里插入图片描述
在这里插入图片描述

注意进入的是PreparedStatementHandler 怎么会进入PreparedStatementHandler的?不是SimpleExecutor处理器,应该进入SimpleStatementHandler吗?

在这里插入图片描述
在这里插入图片描述

参数在哪动态绑定的呢?

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

按照相同的方式可以跟踪下查询的方法,代码就在此不贴出来了。

对象

作用

SqlSessionFactory

顶层API,提供SQLSession对象,获取的同时加载配置文件

configuration

封装的有全局配置文件和各个映射文件的相关信息

SqlSession

顶层API,和数据库交互完成增删改查操作

MappedStatement

封装了一条insert|update|delete|select节点信息。

Executor

执行器,调度核心,SimpleExecutor,ReuseExecutor,BatchExecutor.

StatementHandler

封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数、将Statement结果集转换成List集合

BoundSql

封装的有动态SQL及对应的参数信息。

TypeHandler

类型处理器,java类型和数据库字段类型的转换

ResultSetHandler

负责将jdbc的ResultSet的结果和java中List的数据相互转换

方式二:基于Mapper接口方式

代码语言:javascript
复制
@Test
public void add() throws IOException {
	// 1.通过Resources对象加载配置文件
	InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
	// 2.获取SqlSessionFactory对象
	SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream );
	// 3.通过SqlSessionFactory对象获取SQLSession对象
	SqlSession session = factory.openSession();
	User user = new User();
	user.setName("dpb");
	user.setAge(22);
	//通过Java动态代理自动提供了UserMapper的实现类
	UserMapper mapper = session.getMapper(UserMapper.class);
	int count = mapper.addUser(user);
	System.out.println("影响的行数:"+count);
	session.commit();
}

  该方式本质上是通过jdk动态代理实现的。在看源码之前我们自己来简单的实现下看看。

通过jdk动态代理简单实现

bean对象

代码语言:javascript
复制
	private int id;
	
	private String name;
	
	private int age;

接口文件

代码语言:javascript
复制
public interface UserMapper {

	public int addUser(User user);
	
	public int updateById(User user);
	
	public int deleteById(int id);
	
	public User queryById(int id);
}

接口实现类

代码语言:javascript
复制
public class UserDao implements UserMapper {

	@Override
	public int addUser(User user) {
		
		return DBUtils.getInstall().openSession().insert("com.sxt.dao.UserMapper.addUser", user);
	}

	@Override
	public int updateById(User user) {
		// TODO Auto-generated method stub
		return DBUtils.getInstall().openSession().update("com.sxt.dao.UserMapper.updateById", user);
	}

	@Override
	public int deleteById(int id) {
		// TODO Auto-generated method stub
		return DBUtils.getInstall().openSession().delete("com.sxt.dao.UserMapper.deleteById", id);
	}

	@Override
	public User queryById(int id) {
		// TODO Auto-generated method stub
		return DBUtils.getInstall().openSession().selectOne("com.sxt.dao.UserMapper.queryById", id);
	}
}

映射文件

注意:namespace和接口全路径名称相同,id和接口中的方法名相同

代码语言:javascript
复制
<?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.sxt.dao.UserMapper">
	<insert id="addUser" parameterType="com.sxt.bean.User">
		insert into t_user(name,age)values(#{name},#{age})		
	</insert>
	
	<delete id="deleteById" parameterType="java.lang.Integer">
		delete from t_user where id=#{id}
	</delete>
	
	<update id="updateById" parameterType="com.sxt.bean.User">
		update t_user 
		set name=#{name},age=#{age}
		where id=#{id}
	</update>
	
	<select id="queryById" parameterType="java.lang.Integer"
		resultType="com.sxt.bean.User">
		select * from t_user where id=#{id}
	</select>
</mapper>

目录结构

在这里插入图片描述
在这里插入图片描述

  到此我们发现接口实现UserDao,其实就是个模板,没有特定的内容,这时我们可以将其删掉通过jdk代理的方式实现

测试文件

代码语言:javascript
复制
/**
 * 代理方式
 */
@Test
public void test(){
	UserMapper mapper = (UserMapper) Proxy.newProxyInstance(UserMapper.class.getClassLoader()
			, new Class[]{UserMapper.class},new InvocationHandler() {
				@Override
				public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
					System.out.println(UserMapper.class.getName()+"."+method.getName());
					Object id = null;
					for (Object object : args) {
						System.out.println(object);
						id = object;
					}
					
					// 实现逻辑
					return DBUtils.getInstall().openSession().selectOne(UserMapper.class.getName()+"."+method.getName(), id);
				}
			} );
	System.out.println(mapper.queryById(5));
}
在这里插入图片描述
在这里插入图片描述

测试成功

源码跟踪

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

源码中看到jdk代理实现的代码。结束~~~

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年01月20日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 方式一:传统API方式
    • 1.怎么加载配置文件的
      • 扩展知识
    • 2.怎么获取SqlSessionFactory对象的
      • 源码分析
    • 3.获取SqlSession对象
      • 4.insert方法执行的过程
      • 方式二:基于Mapper接口方式
        • 通过jdk动态代理简单实现
          • bean对象
          • 接口文件
          • 接口实现类
          • 映射文件
          • 测试文件
        • 源码跟踪
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档