Java面试题 - 03

作者: 贪挽懒月 | 来源:发表于2018-11-18 15:15 被阅读0次

    前言:

    再接着Java面试题 - 02,说说剩下的内容。


    欢迎大家关注我的公众号 javawebkf,目前正在慢慢地将简书文章搬到公众号,以后简书和公众号文章将同步更新,且简书上的付费文章在公众号上将免费。


    三、框架篇:

    (三)、mybatis

    1. JDBC编程有什么不足?mybatis是如何解决的?
    答:主要有以下几个方面:

    • JDBC中数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能
      mybatis解决:在mybatis配置文件中配置数据连接池,使用连接池管理数据库连接。

    • Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。
      mybatis解决:将Sql语句配置在mapper.xml文件中,与java代码分离。

    • 向 sql 语句传参数麻烦,因为 sql 语句的 where 条件不一定,可能多也可能少,占位符需要和参数一一对应。
      mybatis解决: Mybatis自动将java对象映射至sql语句。

    • 对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历。
      mybatis解决:Mybatis自动将sql执行结果映射至java对象。

    2. mybatis编程步骤是怎样的?
    答:步骤如下:

    • 创建SqlSessionFactory
    • 通过SqlSessionFactory创建 SqlSession
    • 通过sqlsession执行数据库操作
    • 调用session.commit()提交事务
    • 调用session.close()关闭会话

    3. Mybatis中#和$的区别?
    答: 使用${参数}就是单纯的字符串拼接,拼接完成后才会对SQL进行编译、执行,所以性能较低;#{参数名}在SQL中相当于一个参数占位符“?”,用来补全预编译语句,所有这种方式可以防止SQL注入,它补全预编译语句时,会在此参数值两端加了单引号。但是有些地方必须要用$,比如参数是表名的时候:${表名},因为如果使用#,sql语句就会变成 '表名',会加上单引号,这样就找不到该表。总之,能用#就不要用$。

    4. 使用MyBatis的mapper接口调用时有哪些要求?
    答:有以下规则:

    • Mapper接口方法名和mapper.xml中对应的sql的id相同 ;
    • Mapper接口方法的输入参数类型和mapper.xml中对应的sql 的parameterType的类型相同 ;
    • Mapper接口方法的输出参数类型和mapper.xml中对应的sql的resultType的类型相同 ;
    • Mapper.xml文件中的namespace即是mapper接口的类路径。

    5. 谈谈mybatis中的一级缓存和二级缓存。
    答:

    • 一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空。
    • 二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),即对该namespance对应的配置文件中所有的select操作结果都缓存,这样不同线程之间就可以共用二级缓存。并且可自定义存储源,如 Ehcache。启动二级缓存:在mapper配置文件中加上:<cache />。

    6. 在进行插入操作时如何回传ID?
    答:在insert标签中配置如下属性即可:

    <insert id="insert" parameterType="com.test.User" keyProperty="userId" useGeneratedKeys="true" > 
       ......
    </insert>
    

    用keyProperty指定Id属性,把useGeneratedKeys设置为true即可。

    7. mapper接口工作原理是什么?
    答:mapper接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为mapper接口生成代理对象,代理对象会拦截接口方法,转而执行对应的sql,然后将sql执行结果返回。

    8. mapper接口里的方法可以重载吗?为什么?
    答:不能重载。对应的xml映射文件是根据方法名将方法与sql语句绑定的,如果重载,将无法区分绑定哪个方法。

    9. 你了解mybatis的动态SQL吗?
    答:动态SQL可以完成逻辑判断和动态拼接sql的功能。在mybatis的xml映射文件中,我们可以标签的形式编写动态sql。常用的动态sql标签有<if>、<where>、<set>等。

    10. Mybatis是否支持延迟加载?如果支持,它的实现原理是什么?
    答:Mybatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。在Mybatis配置文件中,可以配置lazyLoadingEnabled=true来启用延迟加载。它的原理是使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用a.getB().getName(),拦截器invoke()方法发现a.getB()是null值,那么就会单独发送事先保存好的查询B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。

    (四)、hibernate

    1. 简单的说一下hibernate的开发流程。
    答:步骤如下:

    • 加载 hibernate 的配置文件,读取其他配置文件(jdbc.properties、表与对象关系映射文件);
    • 创建 SessionFactory 会话工厂;
    • 打开 session 获取连接,构造 session 对象(一次会话维持一个数据连接,也是一级缓存)
    • 开启事务;
    • 使用session进行操作 ;
    • 提交事务;
    • 关闭session;
    • 关闭SessionFactory 。

    2. 说说hibernate中对象的三种状态。
    答:hibernate中,对象有以下3种状态:

    • 临时态:直接new出来的对象,不处于session的管理,数据库中没有对象的记录;调用save方法后就变成持久态。
    • 持久态:当调用session的save/saveOrUpdate/get/load/list等方法的时候,对象就是持久化状态。处于session的管理,数据库中有对应的记录;调用delete方法后变成临时态,调用session.close()后就变成了游离态。
    • 游离态:Session关闭后,对象的状态就是游离态。不处于session的管理,数据库中有对应的记录;调用update方法后又变成持久态。

    3. 你知道hibernate的缓存吗?
    答:使用缓存的目的就是减少对数据库的访问次数,以提高hibernate的执行效率。hibernate有一级缓存和二级缓存之分:

    • 一级缓存:也叫做session的缓存,它可以在session范围内减少数据库的访问次数,只在session范围有效,Session关闭,一级缓存失效,不同的session不会共享缓存数据。当调用session的 save/saveOrUpdate/get/load/list/iterator 方法的时候,都会把对象放入session的缓存中。 Session的缓存由hibernate维护, 用户不能操作缓存内容; 如果想操作缓存内容,必须通过hibernate提供的evit/clear方法操作。

    • 二级缓存:Hibernate提供了基于应用程序级别的缓存, 可以跨多个session,即不同的session都可以访问缓存数据。 这个缓存也叫二级缓存。Hibernate提供的二级缓存有默认的实现,且是一种可插配的缓存框架!如果用户想用二级缓存,只需要在hibernate.cfg.xml中配置即可,不想用,直接移除配置即可。如果用户觉得hibernate提供的缓存框架不好用,可以换其他的缓存框架或自己实现缓存框架都可以。

    4. hibernate有几种查询方式?
    答:hibernate有3种查询方式:

    • HQL查询:面向对象的查询语言,提供了丰富灵活的查询方式。例子:
    String hql = "select userName from User"; // userName是实体类属性名而非表的字段名,User是实体类名
    Query query = session.createQuery(hql);
    List<Object> nameList = query.list();
    
    • QBC(Query By Criteria)查询:Criteria对象提供了一种面向对象的方式查询数据库。Criteria对象需要使用Session对象来获得。例子:
    Criteria c = session.createCriteria(User.class);
    c.add(Restrictions.eq("userName", "James"));
    List<User> userList = c.list();
    
    • 原生SQL查询:就是使用原生的SQL语句进行查询。例子:
    String sql = "select id,username,userpwd from t_user";
    List list = session.createSQLQuery(sql).list();
    

    5. hibernate的ORM思想你了解多少?
    答:ORM 指的是对象关系映射(Object RelationShip Mapping ),指的就是实体类对象和数据库中的表关系进行一一对应,实现通过操作实体类对象来更改数据库里边的数据信息。这就是对象关系映射。hibernate框架也是一个orm框架,主要是通过主配置文件和实体类对应的映射配置文件来实现对象关系映射。

    6. 你知道hibernate的懒加载吗?
    答:通过设置lazy属性开启懒加载(hibernate3之后默认开启)。当Hibernate在查询数据的时候,数据并没有存在与内存中,当程序真正对数据的操作时,对象才存在与内存中,就实现了延迟加载,节省了服务器的内存开销,从而提高了服务器的性能。比如使用hibernate进行查询,可以使用get方法,也可以使用load方法,get方法不支持懒加载,而load方法支持。get方法会先查一级缓存,再查二级缓存,然后查数据库,如果没有找到会返回null。load方法会先查一级缓存,如果没有找到,就创建代理对象,等需要的时候去查询二级缓存和数据库。也就是说,使用load方法的时候,并不会立刻去数据库查找,等你真的要用到该对象的时候,才会去数据库查找,这就是懒加载。

    7. hibernate和mybatis有何异同?
    答:异同如下:
    (1).相同点:

    • Hibernate与MyBatis都是由XML配置文件生成SessionFactory,然后由SessionFactory 生成 Session,最后由 Session 来开启执行事务和 SQL 语句。其中两者的SessionFactory,Session的生命周期都是差不多的。
    • Hibernate和MyBatis都支持JDBC和JTA事务处理。

    (2).不同点:

    • hibernate是全自动,而mybatis是半自动。hibernate完全可以通过对象关系模型实现对数据库的操作,会自动生成sql。而mybatis仅有基本的字段映射,对数据的操作还需要自己编写sql来实现。

    • hibernate数据库移植性远大于mybatis。因为hibernate不需要自己编写sql语句,所有与数据库解耦;而mybatis由于需要手写sql,因此与数据库的耦合性直接取决于程序员写sql的方法,如果sql不具通用性,用了很多数据库特性的sql语句的话,移植性也会随之降低很多,成本很高。

    • hibernate拥有完整的日志系统,mybatis则欠缺一些。hibernate日志系统非常健全,涉及广泛,而mybatis则除了基本记录功能外,功能薄弱很多。

    • sql优化上,mybatis要比hibernate方便很多。由于mybatis的sql都是写在xml里,因此优化sql比hibernate方便很多。而hibernate的sql很多都是自动生成的,无法直接维护sql。

    总的来说,mybatis小巧灵活,易于使用,而hibernate学习成本相对较高,数据库移植性好。

    8. 谈谈Hibernate中inverse的作用。
    答:inverse属性默认是false,就是说双方都维护关联关系。 比如Student和Teacher是多对多关系,用一个中间表TeacherStudent维护。如果Student这边inverse=”true”, 那么关系就由Teacher维护,就是说当插入Student时,不会操作TeacherStudent表。只有Teacher插入或删除时才会触发对中间表的操作。所以两边都inverse=”true”是不对的,会导致任何操作都不触发对中间表的影响;当两边都inverse=”false”或默认时,会导致在中间表中插入两次关系。

    9. Hibernate有哪些核心接口?
    答:有如下核心接口:

    • Configuration 接口:配置Hibernate,根据其启动hibernate,创建SessionFactory 对象;
    • SessionFactory 接口:初始化Hibernate,充当数据存储源的代理,创建session 对象,sessionFactory 是线程安全的,意味着它的同一个实例多个线程共享;
    • Session 接口:负责保存、更新、删除、加载和查询对象,是线程不安全的, 避免多个线程共享同一个session;
    • Transaction 接口:管理事务;
    • Query 和Criteria 接口:执行数据库的查询。

    (五)、Redis

    1. 什么是redis?
    答:redis是使用C语言编写的典型的NoSQL数据库,它是一个key-value存储系统,数据存储在内存中,所以存取速度非常快。

    2. 为什么redis要把数据放到内存中?
    答:Redis为了达到最快的读写速度将数据都读到内存中,并定期将数据写入磁盘。如果不将数据放在磁盘中,会严重影响 redis 的性能。

    3. redis支持哪些数据类型?
    答:redis有5种基本数据类型,分别是String(字符串)、Hash(字典)、List(列表)、Set(集合)、Zset(有序集合)。

    4. 说说redis的优缺点。
    答:优缺点如下:
    (1). 优点:

    • 由于是基于内存的,所以性能极高。
    • 支持丰富的数据类型。
    • Redis 的所有操作都是原子性的。

    (2). 缺点:

    • 由于是内存数据库,所以单台机器存储的数据量,跟机器本身的内存大小。
    • 如果进行完整重同步,由于需要生成 rdb 文件并进行传输,会占用主机的 CPU,消耗带宽。

    相关文章

      网友评论

        本文标题:Java面试题 - 03

        本文链接:https://www.haomeiwen.com/subject/lhlyfqtx.html