MyBatis中binding模块的作用是什么
MyBatis中binding 模块的作用是什么,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。
创新互联从2013年开始,是专业互联网技术服务公司,拥有项目网站建设、成都网站设计网站策划,项目实施与项目整合能力。我们以让每一个梦想脱颖而出为使命,1280元黎川做网站,已为上家服务,为黎川各地企业和个人服务,联系电话:028-86922220
MyBatis binding 模块分析
binding功能代码所在包
org.apache.ibatis.binding
binding模块作用
封装ibatis编程模型 ibatis编程模型中,SqlSession作为sql执行的入口,实用方法为sqlSession.selectOne(namespace+id, 参数列表)的形式(例:sqlSession.selectOne("com.enjoylearning.mybatis.mapper.TUserMapper.selectByPrimaryKey", 2)),不易于维护和阅读
需要解决的问题
找到SqlSession中对应的方法(insert|update|select)
找到命名空间和方法名(两维坐标)
传递参数
核心类
MapperRegistry:mapper接口和对应的代理工厂的注册中心;是Configuration的成员变量
MapperProxyFactory:用于生成mapper接口动态代理的实例对象;保证mapper实例对象是局部变量(为什么不缓存?见文章最后)
MapperMethod:封装了Mapper接口中对应的方法信息,以继对应sql语句的信息.MapperMethod对象不记录任何状态,所以它可以再多个代理对象之间共享;sqlCommand:封装sql语句;MtehodSignature:封装mapper接口的入参和返回类型
个人理解
MapperRegistry的Map
, MapperProxyFactory>> knownMappers = new HashMap<>(); key:mapper的Class对象 value:生产这个mapper的动态代理示例的工厂 MapperProxyFactory:Map
methodCache key:方法的反射类 value 方法的信息(sql语句,入参,返回值)
相关代码
public class MapperRegistry { private final Configuration config;//config对象,mybatis全局唯一的 //记录了mapper接口与对应MapperProxyFactory之间的关系 private final Map, MapperProxyFactory>> knownMappers = new HashMap<>(); public MapperRegistry(Configuration config) { this.config = config; } @SuppressWarnings("unchecked") public T getMapper(Class type, SqlSession sqlSession) { final MapperProxyFactory mapperProxyFactory = (MapperProxyFactory ) knownMappers.get(type); if (mapperProxyFactory == null) { throw new BindingException("Type " + type + " is not known to the MapperRegistry."); } try { return mapperProxyFactory.newInstance(sqlSession); } catch (Exception e) { throw new BindingException("Error getting mapper instance. Cause: " + e, e); }
/** * * 用于生成mapper接口动态代理的实例对象; * @author Lasse Voss */ public class MapperProxyFactory{ //mapper接口的class对象 private final Class mapperInterface; //key是mapper接口中的某个方法的method对象,value是对应的MapperMethod,MapperMethod对象不记录任何状态信息,所以它可以在多个代理对象之间共享 private final Map methodCache = new ConcurrentHashMap<>();
public class MapperMethod { //从configuration中获取方法的命名空间.方法名以及SQL语句的类型 private final SqlCommand command; //封装mapper接口方法的相关信息(入参,返回类型); private final MethodSignature method;
getMapper的过程
public class MapperProxyFactory{ //mapper接口的class对象 private final Class mapperInterface; //key是mapper接口中的某个方法的method对象,value是对应的MapperMethod,MapperMethod对象不记录任何状态信息,所以它可以在多个代理对象之间共享 private final Map methodCache = new ConcurrentHashMap<>(); public MapperProxyFactory(Class mapperInterface) { this.mapperInterface = mapperInterface; } public Class getMapperInterface() { return mapperInterface; } public Map getMethodCache() { return methodCache; } @SuppressWarnings("unchecked") protected T newInstance(MapperProxy mapperProxy) { //创建实现了mapper接口的动态代理对象 return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); } public T newInstance(SqlSession sqlSession) { //每次调用都会创建新的MapperProxy对象 final MapperProxy mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache); return newInstance(mapperProxy); } }
两个newInstance方法生成mapper的动态代理对象MapperProxy
public class MapperProxyimplements InvocationHandler, Serializable { ....... @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { if (Object.class.equals(method.getDeclaringClass())) {//如果是Object本身的方法不增强 return method.invoke(this, args); } else if (isDefaultMethod(method)) { return invokeDefaultMethod(proxy, method, args); } } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } //从缓存中获取mapperMethod对象,如果缓存中没有,则创建一个,并添加到缓存中 final MapperMethod mapperMethod = cachedMapperMethod(method); //调用execute方法执行sql return mapperMethod.execute(sqlSession, args); } private MapperMethod cachedMapperMethod(Method method) { return methodCache.computeIfAbsent(method, k -> new MapperMethod(mapperInterface, method, sqlSession.getConfiguration())); }
从invoke方法可以看出 是mapperMethod调用了execute方法
public class MapperMethod { ...... public Object execute(SqlSession sqlSession, Object[] args) { Object result; //根据sql语句类型以及接口返回的参数选择调用不同的 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()) {//返回值为void executeWithResultHandler(sqlSession, args); result = null; } else if (method.returnsMany()) {//返回值为集合或者数组 result = executeForMany(sqlSession, args); } else if (method.returnsMap()) {//返回值为map result = executeForMap(sqlSession, args); } else if (method.returnsCursor()) {//返回值为游标 result = executeForCursor(sqlSession, args); } else {//处理返回为单一对象的情况 //通过参数解析器解析解析参数 Object param = method.convertArgsToSqlCommandParam(args); result = sqlSession.selectOne(command.getName(), param); if (method.returnsOptional() && (result == null || !method.getReturnType().equals(result.getClass()))) { result = OptionalUtil.ofNullable(result); } } break; case FLUSH: result = sqlSession.flushStatements(); break; default: throw new BindingException("Unknown execution method for: " + command.getName()); } if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) { throw new BindingException("Mapper method '" + command.getName() + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ")."); } return result; }
重点看 result = sqlSession.selectOne(command.getName(), param); 这里使用了ibatis的用法
问题解答
mapperProxy做查询依赖的还是sqlSession.按照现在的代码结构来说,如果缓存了mapperProxy,当sqlSession失效,mapperProxy也就失效了. 如果修改代结构,那么sqlSession就要作为查询参数
// 原本 TUser user = mapper.selectByPrimaryKey(2); // 修改后的写法 TUser user = mapper.selectByPrimaryKey(sqslSession,2);
看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注创新互联行业资讯频道,感谢您对创新互联的支持。
分享文章:MyBatis中binding模块的作用是什么
文章源于:http://ybzwz.com/article/jjjojc.html