Mybatis框架复习大纲【面试+提高】 1.MyBatis面试题汇总1.1 JDBC编程有哪些不足之处,MyBatis是如何解决这些问题的?① 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。 解决:在SqlMapConfig.xml中配置数据链接池,使用连接池管理数据库链接。 ② Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。 解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。 ③ 向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。 解决: Mybatis自动将java对象映射至sql语句。 ④ 对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。 解决:Mybatis自动将sql执行结果映射至java对象。 1.2 MyBatis编程步骤是什么样的? ① 创建SqlSessionFactory ② 通过SqlSessionFactory创建SqlSession ③ 通过sqlsession执行数据库操作 ④ 调用session.commit()提交事务 ⑤ 调用session.close()关闭会话 1.3 MyBatis与Hibernate有哪些不同?1.Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句。mybatis可以通过XML或注解方式灵活配置要运行的sql语句,并将java对象和sql语句映射生成最终执行的sql,最后将sql执行的结果再映射生成java对象。 2.Mybatis学习门槛低,简单易学,程序员直接编写原生态sql,可严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,例如互联网软件、企业运营类软件等,因为这类软件需求变化频繁,一但需求变化要求成果输出迅速。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套sql映射文件,工作量大。 3.Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件(例如需求固定的定制化软件)如果用hibernate开发可以节省很多代码,提高效率。但是Hibernate的学习门槛高,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡,以及怎样用好Hibernate需要具有很强的经验和能力才行。 总之,按照用户的需求在有限的资源环境下只要能做出维护性、扩展性良好的软件架构都是好架构,所以框架只有适合才是最好。 1.4 使用MyBatis的mapper接口调用时有哪些要求?① Mapper接口方法名和mapper.xml中定义的每个sql的id相同 ② Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同 ③ Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同 ④ Mapper.xml文件中的namespace即是mapper接口的类路径。 1.5 SqlMapConfig.xml中配置有哪些内容?SqlMapConfig.xml中配置的内容和顺序如下: properties(属性) settings(配置) typeAliases(类型别名) typeHandlers(类型处理器) objectFactory(对象工厂) plugins(插件) environments(环境集合属性对象) environment(环境子属性对象) transactionManager(事务管理) dataSource(数据源) mappers(映射器) 1.6简单的说一下MyBatis的一级缓存和二级缓存? Mybatis首先去缓存中查询结果集,如果没有则查询数据库,如果有则从缓存取出返回结果集就不走数据库。Mybatis内部存储缓存使用一个HashMap,key为hashCode+sqlId+Sql语句。value为从查询出来映射生成的java对象 Mybatis的二级缓存即查询缓存,它的作用域是一个mapper的namespace,即在同一个namespace中查询sql可以从缓存中获取数据。二级缓存是可以跨SqlSession的。 1.7Mapper编写有哪几种方式? ①接口实现类继承SqlSessionDaoSupport 使用此种方法需要编写mapper接口,mapper接口实现类、mapper.xml文件 1).在sqlMapConfig.xml中配置mapper.xml的位置 2).定义mapper接口 3).实现类集成SqlSessionDaoSupport mapper方法中可以this.getSqlSession()进行数据增删改查。 4).spring 配置 ②使用org.mybatis.spring.mapper.MapperFactoryBean 1).在sqlMapConfig.xml中配置mapper.xml的位置 如果mapper.xml和mappre接口的名称相同且在同一个目录,这里可以不用配置 2).定义mapper接口 注意: 1、mapper.xml中的namespace为mapper接口的地址 2、mapper接口中的方法名和mapper.xml中的定义的statement的id保持一致 3、 Spring中定义 ③使用mapper扫描器 1).mapper.xml文件编写, 注意: mapper.xml中的namespace为mapper接口的地址 mapper接口中的方法名和mapper.xml中的定义的statement的id保持一致 如果将mapper.xml和mapper接口的名称保持一致则不用在sqlMapConfig.xml中进行配置 2).定义mapper接口 注意mapper.xml的文件名和mapper的接口名称保持一致,且放在同一个目录 3).配置mapper扫描器 4).使用扫描器后从spring容器中获取mapper的实现对象 扫描器将接口通过代理方法生成实现对象,要spring容器中自动注册,名称为mapper 接口的名称。 2. 建立工程时选择建立java工程还是web工程?当建立的工程,需要用到request/response时,需要建立web工程,否则Java工程即可。 3. MyBatis介绍 MyBatis本是apache公司一个名叫iBatis的开源项目,在2010年Apache将其转移给了Google公司,从apache software foundation 迁移到了google code,并且改名为MyBatis,后来在2013年11月又被Google将其放到了Github上。 MyBatis是一个优秀的持久层框架,它对jdbc操作数据库的过程进行了封装,开发者只需要关注SQL本身,而不需要浪费精力去处理,例如:注册驱动,创建connection,创建statement,手动设置参数,结果集检索等Jdbc繁杂的过程代码。 MyBatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。 1).和jdbc比较: 2).和hibernate比较: 4. jdbc编程步骤回顾
5. jdbc问题总结
6. MyBatis架构Configuration MyBatis所有的配置信息都保存在Configuration对象之中,配置文件中的大部分配置都会存储到该类中 SqlSession 作为MyBatis工作的主要顶层API,表示和数据库交互时的会话,完成必要数据库增删改查功能 Executor MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护 StatementHandler 封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数等 ParameterHandler 负责对用户传递的参数转换成JDBC Statement 所对应的数据类型 ResultSetHandler 负责将JDBC返回的ResultSet结果集对象转换成List类型的集合 TypeHandler 负责java数据类型和jdbc数据类型(也可以说是数据表列类型)之间的映射和转换 MappedStatement MappedStatement维护一条<select|update|delete|insert>节点的封装 SqlSource 负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回 BoundSql 表示动态生成的SQL语句以及相应的参数信息 7. MyBatis配置(第一种总结方式)1).SqlMapConfig.xml,此文件作为mybatis的全局(核心)配置文件,配置了mybatis的运行环境等信息。 mapper.xml 文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。 例如:User.xml 2).通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂 例如:通过流的形式构造SqlSessionFactory会话工厂 ①InputStream inputStream = Resources.getResourceAsStream(sqlMapConfig.xml路径位置); ②SqlSessionFactory sqlSessionFactory = new sqlSessionFactoryBuilder().build(inputStream); 3).由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。 sqlSession是线程不安全的,每个线程都应该有它独自的sqlSession,使用完就关闭。 4).mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。 (Executor才是真正操作数据库的,不过是底层 所以我们认为是sqlSession在进行操作) 5).Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。 6).Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。 7).Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。 8.Dao开发(第一种总结方式) 8-1.传统dao开发 8-1.1.使用上面的UserMapper.xml和SqlMapConfig.xml 8-1.2.创建Dao接口 方法名要与UserMapper.xml中的sql的id一致 8-1.3.创建Dao实现类 8-1.4.对Dao进行junit测试 原始Dao开发中存在以下问题: Dao方法体存在重复代码:通过SqlSessionFactory创建SqlSession,调用SqlSession的数据库操作方法 调用sqlSession的数据库操作方法需要指定statement的id,这里存在硬编码,不便于开发维护。 8-2.Mapper动态代理开发 Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。 Mapper接口开发需要遵循以下规范: 1).Mapper.xml文件中的namespace与mapper接口的类路径相同。 2).Mapper接口方法名和Mapper.xml中定义的每个statement的id相同 3).Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同 4).Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同 8-2.1.SqlMapConfig.xml 8-2.2.UserMapper.java 接口8-2.3.UserMapper.xml8-2.4.使用junit进行测试 9.MyBatis配置(第二种总结方式)全局配置文件:sqlmapconfig.xml文件中的配置项是有顺序的,按照官方图来配. 例如: settings: 全局参数设置 typeAliases:类型别名 mappers: 映射文件注意点
parameterType:表示输入参数的数据类型 核心API执行流程: SqlSessionFactoryBuilder案例 SqlSessionFactory创建SqlSession的方法: 用openSession方法获取的SqlSession有以下特点: 列举3个执行类型参数(ExecutorType): SqlSessionSqlSession执行增删改查以及事务操作. 10.Dao开发(第二种总结方式)实现方式: 传统的Dao
接口: 实现类: 优化: mapper动态代理的方式mapper代理的方式,只需要写接口,不需要写实现类,实现类由mybatis框架自动创建. 11. #{} 与 ${}区别 #{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换。#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。 ${}表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。 sql注入案例:"%"#{}"%" 如果#{}传入的是<!-- 如果是字符串拼接${}会直接导致误认为注释没完成导致出错。 12.parameterType和resultTypeparameterType:指定输入参数类型,mybatis通过ognl从输入对象中获取参数值拼接在sql中。 resultType:指定输出结果类型,mybatis将sql查询结果的一行记录数据映射为resultType指定类型的对象。如果有多条数据,则分别进行映射,并把对象放到容器List中 13.selectOne和selectListselectOne查询一条记录,如果使用selectOne查询多条记录则抛出异常: org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 3 at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:70) selectList可以查询一条或多条记录。 14.Mybatis解决jdbc编程的问题 1).数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库连接池可解决此问题。 解决:在SqlMapConfig.xml中配置数据连接池,使用连接池管理数据库链接。 2).Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。 解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。 3).向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。 解决:Mybatis自动将java对象映射至sql语句,通过statement中的parameterType定义输入参数的类型。 4).对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。 解决:Mybatis自动将sql执行结果映射至java对象,通过statement中的resultType定义输出结果的类型。 15.分页查询ResultHandler参数:可以把每行记录包装成其他数据类型,如:List,Map,Set.只需要写个接口. 16.控制事务17.缓存一级缓存指的就是sqlsession,在sqlsession中有一个数据区域,是map结构,这个区域就是一级缓存区域。一级缓存中的key是由sql语句、条件、statement等信息组成一个唯一值。一级缓存中的value,就是查询出的结果对象。(本地缓存) 二级缓存指的就是同一个namespace下的mapper,二级缓存中,也有一个map结构,这个区域就是一级缓存区域。一级缓存中的key是由sql语句、条件、statement等信息组成一个唯一值。一级缓存中的value,就是查询出的结果对象。(自定义缓存) 一级缓存是默认使用的。 二级缓存的配置 2. 在mapper映射文件中开启二级缓存 3. 禁止使用缓存 18.MappersMapper是个接口,里面定义方法匹配SqlSession中方法. Mapper注解,参考Mybatis官方文档. 19.动态sqlMyBatis使用OGNL表达式,来支持一些常用的标签. 案例: ifchoose, when, otherwisetrim, where, setforeachbind创建一个ognl表达式,用于语句中. Multi-db vendor supportPluggable Scripting Languages For Dynamic SQL为动态sql定制可插拔脚本语句 使用步骤: 再mybatis-config.xml或sqlmapconfig.xml文件中覆盖默认别名,使用自定义 在映射文件中使用 也可以在mapper中使用 sql片段抽取sql重复代码,提供效率。 20.多表查询输出结果类型
ResultMapresultType使用时,设置值时需要查询的列名和java对象属性名一致.如果不一致的时候,可以使用resultMap.使用时需要先定义,再使用. 映射一对一关系 映射一对多关系 多对多映射 21.mybatis和spring的整合整合的步骤 4). spring的配置文件 5). 数据库、日志的配置文件 log4j.properties MyBatis使用中几点经验1.手动增量配置映射文件 当有工具生成Mapper等配置文件的时候,很多人就不愿意手动写了。其实MyBatis的生成工具不是特别有用,生成的方法几乎不可用,删删改改老半天还不如自己手写快。而且需要新加或修改属性、方法时,也是没法使用生成的文件,因为需要保留好原有的一些属性和方法。手写映射文件时先定义出用到的字段,这样配置文件会简洁清晰,同时结果映射时效率会更高。 2.Mapper层参数为Map,由Service层负责重载。 3.尽量少用if choose等语句,降低维护的难度。 Xml代码 这样的if判断,其实是完全没有必要的,我们可以很简单的采用DECODE来解决默认值问题: Xml代码 当然有人会想,引入CASE WHEN,DECODE会导致需要ORACLE函数解析,会拖慢SQL执行时间,有兴趣的同学可以回去做一下测试,看看是否会有大的影响。就个人经验而 言,在我的开发过程,没有发现因为函数解析导致SQL变慢的情形。影响SQL执行效率的一般情况下是JOIN、ORDER BY、DISTINCT、PARTITATION BY等这些操作,这些操作一般与表结构设计有很大的关联。相对于这些的效率影响程度,函数解析对于SQL执行速度影响应该是可以忽略不计的。 4.用XML注释取代SQL注释。 Xml代码 即使传入的参数中存在对应的参数,实际也不会产生效果,因为后面的内容实际上是被完全注释了。这种错误,如果不经过严格的测试,是很难发现的。一般情况下,XML注释完全可以替代SQL注释,因此这种行为应该可以禁止掉。 5.尽可能使用#{},而不是${}. Mybatis中设计模式: Mybatis至少遇到了以下的设计模式的使用:
接下来挨个模式进行解读,先介绍模式自身的知识,然后解读在Mybatis中怎样应用了该模式。 1、Builder模式Builder模式的定义是“将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。”,它属于创建类模式,一般来说,如果一个对象的构建比较复杂,超出了构造函数所能包含的范围,就可以使用工厂模式和Builder模式,相对于工厂模式会产出一个完整的产品,Builder应用于更加复杂的对象的构建,甚至只会构建产品的一个部分。 在Mybatis环境的初始化过程中,SqlSessionFactoryBuilder会调用XMLConfigBuilder读取所有的MybatisMapConfig.xml和所有的*Mapper.xml文件,构建Mybatis运行的核心对象Configuration对象,然后将该Configuration对象作为参数构建一个SqlSessionFactory对象。 其中XMLConfigBuilder在构建Configuration对象时,也会调用XMLMapperBuilder用于读取*Mapper文件,而XMLMapperBuilder会使用XMLStatementBuilder来读取和build所有的SQL语句。 在这个过程中,有一个相似的特点,就是这些Builder会读取文件或者配置,然后做大量的XpathParser解析、配置或语法的解析、反射生成对象、存入结果缓存等步骤,这么多的工作都不是一个构造函数所能包括的,因此大量采用了Builder模式来解决。 对于builder的具体类,方法都大都用build*开头,比如SqlSessionFactoryBuilder为例,它包含以下方法: 即根据不同的输入参数来构建SqlSessionFactory这个工厂对象。 2、工厂模式在Mybatis中比如SqlSessionFactory使用的是工厂模式,该工厂没有那么复杂的逻辑,是一个简单工厂模式。 简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。 SqlSession可以认为是一个Mybatis工作的核心的接口,通过这个接口可以执行执行SQL语句、获取Mappers、管理事务。类似于连接MySQL的Connection对象。 可以看到,该Factory的openSession方法重载了很多个,分别支持autoCommit、Executor、Transaction等参数的输入,来构建核心的SqlSession对象。 在DefaultSqlSessionFactory的默认工厂实现里,有一个方法可以看出工厂怎么产出一个产品: 这是一个openSession调用的底层方法,该方法先从configuration读取对应的环境配置,然后初始化TransactionFactory获得一个Transaction对象,然后通过Transaction获取一个Executor对象,最后通过configuration、Executor、是否autoCommit三个参数构建了SqlSession。 在这里其实也可以看到端倪,SqlSession的执行,其实是委托给对应的Executor来进行的。 而对于LogFactory,它的实现代码: 这里有个特别的地方,是Log变量的的类型是Constructor<? extends Log>,也就是说该工厂生产的不只是一个产品,而是具有Log公共接口的一系列产品,比如Log4jImpl、Slf4jImpl等很多具体的Log。 3、单例模式单例模式(Singleton Pattern):单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。 单例模式的要点有三个:一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。单例模式是一种对象创建型模式。单例模式又名单件模式或单态模式。 在Mybatis中有两个地方用到单例模式,ErrorContext和LogFactory,其中ErrorContext是用在每个线程范围内的单例,用于记录该线程的执行环境错误信息,而LogFactory则是提供给整个Mybatis使用的日志工厂,用于获得针对项目配置好的日志对象。 ErrorContext的单例实现代码: 构造函数是private修饰,具有一个static的局部instance变量和一个获取instance变量的方法,在获取实例的方法中,先判断是否为空如果是的话就先创建,然后返回构造好的对象。 只是这里有个有趣的地方是,LOCAL的静态实例变量使用了ThreadLocal修饰,也就是说它属于每个线程各自的数据,而在instance()方法中,先获取本线程的该实例,如果没有就创建该线程独有的ErrorContext。 4、代理模式代理模式可以认为是Mybatis的核心使用的模式,正是由于这个模式,我们只需要编写Mapper.java接口,不需要实现,由Mybatis后台帮我们完成具体SQL的执行。 代理模式(Proxy Pattern) :给某一个对象提供一个代 理,并由代理对象控制对原对象的引用。代理模式的英 文叫做Proxy或Surrogate,它是一种对象结构型模式。 代理模式包含如下角色:
这里有两个步骤,第一个是提前创建一个Proxy,第二个是使用的时候会自动请求Proxy,然后由Proxy来执行具体事务; 当我们使用Configuration的getMapper方法时,会调用mapperRegistry.getMapper方法,而该方法又会调用mapperProxyFactory.newInstance(sqlSession)来生成一个具体的代理: 在这里,先通过T newInstance(SqlSession sqlSession)方法会得到一个MapperProxy对象,然后调用T newInstance(MapperProxy<T> mapperProxy)生成代理对象然后返回。 而查看MapperProxy的代码,可以看到如下内容: 非常典型的,该MapperProxy类实现了InvocationHandler接口,并且实现了该接口的invoke方法。 通过这种方式,我们只需要编写Mapper.java接口类,当真正执行一个Mapper接口的时候,就会转发给MapperProxy.invoke方法,而该方法则会调用后续的sqlSession.cud>executor.execute>prepareStatement等一系列方法,完成SQL的执行和返回。 5、组合模式组合模式组合多个对象形成树形结构以表示“整体-部分”的结构层次。 组合模式对单个对象(叶子对象)和组合对象(组合对象)具有一致性,它将对象组织到树结构中,可以用来描述整体与部分的关系。同时它也模糊了简单元素(叶子对象)和复杂元素(容器对象)的概念,使得客户能够像处理简单元素一样来处理复杂元素,从而使客户程序能够与复杂元素的内部结构解耦。 在使用组合模式中需要注意一点也是组合模式最关键的地方:叶子对象和组合对象实现相同的接口。这就是组合模式能够将叶子节点和对象节点进行一致处理的原因。 Mybatis支持动态SQL的强大功能,比如下面的这个SQL: 在这里面使用到了trim、if等动态元素,可以根据条件来生成不同情况下的SQL; 在DynamicSqlSource.getBoundSql方法里,调用了rootSqlNode.apply(context)方法,apply方法是所有的动态节点都实现的接口: 对于实现该SqlSource接口的所有节点,就是整个组合模式树的各个节点: 组合模式的简单之处在于,所有的子节点都是同一类节点,可以递归的向下执行,比如对于TextSqlNode,因为它是最底层的叶子节点,所以直接将对应的内容append到SQL语句中: 但是对于IfSqlNode,就需要先做判断,如果判断通过,仍然会调用子元素的SqlNode,即contents.apply方法,实现递归的解析。 6、模板方法模式模板方法模式是所有模式中最为常见的几个模式之一,是基于继承的代码复用的基本技术。 模板方法模式需要开发抽象类和具体子类的设计师之间的协作。一个设计师负责给出一个算法的轮廓和骨架,另一些设计师则负责给出这个算法的各个逻辑步骤。代表这些具体逻辑步骤的方法称做基本方法(primitive method);而将这些基本方法汇总起来的方法叫做模板方法(template method),这个设计模式的名字就是从此而来。 模板类定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 在Mybatis中,sqlSession的SQL执行,都是委托给Executor实现的,Executor包含以下结构: 其中的BaseExecutor就采用了模板方法模式,它实现了大部分的SQL执行逻辑,然后把以下几个方法交给子类定制化完成: 该模板方法类有几个子类的具体实现,使用了不同的策略:
比如在SimpleExecutor中这样实现update方法: 7、适配器模式适配器模式(Adapter Pattern) :将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。 在Mybatsi的logging包中,有一个Log接口: 该接口定义了Mybatis直接使用的日志方法,而Log接口具体由谁来实现呢?Mybatis提供了多种日志框架的实现,这些实现都匹配这个Log接口所定义的接口方法,最终实现了所有外部日志框架到Mybatis日志包的适配: 比如对于Log4jImpl的实现来说,该实现持有了org.apache.log4j.Logger的实例,然后所有的日志方法,均委托该实例来实现。 8、装饰者模式装饰模式(Decorator Pattern) :动态地给一个对象增加一些额外的职责(Responsibility),就增加对象功能来说,装饰模式比生成子类实现更为灵活。其别名也可以称为包装器(Wrapper),与适配器模式的别名相同,但它们适用于不同的场合。根据翻译的不同,装饰模式也有人称之为“油漆工模式”,它是一种对象结构型模式。 在mybatis中,缓存的功能由根接口Cache(org.apache.ibatis.cache.Cache)定义。整个体系采用装饰器设计模式,数据存储和缓存的基本功能由PerpetualCache(org.apache.ibatis.cache.impl.PerpetualCache)永久缓存实现,然后通过一系列的装饰器来对PerpetualCache永久缓存进行缓存策略等方便的控制。如下图: 用于装饰PerpetualCache的标准装饰器共有8个(全部在org.apache.ibatis.cache.decorators包中):
另外,还有一个特殊的装饰器TransactionalCache:事务性的缓存 正如大多数持久层框架一样,mybatis缓存同样分为一级缓存和二级缓存
Cache对象之间的引用顺序为:SynchronizedCache–>LoggingCache–>SerializedCache–>ScheduledCache–>LruCache–>PerpetualCache 9、迭代器模式迭代器(Iterator)模式,又叫做游标(Cursor)模式。GOF给出的定义为:提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的内部细节。 Java的Iterator就是迭代器模式的接口,只要实现了该接口,就相当于应用了迭代器模式: 比如Mybatis的PropertyTokenizer是property包中的重量级类,该类会被reflection包中其他的类频繁的引用到。这个类实现了Iterator接口,在使用时经常被用到的是Iterator接口中的hasNext这个函数。 可以看到,这个类传入一个字符串到构造函数,然后提供了iterator方法对解析后的子串进行遍历,是一个很常用的方法类。 sql中带有IN的子查询绑定变量实现方式 在sql中经常会带有IN的子查询,如 where id in (1,2,3)。如果这样的语句在数据库中出现,将引起数据库的大量硬解析与共享池SQL碎片, 下面介绍种将这些In list给绑定起来: |
|