目录 MyBatis简单介绍 启动流程分析 简单总结 附录 MyBatis内置别名转换 参考 MyBatis简单介绍# MyBatis是一个持久层框架,使用简单,学习成本较低。可以执行自己手写的SQL语句,比较灵活。但是MyBatis的自动化程度不高,移植性也不高,有时从一个数据库迁移到另外一个数据库的时候需要自己修改配置。 一个Mybatis最简单的使用列子如下: Copy public class UserDaoTest { private SqlSessionFactory sqlSessionFactory; @Before public void setUp() throws Exception{ ClassPathResource resource = new ClassPathResource("mybatis-config.xml"); InputStream inputStream = resource.getInputStream(); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } @Test public void selectUserTest(){ String id = "{0003CCCA-AEA9-4A1E-A3CC-06D884BA3906}"; SqlSession sqlSession = sqlSessionFactory.openSession(); CbondissuerMapper cbondissuerMapper = sqlSession.getMapper(CbondissuerMapper.class); Cbondissuer cbondissuer = cbondissuerMapper.selectByPrimaryKey(id); System.out.println(cbondissuer); sqlSession.close(); } } 从配置文件(通常是XML文件)得到SessionFactory; 从SessionFactory得到SQLSession; 通过SqlSession进行CRUD和事务的操作; 执行完相关操作之后关闭Session。 启动流程分析# 本博客只涉及创建SessionFactory,以及从SessionFactory获取SqlSession的流程。具体执行Sql的流程会在其他博客中分析。 Copy ClassPathResource resource = new ClassPathResource("mybatis-config.xml"); InputStream inputStream = resource.getInputStream(); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 通过上面代码发现,创建SqlSessionFactory的代码在SqlSessionFactoryBuilder中,进去一探究竟: Copy //整个过程就是将配置文件解析成Configration对象,然后创建SqlSessionFactory的过程 //Configuration是SqlSessionFactory的一个内部属性 public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { try { XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); return build(parser.parse()); } catch (Exception e) { throw ExceptionFactory.wrapException("Error building SqlSession.", e); } finally { ErrorContext.instance().reset(); try { inputStream.close(); } catch (IOException e) { // Intentionally ignore. Prefer previous error. } } } public SqlSessionFactory build(Configuration config) { return new DefaultSqlSessionFactory(config); } 下面我们看下解析配置文件过程中的一些细节。 先给出一个配置文件的列子: Copy 下面是解析配置文件的核心方法: Copy private void parseConfiguration(XNode root) { try { //issue #117 read properties first //解析properties标签,并set到Configration对象中 //在properties配置属性后,在Mybatis的配置文件中就可以使用${key}的形式使用了。 propertiesElement(root.evalNode("properties")); //解析setting标签的配置 Properties settings = settingsAsProperties(root.evalNode("settings")); //添加vfs的自定义实现,这个功能不怎么用 loadCustomVfs(settings); //配置类的别名,配置后就可以用别名来替代全限定名 //mybatis默认设置了很多别名,参考附录部分 typeAliasesElement(root.evalNode("typeAliases")); //解析拦截器和拦截器的属性,set到Configration的interceptorChain中 //MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括: //Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed) //ParameterHandler (getParameterObject, setParameters) //ResultSetHandler (handleResultSets, handleOutputParameters) //StatementHandler (prepare, parameterize, batch, update, query) pluginElement(root.evalNode("plugins")); //Mybatis创建对象是会使用objectFactory来创建对象,一般情况下不会自己配置这个objectFactory,使用系统默认的objectFactory就好了 objectFactoryElement(root.evalNode("objectFactory")); objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); reflectorFactoryElement(root.evalNode("reflectorFactory")); //设置在setting标签中配置的配置 settingsElement(settings); //解析环境信息,包括事物管理器和数据源,SqlSessionFactoryBuilder在解析时需要指定环境id,如果不指定的话,会选择默认的环境; //最后将这些信息set到Configration的Environment属性里面 environmentsElement(root.evalNode("environments")); // databaseIdProviderElement(root.evalNode("databaseIdProvider")); //无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。解析typeHandler。 typeHandlerElement(root.evalNode("typeHandlers")); //解析Mapper mapperElement(root.evalNode("mappers")); } catch (Exception e) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e); } } 上面解析流程结束后会生成一个Configration对象,包含所有配置信息,然后会创建一个SqlSessionFactory对象,这个对象包含了Configration对象。 下面是openSession的过程: Copy private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; try { final Environment environment = configuration.getEnvironment(); final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); //获取执行器,这边获得的执行器已经代理拦截器的功能(见下面代码) final Executor executor = configuration.newExecutor(tx, execType); //根据获取的执行器创建SqlSession return new DefaultSqlSession(configuration, executor, autoCommit); } catch (Exception e) { closeTransaction(tx); // may have fetched a connection so lets call close() throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } } Copy //interceptorChain生成代理类,具体参见Plugin这个类的方法 public Executor newExecutor(Transaction transaction, ExecutorType executorType) { executorType = executorType == null ? defaultExecutorType : executorType; executorType = executorType == null ? ExecutorType.SIMPLE : executorType; Executor executor; if (ExecutorType.BATCH == executorType) { executor = new BatchExecutor(this, transaction); } else if (ExecutorType.REUSE == executorType) { executor = new ReuseExecutor(this, transaction); } else { executor = new SimpleExecutor(this, transaction); } if (cacheEnabled) { executor = new CachingExecutor(executor); } executor = (Executor) interceptorChain.pluginAll(executor); return executor; } 到此为止,我们已经获得了SqlSession,拿到SqlSession就可以执行各种CRUD方法了。 简单总结# 对于MyBatis启动的流程(获取SqlSession的过程)这边简单总结下: SqlSessionFactoryBuilder解析配置文件,包括属性配置、别名配置、拦截器配置、环境(数据源和事务管理器)、Mapper配置等;解析完这些配置后会生成一个Configration对象,这个对象中包含了MyBatis需要的所有配置,然后会用这个Configration对象创建一个SqlSessionFactory对象,这个对象中包含了Configration对象; 拿到SqlSessionFactory对象后,会调用SqlSessionFactory的openSesison方法,这个方法会创建一个Sql执行器(Executor),这个Sql执行器会代理你配置的拦截器方法。 获得上面的Sql执行器后,会创建一个SqlSession(默认使用DefaultSqlSession),这个SqlSession中也包含了Configration对象,所以通过SqlSession也能拿到全局配置; 获得SqlSession对象后就能执行各种CRUD方法了。 SQL的具体执行流程见后续博客。 一些重要类总结: SqlSessionFactory SqlSessionFactoryBuilder SqlSession(默认使用DefaultSqlSession) Plugin、InterceptorChain的pluginAll方法 附录# MyBatis内置别名转换 # Copy //TypeAliasRegistry registerAlias("string", String.class); registerAlias("byte", Byte.class); registerAlias("long", Long.class); registerAlias("short", Short.class); registerAlias("int", Integer.class); registerAlias("integer", Integer.class); registerAlias("double", Double.class); registerAlias("float", Float.class); registerAlias("boolean", Boolean.class); registerAlias("byte[]", Byte[].class); registerAlias("long[]", Long[].class); registerAlias("short[]", Short[].class); registerAlias("int[]", Integer[].class); registerAlias("integer[]", Integer[].class); registerAlias("double[]", Double[].class); registerAlias("float[]", Float[].class); registerAlias("boolean[]", Boolean[].class); registerAlias("_byte", byte.class); registerAlias("_long", long.class); registerAlias("_short", short.class); registerAlias("_int", int.class); registerAlias("_integer", int.class); registerAlias("_double", double.class); registerAlias("_float", float.class); registerAlias("_boolean", boolean.class); registerAlias("_byte[]", byte[].class); registerAlias("_long[]", long[].class); registerAlias("_short[]", short[].class); registerAlias("_int[]", int[].class); registerAlias("_integer[]", int[].class); registerAlias("_double[]", double[].class); registerAlias("_float[]", float[].class); registerAlias("_boolean[]", boolean[].class); registerAlias("date", Date.class); registerAlias("decimal", BigDecimal.class); registerAlias("bigdecimal", BigDecimal.class); registerAlias("biginteger", BigInteger.class); registerAlias("object", Object.class); registerAlias("date[]", Date[].class); registerAlias("decimal[]", BigDecimal[].class); registerAlias("bigdecimal[]", BigDecimal[].class); registerAlias("biginteger[]", BigInteger[].class); registerAlias("object[]", Object[].class); registerAlias("map", Map.class); registerAlias("hashmap", HashMap.class); registerAlias("list", List.class); registerAlias("arraylist", ArrayList.class); registerAlias("collection", Collection.class); registerAlias("iterator", Iterator.class); registerAlias("ResultSet", ResultSet.class); 参考# https://blog.csdn.net/luanlouis/article/details/40422941 作者: 写代码的木公 出处:https://www.cnblogs.com/54chensongxia/p/11850420.html 版权:本站使用「CC BY 4.0」创作共享协议,转载请在文章明显位置注明作者及出处。 分类: MyBatis SponsorPayPalAliPayWeChat « 上一篇: 【并发编程】线程状态解析 posted @ 2019-11-13 16:10 写代码的木公 阅读(35) 评论(0) 编辑 收藏 https://www.cnblogs.com/54chensongxia/p/11850420.html