• 深入总结MyBatis


    什么是MyBatis?

           myBatis是一款优秀的持久层框架,它对JDBC进行了封装,简化了大量的配置。将SQL中的大量SQL提取出来,将SQL与程序代码进行分离,将SQL写入XML配置文件中,实现了SQL的灵活配置。可以在不修改代码的条件下,直接在配置文件中修改SQL。

    MyBatis的优点是什么?

    • 与JDBC相比,减少了大量的代码量
    • 简单易学的开源持久层框架(与hibernate)
    • MyBatis相当灵活,SQL写入XML文件中,实现SQL与程序代码相分离,实现了SQL的灵活配置,降低了耦合度,便于统一管理和重用。
    • 提供XML文件的配置,支持动态SQL的编写。
    • 提供映射标签,支持对象与数据库的ORM关系映射

    #{}与${}区别是什么?

    • #{}采用的是预编译的方式,而${}是字符串替换
    • Mybatis在处理#{}替换为?号,调用PrepareStatement的set方法来赋值,而${}时,就是将替换为变量的值。
    • 使用#{}可以有效的防止SQL注入,提高系统的安全性。而使用${}使用的话,需要进行变量的过滤,以防止SQL注入攻击。

     MyBatis是如何做到防止SQL注入的?

    因为SQL语句是我们自己手动编写的,这时需要防止SQL注入。

    这时我们使用ParameType表示输入参数类型,使用#{}来表示输入参数在SQL中的拼接部分,因为MyBatis启用了预编译的功能,在sql执行前,会将SQL发送给数据库进行编译,然后执行时,直接使用编译好的SQL语句,替换占位符“?”。

    SQL注入只对编译过程起作用,可以很好的避免SQL注入的问题。

    MyBatis与Hibernate的区别 

    • Mybatis与Hibernate的区别在于,Mybatis是半个ORM框架,需要自己编写SQL语句。
    • MyBatis直接编写原生态的SQL,可以严格控制SQL执行性能灵活度高,适用于对关系模式要求不高,需要变化频繁的软件。如果软件关联多个数据库,需要编写大量的SQL语句,需自定义多套SQL,工作量大。
    • 而Hibernate对象/映射能力强,不需要编写SQL,数据库的无关系较好,适用于关系模式要求较高的软件,可以减少代码量,提高效率。

    为什么说 Mybatis 是半自动 ORM 映射工具?它与全自动的区别在哪里?

            Hibernate是全自动额的ORM映射工具,使用它进行对关联对象或者关联对象集合查询时,可以根据对象的关联方式直接获得,而MyBatis则需要编写SQL语句来实现对关联对象或者关联对象集合的查询。

    MyBatis的一级、二级缓存

    一级缓存:它是默认存在的,基于 PerpetualCache 的 HashMap 本地缓存,是Sqlsession 级别的,在同一个sqlsession中,执行两次相同的sql语句,会将第一次查询的数据缓存到sqlsession对象中,第二次查询时,可以不用访问数据库,直接从一级缓存中获取即可。

    一级缓存失效:

    (1)sqlsession 关闭

    sqlSession.close();

    (2) 主动清除一级缓存数据。

    sqlSession.clearCache();

    (3)在期间执行增,删,改提交事务会清除一级缓存中的数据,但该对象可以继续使用

    二级缓存:如果开启二级缓存,在第一次查询到的数据后,关闭sqlsession时,会将数据存入到二级缓存中,之后另一个sqlsession查询时,可以从二级缓存中获取数据。

    使用二级缓存属性类需要实现 Serializable 序列化接口(可用来保存对象的状态)

           对于缓存数据更新机制,当某一个作用域(一级缓存 Session/二级缓存Namespaces)的进行了 I/U/D 操作后,默认该作用域下所有 select 中的缓存将被 clear。

    什么是MyBatis接口绑定?有哪些实现方式?

    接口绑定:就是在MyBatis中任意定义接口,然后把接口里面的方法和SQL语句绑定,可以灵活的选择和配置。

    两种实现方式:

    1. 注解绑定,在接口方法上加入@Select、@Update等注解,里面包含SQL语句来绑定
    2. 在XML文件中写入SQL绑定。在XML文件中的namespace必须为接口定义全路径名。

    sql简单实用这几绑定,复杂的使用XML绑定。

    MyBatis实现一对一有几种方式,怎么操作的?

    联合查询和嵌套查询

    联合查询:几张表的联合查询,只查询一次,通过resultMap里面的association节点来进行配置一对一完成查询

    嵌套查询:先查询一张表,得到外键id,使用id对另一张表进行查询数据,使用association配置,另一张也是通过select进行配置。

    MyBatis实现一对多有几种方式,怎么操作的?

    联合查询和嵌套查询

    联合查询:几张表的联合查询,只查询一次,通过resultMap里面的collection节点来进行配置一对一完成查询

    嵌套查询:先查询一张表,得到外键id,使用id对另一张表进行查询数据,使用collection配置,另一张也是通过select进行配置。

    在 mapper 中如何传递多个参数?

    第一种:DAO 层的函数

    public UserselectUser(String name,String area);

    对应的 xml,#{0}代表接收的是 dao 层中的第一个参数,#{1}代表 dao 层中第二参数,更多参数一致往后加即可。

    1. <select id="selectUser"resultMap="BaseResultMap">
    2. select * fromuser_user_t whereuser_name = #{0}
    3. anduser_area=#{1}
    4. select>

    第二种: 使用 @param 注解:

    1. public interface usermapper {
    2.     user selectuser(@param(“username”) string
    3.     username,@param(“hashedpassword”) string hashedpassword);
    4. }

    然后,就可以在 xml 像下面这样使用(推荐封装为一个 map,作为单个参数传递给mapper):

    1. <select id=”selectuser” resulttype=”user”>
    2. select id, username, hashedpassword
    3. from some_table
    4. where username = #{username}
    5. and hashedpassword = #{hashedpassword}
    6. select>

    第三种:多个参数封装成 map

    1. try {
    2.     //映射文件的命名空间.SQL 片段的 ID,就可以调用对应的映射文件中的
    3.     SQL
    4.     //由于我们的参数超过了两个,而方法中只有一个 Object 参数收集,因此
    5.     我们使用 Map 集合来装载我们的参数
    6.     Map < String, Object > map = new HashMap();
    7.     map.put("start", start);
    8.     map.put("end", end);
    9.     return sqlSession.selectList("StudentID.pagination", map);
    10. }
    11. catch (Exception e) {
    12.     e.printStackTrace();
    13.     sqlSession.rollback();
    14.     throw e;
    15. }
    16. finally {
    17.     MybatisUtil.closeSqlSession();
    18. }

    当实体类中的属性名和表中的字段名不一样 ,怎么办 ?

    1.在sql 语句中定义别名,让字段名的别名和实体类的属性名一致。

    1. <select id=”selectorder” parametertype=”int” resultetype=
    2. me.gacl.domain.order”>
    3. select order_id id, order_no orderno ,order_price price form
    4. orders where order_id=#{id};
    5. select>

    2. 通过来映射字段名和实体类属性名的一一对应的关系。

    1. <select id="getOrder" parameterType="int"
    2. resultMap="orderresultmap">
    3. select * from orders where order_id=#{id}
    4. select>
    5. <resultMap type=”me.gacl.domain.order” id=”orderresultmap”>
    6. <id property=”id” column=”order_id”>
    7. 为数据表中的属性–>
    8. <result property = “orderno” column =”order_no”/>
    9. <result property=”price” column=”order_price” />
    10. reslutMap>

    通常一个 XML 映射文件,都会写一个 Dao 接口与之对应,请问,这个 Dao 接口的工作原理是什么?Dao 接口里的方法,参数不同时,方法能重载吗?

    Dao接口在MyBatis框架中是Mapper接口。Dao接口在xml中映射文件中的namespace的值,接口的方法名,就是映射文件中Mapper的Statement的id值;接口方法内的参数,就是传递给sql的参数。

    Mapper 接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为 key 值,可唯一定位一个 MapperStatement。在 Mybatis 中,每一个