一、Mybatis 简介

1、简要历史

原来的名字叫ibatis,从 Apache 迁移到 Google 的时候, 改名为Mybatis

2、Mybatis 总体技术体系

3、Mybatis 和其他持久化层技术对比

① 开发效率

Hibernate>Mybatis>JDBC

② 运行效率

JDBC>Mybatis>Hibernate

4、了解 Java 实体类

实体类是和现实世界中某一个具体或抽象的概念对应,是软件开发过程中,为了管理现实世界中的数据而设计的模型。

实体类的多个不同的叫法:

domain:领域模型

entity:实体

POJO:Plain Old Java Object

Java bean:一个 Java 类

二、搭建 Mybatis 框架的开发环境

① 导入 jar 包

[1]mybatis 需要的 jar 包:

  • mybatis-3.4.1.jar:Mybatis 核心包
  • mysql-connector-java-5.1.37-bin.jar:MySQL 驱动

[2]junit 框架需要的 jar 包:

  • junit-4.12.jar:junit 框架
  • hamcrest-core-1.3.jar:junit 框架

添加到当前工程模块的运行时环境

② 准备配置文件

[1]Mybatis 全局配置文件

习惯上命名为 mybatis-config.xml,这个文件名仅仅只是建议,并不是强制要求。将来整合 Spring 之后,这个配置文件可以省略。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?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>
<!-- 使用properties标签引入外部属性文件 -->
<!-- 使用resource属性指定外部属性文件所在的路径 -->
<properties resource="jdbc.properties"/>

<!-- 配置Mybatis全局设置 -->
<settings>
<!-- 开启自动识别驼峰式命名规则 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

<!-- environments表示配置Mybatis的开发环境,可以配置多个环境,在众多具体环境中,使用default属性指定实际运行时使用的环境 -->
<!--我们一般会设置两个environment
一个用户开发环境,使用id为development,一个用于正式环境使用id为final,
那么通过配置environments的default属性,就能选择使用对应的environment了-->

<environments default="development">
<!-- environment表示配置Mybatis的一个具体的环境 -->
<environment id="development">

<!-- Mybatis的内置的事务管理器,声明使用jdbc方式来提交和回滚事务,依赖于从数据源得到的连接来管理事务范围 -->
<transactionManager type="JDBC"/>

<!-- 配置数据源,POOLED – 声明使用数据库连接池,从而避免频繁的创建和销毁链接造成资源的浪费 -->
<dataSource type="POOLED">

<!-- 建立数据库连接的具体信息(引用了外部属性文件中的数据) -->
<property name="driver" value="${wechat.dev.driver}"/>
<property name="url" value="${wechat.dev.url}"/>
<property name="username" value="${wechat.dev.username}"/>
<property name="password" value="${wechat.dev.password}"/>

<!--建立数据库连接的具体信息
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
-->

</dataSource>
</environment>
</environments>

<mappers>
<!-- 指定Mybatis映射文件的具体位置 -->
<mapper resource="com/atguigu/mybatis/dao/EmployeeMapper.xml"/>
</mappers>
</configuration>

注意:配置文件存放的位置是 src 根目录下。

[2]关联外部属性文件

① 需求

在实际开发时,同一套代码往往会对应多个不同的具体服务器环境。使用的数据库连接参数也不同。为了更好的维护这些信息,我们建议把数据库连接信息提取到 Mybatis 全局配置文件外边。

② 做法

创建 jdbc.properties 配置文件

1
2
3
4
5
6
7
8
9
wechat.dev.driver=com.mysql.jdbc.Driver
wechat.dev.url=jdbc:mysql://localhost:3306/mybatis
wechat.dev.username=root
wechat.dev.password=root

wechat.test.driver=com.mysql.jdbc.Driver
wechat.test.url=jdbc:mysql://localhost:3306/mybatis
wechat.test.username=root
wechat.test.password=root

在 Mybatis 全局配置文件中指定外部 jdbc.properties 文件的位置

1
<properties resource="jdbc.properties"/>

在需要具体属性值的时候使用${key}格式引用属性文件中的键

1
2
3
4
5
6
<dataSource type="POOLED">
<property name="driver" value="${wechat.dev.driver}"/>
<property name="url" value="${wechat.dev.url}"/>
<property name="username" value="${wechat.dev.username}"/>
<property name="password" value="${wechat.dev.password}"/>
</dataSource>

[3]Mybatis 映射文件

相关概念:ORM(Object Relationship Mapping)对象关系映射。对象指的是 Java 的实体类对象,关系指的是关系型数据库,映射指的是二者之间的对应关系。

Java 概念数据库概念
属性字段/列
对象记录/行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?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属性:在Mybatis全局范围内找到一个具体的Mapper配置 -->
<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapper">

<!-- 编写具体的SQL语句,使用id属性唯一的标记一条SQL语句 -->
<!-- resultType属性:指定封装查询结果的Java实体类的全类名 -->
<select id="selectEmployee" resultType="com.atguigu.mybatis.entity.Employee">
<!-- Mybatis负责把SQL语句中的#{}部分替换成“?”占位符,在#{}内部还是要声明一个见名知意的名称 -->
select emp_id empId,emp_name empName,emp_salary empSalary from t_emp where emp_id=#{empId}
</select>
</mapper>

三、junit 测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Test
public void testSelectEmployee() throws IOException {

// 1.创建SqlSessionFactory对象
// ①声明Mybatis全局配置文件的路径
String mybatisConfigFilePath = "mybatis-config.xml";

// ②以输入流的形式加载Mybatis配置文件
InputStream inputStream = Resources.getResourceAsStream(mybatisConfigFilePath);

// ③基于读取Mybatis配置文件的输入流创建SqlSessionFactory对象
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

// 2.使用SqlSessionFactory对象开启一个会话
SqlSession session = sessionFactory.openSession();

// 3.根据Mapper配置文件的名称空间+SQL语句的id找到具体的SQL语句
// 格式是:名称空间.SQL语句的id
String statement = "com.atguigu.mybatis.dao.EmployeeMapper.selectEmployee";

// 要传入SQL语句的参数
Integer empId = 2;

// 执行SQL语句
Object result = session.selectOne(statement, empId);

System.out.println("o = " + result);

// 4.关闭SqlSession
session.close();
}

说明:

  • SqlSession:代表 Java 程序和数据库之间的会话。(HttpSession 是 Java 程序和浏览器之间的会话)
  • SqlSessionFactory:是“生产”SqlSession 的“工厂”。
  • 工厂模式:如果创建某一个对象,使用的过程基本固定,那么我们就可以把创建这个对象的相关代码封装到一个“工厂类”中,以后都使用这个工厂类来“生产”我们需要的对象。

1、图解整体思路

  • 根据 Mybatis 全局配置文件创建 SqlSessionFactory 对象
  • 根据 Mybatis 全局配置文件中 mappers/mapper 配置加载映射配置文件
  • 通过 SqlSessionFactory 对象开启会话,创建 SqlSession 对象
  • 调用 SqlSession 对象的方法,根据名称空间和 SQL 的 id 找到具体的一条 SQL 语句
  • Mybatis 底层把 SQL 语句封装到 PreparedStatement 对象中发送给数据库执行

2、加入 log4j 日志打印

① 需求

在 Mybatis 工作过程中,通过打印日志的方式,将要执行的 SQL 语句打印出来。

② 操作

[1]加入 log4j 的 jar 包

log4j.jar

[2]加入 log4j 的配置文件

支持 XML 和 properties 属性文件两种形式。无论使用哪种形式,文件名是固定的:

  • log4j.xml
  • log4j.properties
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<param name="Encoding" value="UTF-8" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n" />
</layout>
</appender>
<logger name="java.sql">
<level value="debug" />
</logger>
<logger name="org.apache.ibatis">
<level value="info" />
</logger>
<root>
<level value="debug" />
<appender-ref ref="STDOUT" />
</root>
</log4j:configuration>

注意:配置文件存放的位置是 src 根目录下。

③ 日志的级别

FATAL(致命)>ERROR(错误)>WARN(警告)>INFO(信息)>DEBUG(调试)

从左到右打印的内容越来越详细

④STDOUT

是 standard output 的缩写,意思是标准输出。对于 Java 程序来说,打印到标准输出就是打印到控制台。

3、用上 Mapper 接口

Mybatis 中的 Mapper 接口相当于以前的 Dao。但是区别在于,Mapper 仅仅是接口,我们不需要提供实现类。

① 思路

② 调整 junit 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class PromotedMybatisTest {

private SqlSessionFactory sessionFactory;

@Before
public void init() throws IOException {
// 1.创建SqlSessionFactory对象
// ①声明Mybatis全局配置文件的路径
String mybatisConfigFilePath = "mybatis-config.xml";

// ②以输入流的形式加载Mybatis配置文件
InputStream inputStream = Resources.getResourceAsStream(mybatisConfigFilePath);

// ③基于读取Mybatis配置文件的输入流创建SqlSessionFactory对象
sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}

@Test
public void testSelectEmployee() throws IOException {

SqlSession session = sessionFactory.openSession();
session.close();
}

}

③ 完成 Mapper 接口

1
2
3
4
5
public interface EmployeeMapper {

Employee selectEmployee(Integer empId);

}
  • 方法名和 SQL 的 id 一致
  • 方法返回值和 resultType 一致
  • 方法的参数和 SQL 的参数一致
  • 接口的全类名和映射配置文件的名称空间一致

④ 最终的 junit 测试方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Test
public void testSelectEmployee() throws IOException {

// 1.从工厂对象中获取SqlSession对象
SqlSession session = sessionFactory.openSession();

// 2.通过SqlSession对象获取Mapper接口对象
EmployeeMapper employeeMapper = session.getMapper(EmployeeMapper.class);

// 3.调用Mapper接口的方法
Employee employee = employeeMapper.selectEmployee(2);

// 4.打印返回值
System.out.println("employee = " + employee);

// 5.关闭Session
session.close();
}

4、实现增删改操作

①insert

SQL 语句

1
2
3
<insert id="insertEmployee">
insert into t_emp(emp_name,emp_salary) values(#{empName},#{empSalary})
</insert>

Java 代码中的 Mapper 接口:

1
2
3
4
5
6
public interface EmployeeMapper {

Employee selectEmployee(Integer empId);

int insertEmployee(Employee employee);
}

Java 代码中的 junit 测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Test
public void testSaveEmployee() {

SqlSession session = sessionFactory.openSession();

EmployeeMapper employeeMapper = session.getMapper(EmployeeMapper.class);

// 创建要保存到数据库的对象
Employee employee = new Employee();

// 给实体类对象设置具体属性值
employee.setEmpName("jerry");
employee.setEmpSalary(5000.33);

// 执行保存操作
int result = employeeMapper.insertEmployee(employee);

// 打印受影响的行数
System.out.println("result = " + result);

// 提交事务
session.commit();

session.close();
}

②delete

SQL 语句

1
2
3
<delete id="deleteEmployee">
delete from t_emp where emp_id=#{empId}
</delete>

Java 代码中的 Mapper 接口:

1
2
3
4
5
6
7
8
public interface EmployeeMapper {

Employee selectEmployee(Integer empId);

int insertEmployee(Employee employee);

int deleteEmployee(Integer empId);
}

Java 代码中的 junit 测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test
public void testRemoveEmployee() {
SqlSession session = sessionFactory.openSession();

EmployeeMapper employeeMapper = session.getMapper(EmployeeMapper.class);

int result = employeeMapper.deleteEmployee(1);

System.out.println("result = " + result);

session.commit();

session.close();
}

③update

SQL 语句:

1
2
3
<update id="updateEmployee">
update t_emp set emp_name=#{empName},emp_salary=#{empSalary} where emp_id=#{empId}
</update>

Java 代码中的 Mapper 接口:

1
2
3
4
5
6
7
8
9
10
public interface EmployeeMapper {

Employee selectEmployee(Integer empId);

int insertEmployee(Employee employee);

int deleteEmployee(Integer empId);

int updateEmployee(Employee employee);
}

Java 代码中的 junit 测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Test
public void testUpdateEmployee() {
SqlSession session = sessionFactory.openSession();

EmployeeMapper employeeMapper = session.getMapper(EmployeeMapper.class);

Employee employee = new Employee(2, "AAAAAA", 6666.66);

int result = employeeMapper.updateEmployee(employee);

System.out.println("result = " + result);

session.commit();

session.close();
}