java面试总结之四

前言

  前一篇简单的介绍了一下mysql的相关知识,说到mysql就不得不说一下mybatis框架,这一篇主要讲一讲mybatis的应用和面试的问题。总体来说,mybatis更多的可以理解为一个工具,面试中问到的问题相对较少,大家也可以了解一下hibernate,在面试过程中可以给面试官一种知识丰富的感觉。

  mybatis的架构

  mybatis和数据库交互的方式有两种,一种是传统的根据statementId调用API,另一种是基于Mapper接口实现的,这里我们主要说一说Mapper接口的方式。通过Mapper接口来访问数据库的好处,个人总结有两点,一是符合面向对象编程的依赖接口而不是依赖于实现类,二是通过实现接口可以满足java的动态代理。所以这里也隐身出一个问题,mybatis使用的设计模式是什么——代理模式。

  通过上图可以知道每个Mapper接口对应着一个Mapper.xml配置文件,其中xml中的每个节点(select、insert、update、delete)的id值对应Mapper接口中的方法名,mybatis会将Mapper.xml中的每个节点转成一个statement对象,放在configuration中,每次在通过接口调用方法时,根据方法名,也就是statement对象的statementId去查找对应的statement对象,进而进行动态生成sql,调用jdbc执行sql等一系列操作,说到这,我们将Mapper接口和Mapper.xml连接到了一起。mybatis也支持注解的方式将方法和sql整合,可以在接口的方法上直接编写sql,如下:

1 @Select("select * from debate")
2 List<Debate> selectDebate(Row row);

  这里再说一说关于入参的配置,也就是parameterType和parameterMap,两者的区别很简单,一个参数和多个参数而已,了解即可,parameterMap通常为java.lang.HashMap,通过key-value的形式传参。sql中获取参数的方式有两种#{}和${},对于同一个sql两者的解析结果是不同的,如下:

1 select * from tableName where id = #{id}

  当我们传递id=1时,最终的sql是

1 select * from tableName where id = ‘1‘

  而当我们使用${id}时,最终的sql是

1 select * from tableName where id = 1

  两者的区别就是单引号这个地方,所以说使用#{}可以防止sql注入,而#{}不能,关于sql注入这个地方可以稍作了解,举个简单的例子,依然使用上面的sql,假设id的类型是String,当我们将id的值传为"1 or 1 = 1"时,最终的sql为

1 select * from tableName where id = 1 or 1 = 1

  因为1 = 1恒成立,所以会将所有的数据都查询出来,对于用户个人信息之类的数据,这样是很不安全的,更可怕的是下面这种情况,当我们将id的值传为"1;delete from tableName",最终的sql为

1 select * from tableName where id = 1;delete from tableName

  查询一次数据之后,数据库被清空了,你就哭去吧!

  那有人说,既然${}不能防止sql注入,那我们还用它干嘛,存在就一定有价值的,假如我们需要动态传入表名时,就必须使用${},因为#{}会为参数加上单引号

1 select * from ‘tableName‘ where id = 1

  很显然,这是一个错误的sql。

  再说一说resultMap和resultClass两个属性。通常resultClass指定的是java中定义的model类,将返回结果resultSet映射到实体类上。但是由于命名规则的原因,对于数据库字段,我们通常使用"_"来分割,如用户名:user_name,而对于model实体类,我们通常使用驼峰的方式来命名:userName。当两处的名称不一样时,使用resultClass是没办法自动映射的,这时候就需要使用resultMap来实现。

 1     <resultMap type="User" id="UserMapper">
 2         <id property="id" column="id"/>
 3         <!-- 只需要修改不一致的字段 -->
 4         <result property="sex" column="user_sex"/>
 5     </resultMap>
 6
 7     <!-- 查询学生,根据id -->
 8     <select id="getById" parameterType="int" resultType="User">
 9         <![CDATA[
10             SELECT * from sys_user
11                 WHERE id = #{id}
12         ]]>
13     </select>

  这里我只写了不一样的列,名字相同的会自动映射,不过个人建议写全,看着更加直观,有利于后期维护。

  讲到这顺便提一下关于一对一、一对多和多对多的映射关系,虽然面试的时候没有被问过,算是作为一个知识点的扩展。这里有一篇博客,有兴趣的同学可以看看《mybatis一对一,一对多,多对一,多对多的理解》。到此sql的查询结果resultSet和我们的model也关联到了一起,下面再说一说Mapper接口如何使用的。

  我们在使用mybatis时,通常将我们的Mapper接口注入到具体的dao类中,那么spring是如何管理这些Mapper接口的呢?在spring的配置中添加如下配置:

1 <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
2     <property name="basePackage" value="test.mapper"></property>
3     <property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
4 </bean>

  org.mybatis.spring.mapper.MapperScannerConfigurer类会自动扫描test.mapper包下的所有Mapper接口,并使用代理模式为每个Mapper接口生成一个代理类,所以说实际上注入到dao类中的是代理类,这点千万要记住!至此mybatis就可以使用了,下面再说一说mybatis的组成和sql执行的整体流程。

  这里只需要了解每一个对象的作用即可,大致的流程就是SqlSession负责调用API,将请求方法名作为statementId从Configuration对象中查找对应的MappedStatement对象,Configuration对象是一个以statementId为key,MappedStatement为value的键值对。MappedStatement对象就是xml配置中的一个个节点(select、insert、update、delete),之后SqlSession将请求委派给了Executors来执行,Executor负责动态sql语句的生成和查询缓存的维护,最终生成一个StatementHandler对象,而StatementHandler对象负责java.sql.Statement参数的入参,调用JDBC查询数据库并将结果java.sql.ResultSet转成list。可能乍一看有点乱,对于这些名词有点生疏,这里有一篇文章推荐给大家《MyBatis原理深入解析》,看完之后再回来看这段话就会感觉清晰了很多。

  讲实话,mybatis其实也没有太多可以说的地方,作为一个对JDBC封装的框架来说,内部结构非常简单,使用起来也很顺手,要说弊端就是sql必须程序猿自己手写,不过作为一个合格的开发人员,sql应该是必备技能。还有一点就是关于数据库切换,这种情况我在开发中遇到的不多,由于手写sql的原因,不同数据库对于sql的支持也不一样,可能需要修改sql语句,而hibernate则没有这种问题(如oracle和mysql的分页就是不一样的)。mybatis的总结大概这么多吧,以后想到了再补充!

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

原文链接:http://www.cnblogs.com/1ning/p/6727416.html

时间: 2024-08-05 15:57:04

java面试总结之四的相关文章

JAVA面试中问及HIBERNATE与 MYBATIS的对比,在这里做一下总结(转)

hibernate以及mybatis都有过学习,在java面试中也被提及问道过,在项目实践中也应用过,现在对hibernate和mybatis做一下对比,便于大家更好的理解和学习,使自己在做项目中更加得心应手. 第一方面:开发速度的对比 就开发速度而言,Hibernate的真正掌握要比Mybatis来得难些.Mybatis框架相对简单很容易上手,但也相对简陋些.个人觉得要用好Mybatis还是首先要先理解好Hibernate. 比起两者的开发速度,不仅仅要考虑到两者的特性及性能,更要根据项目需求

转:最近5年133个Java面试问题列表

最近5年133个Java面试问题列表 Java 面试随着时间的改变而改变.在过去的日子里,当你知道 String 和 StringBuilder 的区别就能让你直接进入第二轮面试,但是现在问题变得越来越高级,面试官问的问题也更深入. 在我初入职场的时候,类似于 Vector 与 Array 的区别.HashMap 与 Hashtable 的区别是最流行的问题,只需要记住它们,就能在面试中获得更好的机会,但这种情形已经不复存在.如今,你将会被问到许多 Java 程序员都没有看过的领域,如 NIO,

java 面试 -- 4

Java面试知识点总结 本篇文章会对面试中常遇到的Java技术点进行全面深入的总结,帮助我们在面试中更加得心应手,不参加面试的同学也能够借此机会梳理一下自己的知识体系,进行查漏补缺(阅读本文需要有一定的Java基础:若您初涉Java,可以通过这些问题建立起对Java初步的印象,待有了一定基础后再后过头来看收获会更大).本文的问题列表来自于http://www.nowcoder.com/discuss/3043,在此感谢原作者的无私分享:) 1. Java中的原始数据类型都有哪些,它们的大小及对应

Java 面试-- 1

JAVA面试精选[Java基础第一部分] 这个系列面试题主要目的是帮助你拿轻松到offer,同时还能开个好价钱.只要能够搞明白这个系列的绝大多数题目,在面试过程中,你就能轻轻松松的把面试官给忽悠了.对于那些正打算找工作JAVA软件开发工作的童鞋们来说,当你看到这份题目的时候,你应该感动很幸运,因为,只要你把题目中的内容都搞懂了,在笔试的时候就可以游刃有余,通过面试只有半步之遥了,笔试只能反映你的JAVA技能.不管你是面试各个级别的JAVA工程师.架构师.还是项目经理,这个系列文章都是你最宝贵的资

[转载]java面试中经常会被问到的一些算法的问题

Java面试中经常会被问到的一些算法的问题,而大部分算法的理论及思想,我们曾经都能倒背如流,并且也能用开发语言来实现过, 可是很多由于可能在项目开发中应用的比较少,久而久之就很容易被忘记了,在此我分享一下在面试中经常被问到的一些基本的算法,也当做一次知识的巩固. 排序算法的一些特点: * 排序算法的分类如下:* 1.插入排序(直接插入排序.折半插入排序.希尔排序):* 2.交换排序(冒泡泡排序.快速排序):* 3.选择排序(直接选择排序.堆排序):* 4.归并排序:* 5.基数排序.* * 关于

java微信接口之四—上传素材

一.微信上传素材接口简介 1.请求:该请求是使用post提交地址为: https://api.weixin.qq.com/cgi-bin/media/uploadnews?access_token=ACCESS_TOKEN 其中ACCESS_TOKEN是我们动态获取的. 发送的数据: {"articles":[ { "thumb_media_id":"qI6_Ze_6PtV7svjolgs-rN6stStuHIjs9_DidOHaj0Q-mwvBelOXC

Java面试宝典

http://www.cnblogs.com/bluestorm/p/6429894.html Java面试宝典 面向对象的三个特征 封装,继承,多态.这个应该是人人皆知.有时候也会加上抽象. 多态的好处 允许不同类对象对同一消息做出响应,即同一消息可以根据发送对象的不同而采用多种不同的行为方式(发送消息就是函数调用).主要有以下优点: 可替换性:多态对已存在代码具有可替换性. 可扩充性:增加新的子类不影响已经存在的类结构. 接口性:多态是超累通过方法签名,想子类提供一个公共接口,由子类来完善或

java面试回忆录

本文地址:http://blog.csdn.net/sushengmiyan/article/details/28479895 作者:sushengmiyan ------------------------- 1.报文格式定义如下: 20字符长的姓名+1字符长的性别+3字符长的年龄 姓名长度不足20的右边补空格 性别中0表示男,1表示女 年龄不足3字符的左边补0 如: denny     0026 这一段报文解析后表示姓名为denny性别为男,年龄为26 数据库表结构如下: create ta

Java面试问题总结

前几天Java面试中遇到的问题,这只是其中的一部分问题,面试中有很多问题是关于数据结构和算法的.在这里做下总结,希望有能力的人可以试着做一下,并在评论区留下您的答案,让大家相互学习.谢谢 程序设计部分 第1题* 已知类定义如下 class Node { public Double value; public List<Node> children; } 将以下递归程序改成非递归程序(两个程序的输出应保持顺序一致) publicstaticvoid process(Node node) { fo