前言
本篇文章我主要分享几个我认为MyBtis比较重要的点,亦或是MyBatis在面试中高频的几个问题的分析,好~
废话不多说,我们直接开始干货!!!
MyBatis框架
一、基础概述
1.概述:
学过MyBatis的人都知道,MyBatis可以说是一种增强版的JDBC,既然和JDBC有关,那么MyBatis的作用想必大家也能够知道,自然而然离不开数据库
MyBatis是一种主流的ORM框架,之前叫做iBatis,后来更名为MyBatis,实现数据持久化的框架。
2.优点:
既然是JDBC的增强版,我们在学习JDBC的时候,可以知道JDBC的代码量是相对较多的,而MyBatis则对JDBC进行了封装,大大减少了代码量
- 极大简化了JDBC代码的开发
- 简单好用、容易上手、具有更好的灵活性
- 通过将SQL定义在XML中的方式降低程序的耦合性
- 支持动态SQL,可以根据具体业务需求灵活实现功能
3.缺点:
MyBatis是最好的嘛?任何事物都会有其的优越点,即使是优化了的JDBC也不例外
- 相比于Hibernate,开发者需要完成更多的工作,eg:定义SQL,设置POJO与数据的映射关系等
- 要求开发者具备一定的SQL编写能力,在一些特定场景下工作量较大
- 数据库的移植性差,SQL依赖于底层数据库,如果进行数据库的迁移,部分SQL需要重编写
二、环境搭建问题
对于一些刚开始学习MyBatis的小伙伴来说,搭建环境可谓是令人头疼的一项操作,接下来我总结一下大家在初次搭建环境及测试时可能会出现的错误
1.配置文件没用注册
2.绑定接口错误
3.方法名不对
4.返回值类型不对
5.Maven导出资源错误
6.mysql是5.7之前在注册驱动时应该是com.mysql.jdbc.Driver
而mysql5.7之后则是com.mysql.cj.jdbc.Driver
三、CRUD注意事项
在进行数据库操作的时候:增删改要提交事务!!!
方式有两种:
手动提交: sqlSession.commit();方法提交事务
自动提交:
我们可以在编写工具类的时候,手动设置为true
//既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
// SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession(true);
}
四、配置解析
1.环境和属性
①environments:
MyBatis 可以配置成适应多种环境,不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
Mybatis默认的事务管理器就是JDBC
连接池:POOLED
②properties:
我们可以通过properties属性来实现引用配置文件
这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置【db.properties】
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
2.常见配置
接下来给大家说一下:类型别名
类型别名可为 Java 类型设置一个缩写名字。
它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:
<typeAliases>
<typeAlias type="com.zjd.pojo.User" alias="User"/>
</typeAliases>
或者用包名:
扫描实体类的包,它的默认别名就为这个类的 类名小写
<typeAliases>
<package name="com.zjd.pojo"/>
</typeAliases>
总结:
实体类比较少,使用第一种方式
如果实体类过多,可以使用第二种
但是第一种可以diy起别名
第二种可以通过加注解起别名@Alias()
3.映射器
大家在第一次跑mybatis的程序时,想必都见过这个错误吧:MapperRegistry
翻译过来也就是说:未注册绑定我们的mapper文件
我们在运行时,如果不在核心配置文件中绑定我们对应接口的Mapper.xml,程序怎么能够识别呢?
方式一:
<mappers>
<mapper resource="com/wdit/dao/userMapper.xml"/>
</mappers>
方式二:
使用class文件绑定注册
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mappers>
注意点:
- 接口和它的mapper配置文件必须同名
- 接口和它的mapper配置文件必须在同一个包下
方式三:
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
注意点:
- 接口和它的mapper配置文件必须同名
- 接口和它的mapper配置文件必须在同一个包下
4.生命周期和作用域
SqlSessionFactoryBuilder:
- 一旦创建了 SqlSessionFactory,就不再需要它了
- 局部变量
SqlSessionFactory:
- 说白了就是可以理解成:数据库连接池
- SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例
- 因此 SqlSessionFactory 的最佳作用域是应用作用域
- 最简单的就是使用单例模式或者静态单例模式。
SqlSession:
- 连接到连接池的一个请求!
- 用完之后需要赶紧关闭,否则资源被占用
- SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域
五、解决属性名和字段名不一致问题
有时候,我们会发现比如数据库表中写到是pwd,然而我们创建实体类的时候却写成了password,结果我们在测试时,就会报错,这种情况怎么办呢?
1.方法一:
起别名
select id,name,pwd as password from user where id= #{id}
2.方法二:
使用ResultMap结果集映射
<!-- 结果集映射-->
<resultMap id="UserMap" type="User">
<!-- column数据库中的字段,property实体类中的属性-->
<result column="id" property="id"/>
<result column="name" property="name"/>
<result column="pwd" property="password"/>
</resultMap>
<select id="getUserByID" resultMap="UserMap">
select * from mybatis.user where id= #{id}
</select>
六、多对一和一对多问题
多对一和一对多问题是MyBatis里常见的问题,也是面试官比较爱问的问题
在这里,我简单的说一下实现的两种方法:
①按照结果嵌套查询---------------------->sql语句完整
②按照查询嵌套查询---------------------->类似于子查询,sql语句嵌套sql语句
两种方法都是解决问题的方法,也没什么优略之分,但是要注意
- 保证sql的可读性【通俗易懂】
- 注意一对多和多对一,属性名和字段的问题
- 问题不好排除,可以用日志
七、动态SQL
所谓动态sql,我们就可以理解成根据不同条件动态的生成sql
动态sql还是相对好理解的,在这里,我就主要说一下sql片段
<sql id="if-title-author">
<if test="title != null">
and title=#{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</sql>
当我们去写动态sql时发现,频繁的出现相同的代码,此时我们可以采取sql片段的方法,将重复的提取出来
<include refid="if-title-author"></include>
在后续的sql语句中,插入include标签即可使用,减少了代码的复杂量
八、缓存
这里我主要说一下MyBatis的缓存原理:
用户查询的顺序:
其实是从右往左,也就是从二级缓存----一级缓存----再去数据库