六、MyBatis
1.1 什么是Mybatis
Mybatis是一个半ORM框架,它简化了JDBC操作,让开发者只需关注SQL语句本身,而无需处理底层连接、语句创建等细节。Mybatis支持XML或注解配置,可灵活映射POJO与数据库记录,自动生成并执行SQL,最终将结果映射回Java对象。这大大减少了JDBC代码量,提高了开发效率。
1.2 Mybatis的优点
- 灵活性与解耦:基于SQL编程,灵活度高,不影响应用或数据库设计。SQL与代码解耦,便于管理。
- 减少代码量:与JDBC相比,代码量大幅减少,无需处理连接等冗余代码。
- 数据库兼容性:兼容各种数据库,因底层使用JDBC。
- 与Spring集成:与Spring框架能很好地整合。
- ORM支持:提供映射标签,支持对象与数据库的字段关系映射。
1.3 MyBatis框架的缺点
- SQL编写工作量:当字段和关联表较多时,SQL编写工作量大,对开发人员有一定要求。
- 数据库移植性:SQL语句依赖数据库,移植性差。
1.4 MyBatis框架适用场合
- 需要灵活DAO层解决方案:Mybatis专注于SQL,提供了足够的灵活性。
- 性能要求高或需求变化多:如互联网项目,Mybatis是不错的选择。
1.5 Mybatis组件的生命周期
- SqlSessionFactoryBuilder
作用是生成SqlSessionFactory,在构建完毕后,它的生命周期就结束了。
- SqlSessionFactory
创建SqlSession,SqlSessionFactory是一个重量级的对象,不应该频繁地创建和销毁。它通常会在应用的整个生命周期中存在,并且应该是线程安全的。
- SqlSession
和数据库的一次会话,类似于JDBC中的Connection对象。在一个请求或事务处理过程中,你可能会打开一个SqlSession,处理完所有数据库操作后关闭它。这有助于管理资源,并避免潜在的资源泄露。
4.Mapper
Mapper是MyBatis中的一个接口,用于映射SQL语句到方法调用。当你通过SqlSession获取Mapper的代理实现时,这个代理对象的生命周期与SqlSession相同。
1.6 MyBatis与Hibernate有哪些不同
ORM程度:MyBatis不是一个完全的ORM框架,它需要程序员自己编写SQL语句,因此具有更高的灵活性。而Hibernate则是一个强大的对象/关系映射框架,能够自动处理大部分的数据访问逻辑。
SQL控制:MyBatis允许直接编写原生态的SQL,这使得开发者能够严格控制SQL的执行性能,特别适合需求变化频繁、对关系数据模型要求不高的软件开发。然而,这也导致MyBatis无法实现完全的数据库无关性,需要为不同的数据库编写不同的SQL映射文件。
适用场景:Hibernate由于其强大的对象/关系映射能力和良好的数据库无关性,更适合用于关系模型要求较高的软件开发,能够显著减少代码量,提高开发效率。而MyBatis则更适合那些需要高度灵活性和对SQL执行性能有严格要求的应用场景。
1.7 预编译的作用
预编译主要对SQL的执行进行优化。经过预编译的SQL多数情况下可以直接执行,数据库服务器无需再次编译,从而提升了性能。此外,预编译语句对象可以重复利用,对于相同的SQL,可以直接使用缓存的预编译对象,进一步提高了效率。
更为关键的是,预编译有助于防止SQL注入攻击。由于预编译后的参数不会再进行SQL编译,系统默认其为普通参数而非SQL语句,从而增强了系统的安全性。
1.8 MyBatis中${}和#{}的区别
#{}能够防止SQL注入,因为底层使用PreparedStatement对象,预编译,性能较高
${}不能防止SQL注入,因为底层使用Statement对象,不会预编译而是拼接字符串,性能较低
能使用#{}时尽量使用#{},如果需要动态传入表名或者字段名需要用 比如,像 O R D E R B Y 时只能使用 {}比如,像 ORDER BY 时只能使用 比如,像ORDERBY时只能使用{}
1.9 MyBatis一级缓存和二级缓存的区别
作用域:一级缓存是SqlSession级别的,仅在当前SqlSession中有效;而二级缓存是mapper级别的,整个应用共享,可以跨线程使用。
开启方式:一级缓存默认开启,无需额外配置;而二级缓存默认不开启,需要手动配置。
缓存地址:一级缓存主要存储在SqlSession内部;二级缓存则通常存储在应用的外部,如内存或硬盘。
存储对象:一级缓存存储的是具体的查询结果集;二级缓存存储的则是mapper映射文件对应的namespace下的数据对象。
2.0 xml中结果类型映射方式
第 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 type=”me.gacl.domain.order” id=”orderMap”>
<!–用id属性来映射主键字段–>
<id property=”id” column=”order_id”>
<!–用result属性来映射非主键字段,property为实体类属性名,column 为数据表中的属性–>
<result property = “orderno” column =”order_no”/>
<result property=”price” column=”order_price” />
</reslutMap>
<select id="getOrder" parameterType="int" resultMap="orderMap">
select * from orders where order_id=#{id}
</select>