mybatis教程之原理剖析
MyBatis是目前非常流行的ORM框架,功能很强大,然而其实现却比较简单、优雅。本文通过代理的方式来看下其实现
方式一:传统API方式
@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.怎么加载配置文件的
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对象的
// 2.获取SqlSessionFactory对象 SqlSessionFactory factory = new SqlSessionFactoryBuilder() .build(inputStream );
源码分析
小结:
通过SqlSessionFactoryBuilder的builder方法获取SqlSessionFactory对象,实际是获取的是DefaultSqlSessionFactory对象,且同时解析了配置文件,并将信息封装到了Configuration对象中。加载配置文件的方式在项目中肯定只需要加载一次。所以在整个项目生命周期中SqlSessionFactory的实例只需要一个,所以此处可以将SqlSessionFactory设计为单例模式。
3.获取SqlSession对象
SqlSession session = factory.openSession();
处理器|说明
-----|:----
SimpleExecutor |就是普通的执行器
ReuseExecutor |执行器会重用预处理语句(prepared statements)
BatchExecutor |批量执行器
同时创建了Transaction对象,该对象有数据库连接对象Connection
创建执行器的过程
小结:
通过openSession()方法获取SqlSession对象,我们获取到了一个DefaultSqlSession实例,不会自动提交事务。实例化了一个执行器,如果我们没有专门指定执行器的类型,那么默认的执行器是SimpleExecutor。且获取了Transaction对象。
4.insert方法执行的过程
int i = session.insert("aaa.addUser", user);
<?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接口方式
@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对象
private int id; private String name; private int age;
接口文件
public interface UserMapper { public int addUser(User user); public int updateById(User user); public int deleteById(int id); public User queryById(int id); }
接口实现类
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和接口中的方法名相同
<?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代理的方式实现
测试文件
/** * 代理方式 */ @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代理实现的代码。结束~~~
- iPhone/Mac Objective-C内存管理教程和原理剖析
- 深入剖析 mybatis 原理(一)
- 深入剖析 mybatis 原理(二)
- Objective-C内存管理教程和原理剖析(三)
- Objective-C内存管理教程和原理剖析
- 很详细的Objective-C内存管理教程和原理剖析
- Objective-C内存管理教程和原理剖析(三)@property (retain)和@synthesize的默认实现
- iPhone/Mac Objective-C内存管理教程和原理剖析
- mybatis原理概述入门教程
- iPhone/Mac Objective-C内存管理教程和原理剖析
- iPhone/Mac Objective-C 内存管理教程和原理剖析
- iPhone/Mac Objective-C内存管理教程和原理剖析(三)@property (retain)和@synthesize的默认实现
- iPhone/Mac Objective-C内存管理教程和原理剖析(二)口诀与范式
- iPhone/Mac Objective-C内存管理教程和原理剖析
- iPhone/Mac Objective-C内存管理教程和原理剖析
- iPhone/Mac Objective-C内存管理教程和原理剖析(三)@property (retain)和@synthesize的默认实现
- iPhone/Mac Objective-C内存管理教程和原理剖析(二)口诀与范式
- SQL报错型盲注教程(原理全剖析)
- iPhone/Mac Objective-C内存管理教程和原理剖析(一)基本原理
- Objective-C内存管理教程和原理剖析(四)系统自动创建新的autorelease pool