文章目录
- 1. 前言
- 2. JDBC 存在的缺点
- 3. MyBatis 优化
- 4. MyBatis 快速入门
- 5. 总结
- Java编程基础教程系列
1. 前言
JavaEE 企业级 Java 项目中的经典三层架构为表现层,业务层和持久层,使用Java 代码操作数据库属于持久层内容,而 MyBatis 对 JDBC 代码进行了封装,作为一款优秀的持久层框架,专门用于简化JDBC开发。
MyBatis 支持自定义 SQL,存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型,接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
MyBatis 本是 Apache 的一个开源项目 iBatis, 2010 年这个项目由 Apache software foundation 迁移到了google code,并且改名为 MyBatis 。2013 年 11 月迁移到 Github。
小tips:在学习一门全新的技术前,尽量做到从头到尾通读官网信息,MyBatis 的中文版官网相比于其他的网站还是非常友好的,建议首先阅读官网信息。
什么是框架呢?
框架的概念其实不难理解,这里的框架是指一个半成品的软件,是一套可重用,通用的,软件基础代码模型,在框架基础之上构建项目使编码更加高效,规范,通用并且扩展性强。
2. JDBC 存在的缺点
之前使用 JDBC 代码操作数据库时,我们一般分为注册驱动,获取连接,定义sql,设置参数值,获取 sql 执行对象,执行 sql,处理返回数据,释放资源等几个步骤。下面使用一个简单的例子分析 JDBC 究竟存在哪些缺点。
需求:使用 Java 代码操作数据库,查询学生表中所有男生信息,并且将其封装为对象,最终存放在集合中。
public class JDBCDemo {
public static void main(String[] args) throws Exception {
//1. 注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2. 获取连接
String url = "jdbc:mysql://localhost:3306/blog?useSSL=false";
String username = "root";
String ppassword = "abc123";//密码
Connection conn = DriverManager.getConnection(url, username, password);
//接收输入的查询条件
String gender = "男";
//3. 定义sql
String sql = "select * from student where gender=?";
//4. 获取sql执行对象
Statement stmt = conn.createStatement();
//设置参数的值
pstmt.setString(1,gender);
//5. 执行sql
ResultSet rs = stmt.executeQuery(sql);
//6. 处理结果
//遍历结果集,获取数据,封装为对象,装入集合
Student s = null;
List<Student> students = new ArrayList<>();
while (rs.next()) {
s = new Student();
int id = rs.getInt(1);
String name = rs.getString(2);
String gender = rs.getString(3);
s.setId(id);
s.setName(name);
s.setGender(gender);
students.add(s);
}
System.out.println(students);
//7. 释放资源
rs.close();
stmt.close();
conn.close();
}
}
上面是一段简单标准的使用 JDBC 操作数据库的代码,分析代码我们不难看出,在注册驱动,获取连接和定义 sql 部分,代码中出现了大量的字符串信息,这些字符串信息非常不利于后期的维护,例如后期修改要连接的数据库等。我们把这个问题称为 JDBC 的硬编码问题
。示例,存在硬编码问题的代码:
//1. 注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2. 获取连接
String url = "jdbc:mysql://localhost:3306/blog?useSSL=false";
String username = "root";
String ppassword = "abc123";//密码
Connection conn = DriverManager.getConnection(url, username, password);
//接收输入的查询条件
String gender = "男";
//3. 定义sql
String sql = "select * from student where gender=?";
在手动设置参数,封住结果集对象部分,代码中出现了大量的相似代码,例如将来的参数较多时,手动设置参数也是一件麻烦的事情等,这个问题被称为 JDBC 的操作繁琐问题
。示例,存在操作繁琐问题的代码:
//设置参数的值
pstmt.setString(1,gender);
//5. 执行sql
ResultSet rs = stmt.executeQuery(sql);
//6. 处理结果
//遍历结果集,获取数据,封装为对象,装入集合
Student s = null;
List<Student> students = new ArrayList<>();
while (rs.next()) {
s = new Student();
int id = rs.getInt(1);
String name = rs.getString(2);
String gender = rs.getS
s.setId(id);
s.setName(name);
s.setGender
students.add(s);
}
JDBC的缺点,如下图:
3. MyBatis 优化
JDBC 作为基础性的代码,固然会出现很多操作繁琐等的问题,那么这个问题怎么解决呢?前面说使用 MyBatis 简化 JDBC 开发,那么具体是怎么避免这些问题的呢?
首先,要解决操作繁琐的问题,只需要让JDBC中手动设置参数和手动封装结果集对象的操作由程序自动封装完成。例如下面一行代码就解决了 JDBC 封装结果集对象操作繁琐的问题:
List<Student> students = sqlSession.selectList("test.selectAll"); //参数是一个字符串,该字符串必须是映射配置文件的namespace.id
MyBatis 将注册驱动,获取连接,定义sql 的语句从 Java 代码中抽离,并单独写到配置文件中,解决了硬编码的问题。例如:在 mybatis-cinfig.xml
配置文件中定义数据库连接信息。
4. MyBatis 快速入门
每一个初学者,在学习一门全新的技术时,都要在实战练习中掌握其使用方法。今天,我们使用一个小小的案例来入门 MyBatis,学会 MyBatis 的基本使用。
需求:查询数据库中 student 表中所有的数据。
我们使用以下 5 个步骤来解决这个问题:
-
创建 student 表,添加数据
-
创建新项目,创建Maven模块,导入坐标
-
编写MyBatis核心配置文件
-
编写sql映射文件
-
编写代码
- 定义 POJO实体类
- 加载核心配置文件,获取 SqlSessionFactory 对象
- 获取 SqlSession 对象,执行 sql 语句
- 释放资源
接下来,我们按照上面的步骤讲解需求中的问题,学习 MyBatis 的基本使用。下面为详细过程和代码演示,整个过程的分析参考文末的过程剖析。
第一步:创建 student 表,添加数据
drop table if exists student;
create table student(
id int primary key auto_increment,
name varchar(10),
gender char(1)
);
insert into student(name,gender) values
('张三','男'),
('李四','女'),
('王五','男');
第二步:
创建空项目,创建 Maven 模块,项目结构如下图:
在创建好的模块中的 pom.xml
配置文件中添加依赖坐标,点击刷新使坐标信息生效:
<dependencies>
<!--mybatis 依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<!--mysql 驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<!--junit 单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<!-- 添加slf4j日志api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.20</version>
</dependency>
<!-- 添加logback-classic依赖 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!-- 添加logback-core依赖 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
在 resources 目录下创建 logback 的配置文件 logback.xml
,用于查看日志信息:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!--
CONSOLE :表示当前的日志信息是可以输出到控制台的。
-->
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>[%level] %blue(%d{HH:mm:ss.SSS}) %cyan([%thread]) %boldGreen(%logger{15}) - %msg %n</pattern>
</encoder>
</appender>
<logger name="org.chengzi" level="DEBUG" additivity="false">
<appender-ref ref="Console"/>
</logger>
<!--
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF, 默认debug
<root>可以包含零个或多个<appender-ref>元素,标识这个输出位置将会被本日志级别控制。
-->
<root level="DEBUG">
<appender-ref ref="Console"/>
</root>
</configuration>
第三步:编写 MyBatis 核心配置文件
编写 MyBatis 核心配置文件,可以用于替换连接信息,解决了 JDBC 硬编码的问题。在模块下的 resources 目录下创建 MyBatis 的配置文件 mybatis-config.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>
<typeAliases>
<package name="org.chengzi.pojo"/>
</typeAliases>
<!--
environments:配置数据库连接环境信息。可以配置多个environment,通过default属性切换不同的environment
-->
<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/blog?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="abc123"/>
</dataSource>
</environment>
<environment id="test">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--数据库连接信息-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/blog?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="abc123"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--加载sql映射文件-->
<mapper resource="StudentMapper.xml"/>
</mappers>
</configuration>
这里使用了<typeAliases>
标签以后,在 sql 映射配置文件中的 resultType 的值可以直接设置为 Student ,而不是:
第四步:编写 sql 映射文件
编写 sql 映射配置文件,用于统一管理 sql 语句,同样也是为了解决 JDBC 硬编码的问题。在模块的 resources 目录下创建映射配置文件 StudentMapper.xml
,内容如下:
<?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="test">
<select id="selectAll" resultType="org.chengzi.pojo.User">
select * from student;
</select>
</mapper>
第五步:编写代码
在编写代码时,大概可以分为四步。首先是定义 POJO 类,在指定的包下创建 Student 类,如下:
package org.chengzi.pojo;
public class Student {
private int id;
private String name;
private String gender;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", gender='" + gender + '\'' +
'}';
}
}
接下来在 org.chengzi
包下创建 MyBatisDemo 测试类,用于加载核心配置文件,获取SqlSessionFactory 对象,获取 SQLSession 对象并执行 sql 语句,最后释放资源。
public class MyBatisDemo {
public static void main(String[] args) throws IOException {
//1. 加载mybatis的核心配置文件,获取 SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2. 获取SqlSession对象,用它来执行sql
SqlSession sqlSession = sqlSessionFactory.openSession();
//3. 执行sql
List<Student> students = sqlSession.selectList("test.selectAll"); //参数是一个字符串,该字符串必须是映射配置文件的namespace.id
System.out.println(students);
//4. 释放资源
sqlSession.close();
}
}
过程剖析:
在使用 MyBatis 持久层框架开发时,我们首先创建 Maven 模块,使用 Maven 构建和管理这个 Java 项目,所以我们要导入项目依赖的坐标信息,例如 MySQL 数据库的驱动坐标,用于单元测试的 Junit 和用于查看日志信息的依赖坐标。
接下来是编写 MyBatis 核心配置文件,一般命名为 mybatis-config.xml
,其中<environments>
标签用于配置数据库连接环境信息,可以配置多个<environment>
标签,通过 default 属性切换不同的环境。我们还要定义<mapper>
标签用于加载 sql 映射文件。
而 sql 映射文件在哪里呢?接下来一步就是编写 sql 映射文件,在模块的 resources 文件目录下创建映射文件的核心配置文件,一般命名有其语法规则,使用 xxxMapper.xml
命名,而 xxx 表示要操作的数据库表。其中使用 namespace 作为命名空间,而 id 作为标签中 sql 语句的唯一标识,使用命名空间的方式类似于 Java 中包的概念,允许在不同的命名空间中存在相同名称的 id ,方便在不同的 sql 映射文件中使用相同的 id,resultType 参数表示对应语句返回结果的类型,例如案例中将数据包装为 Student 类型的对象,其 resultType 参数的值就为 Student。
接下来就是定义 POJO 实体类,用于封装查询结果数据,例如案例中查询学生表,将每条记录封装为一个对象,这里就在 POJO 包中定义 Student 类。
最后就是核心的一部分,编写相关测试类来操作数据库,在源代码 Java 文件目录对应的包中创建测试类来操作数据库并封装结果集对象。内容大致为加载核心配置文件 mybatis-config.xml
,获取 SqlSessionFactory 类对象,使用该对象的openSession() 方法获取 SqlSession 对象,用于执行 sql,然后封装结果集对象 ,此时传入的参数是一个字符串,该字符串是映射配置文件的 namespace.id ,最后释放资源。
5. 总结
初学者入门时,整个构建过程可以多参考官网给出的示例教程和代码,直接 C V 到 IDE 练习即可。
本文是 MyBatis 持久层框架的入门篇,MyBatis 作为大多数Java 开发者第一个学习的大型框架,其思想十分重要,慢慢体会其中每个步骤的意义,多练习就能熟练掌握。
Java编程基础教程系列
JDBC快速入门,如何使用JDBC操作数据库?
如何使用JDBC操作数据库?JDBC API的使用详细解读
什么是数据库连接池?Druid(德鲁伊)连接池的使用详细解读