MyBatis
Mybatis
MyBatis最初是Apache的一个开源项目IBatis
2010年迁移到了Google Code,并且在iBatis3.x版本时正式更名为MyBatis,2013年迁移到Githubs
在Mybatis使用过程中,如果导包iBatis也属于正常现象
持久性框架对比
JDBC:
- SQL夹杂在Java代码中,耦合度高,导致硬编码内伤
- 维护不易且实际开发需求中SQL有变化,修改源码的情况多见
- 代码冗长,开发效率低
Hibernate和JPA:
- 操作简单,开发效率高
- 程序中长难复杂的SQL需要绕过框架
- 内部自动生成的SQL,不容易做特殊优化
- 基于全映射的全自动框架,大量字段的POJO部分进行映射比较困难
- 反射操作太多,导致数据库性能下降
MyBatis:
- 轻量级,性能出色
- SQL和Java编码分开,功能边界清晰(Java代码专注于业务,SQL语句服务于数据)
- 开发效率稍逊色于Hibernate,但是能接受
开发效率: Hibernate > Mybatis > JDBC
运行效率:JDBC > Mybatis >Hibernate
Mapper接口&MapperXML文件
对比于之前学习的JDBC使用方式,MyBatis自带连接池,需要导入的依赖如下
- mybatis:MyBatis使用的核心依赖
- mysql:MySQL数据库的驱动依赖
在使用JDBC时,我们对数据库的操作是使用Dao和DaoImpl
在MyBatis中,对数据库操作使用Mapper和MapperXMl
其中,Mapper接口中不再有SQL语句,而是对数据库操作的功能方法,而MapperXML专门用来写SQL语句
在com.xiaobai下新建软件包名为mapper,用以存放Mapper接口
在resources下建立目录名为mappers,用以存放MapperXML文件
mybatis-config.xml
MyBatis不需要使用连接池,因为他自己内置了连接池
那么就需要为MyBatis配置一些参数(例如JDBC四大件)
以下代码是由尚硅谷提供的原生mybatis配置文件的写法
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- environments表示配置Mybatis的开发环境,可以配置多个环境,在众多具体环境中,使用default属性指定实际运行时使用的环境。default属性的取值是environment标签的id属性的值。 -->
<environments default="development">
<!-- environment表示配置Mybatis的一个具体的环境 -->
<environment id="development">
<!-- Mybatis的内置的事务管理器 -->
<transactionManager type="JDBC"/>
<!-- 配置数据源 -->
<dataSource type="POOLED">
<!-- 建立数据库连接的具体信息 -->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis-example"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- Mapper注册:指定Mybatis映射文件的具体位置 -->
<!-- mapper标签:配置一个具体的Mapper映射文件 -->
<!-- resource属性:指定Mapper映射文件的实际存储位置,这里需要使用一个以类路径根目录为基准的相对路径 -->
<!-- 对Maven工程的目录结构来说,resources目录下的内容会直接放入类路径,所以这里我们可以以resources目录为基准 -->
<mapper resource="mappers/EmployeeMapper.xml"/>
</mappers>
</configuration>
MyBatis原生调用
在之前原生JDBC的学习中,我们最后通过Dao调用JDBC的的过程是:
DAO -> BaseDao -> JDBCUtil
其实使用起来也是比较麻烦,只是两个工具类为我们封装好了对象和方法而已
后来学习了JDBCTemplate,才简化了这两个类和对JDBC的操作
原生的MyBatis在调用起来也是一样的麻烦,但后面由SpringIoC接管后,这个过程就会被简化
public class MybatisTest {
@Test
public void test() throws IOException {
// 使用流读取外部配置文件(mybatis-config.xml)
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
// 创建sqlSessionFactory 这个对象是带有配置的模板,全局唯一
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
// 使用sqlSessionFactory创建sqlSession 每个业务创建一个sqlSession,相当一次会话,用完释放
SqlSession sqlSession = sqlSessionFactory.openSession();
// 获取接口的代理对象,这个接口没有具体的实现类,他代理的是Mapper接口的方法+mapperXMl中的sql语句
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
Employee employee = mapper.queryById(1);
System.out.println("employee = " + employee);
// 提交事务(非DQL)和释放资源
sqlSession.close();
}
}
注:mybatis在配置中是针对非查询开启事务的,所以在执行非查询的时候要提交事务
事务管理器
在 MyBatis 中有两种类型的事务管理器
JDBC – 这个配置直接使用了 JDBC 的提交和回滚功能,它依赖从数据源获得的连接来管理事务作用域。默认情况下,为了与某些驱动程序兼容,它在关闭连接时启用自动提交。然而,对于某些驱动程序来说,启用自动提交不仅是不必要的,而且是一个代价高昂的操作。因此,从 3.5.10 版本开始,你可以通过将 "skipSetAutoCommitOnClose" 属性设置为 "true" 来跳过这个步骤。例如:
<transactionManager type="JDBC">
<property name="skipSetAutoCommitOnClose" value="true"/>
</transactionManager>
iBatis
与MyBatis不同,iBatis没有Mapper接口
在调用iBatis时,不使用代理模式,sqlSession对象提供了增删改查方法,由此对象直接调用标签中的sql语句完成增删改查
sqlSession在调用增删改查的方法时,将mapper标签的namespace + crud标签的id值作为参数传递进去
缺点:
- 传入的标签定位参数是一个字符串,没有报错提示,容易写错
- sql的参数需要整合,每次只能传递一个参数
- 返回值类型为Object,需要强制转型
执行逻辑
iBatis将MapperXML文件中的sql语句,存成类似键值对的形式
键:mapper标签的namespace + crud标签的id值 ,值:sql语句
mybatis-config.xml,配置好四大件之后将数据库信息缓存,同时将mapper.xml的sql语句(键值对缓存起来)
调用iBatis时,通过配置文件读取到四大件和sql,创建SqlSession工厂,创建SqlSession
调用SqlSession的增删改查时,就是在缓存中通过key找到value,带入对sql的参数并执行
MyBatis执行逻辑
为了解决iBatis存在的问题,多建立一个对应mapper.xml的接口
Mapper接口中的全限定类名对应mapper标签的namespace属性值
Mapper接口中的方法名对应crud标签的id值
这样,全限定类名+方法名的格式,也能找到具体的sql语句
代理技术
通过SqlSession对象调用getMapper,将接口的类对象作为参数传入
底层使用JDK动态代理,为此接口生成一个代理对象,利用反射的机制获取到接口的全类名和要执行的方法名
这个全类名和方法名拼成字符串(这也是IBatis时调用具体方法的所需参数),再去调用iBatis对应的方法
使用代理模式对接口内容进行丰富,将mapper.xml的sql内容填入其中,形成一个对象
使用对象调用接口的方法,我们发现参数类型和返回值类型早已规定好
Mybatis日志输出
MyBatis的中文官网为我们提供了非常完善的使用说明,其中就包括了MyBatis的配置文件(mybatis-config.xml)的标签含义
其中,settings标签可以配置 MyBatis 的运行时行为,是个极为重要的标签
<configuration>
<settings>
<!-- 开启MyBaits日志输出 -->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
……
</configuration>
在之后的学习中,我们会学习更多的settings的配置参数,让MyBatis使用起来更简单