mybatis-高级篇
一、mybatis原理
Mybatis的四大对象
Executor
ParameterHandler
ResultSetHandler
StatementHandler
一个MappedStatement代表一个增删改查的详细信息
Configuration包含全局配置,所有映射文件信息,接口信息
MappedStatement:一个sql对应一个MappedStatement
MapperProxyFactory:生成MapperProxy实例
Executor:执行增删改查,其中调用StatementHandler处理
原理分析
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// (1)
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// (2)
try (SqlSession session = sqlSessionFactory.openSession()){
// (3)
SellMapper mapper = session.getMapper(SellMapper.class);
// (4)
Sell sell = mapper.getSellById(1);
System.out.println(sell);
}
1、获取SqlSessionFactory对象
把配置文件的信息解析并保存在Configuration对象中(包含所有的映射文件信息、接口信息等),返回包含了Configuration的DefaultSqlSession对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
一个MappedStatement代表一个增删改查的详细信息
2、获取SqlSession
返回SqlSession的实现类Default对象,包含了Executor和Configuration;会有拦截器链(interceptChain.pluginAll(executor))对Executor进行插入修饰。
Executor:执行器,执行增删改查操作
CachingExecutor:包装了Executor,用于二级缓存
3、getMapper
getMapper使用MapperProxyFactory创建一个MapperProxy的代理对象,包含了DefaultSqlSession(Executor)
4、执行方法
创建MapperMethodInvoker(接口,有invoke方法),PlainMethodInvoker写入本次方法查询相关信息(MapperMethod),MapperMethod包括SqlCommand和MethodSignature。调用MapperMethodInvoker.invoke方法执行操作=>PlainMethodInvoker中调用MapperMethod.excute方法。MapperMethod.excute是真正执行方法。调用MapperStatment
通过调用代理类执行方法,创建StatementHandler(ParameterHandler,ResultSetHandler)处理器对象,使用处理器调用底层JDBC执行SQL返回结果。
StatementHandler:创建出Statement对象,预编译设置参数结果返回等工作,包含ParameterHandler和ResultSetHandler
ParameterHandler:设置参数,包含TypeHandler
ResultSetHandler:处理结果,包含TypeHandler
总结:
- 1、根据配置文件(全局,sql映射)初始化出Configuration对象
- 2、创建一个DefaultSqlSession对象,他里面包含Configuraiton以及Executor(根据全局配置文件中的defaultExecutorType创建出对应的Executor)
- 3、DefaultSqlSession.getMapper():拿到Mapper接口对应的MapperProxy;
- 4、MapperProxy包含了DefaultSqlSession
- 5、执行增删改查方法:
1)调用DefaultSqlSession的增删改查(Executor)
2)会创建一个StatementHandler对象(同时创建出ParameterHandler和ResultSetHandler)
3)、调用StatementHandler预编译参数以及设置参数值;使用ParaterHandler给sql设置参数
4)、调用StatementHandler的增删改查方法;
5)ResultSetHandler封装结果
二、mybatis插件
责任链模式+动态代理+反射机制
插件编写
- 1、实现Interceptor
- 2、使用@Intercepts注解完成插件签名
- 3、将写好的插件注册到全局的配置文件
@Intercepts({
@Signature(type = StatementHandler.class,method = "parameterize",args = Statement.class)
})
public class MyFirstPlugin implements Interceptor {
//如果符合插件插入规则,在对应方法执行时替换为当前方法
@Override
public Object intercept(Invocation invocation) throws Throwable {
System.out.println("插件:"+this.getClass());
Object target = invocation.getTarget();
MetaObject metaObject = SystemMetaObject.forObject(target);
Object value = metaObject.getValue("parameterHandler.parameterObject");
System.out.println("插件查出参数:"+value);
metaObject.setValue("parameterHandler.parameterObject",(int)value+1);
Object proceed = invocation.proceed();
return proceed;
}
//如果符合插件插入规则,生成代理对象,将本实例handler传入
@Override
public Object plugin(Object target) {
System.out.println("插件"+this.getClass()+":"+target);
return Plugin.wrap(target,this);
}
//从配置文件中获得信息
@Override
public void setProperties(Properties properties) {
}
}
<plugins>
<plugin interceptor="com.example.mybatistest.plugin.MyFirstPlugin">
<property name="" value=""/>
</plugin>
</plugins>
三、拓展-pagehelper
https://github.com/abel533/MyBatis-Spring-Boot
四、批量处理
方法一:
设置全局步骤defaultExecutorType=BATCH,表示所有的查询都使用批量处理
方法二:
获得批量处理的sqlSession进行处理SqlSession sqlSessin = sqlSessionFactory.openSession(Executor.BATCH)
方法三:
整合注入sqlSession,class=SqlSessionTemplate,类型executorTyepe=BATCH,然后aurowired使用
五、自定义TypeHandler
1、实现TypeHandler接口,或者继承BaseTypeHandler
public class MyTypeHandler implements TypeHandler<EmpStatus> {
// 设置参数到数据库中
@Override
public void setParameter(PreparedStatement ps, int i, EmpStatus parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i,parameter.getCode().toString());
}
// 从数据库中映射到java
@Override
public EmpStatus getResult(ResultSet rs, String columnName) throws SQLException {
int code = rs.getInt(columnName);
//code再进行替换返回成EmpStatus
return null;
}
@Override
public EmpStatus getResult(ResultSet rs, int columnIndex) throws SQLException {
int code = rs.getInt(columnIndex);
//code再进行替换返回成EmpStatus
return null;
}
@Override
public EmpStatus getResult(CallableStatement cs, int columnIndex) throws SQLException {
int code = cs.getInt(columnIndex);
//code再进行替换返回成EmpStatus
return null;
}
}
2、配置使用自定义TypeHandler
方式一:全局配置
<typeHandlers>
<typeHandler handler="com.example.mybatistest.typehandler.MyTypeHandler" javaType="com.example.mybatistest.bean.EmpStatus"/>
</typeHandlers>
方式二:独立配置
保存时:#{emp, typeHandler=xxx}
查询时:使用resultMap,resoult 中指定typeHandler=""