1. 什么是MyBatis?
mybatis 是一个优秀的基于 java 的持久层框架,它内部封装了 jdbc,使开发者只需要关注 sql 语句本身,而不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。
mybatis 通过 xml或注解的方式将要执行的各种 statement 配置起来,并通过 java 对象和 statement 中 sql的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射为 java 对象并返回。采用 ORM 思想解决了实体和数据库映射的问题,对 jdbc 进行了封装,屏蔽了 jdbc api 底层访问细节,使我们不用与 jdbc api 打交道,就可以完成对数据库的持久化操作。
2.什么是持久化?
持久化(Persistence),即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的对象存储在数据库中,或者存储在磁盘文件中、XML数据文件中等等。持久化是将程序数据在持久状态和瞬时状态间转换的机制。JDBC就是一种持久化机制。文件IO也是一种持久化机制。
3.什么是持久层?
数据访问层又称为DAL层,有时候也称为是持久层,其功能主要是负责数据库的访问。简单的说法就是实现对数据表的Select(查询),Insert(插入),Update(更新),Delete(删除)等操作。如果要加入ORM的元素,那么就会包括对象和数据表之间的mapping,以及对象实体的持久化。最常见的持久层框架有两个:Hibernate和MyBatis。
4.JDBC编程分析
4.1 代码回顾
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
//加载数据库驱动
Class.forName("com.mysql.jdbc.Driver");
//通过驱动管理类获取数据库链接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", " root");
//定义 sql 语句 ?表示占位符
String sql = "select * from user where username = ?";
//获取预处理 statement
preparedStatement = connection.prepareStatement(sql);
//设置参数,第一个参数为 sql 语句中参数的序号(从 1 开始),第二个参数为设置的参数值
preparedStatement.setString(1, "王五");
//向数据库发出 sql 执行查询,查询出结果集
resultSet = preparedStatement.executeQuery();
//遍历查询结果集
while (resultSet.next()) {
System.out.println(resultSet.getString("id") + " " + resultSet.getString("username"));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//释放资源
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
4.2 JDBC缺陷总结
-
数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
-
mybatis中自带连接池
-
-
Sql 语句在代码中硬编码,造成代码不易维护,实际应用 sql 变化的可能较大, sql 变动需要改变java 代码。
-
mybatis中的SQL语句不是写在代码中,而是写在配置文件中
-
-
使用 preparedStatement 向占位符号传参数存在硬编码,因为 sql 语句的 where 条件不一定,可能多也可能少,修改 sql 还要修改代码,系统不易维护。
-
mybatis中的根据不同的参数添加SQL语句中不同条件也在配置文件可以完成
-
-
对结果集解析存在硬编码(查询列名), sql 变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成 pojo 对象解析比较方便。
-
mybatis中会使用反射将结果集中的数据自动封装到JavaBean对象中
-
5.MyBatis的整体架构
6.MyBatis快速入门
6.1 官网下载 Mybatis 框架
网址:http://www.mybatis.org/mybatis-3/zh/getting-started.html
对应依赖包下载 :https://github.com/mybatis/mybatis-3/releases
6.2 搭建 Mybatis 开发环境
创建工程之前,我们先新建数据库mybatis,并在数据库中新建一张User表,并加一些数据。表结构入下
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(32) NOT NULL COMMENT '用户名称',
`birthday` datetime DEFAULT NULL COMMENT '生日',
`sex` char(1) DEFAULT NULL COMMENT '性别',
`address` varchar(256) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=58 DEFAULT CHARSET=utf8;
6.2.1 创建maven工程
-
创建 mybatis-day01-demo1 的工程, 工程信息如下:
-
Groupid:com.itttt
-
ArtifactId:mybatis-day01-demo1
-
Packing:jar
6.2.2 pom.xml导入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itttt</groupId>
<artifactId>mybatis-day01-demo1</artifactId>
<version>1.0-SNAPSHOT</version>
<!--打包方式-->
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<!--引入相关依赖-->
<dependencies>
<!--MyBatis依赖包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<!--MySQL驱动包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
<scope>runtime</scope>
</dependency>
<!--日志包-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<!--测试包-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
</project>
6.2.3 创建User
创建com.itttt.domain包,在该包下创建User对象,并添加对应的属性
public class User implements Serializable {
private Integer id;
private String username;
private String birthday;
private String sex;
private String address;
//略 get...set...toString...
}
6.2.4 创建UserMapper接口
创建com.itttt.mapper包,并在该包下创建接口,代码如下:
它其实就是dao层的接口
public interface UserMapper {
List<User> findAll();
}
6.2.5 创建UserMapper.xml
这个xml配置文件的位置,必须和对应的那个Mapper接口的位置一样。而且其文件名也要和接口名一样
在com.itttt.mapper包下创建UserMapper.xml,并在UserMapper.xml中添加一个select查询结点,代码如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itttt.mapper.UserMapper">
<!--findAll-->
<select id="findAll" resultType="com.itheima.domain.User">
SELECT * FROM user
</select>
</mapper>
6.2.6 创建SqlMapConfig.xml
在main/resources下创建SqlMapConfig.xml,在文件中配置数据源信息和加载映射文件,代码如下:
这个配置文件的名字不是固定的,你可以随便命名
<?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 default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="123"/>
</dataSource>
</environment>
</environments>
<!--加载映射文件-->
<mappers>
<mapper resource="com/itttt/mapper/UserMapper.xml"/>
</mappers>
</configuration>
6.2.7 为了方便查看日志,在main/resources下创建log4j.properties文件,代码如下
log4j.rootLogger=DEBUG,Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
log4j.logger.org.apache=DEBUG
6.3 编写测试类
在test包下创建com.itttt.test,再在该包下创建MyBatisTest类,代码如下
public class MyBatisTest {
@Test
public void testFindAll() throws IOException {
//读取配置文件
InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//通过SqlSessionBuilder对象构建一个SqlSessionFactory
SqlSessionFactory sqlSessionFactory = builder.build(is);
//通过SqlSessionFactory构建一个SqlSession
SqlSession session = sqlSessionFactory.openSession();
//通过SqlSession实现增删改查
UserMapper userMapper = session.getMapper(UserMapper.class);
List<User> users = userMapper.findAll();
//打印输出
for (User user : users) {
System.out.println(user);
}
//关闭资源
session.close();
is.close();
}
}
mybatis入门程序的小结
-
引入依赖
-
编写一个接口,以及其对应的映射配置文件
-
映射配置文件的路径和文件名要和对应的接口一致
-
映射配置文件的根标签(mapper)的namespace属性的值要和对应的接口的全限定名一致
-
接口中的每一个方法就对应映射配置文件中的一个标签
-
标签的id属性就对应方法的方法名
-
标签的parameterType属性就对应方法的参数类型
-
标签的resultType属性就对应方法的返回值的类型,如果返回值有泛型就对应泛型类型
-
-
-
编写一个主配置文件
-
配置环境
-
加载映射配置文件
-
-
在单元测试用例中,编写mybatis的测试代码
Mybatis和hibernate的区别
1.编写实现
Mybatis需要手动编写SQL语句,以及ResultMap。而Hibernate有良好的映射机制,开发者无需关心SQL的生成与结果映射,可以更专注于业务流程。(hibernate自动生成SQL语句机制)
2.性能比较
Hibernate的查询会将表中的所有字段查询出来,这一点会有性能消耗。Hibernate也可以自己写SQL来指定需要查询的字段,但这样就破坏了Hibernate开发的简洁性。而Mybatis的SQL是手动编写的,所以可以按需求指定查询的字段。(hibernate的性能低于Mybatis)
3.执行细节
Hibernate 是完整的对象/关系映射解决方案,它提供了对象状态管理(state management)的功能,使开发者不再需要理会底层数据库系统的细节。也就是说,相对于常见的 JDBC/SQL 持久层方案中需要管理 SQL 语句,Hibernate采用了更自然的面向对象的视角来持久化 Java 应用中的数据。换句话说,使用 Hibernate 的开发者应该总是关注对象的状态(state),不必考虑 SQL 语句的执行。这部分细节已经由 Hibernate 掌管妥当,只有开发者在进行系统性能调优的时候才需要进行了解。而MyBatis在这一块没有文档说明,用户需要对对象自己进行详细的管理。
4.缓存机制
Hibernate一级缓存是Session缓存,Hibernate二级缓存是SessionFactory级的缓存。 SessionFactory的缓存分为内置缓存和外置缓存。内置缓存中存放的是SessionFactory对象的一些集合属性包含的数据(映射元素据及预定SQL语句等),对于应用程序来说,它是只读的。外置缓存中存放的是数据库数据的副本,其作用和一级缓存类似.二级缓存除了以内存作为存储介质外,还可以选用硬盘等外部存储设备。二级缓存称为进程级缓存或SessionFactory级缓存,它可以被所有session共享,它的生命周期伴随着SessionFactory的生命周期存在和消亡。
MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。MyBatis 3 中的缓存实现的很多改进都已经实现了,使得它更加强大而且易于配置。
默认情况下是没有开启缓存的,除了局部的 session 缓存,可以增强变现而且处理循环 依赖也是必须的。要开启二级缓存,你需要在你的 SQL 映射文件中添加一行:
MyBatis的优点:
Mybatis优势
- MyBatis可以进行更为细致的SQL优化,可以减少查询字段。
- MyBatis容易掌握,而Hibernate门槛较高。
Hibernate优势:
- Hibernate的DAO层开发比MyBatis简单,Mybatis需要维护SQL和结果映射。
- Hibernate对对象的维护和缓存要比MyBatis好,对增删改查的对象的维护要方便。
- Hibernate数据库移植性很好,MyBatis的数据库移植性不好,不同的数据库需要写不同SQL。
- Hibernate有更好的二级缓存机制,可以使用第三方缓存。MyBatis本身提供的缓存机制不佳。
- Hibernate功能强大,数据库无关性好,O/R映射能力强,如果你对Hibernate相当精通,而且对Hibernate进行了适当的封装,那么你的项目整个持久层代码会相当简单,需要写的代码很少,开发速度很快,非常爽。
- MBATIS入门简单,即学即用,提供了数据库查询的自动对象绑定功能,而且延续了很好的SQL使用经验,对于没有那么高的对象模型要求的项目来说,相当完美。
- MBATIS的缺点就是框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写的,工作量也比较大,而且不太容易适应快速数据库修改。
MyBatis相关部分面试题:
1.Mybatis比IBatis比较大的几个改进是什么
a.有接口绑定,包括注解绑定sql和xml绑定Sql ,
b.动态sql由原来的节点配置变成OGNL表达式,
c. 在一对一,一对多的时候引进了association,在一对多的时候引入了collection节点,不过都是在resultMap里面配置
2.什么是MyBatis的接口绑定,有什么好处
接口映射就是在IBatis中任意定义接口,然后把接口里面的方法和SQL语句绑定,
我们直接调用接口方法就可以,这样比起原来了SqlSession提供的方法我们可以有更加灵活的选择和设置.
3.接口绑定有几种实现方式,分别是怎么实现的?
接口绑定有两种实现方式,一种是通过注解绑定,就是在接口的方法上面加上
@Select@Update等注解里面包含Sql语句来绑定,另外一种就是通过xml里面写SQL来绑定,
在这种情况下,要指定xml映射文件里面的namespace必须为接口的全路径名.
4.什么情况下用注解绑定,什么情况下用xml绑定
当Sql语句比较简单时候,用注解绑定,
当SQL语句比较复杂时候,用xml绑定,一般用xml绑定的比较多
5.MyBatis实现一对一有几种方式?具体怎么操作的
有联合查询和嵌套查询,联合查询是几个表联合查询,只查询一次,
通过在resultMap里面配置association节点配置一对一的类就可以完成;
嵌套查询是先查一个表,根据这个表里面
的结果的外键id,去再另外一个表里面查询数据,也是通过association配置,但另外一个表
的查询通过select属性配置
6.MyBatis实现一对多有几种方式,怎么操作的
有联合查询和嵌套查询,联合查询是几个表联合查询,只查询一次,通过在resultMap里面配
置collection节点配置一对多的类就可以完成;
嵌套查询是先查一个表,根据这个表里面的
结果的外键id,去再另外一个表里面查询数据,也是通过配置collection,但另外一个表的
查询通过select节点配置
7.MyBatis里面的动态Sql是怎么设定的?用什么语法?
MyBatis里面的动态Sql一般是通过if节点来实现,通过OGNL语法来实现,但是如果要写的完
整,必须配合where,trim节点,where节点是判断包含节点有内容就插入where,否则不插
入,trim节点是用来判断如果动态语句是以and 或or开始,那么会自动把这个and或者or取
掉
8.IBatis和MyBatis在核心处理类分别叫什么
IBatis里面的核心处理类交SqlMapClient,
MyBatis里面的核心处理类叫做SqlSession
9.IBatis和MyBatis在细节上的不同有哪些
在sql里面变量命名有原来的#变量# 变成了#{变量}
原来的$变量$变成了${变量},
原来在sql节点里面的class都换名字交type
原来的queryForObject queryForList 变成了selectOne selectList
原来的别名设置在映射文件里面放在了核心配置文件里
10.讲下MyBatis的缓存
MyBatis的缓存分为一级缓存和二级缓存,
一级缓存放在session里面,默认就有,二级缓存放在它的命名空间里,默认是打开的,
使用二级缓存属性类需要实现Serializable序列化接
口(可用来保存对象的状态),可在它的映射文件中配置<cache/>
11.MyBatis(IBatis)的好处是什么
ibatis把sql语句从Java源程序中独立出来,
放在单独的XML文件中编写,给程序的维护带来了很大便利。
ibatis封装了底层JDBC API的调用细节,并能自动将结果集转换成Java Bean对象,
大大简化了Java数据库编程的重复工作。
因为Ibatis需要程序员自己去编写sql语句,
程序员可以结合数据库自身的特点灵活控制sql语句,
因此能够实现比hibernate等全自动orm框架更高的查询效率,能够完成复杂查询。
MyBatis的优点:
(1)基于SQL语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL写在XML里,解除sql与程序代码的耦合,便于统一管理;提供XML标签,支持编写动态SQL语句,并可重用。
(2)与JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接;
(3)很好的与各种数据库兼容(因为MyBatis使用JDBC来连接数据库,所以只要JDBC支持的数据库MyBatis都支持)。
(4)能够与Spring很好的集成;
(5)提供映射标签,支持对象与数据库的ORM字段关系映射;提供对象关系映射标签,支持对象关系组件维护。
MyBatis的缺点:
(1)SQL语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL语句的功底有一定要求。
(2)SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。