mybatis查询语句的背后揭秘

这篇文章主要给大家介绍了关于mybatis查询语句的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用mybatis具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

一、前言

在先了解mybatis查询之前,先大致了解下以下代码的为查询做了哪些铺垫,在这里我们要事先了解,myabtis会默认使用DefaultSqlSessionFactory作为sqlSessionFactory的实现类,而sqlSession的默认实现类为DefaultSqlSession

 public static SqlSessionFactory getSessionFactory() throws IOException { Reader reader = Resources.getResourceAsReader("mybatis/mybatis-config.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); return builder.build(reader); }

获取mybatis的配置文件流,交给sqlSessionFactoryBuilder进行解析,在这里只会涉及到一部分,具体,请大家移步mybatis源码进行分析

解析大致步骤(以下说的配置文件,是mybatis配置数据库连接信息的那个配置文件,不是mapper.xml文件)

解析配置文件的核心类在XMLConfigBuilder类中,

代码如下

 public Configuration parse() { if (parsed) { throw new BuilderException("Each XMLConfigBuilder can only be used once."); } parsed = true; parseConfiguration(parser.evalNode("/configuration")); return configuration; } private void parseConfiguration(XNode root) { try { // 解析properties节点信息 propertiesElement(root.evalNode("properties")); // 解析settings节点配置信息,其中二级缓存的总开关就是这里配置,当然mybatis默认是开启的,详细见Configuration类中的cacheEnabled属性 Properties settings = settingsAsProperties(root.evalNode("settings")); loadCustomVfs(settings); loadCustomLogImpl(settings); // 解析别名 typeAliasesElement(root.evalNode("typeAliases")); // 解析插件 pluginElement(root.evalNode("plugins")); // 这个节点一般不进行配置,myabtis也提供了一个默认实现类DefaultObjectFactory,除非自定义对象工厂实现,才需配置 objectFactoryElement(root.evalNode("objectFactory")); objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); reflectorFactoryElement(root.evalNode("reflectorFactory")); settingsElement(settings); // read it after objectFactory and objectWrapperFactory issue #631 environmentsElement(root.evalNode("environments")); databaseIdProviderElement(root.evalNode("databaseIdProvider")); // 处理java类型和数据库类型的转换,mybatis提供了许多默认实现,详细见TypeHandlerRegistry类,如果需自定义,可在此节点中进行配置 typeHandlerElement(root.evalNode("typeHandlers")); // 这也是一个核心的配置,mapperElement方法会对mapper.xml文件内容进行一个解析 mapperElement(root.evalNode("mappers")); } catch (Exception e) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e); } }

解析mapper.xml文件 的类XMLMapperBuilder,

 public void parse() { // 也就是检测配置文件配置的mapper节点有没有加载到configuration类中,防止重复加载 if (!configuration.isResourceLoaded(resource)) { configurationElement(parser.evalNode("/mapper")); configuration.addLoadedResource(resource); // 这个是绑定,mapper接口的,当处理成功,在configuration类中的mapper注册器中,会添加一个mapper bindMapperForNamespace(); } parsePendingResultMaps();// 解析resultMap节点 parsePendingCacheRefs(); // 解析缓存节点,如 parsePendingStatements();// 解析select|update等节点,并封装成mappedStatement类 }

其中bindMapperForNamespace()方法的操作会导致以下结果

在configuration类中的MapperRegistry属性中添加一个mapper,结果存储在MapperRegistry类的一个map中,key为mapper的class value为一个代理工厂,负责产生mapper接口代理类。

 二、查询操作

当我们使用要使用mybatis进行查询操作,无非大致就是两种方式

 /** * 通过mapper接口形式查询数据 */ @Test public void testSelectByMapper() throws IOException { SqlSession sqlSession = MybatisUtil.getSessionFactory().openSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.selectByPrimaryKey(10); System.out.println(user); sqlSession.close(); } /** * 通过mapper接口的全限定名来进行查询 * @throws IOException */ @Test public void testSelectByString() throws IOException { SqlSessionFactory sessionFactory = MybatisUtil.getSessionFactory(); SqlSession sqlSession = sessionFactory.openSession(); User user = sqlSession.selectOne("com.mybatis.demo.mybatisdemo.mapper.UserMapper.selectByPrimaryKey",10); System.out.println(user); sqlSession.close(); }

先来看第一种的分析,当我们点击getMapper进去,它会去调用configuration类中getMapper方法,就如上面介绍的解析出mapper节点后,会存储在configuration类中的mapper注册器中,

 // defaultSqlSession类 public  T getMapper(Class type) { return configuration.getMapper(type, this); } //configuration类 public  T getMapper(Class type, SqlSession sqlSession) { return mapperRegistry.getMapper(type, sqlSession); } // 最终获取mapper对象的方法,其主要是创建一个mapper代理工厂,我们都知道mybatis的mapper接口是没有实现类的, // 但是我们直接查询是能获取数据,这里起作用的就是代理(采用的是jdk动态代理) 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); } }

然后最终会经过代理类MapperProxy的invoke方法,进行返回结果。在这里为了更好的能理解这个类,举个例子,步骤如下

先创建一个接口,再使用一个类去实现java的jdk代理的核心接口InvocationHandler,

未经允许不得转载:0133技术站首页 » Java