8.2 MyBatis入门

8.2 MyBatis入门

MyBatis的用法非常简单,我们只要在Java项目中引入 MyBatis框架,就能以面向对象的方式操作关系数据库

8.2.1 MyBatis下载和安装

下载mybatis

进入mybatis在github上的仓库,进入releases,找到最近发布版本,展开Assets下拉列表,然后点击mybatis-3.5.2.zip超链接,下载连接即可.

mybatis目录结构

下载后,解压mybatis的压缩包,进入解压后的目录,目录结构如下:

D:\Desktop\随书源码\库文件\mybatis-3.5.2
├─lib\
│ ├─ant-1.10.3.jar
│ ├─ant-launcher-1.10.3.jar
│ ├─asm-7.0.jar
│ ├─cglib-3.2.10.jar
│ ├─commons-logging-1.2.jar
│ ├─javassist-3.24.1-GA.jar
│ ├─log4j-1.2.17.jar
│ ├─log4j-api-2.11.2.jar
│ ├─log4j-core-2.11.2.jar
│ ├─ognl-3.2.10.jar
│ ├─slf4j-api-1.7.26.jar
│ └─slf4j-log4j12-1.7.26.jar
├─LICENSE
├─mybatis-3.5.2.jar
├─mybatis-3.5.2.pdf
└─NOTICE

我们需要的是,当前目录下的mybatis-3.5.2.jar这个文件.

提示

由于MyBatis的底层依然是基于JDBC的,因此在应用程序中使用MyBatis执行持久化时同样少不了JDBC驱动。本示例程序底层采用了MySQL数据库,因此还需要将MySQL数据库驱动添加到应用程序的类加载路径中

下载MySQL的Java驱动

进入这个站点,即可下载mysql驱动。在写这篇文章的时候,最新的驱动版本是8.0版本的驱动。8.0版本的驱动支持MySQL5.5开始的后续MySQL版本。下载最新版本即可.

MySQL的Java驱动目录结果

展开/折叠
D:\Desktop\随书源码\库文件\mysql-connector-java-8.0.17
├─build.xml
├─CHANGES
├─INFO_BIN
├─INFO_SRC
├─LICENSE
├─mysql-connector-java-8.0.17.jar
├─README
└─src\

下载log4j

使用log4j来输出日志,如打印运行的SQL命令等.
进入log4j下载站点,然后选择镜像,在镜像的HTTP几个大字下,点击log4j对应的链接,即可下载.

log4j目录结构

展开/折叠
D:\Desktop\随书源码\库文件\apache-log4j-2.13.3-bin
├─LICENSE.txt
├─log4j-1.2-api-2.13.3-javadoc.jar
├─log4j-1.2-api-2.13.3-sources.jar
├─log4j-1.2-api-2.13.3.jar
├─log4j-api-2.13.3-javadoc.jar
├─log4j-api-2.13.3-sources.jar
├─log4j-api-2.13.3.jar
├─log4j-appserver-2.13.3-javadoc.jar
├─log4j-appserver-2.13.3-sources.jar
├─log4j-appserver-2.13.3.jar
├─log4j-cassandra-2.13.3-javadoc.jar
├─log4j-cassandra-2.13.3-sources.jar
├─log4j-cassandra-2.13.3.jar
├─log4j-core-2.13.3-javadoc.jar
├─log4j-core-2.13.3-sources.jar
├─log4j-core-2.13.3-tests.jar
├─log4j-core-2.13.3.jar
├─log4j-couchdb-2.13.3-javadoc.jar
├─log4j-couchdb-2.13.3-sources.jar
├─log4j-couchdb-2.13.3.jar
├─log4j-docker-2.13.3-javadoc.jar
├─log4j-docker-2.13.3-sources.jar
├─log4j-docker-2.13.3.jar
├─log4j-flume-ng-2.13.3-javadoc.jar
├─log4j-flume-ng-2.13.3-sources.jar
├─log4j-flume-ng-2.13.3.jar
├─log4j-iostreams-2.13.3-javadoc.jar
├─log4j-iostreams-2.13.3-sources.jar
├─log4j-iostreams-2.13.3.jar
├─log4j-jcl-2.13.3-javadoc.jar
├─log4j-jcl-2.13.3-sources.jar
├─log4j-jcl-2.13.3.jar
├─log4j-jdbc-dbcp2-2.13.3-javadoc.jar
├─log4j-jdbc-dbcp2-2.13.3-sources.jar
├─log4j-jdbc-dbcp2-2.13.3.jar
├─log4j-jmx-gui-2.13.3-javadoc.jar
├─log4j-jmx-gui-2.13.3-sources.jar
├─log4j-jmx-gui-2.13.3.jar
├─log4j-jpa-2.13.3-javadoc.jar
├─log4j-jpa-2.13.3-sources.jar
├─log4j-jpa-2.13.3.jar
├─log4j-jul-2.13.3-javadoc.jar
├─log4j-jul-2.13.3-sources.jar
├─log4j-jul-2.13.3.jar
├─log4j-liquibase-2.13.3-javadoc.jar
├─log4j-liquibase-2.13.3-sources.jar
├─log4j-liquibase-2.13.3.jar
├─log4j-mongodb2-2.13.3-javadoc.jar
├─log4j-mongodb2-2.13.3-sources.jar
├─log4j-mongodb2-2.13.3.jar
├─log4j-mongodb3-2.13.3-javadoc.jar
├─log4j-mongodb3-2.13.3-sources.jar
├─log4j-mongodb3-2.13.3.jar
├─log4j-slf4j-impl-2.13.3-javadoc.jar
├─log4j-slf4j-impl-2.13.3-sources.jar
├─log4j-slf4j-impl-2.13.3.jar
├─log4j-slf4j18-impl-2.13.3-javadoc.jar
├─log4j-slf4j18-impl-2.13.3-sources.jar
├─log4j-slf4j18-impl-2.13.3.jar
├─log4j-spring-cloud-config-client-2.13.3-javadoc.jar
├─log4j-spring-cloud-config-client-2.13.3-sources.jar
├─log4j-spring-cloud-config-client-2.13.3.jar
├─log4j-taglib-2.13.3-javadoc.jar
├─log4j-taglib-2.13.3-sources.jar
├─log4j-taglib-2.13.3.jar
├─log4j-to-slf4j-2.13.3-javadoc.jar
├─log4j-to-slf4j-2.13.3-sources.jar
├─log4j-to-slf4j-2.13.3.jar
├─log4j-web-2.13.3-javadoc.jar
├─log4j-web-2.13.3-sources.jar
├─log4j-web-2.13.3.jar
├─NOTICE.txt
└─RELEASE-NOTES.md

MyBatis的数据库操作入门

项目结构

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
D:\Desktop\随书源码\Spring+Mybatis企业应用实战(第2版)\codes\08\MyBatisQs
├─src\
│ ├─log4j.properties
│ ├─mybatis-config.xml
│ └─org\
│ └─fkit\
│ ├─domain\
│ │ ├─crateDatabase.sql
│ │ ├─createTable.sql
│ │ ├─test.sql
│ │ ├─User.java
│ │ └─user_inf.sql
│ ├─mapper\
│ │ └─UserMapper.xml
│ └─test\
│ └─MyBatisTest.java
└─WebContent\
├─META-INF\
│ └─MANIFEST.MF
└─WEB-INF\
├─lib\
│ ├─commons-logging-1.2.jar
│ ├─log4j-1.2.17.jar
│ ├─log4j-api-2.3.jar
│ ├─log4j-core-2.3.jar
│ ├─mybatis-3.4.5.jar
│ ├─mysql-connector-java-5.1.44-bin.jar
└─web.xml

引入jar文件到lib目录

引入mybatis的jar文件

进入mybatis目录,使用如下copy命令把mybatisjar包复制到web项目的lib目录中.

1
copy mybatis-3.5.2.jar E:\workspacne_JDK8Tomcat8.5\MyBatisTest\WebContent\WEB-INF\lib

复制效果如下:

D:\Desktop\随书源码\库文件\mybatis-3.5.2>copy mybatis-3.5.2.jar E:\workspacne_JDK8Tomcat8.5\MyBatisTest\WebContent\WEB-INF\lib
已复制         1 个文件。

引入mysql驱动

进入解压后的mysql驱动目录,打开cmd,输入如下命令进行复制:

1
copy mysql-connector-java-8.0.17.jar E:\workspacne_JDK8Tomcat8.5\MyBatisTest\WebContent\WEB-INF\lib

复制效果如下:

D:\Desktop\随书源码\库文件\mysql-connector-java-8.0.17>copy mysql-connector-java-8.0.17.jar E:\workspacne_JDK8Tomcat8.5\MyBatisTest\WebContent\WEB-INF\lib
已复制         1 个文件。

引入log4j的jar包

解压下载好的log4j压缩包,我发现有好多jar包啊,官网上给出的消息如下:

Using Log4j on your classpath
To use Log4j 2 in your application make sure that both the API and Core jars are in the application’s classpath. Add the dependencies listed below to your classpath.

log4j-api-2.13.3.jar
log4j-core-2.13.3.jar

You can do this from the command line or a manifest file.

所以,复制log4j-api-版本号.jar,和log4j-core-版本号.jar这两个文件到web项目的lib目录下即可.

1
2
copy log4j-api-2.13.3.jar E:\workspacne_JDK8Tomcat8.5\MyBatisTest\WebContent\WEB-INF\lib
copy log4j-core-2.13.3.jar E:\workspacne_JDK8Tomcat8.5\MyBatisTest\WebContent\WEB-INF\lib
D:\Desktop\随书源码\库文件\apache-log4j-2.13.3-bin>copy log4j-api-2.13.3.jar E:\workspacne_JDK8Tomcat8.5\MyBatisTest\WebContent\WEB-INF\lib
已复制         1 个文件。

D:\Desktop\随书源码\库文件\apache-log4j-2.13.3-bin>copy log4j-core-2.13.3.jar E:\workspacne_JDK8Tomcat8.5\MyBatisTest\WebContent\WEB-INF\lib
已复制         1 个文件。

创建数据库 mybatis

1
2
# 创建一个数据库,指定数据库的字符为真正的utf-8编码
create database `mybatis` default character set utf8;

创建数据表 tb_user

1
2
3
4
5
6
7
8
9
10
11
# 使用刚才创建的数据库
use mybatis;
# 创建表格tb_user
drop table if exists tb_user;
create table tb_user(
id int(11) not null auto_increment,
name varchar(18) default null,
sex char(2) default null,
age int(11) default null,
primary key (id)
);

创建成功效果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
mysql> # 创建一个数据库,指定数据库的字符为真正的utf-8编码
create database `mybatis` default character set utf8;
Query OK, 1 row affected (0.02 sec)

mysql> # 使用刚才创建的数据库
use mybatis;
# 创建表格tb_user
drop table if exists tb_user;
create table tb_user(
id int(11) not null auto_increment,
name varchar(18) default null,
sex char(2) default null,
age int(11) default null,
primary key (id)
);
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.04 sec)

好了,有了数据表,现在来创建对应的持久化类.

创建持久化类 User.java

持久化对象 PO

在所有的ORM框架中都有一个非常重要的媒介:PO(持久化对象)。持久化对象的作用就是完成持久化操作,简单地说,就是通过持久化对象来对数据库执行增、删、改的操作,以面向对象的方式操作数据库
应用程序无须直接访问数据库,甚至无须理会底层数据库采用何种数据库,应用程序只需创建、修改、删除持久化对象即可;与此同时**MyBatis则负责把这种操作转换为对指定数据库表的操作**。
MyBatis完全采用普通的Java对象作为持久化对象使用

User.java

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
public class User
implements Serializable
{
private static final long serialVersionUID = 1L;
// 用户标识
private Integer id;
// 用户姓名
private String name;
// 用户性别
private String sex;
// 用户年龄
private Integer age;
// 无参数构造器
public User()
{
super();
}
// 有参数构造器
public User(String name, String sex, Integer age)
{
super();
this.name = name;
this.sex = sex;
this.age = age;
}
// 此处省略getter和setter方法,请自己补上
@Override
public String toString()
{
return "User [id=" + id + ", name=" + name + ", sex=" + sex + ", age=" + age + "]";
}
}

POJO

仔细看上面这个类的代码,会发现这个类与普通的JavaBean没有任何区别。实际上,MyBatis直接采用了POJO(普通的、传统的Java对象)作为持久化类,这就是MyBatis被称非低侵入式设计的原因。 MyBatis不要求持久化类继承任何父类,或者实现任何接口 ,这样可保证代码不被污染。

UserMapper.xml 映射持久化类和数据表

MyBatis是通过XML文件去完成持久化类和数据库表之间的映射关系的.

1
2
3
4
5
6
7
8
9
10
11
12
13
<?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">
<!-- namespace指用户自定义的命名空间。 -->
<mapper namespace="org.fkit.mapper.UserMapper">
<!-- id="save"是唯一的标示符 -->
<!-- parameterType属性指明插入时使用的参数类型,也就是PO类的全路径 -->
<!-- useGeneratedKeys="true"表示使用数据库的自动增长策略 -->
<insert
id="save"
parameterType="org.fkit.domain.User"
useGeneratedKeys="true"> insert into tb_user(name,sex,age) values(#{name},#{sex},#{age})
</insert>
</mapper>

mapper标签的namespace属性

上面的XML配置中定义了一条insert语句,详细解释如下
<mapper namespace="org.fkit.mapper.UserMapper">:
为这个mapper指定一个唯一的namespace,namespace的值习惯上设置成包名+SQL映射文件名,这样就能够保证namespace的值是唯一的,例如namespace="org.fkit.mapper.UserMapper"就是org.fkit.mapper(包名)+UserMapper(UserMapper.xml去除后缀后的文件名)

mapper标签的子标签insert详解

1
2
3
4
5
<insert
id="save"
parameterType="org.fkit.domain.User"
useGeneratedKeys="true"> insert into tb_user(name,sex,age) values(#{name},#{sex},#{age})
</insert>

id属性

insert标签中编写了SQL插入语句,设置insert标签的id属性值为saveid属性值必须是唯一的,不能够重复

parameterType属性

使用parameterType属性指明插入时使用的参数类型,属性值设置为持久化对象的全限定名

useGeneratedKeys属性

使用useGeneratedKeys="true"表示使用数据库的自动增长策略,这需要底层数据库的支持。

insert语句

insert标签中只有一条标准的insert语句,用来向tb_user表插入一条数据,#{name}表示取参数中的对象的name属性值。

mybatis-config.xml Mybatis根配置文件

对于MyBatis来说,现在还不知道需要连接哪个数据库,以及连接数据库时所用的连接池用户名密码等详细信息。这些信息对于所有的持久化类都是通用的,MyBatis把这些通用信息称为根配置信息,根配置信息需要使用配置文件指定。
MyBatis根配置文件默认被命名为mybatis-config.xml,应用程序运行时需要先加载该文件.

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
<?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">
<!-- XML 配置文件包含对 MyBatis 系统的核心设置 -->
<configuration>
<!-- 指定 MyBatis 所用日志的具体实现 -->
<settings>
<setting
name="logImpl"
value="LOG4J"/>
</settings>
<environments default="mysql">
<!-- 环境配置,即连接的数据库。 -->
<environment id="mysql">
<!-- 指定事务管理类型,type="JDBC"指直接简单使用了JDBC的提交和回滚设置 -->
<transactionManager type="JDBC"/>
<!-- dataSource指数据源配置,POOLED是JDBC连接对象的数据源连接池的实现。 -->
<dataSource type="POOLED">
<property
name="driver"
value="com.mysql.jdbc.Driver"/>
<!-- 数据库的URL -->
<property
name="url"
value="jdbc:mysql://127.0.0.1:3306/mybatis"/>
<!-- 数据库的账户 -->
<property
name="username"
value="root"/>
<!-- 数据的密码 -->
<property
name="password"
value="root"/>
</dataSource>
</environment>
</environments>
<!-- mappers告诉了MyBatis去哪里找持久化类的映射文件 -->
<mappers>
<mapper resource="org/fkit/mapper/UserMapper.xml"/>
</mappers>
</configuration>

配置文件详解

XML文件声明

MyBatis配置文件是一个XML文件,该文件第一行是XML文件声明,指定该XML文件的版本和存储该文件所用的字符集:

1
<?xml version="1.0" encoding="UTF-8" ?>

根元素 configuration

MyBatis配置文件的根元素是configuration,

settings子元素
  • 根元素configuration中有settings子元素,该元素有很多子元素,本示例只是配置了日志信息,之后可以在控制台看到输出的SQL语句,其在调试中非常有用。
environments子元素
  • 根元素configuration中还有environments子元素,用来配置MyBatis的环境,即连接的数据库,该子元素用于将SQL映射应用于多种数据库中。每个数据库对应一个SqlsessionFactory,可以配置多种环境,但只能为SqlsessionFactory实例选择一个环境,default属性表示选择的环境。
environment子元素
  • environments元素的environment子元素用于配置一个环境,
    • environmenttransactionManager子元素用来配置MyBatis当中的事务管理,JDBC属性表示直接简单使用JDBC的提交和回滚设置。
    • environment的**datasource子元素用来配置数据源**,MyBatis并不推荐采用DriverManager来连接数据库,而是推荐使用薮据源来管理数据库连接,这样能保证最好的性能。
      • datasource元素依次有很多property子元素,这些property子元素用于配置MyBatis连接数据库的必要信息,如连接数据库的驱动、URL、用户名、密码等信息

mapper子元素

  • 根元素configuration中还有mappers子元素,它可以支持多个mapper子元素,每个mapper子元素用于指定一个持久化配置文件

数据源介绍

数据源是一种用来提高数据库连接性能的常规手段,数据源会负责维持一个数据库连接池,当程序创建数据源实例时,系统会一次性地创建多个数据库连接,并把这些数据库连接保存在连接池中。当程序需要进行数据库访问时,无须重新获得数据库连接,而是从连接池中取出一个空闲的数据库连接,当程序使用数据库连接访问数据库结束后无须关闭数据库连接,而是将数据库连接归还给连接池即可。通过这种方式,就可避免频繁地获取数据库连接、关闭数据库连接所导致的性能下降

MyBatisTest.java

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
public class MyBatisTest {
public static void main(String[] args)
{
// 创建Session实例
SqlSession sqlSession = null;
try (
// 读取mybatis-config.xml文件
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");)
{
// 读取配置文件,初始化mybatis,创建SqlSessionFactory类的实例
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
sqlSession = sqlSessionFactory.openSession();
// 创建User对象
User user = new User("admin", "男", 26);
// 插入数据
sqlSession.insert("org.fkit.mapper.UserMapper.save", user);
// 提交事务
sqlSession.commit();
} catch (Exception e)
{
// 回滚事务
sqlSession.rollback();
e.printStackTrace();
} finally
{
try
{
// 关闭sqlSession
if (sqlSession != null)
sqlSession.close();
} catch (Exception e)
{
e.printStackTrace();
}
}
}
}

上面持久化操作的代码非常简单。程序先创建一个User对象,再使用SqlSessioninsert()方法来保存User对象即可,这是完全对象化的操作方式,可以说非常简单明了。当Java程序以面向对象的方式来操作持久化对象时,MyBatis负责将这种操作转换为底层SQL操作。

log4j.properties 显示执行的SQL语句

执行持久化操作之前,为了查看控制台输出的SQL语句,需要加入日志框架log4j的相关jar包,在CLASSPATH下增加一个log4.properties文件:

# 全局的日志配置
log4j.rootLogger=ERROR, stdout
# Mybatis的日志配置:追踪SQL运行结果
log4j.logger.org.fkit.mapper.UserMapper=DEBUG
# 控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] %m%n

运行效果

运行MyBatisTest类的main()方法,运行完成后,可以看到mybatis数据库中的TB_USER表中包含了User实例对应的记录,如下图所示:
这里有一张图片
控制台输出

1
2
3
DEBUG [main] ==>  Preparing: insert into tb_user(name,sex,age) values(?,?,?) 
DEBUG [main] ==> Parameters: admin(String), 男(String), 26(Integer)
DEBUG [main] <== Updates: 1

使用MyBatis持久化操作步骤

在执行sqlSession.insert("org.fkit.mapper.UserMapper.save", user);之前,先要获取SqlSession对象。PO只有在SqlSession的管理下才可完成数据库访问。为了使用MyBatis进行持久化操作,通常需要执行如下操作步骤

  1. 开发持久化类PO和编写持久化操作的Mapper.xml,在其中定义要执行的SQL语句
  2. 获取SqlSessionFactorySqlSessionFactory是数据库编译后的内存镜像,通常一个应用对应一个SqlSessionFactory对象。SqlSessionFactory对象通过加载mybatis-config.xml配置文件生成.
  3. 获取SqlSessionSqlSessionSqlSessionFactory工厂产生,对PO的操作必须在SqlSession的管理下才能同步到数据库。
  4. 用面向对象的方式操作数据库。
  5. 关闭事务,关闭SqlSession

MyBatis相较JDBC的优点

MyBatis相较JDBC有如下两个显著优点

  • 只需要在Mapper.xml配置文件中编写SQL语句,在应用程序中就可以采用PO方式来访问数据库。
  • JDBC访问过程中大量的checked异常被包装成MyBatisRuntime异常,从而不再要求程序必须处理所有异常。