MyBatis专题
● 谈一谈你对ORM的理解?
对象关系映射(Object Relational Mapping,简称ORM)是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。 简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将java程序中的对象自动持久化到关系数据库中。当然反过来也是可以的,例如将数据库表当中的记录查询出来,然后映射为Java程序中的Java对象。
● 在MyBatis中$和#的区别?
$进行sql语句的拼接,#是专门给sql语句传值的。$就是JDBC当中的Statement,#就是JDBC当中的PreparedStatement。$的这种方式使用时需要特别注意sql注入问题。
● 你对MyBatis的一级缓存和二级缓存有了解吗,说一下?
Mybatis对缓存提供支持,但是在没有配置的默认情况下,它只开启一级缓存,一级缓存只是相对于同一个SqlSession而言。所以在参数SQL完全一样的情况下,我们使用同一个SqlSession对象调用一个Mapper方法,往往只执行一次SQL,因为使用SqlSession第一次查询后,MyBatis会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession都会取出当前缓存的数据,而不会再次发送SQL到数据库。
MyBatis的二级缓存是Application级别的缓存,它可以提高对数据库查询的效率,以提高应用的性能。SqlSessionFactory层面上的二级缓存默认是不开启的,二级缓存的开启需要进行配置,实现二级缓存的时候,MyBatis要求返回的POJO必须是可序列化的。 也就是要求实现Serializable接口,配置方法很简单,只需要在映射XML文件配置就可以开启缓存了。
由于我们在实际的开发中目前都会使用第三方的缓存技术,例如Redis,所以MyBatis这块的二级缓存没有太多的了解。
● MyBatis一对多你是怎么实现的?
有联合查询和嵌套查询。联合查询是几个表联合查询,只查询一次,通过在resultMap里面配 置collection节点配置一对多的类就可以完成; 嵌套查询是先查一个表,根据这个表里面的结果的外键id再去另外一个表里面查询数据,也是通过配置collection,但另外一个表的查询通过select节点配置。
● MyBatis的parameterType怎么理解的?
parameterType属性用来指定参数类型,parameterType属性是专门用来给sql语句占位符#{}传值的,底层原理使用了反射机制,#{}的大括号当中需要提供实体类的属性名,底层使用属性名拼接get方法来获取属性值,将属性值传递给sql语句。
● MyBatis的resultType是怎么理解的?
resultType用来指定结果集封装的数据类型,当一个select语句查询之后得到结果集,结果集的列名需要和java实体类的属性名一致,不一致的可以使用as关键字给列起别名,拿着列名拼接set方法,通过反射机制调用set方法给结果集对象的属性赋值。
● MyBatis中resultMap用过吗,它是干什么的?
在MyBatis当中,查询结果集被封装为Java对象,可以通过resultType,也可以通过resultMap,在resultMap当中描述了数据库表的列与Java对象的属性之间的对应关系。在映射关系中,还可以通过resultMap的typeHandler设置实现查询结果值的类型转换。另外,最重要的是通过resultMap的子标签比如、等,可以实现一对一、一对多等的映射。
● MyBatis底层实现原理?
MyBatis是一个持久层框架,实现了ORM思想,可以将查询的结果集自动转换成Java对象,也可以将Java对象转换成一条数据插入到数据库表当中。
那么,查询结果集是如何自动转换成Java对象的呢?实际上这里使用了反射机制,在配置文件中假设编写了一条select语句,查询之后,列名与属性名要一一对应(不对应的可以采用给列起别名),然后每个列名前添加“set”,通过反射机制获取set方法,然后再通过反射机制的method.invoke()来调用这个set方法,给Java对象的属性赋值。这样就完成了对象的封装。
另外,Java对象是如何转换成一条记录插入到数据库的呢?假设在配置文件中编写了一条insert语句,那么这条语句需要的值从哪里来呢,在mybatis的mapper配置中有parameterType属性,该属性是专门给sql语句占位符传值的,其实这里也是使用了反射机制,其中sql语句的占位符采用#{},其中大括号当中需要提供java对象的属性名,该属性名和get进行拼接得到get方法名,然后通过反射机制获取该get方法,再通过method.invoke()来调用这个get方法,这样就可以获取到对应的属性值,然后传入了。
其实MyBatis设计最牛的地方当然是采用JDK动态代理的方式生成DAO接口的实现类了。其中DAO接口中的每一个方法名对应sql语句的id。DAO接口中的方法不允许重载,因为id是不允许重复的。以上大概就是我了解的MyBatis实现原理。
● 谈谈MyBatis和Hibernate的区别?
Hibernate属于全自动ORM映射框架,使用Hibernate查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。而Mybatis在查询关联对象或关联集合对象时,需要手动编写sql来完成,所以,称之为半自动ORM映射工具。
也正因为MyBatis的sql语句由程序员自己编写,所以sql更容易优化,这也是目前互联网公司使用MyBatis较多的重要原因。
● MyBatis中除了之外你还用过哪些标签?
还有很多其他的标签,、、、、,加上动态sql的9个标签,trim|where|set|foreach|if|choose|when|otherwise|bind等,其中为sql片段标签,通过标签引入sql片段,为不支持自增的主键生成策略标签。
● 在MyBatis当中,通常一个Mapper映射文件,都会写一个Dao接口与之对应,请问,这个Dao接口的工作原理是什么?
Dao接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Dao接口生成代理proxy对象,代理对象proxy会拦截接口方法,转而执行MappedStatement所代表的sql,然后将sql执行结果返回。
● MyBatis注解用过吗,都有哪些?
到目前为止,我们在项目中还没有使用过MyBatis的注解,因为MyBatis最主要是编写sql语句,sql语句涉及到后期优化,可能会频繁修改,所以我们一直都在使用配置文件的形式。
● Mybatis动态sql是做什么的?都有哪些动态sql?能简述一下动态sql的执行原理吗?
Mybatis动态sql可以让我们在Xml映射文件内以标签的形式编写动态sql,完成逻辑判断和动态拼接sql的功能,Mybatis提供了9种动态sql标签trim|where|set|foreach|if|choose|when|otherwise|bind。其执行原理为,使用OGNL从sql参数对象中计算表达式的值,根据表达式的值动态拼接sql,以此来完成动态sql的功能。
● Mybatis是如何将sql执行结果封装为目标对象并返回的?
第一种是使用resultMap,逐一定义列名和对象属性名之间的映射关系。 第二种是使用resultType,使用sql列的别名功能,将列别名书写为对象属性名,比如T_NAME AS NAME,对象属性名一般是name,小写,但是列名不区分大小写,Mybatis会忽略列名大小写,智能找到与之对应对象属性名,你甚至可以写成T_NAME AS NaMe,Mybatis一样可以正常工作。 有了列名与属性名的映射关系后,Mybatis通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。
● MyBatis接口Mapper中的方法能够重载吗?
不能。MyBatis使用package+Mapper+method全限名作为key,去xml内寻找唯一sql来执行的。类似:key=x.y.UserMapper.getUserById,那么,重载方法时将导致矛盾。对于Mapper接口,Mybatis禁止方法重载(overload)。
● 在MyBatis当中,给sql语句传值,你知道哪几种方式?
通过POJO(Javabean)可以传值,但要求#{}的大括号当中提供POJO的属性名。如果没有合适的POJO,可以使用Map集合进行传值,但要求#{}的大括号当中提供Map集合的key。如果DAO接口的方法参数有多个,并且数量不多,而且每个都是简单类型,也可以通过#{arg0}、#{arg1}的方式传参。
● 谈谈你对Spring框架的理解?
● Spring IoC的理解以及实现原理?
● Spring AOP的理解以及实现原理?
● Spring是如何进行事务管理的?
事务就是对一系列的数据库操作(比如插入多条数据)进行统一的提交或回滚操作,如果插入成功,那么一起成功,如果中间有一条出现异常,那么回滚之前的所有操作。这样可以防止出现脏数据,防止数据库数据出现问题。开发中为了避免这种情况一般都会进行事务管理。 Spring的声明式事务通常是指在配置文件中对事务进行配置声明,其中包括了很多声明属性,它是通过Spring Proxy帮你做代理,自己不用额外的写代码,只要在Spring配置文件中声明即可;通常用在数据库的操作里面; 编程式事务就是指通过硬编码的方式做事务处理,这种处理方式需要写代码,事务中的逻辑可以自己定制;可以是数据库的东东,也可以是其他的操作。 Spring中也有自己的事务管理机制,一般是使用TransactionMananger进行管理,可以通过Spring的注入来使用此功能。
● Spring事务的传播特性有了解吗?
● Spring常用注解说几个?
● @Autowired 与@Resource的区别?
● IoC和DI的关系?
● 解释Spring支持的几种bean的作用域,怎么配置?
● 依赖注入的实现方式包括哪些?
● 说一下Spring Bean的生命周期?
● 什么是Spring的自动装配机制,包括哪些?
● 在Spring中怎么启用注解? 使用 配置。
● Spring支持的事务管理类型有哪些?
● Spring AOP中什么是切面?
● Spring AOP中什么是关注点?
●Spring AOP中什么是通知,包括哪些?
● Spring AOP中什么是切入点?
● Spring AOP中什么是连接点?
● Spring AOP中什么是目标对象?
● Spring AOP中什么是代理对象?
● Spring AOP中什么是织入?
● 你在实际开发中使用Spring AOP干什么了?
● Spring框架中的单例bean是否是线程安全的?
● Spring框架中BeanFactory和ApplicationContext有什么区别?
● 说一下SpringMVC的执行流程?
(1)用户发送请求至前端控制器DispatcherServlet;
(2) DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handle;
(3)处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet;
(4)DispatcherServlet 调用 HandlerAdapter处理器适配器;
(5)HandlerAdapter 经过适配调用 具体处理器(Handler,也叫后端控制器);
(6)Handler执行完成返回ModelAndView;
(7)HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet;
(8)DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析;
(9)ViewResolver解析后返回具体View;
(10)DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
(11)DispatcherServlet响应用户。
● 说一下SpringMVC框架的理解?
Spring MVC是一个基于Java实现了MVC架构模式的请求驱动类型的轻量级Web框架,通过把Model,View,Controller分离,将web层职能分工(解耦合),把复杂的web应用分成逻辑清晰的几部分,简化开发,减少出错,方便组内开发人员之间的配合。
● SpringMVC常用注解?
@RequestMapping:用于处理请求地址映射,可以作用于类和方法上。
@RequestParam:用于获取传入参数的值 @RequestBody:将客户端请求过来的json转成java对象 @RestController:@Controller+ @ResponseBody @GetMapping@DeleteMapping@PostMapping@PutMapping
@PathViriable:用于定义路径参数值 @ResponseBody:作用于方法上,可以将整个返回结果以某种格式返回,如json或xml格式。
@ModelAttribute:用于把参数保存到model中,可以注解方法或参数,注解在方法上的时候,该方法将在处理器方法执行之前执行,然后把返回的对象存放在 session(前提时要有@SessionAttributes注解) 或模型属性中,@ModelAttribute(“attributeName”) 在标记方法的时候指定,若未指定,则使用返回类型的类名称(首字母小写)作为属性名称。
● SpringMVC的控制器是不是单例,如果是,有什么问题,怎么解决?
是单例,所以在多线程访问的时候有线程安全问题,不要用同步,会影响性能的,解决方案是在控制器里面不能写字段。
● 谈谈你对RESTful的理解?
一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。 REST 指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是 RESTful。 REST被翻译为“表现层状态转换”,具体来说,就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源。使用REST编程风格要求URL中不允许出现动词。
● 如何解决POST请求中文乱码问题,GET的又如何处理呢?
POST乱码:web.xml文件中添加以下配置 CharacterEncodingFilter org.springframework.web.filter.CharacterEncodingFilter encoding utf-8 CharacterEncodingFilter /* GET乱码,修改Tomcat服务器server.xml文件:
● 你进行过压测吗,怎么进行的?
●Redis你在项目中哪里使用了,用来解决什么问题?
●Redis支持哪些数据类型?
● 什么是Redis持久化?Redis有哪几种持久化方式?优缺点是什么?
● 什么是缓存穿透,如何避免?什么是缓存雪崩,如何避免?
● 数据库和Redis缓存数据一致性问题,你是怎么解决的?
● Redis有哪几种数据淘汰策略?
● Redis有哪些适合的场景?
(1)会话缓存(Session Cache)最常用的一种使用Redis的情景是会话缓存(session cache)。 用Redis缓存会话比其他存储(如Memcached)的优势在于:Redis提供持久化。当维护一个不是严格要求一致性的缓存时,如果用户的购物车信息全部丢失,大部分人都会不高兴的,现在,他们还会这样吗?幸运的是,随着 Redis 这些年的改进,很容易找到怎么恰当的使用Redis来缓存会话的文档。甚至广为人知的商业平台Magento也提供Redis的插件。
(2)全页缓存(FPC)除基本的会话token之外,Redis还提供很简便的FPC平台。 回到一致性问题,即使重启了Redis实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降,这是一个极大改进,类似PHP本地FPC。再次以Magento为例,Magento提供一个插件来使用Redis作为全页缓存后端。此外,对WordPress的用户来说,Pantheon有一个非常好的插件 wp-redis,这个插件能帮助你以最快速度加载你曾浏览过的页面。
(3)队列Reids在内存存储引擎领域的一大优点是提供 list 和 set 操作,这使得Redis能作为一个很好的消息队列平台来使用。 Redis作为队列使用的操作,就类似于本地程序语言(如Python)对 list 的 push/pop 操作。如果你快速的在Google中搜索“Redis queues”,你马上就能找到大量的开源项目,这些项目的目的就是利用Redis创建非常好的后端工具,以满足各种队列需求。例如,Celery有一个后台就是使用Redis作为broker,你可以从这里去查看。
(4)排行榜/计数器Redis在内存中对数字进行递增或递减的操作实现的非常好。 集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操作的时候变的非常简单,Redis只是正好提供了这两种数据结构。所以,我们要从排序集合中获取到排名最靠前的10个用户–我们称之为“user_scores”,我们只需要像下面一样执行即可:当然,这是假定你是根据你用户的分数做递增的排序。如果你想返回用户及用户的分数,你需要这样执行:ZRANGE user_scores 0 10 WITHSCORESAgora Games就是一个很好的例子,用Ruby实现的,它的排行榜就是使用Redis来存储数据的,你可以在这里看到。
(5)发布/订阅最后(但肯定不是最不重要的)是Redis的发布/订阅功能。 发布/订阅的使用场景确实非常多。我已看见人们在社交网络连接中使用,还可作为基于发布/订阅的脚本触发器,甚至用Redis的发布/订阅功能来建立聊天系统!
● 可以说一下你对Dubbo的理解吗,什么是Dubbo?
Dubbo是阿里巴巴开源的基于 Java 的高性能 RPC 分布式服务框架,现已成为 Apache 基金会孵化项目。 因为是阿里开源项目,国内很多互联网公司都在用,已经经过很多线上考验。内部使用了 Netty、Zookeeper,保证了高性能高可用性。 使用 Dubbo 可以将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,可用于提高业务复用灵活扩展,使前端应用能更快速的响应多变的市场需求。 最重要的一点是,分布式架构可以承受更大规模的并发流量。比如某个服务并发量很大的话,可以针对此服务部署多台服务器提高性能。
● Dubbo的实现原理?
● 你对zookeeper是怎么理解的,为什么要用它?
● 据你了解,zookeeper都能干什么?
● Dubbo支持负载均衡吗,有哪些策略?
● Dubbo超时重试之后导致的数据重复怎么解决?
对于核心的服务中心,去除dubbo超时重试机制,并重新评估设置超时时间。业务处理代码必须放在服务端,客户端只做参数验证和服务调用,不涉及业务流程处理。
● RPC是什么,你知道哪些RPC框架?