深入总结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 层中第二参数,更多参数一致往后加即可。

<select id="selectUser"resultMap="BaseResultMap">
select * fromuser_user_t whereuser_name = #{0}
anduser_area=#{1}
</select>

第二种: 使用 @param 注解:

public interface usermapper {
    user selectuser(@param(“username”) string
    username,@param(“hashedpassword”) string hashedpassword);
}

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

<select id=”selectuser” resulttype=”user”>
select id, username, hashedpassword
from some_table
where username = #{username}
and hashedpassword = #{hashedpassword}
</select>

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

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

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

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

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

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

<select id="getOrder" parameterType="int"
resultMap="orderresultmap">
select * from orders where order_id=#{id}
</select>
<resultMap type=”me.gacl.domain.order” id=”orderresultmap”>
<!–用 id 属性来映射主键字段–>
<id property=”id” column=”order_id”>
<!–用 result 属性来映射非主键字段,property 为实体类属性名,column
为数据表中的属性–>
<result property = “orderno” column =”order_no”/>
<result property=”price” column=”order_price” />
</reslutMap>

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

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

Mapper 接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为 key 值,可唯一定位一个 MapperStatement。在 Mybatis 中,每一个<select>、<insert>、<update>、<delete>标签,都会被解析为一个MapperStatement 对象。

Mapper 接口里的方法,是不能重载的,因为是使用 全限名+方法名 的保存和寻找策略。Mapper 接口的工作原理是 JDK 动态代理,Mybatis 运行时会使用 JDK动态代理为 Mapper 接口生成代理对象 proxy,代理对象会拦截接口方法,转而执行 MapperStatement 所代表的 sql,然后将 sql 执行结果返回。

Mybatis 是如何将 sql 执行结果封装为目标对象并返回的?都有哪些映射形式?

1. 使用<resultMap>标签,对数据库的表中的列名与属性名进行对应映射

2. 使用 sql 的别名功能,将列的别名书写为对象属性名。

Mybatis 是否支持延迟加载?如果支持,它的实现原理是什么?

     Mybatis 仅支持 association 关联对象和 collection 关联集合对象的延迟加载,association 指的就是一对一,collection 指的就是一对多查询。在 Mybatis配置文件中,可以配置是否启用延迟加载 lazyLoadingEnabled=true|false。

   原理:使用cjlib代理的方式为目标对象创建代理对象,当调用目标方法时,进入拦截器的invoke()方法。

例如:

1、调用 a.getB().getName()

2、进入拦截器invoke()发现a.getB()是null值

3、发送事先保存好的查询关联B对象的sql

4、获取B,然后调用a.setB(b),得到B的值

5、完成 a.getB().getName()方法的调用

使用MyBatis的Mapper接口调用时有哪些要求?

  • Mapper接口方法名和mapper.xml中定义的每个sql的id相同
  • Mapper接口方法的输入类型参数和Mapper,xml中定义的每个sql的parameterType的类型相同
  • 输入参数类型和Mapper.xml中定义的每个sql的resultType的类型相同,namespace即是mapper接口的类路径

Mybatis是如何做到SQL预编译的呢?

        在框架底层,是JDBC中的PreparedStement类在起作用,PreparedStatement是Statement的子类,它的对象包含了编译好的SQL语句,这种可以提高安全性,而且在多次执行同一个SQL时,能够提高效率。(SQL已编译好,再次执行时无需再编译

简述 Mybatis 的插件运行原理,以及如何编写一个插件。

       Mybatis 仅可以编写针对 ParameterHandler、ResultSetHandler、StatementHandler、Executor 这 4 种接口的插件,Mybatis 使用 JDK 的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这 4 种接口对象的方法时,就会进入拦截方法,具体就是 InvocationHandler 的 invoke()方法,当然,只会拦截那些你指定需要拦截的方法。

   编写插件:实现 Mybatis 的 Interceptor 接口并复写 intercept()方法,然后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可,最后再配置文件中配置插件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值