总体流程概述
* 1、获取sqlSessionFactory对象: * 解析文件的每一个信息保存在Configuration中,返回包含Configuration的DefaultSqlSession; * 注意:【MappedStatement】:代表一个增删改查的详细信息* 2、获取sqlSession对象 * 返回一个DefaultSQlSession对象,包含Executor和Configuration; * 这一步会创建Executor对象;* 3、获取接口的代理对象(MapperProxy) * getMapper,使用MapperProxyFactory创建一个MapperProxy的代理对象 * 代理对象里面包含了,DefaultSqlSession(Executor) * 4、执行增删改查方法总结: * 1、根据配置文件(全局,sql映射)初始化出Configuration对象 * 2、创建一个DefaultSqlSession对象, * 他里面包含Configuration以及 * Executor(根据全局配置文件中的defaultExecutorType创建出对应的Executor) * 3、DefaultSqlSession.getMapper():拿到Mapper接口对应的MapperProxy; * 4、MapperProxy里面有(DefaultSqlSession); * 5、执行增删改查方法: * 1)、调用DefaultSqlSession的增删改查(Executor); * 2)、会创建一个StatementHandler对象。 * (同时也会创建出ParameterHandler和ResultSetHandler) * 3)、调用StatementHandler预编译参数以及设置参数值; * 使用ParameterHandler来给sql设置参数 * 4)、调用StatementHandler的增删改查方法; * 5)、ResultSetHandler封装结果 * 注意: * 四大对象每个创建的时候都有一个interceptorChain.pluginAll(parameterHandler);
代码实现
通用mapper就是预先将一些方法映射成 MappedStatement存起来,mybatis-plus就集成了通用mapper
插件机制
生成 Executor,StatementHandler ,ParameterHandler,ResultSetHandler 这几大对象时,都会对其进行包装生成代理对象。代理对象可拦截要执行的方法。
package org.apache.ibatis.plugin;
public interface Interceptor {
//拦截指定的方法
Object intercept(Invocation invocation) throws Throwable;
//生成代理对象
Object plugin(Object target);
//设置属性相关值
void setProperties(Properties properties);
}
/**
* 完成插件签名:
* 告诉MyBatis当前插件用来拦截哪个对象的哪个方法
*/
@Intercepts(
{
@Signature(type=StatementHandler.class,method="parameterize",args=java.sql.Statement.class)
})
public class MyFirstPlugin implements Interceptor{
/**
* intercept:拦截:
* 拦截目标对象的目标方法的执行;
*/
@Override
public Object intercept(Invocation invocation) throws Throwable {
// TODO Auto-generated method stub
System.out.println("MyFirstPlugin...intercept:"+invocation.getMethod());
//动态的改变一下sql运行的参数:以前1号员工,实际从数据库查询3号员工
Object target = invocation.getTarget();
System.out.println("当前拦截到的对象:"+target);
//拿到:StatementHandler==>ParameterHandler===>parameterObject
//拿到target的元数据
MetaObject metaObject = SystemMetaObject.forObject(target);
Object value = metaObject.getValue("parameterHandler.parameterObject");
System.out.println("sql语句用的参数是:"+value);
//修改完sql语句要用的参数
metaObject.setValue("parameterHandler.parameterObject", 11);
//执行目标方法
Object proceed = invocation.proceed();
//返回执行后的返回值
return proceed;
}
/**
* plugin:
* 包装目标对象的:包装:为目标对象创建一个代理对象
*/
@Override
public Object plugin(Object target) {
// TODO Auto-generated method stub
//我们可以借助Plugin的wrap方法来使用当前Interceptor包装我们目标对象
System.out.println("MyFirstPlugin...plugin:mybatis将要包装的对象"+target);
Object wrap = Plugin.wrap(target, this);
//返回为当前target创建的动态代理
return wrap;
}
/**
* setProperties:
* 将插件注册时 的property属性设置进来
*/
@Override
public void setProperties(Properties properties) {
// TODO Auto-generated method stub
System.out.println("插件配置的信息:"+properties);
}
}
/*
PageHelper 的拦截分页方法 举例
*/
@Intercepts(
{
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
}
)
public class PageInterceptor implements Interceptor {
}
二级缓存(和插件机制无关)
一级缓存时会话级别
二级缓存是命名空间级别(二级缓存可以指定缓存实现默认map实现 可以用ecache等)
详细介绍:
代码测试
<?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>
<settings>
<!-- 打印查询语句 -->
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"/>
</plugins>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mybatis" />
<property name="username" value="root" />
<property name="password" value="" />
</dataSource>
</environment>
</environments>
<!-- 将我们写好的sql映射文件(EmployeeMapper.xml)一定要注册到全局配置文件(mybatis-config.xml)中 -->
<mappers>
<mapper resource="EmployeeMapper.xml" />
</mappers>
</configuration>
<?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="mybatis.dao.EmployeeMapper">
<!--
namespace:名称空间;指定为接口的全类名
id:唯一标识
resultType:返回值类型
#{id}:从传递过来的参数中取出id值
public Employee getEmpById(Integer id);
-->
<select id="getEmpById" resultType="mybatis.bean.Employee"
>
select id,last_name lastName,email,gender from tbl_employee where id = #{id}
</select>
<select id="getEmpByName" resultType="mybatis.bean.Employee">
select id,last_name lastName,email,gender from tbl_employee where last_name = #{name}
</select>
</mapper>
public class MyBatisTest {
public SqlSessionFactory getSqlSessionFactory() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
return new SqlSessionFactoryBuilder().build(inputStream);
}
/**
* 1、获取sqlSessionFactory对象:
* 解析文件的每一个信息保存在Configuration中,返回包含Configuration的DefaultSqlSession;
* 注意:【MappedStatement】:代表一个增删改查的详细信息
*
* 2、获取sqlSession对象
* 返回一个DefaultSQlSession对象,包含Executor和Configuration;
* 这一步会创建Executor对象;
*
* 3、获取接口的代理对象(MapperProxy)
* getMapper,使用MapperProxyFactory创建一个MapperProxy的代理对象
* 代理对象里面包含了,DefaultSqlSession(Executor)
* 4、执行增删改查方法
*
* 总结:
* 1、根据配置文件(全局,sql映射)初始化出Configuration对象
* 2、创建一个DefaultSqlSession对象,
* 他里面包含Configuration以及
* Executor(根据全局配置文件中的defaultExecutorType创建出对应的Executor)
* 3、DefaultSqlSession.getMapper():拿到Mapper接口对应的MapperProxy;
* 4、MapperProxy里面有(DefaultSqlSession);
* 5、执行增删改查方法:
* 1)、调用DefaultSqlSession的增删改查(Executor);
* 2)、会创建一个StatementHandler对象。
* (同时也会创建出ParameterHandler和ResultSetHandler)
* 3)、调用StatementHandler预编译参数以及设置参数值;
* 使用ParameterHandler来给sql设置参数
* 4)、调用StatementHandler的增删改查方法;
* 5)、ResultSetHandler封装结果
* 注意:
* 四大对象每个创建的时候都有一个interceptorChain.pluginAll(parameterHandler);
*
* @throws IOException
*/
@Test
public void test01() throws IOException {
// 1、获取sqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
// 2、获取sqlSession对象
SqlSession openSession = sqlSessionFactory.openSession();
try {
// 3、获取接口的实现类对象
//会为接口自动的创建一个代理对象,代理对象去执行增删改查方法
PageHelper.startPage(1,5);
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
Employee employee = mapper.getEmpByName("zhangsan");
System.out.println(mapper);
System.out.println(employee);
} finally {
openSession.close();
}
}
}