先看一个MyBatis的使用demo
@Resource
SqlSessionFactory sqlSessionFactory;
@RequestMapping(value = "/query", method = RequestMethod.GET)
public String query(@RequestParam("name") String name) {
//获取sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取代理对象
MapperProxyFactory<UserDao> proxyFactory = new MapperProxyFactory<>(UserDao.class);
UserDao userDao = proxyFactory.newInstance(sqlSession);
//执行并判断结果
return userDao.queryByName(name) != null ? "success" : "fail";
}
DAO如图
@Mapper
public interface UserDao {
@Select("select id from tb_passbook_user where `user_id`=#{name}")
Long queryByName(@Param("name")String name);
}
其中
1.MapperProxyFactory 是生成代理对象的工厂类
2.MapperProxy是InvocationHandler的实现类,invoke方法里面执行真正的逻辑。MapperProxy中维护了Dao接口中的方法的Method对象与MapperMethod对象的映射关系
protected T newInstance(MapperProxy<T> mapperProxy) {
//生成代理对象
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
//初始化动态代理相应的InvocationHandler
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
//生成代理对象
return newInstance(mapperProxy);
}
MapperProxy.invoke方法里面的核心逻辑:
//1.取出方法对应的sql语句
final MapperMethod mapperMethod = cachedMapperMethod(method);
//2.传入sqlSession并执行,如下代码可知执行的是MapperMethod.execute方法
return mapperMethod.execute(sqlSession, args);
3.MapperMethod是实际执行sql逻辑的类
MapperMethod.execute里面的逻辑
switch (command.getType()) {
//插入
case INSERT: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
//更新
case UPDATE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
break;
}
//删除
case DELETE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
break;
}
//查询
case SELECT:
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {
result = executeForCursor(sqlSession, args);
} else {
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + command.getName());
}