Mybatis 入门案例
# 10.Mybatis 入门案例
本文来实现一个最简单的 Mybatis 案例。
# 创建项目
本文使用 Maven 来创建项目,项目名 LearnMybatis,并用 Git 管理,上传到了 GitHub (opens new window) 和 Gitee (opens new window) 上。
主要就是新建一个文件夹,创建对应的目录。这里我们设置打包方式为 jar,并设置源码和字节码版本为 1.8
<?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.peterjxl</groupId>
<artifactId>LearnMybatis</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 数据库准备
我们创建一个数据库 LearnMybatis,并创建如下表:
- user 表,存储用户信息
- account 表,存储每个用户的账号信息
- role 表:存储用户的角色信息
- user_role:存储用户和角色的关联信息
然后创建数据库用户 LearnMybatisUser
,配置密码为 LearnMybatisUserPassword
。
SQL 文件已存放在项目在中:src\main\resources\MybatisDB_init.sql。内容如下:
create database LearnMybatis;
use LearnMybatis;
CREATE USER IF NOT EXISTS LearnMybatisUser@'%' IDENTIFIED BY 'LearnMybatisUserPassword';
GRANT ALL PRIVILEGES ON learnmybatis.* TO LearnMybatisUser@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
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 DEFAULT CHARSET=utf8;
insert into `user`(`id`,`username`,`birthday`,`sex`,`address`) values
(41,'张三','2018-02-27 17:47:08','男','北京'),
(42,'李四','2018-03-02 15:09:37','女','北京'),
(43,'王五','2018-03-04 11:34:34','女','北京'),
(45,'赵六','2018-03-04 12:04:06','男','北京'),
(46,'小七','2018-03-07 17:37:26','男','北京'),
(48,'老八','2018-03-08 11:44:00','男','北京');
CREATE TABLE `account` (
`ID` int(11) NOT NULL COMMENT '编号',
`UID` int(11) default NULL COMMENT '用户编号',
`MONEY` double default NULL COMMENT '金额',
PRIMARY KEY (`ID`),
KEY `FK_Reference_8` (`UID`),
CONSTRAINT `FK_Reference_8` FOREIGN KEY (`UID`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into `account`(`ID`,`UID`,`MONEY`) values (1,46,1000),(2,45,1000),(3,46,2000);
CREATE TABLE `role` (
`ID` int(11) NOT NULL COMMENT '编号',
`ROLE_NAME` varchar(30) default NULL COMMENT '角色名称',
`ROLE_DESC` varchar(60) default NULL COMMENT '角色描述',
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into `role`(`ID`,`ROLE_NAME`,`ROLE_DESC`) values (1,'院长','管理整个学院'),(2,'总裁','管理整个公司'),(3,'校长','管理整个学校');
CREATE TABLE `user_role` (
`UID` int(11) NOT NULL COMMENT '用户编号',
`RID` int(11) NOT NULL COMMENT '角色编号',
PRIMARY KEY (`UID`,`RID`),
KEY `FK_Reference_10` (`RID`),
CONSTRAINT `FK_Reference_10` FOREIGN KEY (`RID`) REFERENCES `role` (`ID`),
CONSTRAINT `FK_Reference_9` FOREIGN KEY (`UID`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into `user_role`(`UID`,`RID`) values (41,1),(45,1),(41,2);
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
53
54
55
56
57
58
59
60
61
62
63
# 导入依赖
接下来,我们就要导入 Mybatis 框架所用到的依赖了:
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
2
3
4
5
注:可以通过 Mybatis 官网 (opens new window) 查看最新的版本
Mybatis 只是对 JDBC 的封装,因此我们还需 JDBC 的依赖;这里顺便将 Log4j 和 Junit 的依赖都引入:
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 创建实体类
package com.peterjxl.domain;
import java.io.Serializable;
import java.util.Date;
public class User implements Serializable {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
}
2
3
4
5
6
7
8
9
10
11
12
然后创建 getter 、setter 和 toString 方法,这里不演示了
# 创建 Dao 的接口
package com.peterjxl.dao;
import com.peterjxl.domain.User;
import java.util.List;
public interface IUserDao {
/**
* 查询所有用户
* @return
*/
List<User> findAll();
}
2
3
4
5
6
7
8
9
10
11
12
13
# 新建 Mybatis 配置文件
我们在 resources 目录下,新建 SqlMapConfig.xml,作为 Mybatis 的文件。其实 Mybatis 对配置文件名并没做要求,可自行修改。
然后我们引入约束 DTD 文件,并创建根元素 <configuration>
:
<?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>
</configuration>
2
3
4
5
6
7
# 配置数据源
然后我们就可以配置数据库连接信息了:
<?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">
<!-- Mybatis的主配置文件 -->
<configuration>
<!--配置环境-->
<environments default="mysql">
<environment id="mysql">
<!-- 配置事务的类型 -->
<transactionManager type="JDBC"/>
<!-- 配置数据源(连接池) -->
<dataSource type="POOLED">
<!-- 配置连接数据库的4个基本信息 -->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///LearnMybatis"/>
<property name="username" value="LearnMybatisUser"/>
<property name="password" value="LearnMybatisUserPassword"/>
</dataSource>
</environment>
</environments>
</configuration>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<environments>
标签里可以配置多个数据源,default 则是指定默认的数据源是哪个;
<environment>
标签里则是一个数据源的相关信息,id 则是表明该数据源的标识符,然后可以配置连接信息
# 配置映射文件
之前我们说过可以通过配置,完成实体类到数据库表的映射,这也算通过 XML 配置文件来实现的。
我们可以在 Mybatis 的配置文件里指定映射文件(mapper)的路径:
<?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">
<!-- Mybatis的主配置文件 -->
<configuration>
<!-- 省略其他信息...... -->
<mappers>
<mapper resource="com/peterjxl/dao/IUserDao.xml"/>
</mappers>
</configuration>
2
3
4
5
6
7
8
9
10
11
12
13
这里取名为 IUserDao.xml,是为了和之前的三层架构里提到的 DAO 层保持一致,在有的项目中,映射文件也叫 Mapper:IUserMapper.xml。
然后我们在 resources 目录里创建对应的文件夹和文件:
注意是三级目录结构,映射配置文件所在的目录结构,必须和 dao 接口的包结构相同。由于 resources 里的文件编译后会放到 claesses 目录下,因此最后该配置文件是和字节码文件同一个路径的,例如这是我打包后的文件结构:
引入 mapper 的约束,和创建根元素 <mapper>
:
<?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.peterjxl.dao.IUserDao">
</mapper>
2
3
4
5
6
7
namespace 属性的值,得是接口的全类名。
然后我们就可以设置 SQL 语句了:
<?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.peterjxl.dao.IUserDao">
<!-- 配置查询所有用户,id要写方法名称-->
<select id="findAll" resultType="com.peterjxl.domain.User">
select * from user
</select>
</mapper>
2
3
4
5
6
7
8
9
10
这里配置了一个 select 标签,表明是查询的 SQL,id 的属性值是接口的方法名;并且设置查询出来的结果集,是和 User 类型做映射。
# 小结
注意事项:
- 映射配置文件所在的目录结构,必须和 dao 接口的包结构相同。
- 映射配置文件中,namespace 属性的值,必须得是 dao 接口的全限定类名
- 映射配置文件中,id 属性的取指必须是 dao 接口的方法名
当我们做到上述要求后,我们就不用再写 dao 实现类了!剩下的事情就交给 Mybatis 完成。其原理就是创建代理对象,我们在讲解 Servlet 的时候有简单讲解过
# 新建日志配置文件
我们在 resources 文件夹里新建 log4j.properties 文件:
# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE
# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=d:\axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 创建测试类
我们在测试类里,完成对 Mybatis 的入门案例,步骤如下:
- 读取配置文件
- 创建 SqlSessionFactory 工厂
- 使用工厂生成 SqlSession 对象
- 使用 SqlSession 创建 Dao 接口的代理对象
- 使用代理对象执行方法
- 释放资源
package com.peterjxl.test;
import com.peterjxl.dao.IUserDao;
import com.peterjxl.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.InputStream;
import java.util.List;
public class MybatisTest {
@Test
public void helloMybatis() throws Exception{
// 1. 读取配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
// 2. 创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
// 3. 使用工厂生成SqlSession对象
SqlSession session = factory.openSession();
// 4. 使用SqlSession创建Dao接口的代理对象
IUserDao userDao = session.getMapper(IUserDao.class);
// 5. 使用代理对象执行方法
List<User> users = userDao.findAll();
for(User user : users){
System.out.println(user);
}
// 6. 释放资源
session.close();
in.close();
}
}
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
运行结果:
User{id=41, username='张三', birthday=Tue Feb 27 17:47:08 CST 2018, sex='男', address='北京'}
User{id=42, username='李四', birthday=Fri Mar 02 15:09:37 CST 2018, sex='女', address='北京'}
User{id=43, username='王五', birthday=Sun Mar 04 11:34:34 CST 2018, sex='女', address='北京'}
User{id=45, username='赵六', birthday=Sun Mar 04 12:04:06 CST 2018, sex='男', address='北京'}
User{id=46, username='小七', birthday=Wed Mar 07 17:37:26 CST 2018, sex='男', address='北京'}
User{id=48, username='老八', birthday=Thu Mar 08 11:44:00 CST 2018, sex='男', address='北京'}
2
3
4
5
6
# 测试类解读
我们来解读下测试类的代码。
首先是读取配置文件:
//1.读取配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
2
一般不用绝对路径 或者 相对路径。而是使用以下两种:
- 使用类加载器。它只能读取类路径的配置文件
- 使用 ServletContext 对象的
getRealPath()
方法
然后是创建工厂:
//2.创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
2
3
Mybatis 使用了构建者模式。
什么是构建者模式:工厂不是我们自己创建的,而是用 SqlSessionFactoryBuilder
。如果自己创建工厂类,费时费力。
举个生活中的例子,假设我们要创建一个工厂,那么首先要选址,买建筑材料,预估人工等,什么都要自己做;而我们可以买现成的建好的工厂,或者找一个包工队,让包工队帮我们干活。我们想要创建工厂类,无需自己构造工厂,只需交给 SqlSessionFactoryBuilder 即可。
生成 SqlSesion 对象,则使用了工厂模式。使用工厂模式的好处:解耦,降低类之间的依赖关系
//3.使用工厂生产SqlSession对象
SqlSession session = factory.openSession();
2
创建 Dao 接口实现类使用了代理模式。 优势:不修改源码的基础上对已有方法增强
// 4. 使用SqlSession创建Dao接口的代理对象
IUserDao userDao = session.getMapper(IUserDao.class);
//5.使用代理对象执行方法
List<User> users = userDao.findAll();
for(User user : users){
System.out.println(user);
}
//6.释放资源
session.close();
in.close();
2
3
4
5
6
7
8
9
10
11
12
可以看到,使用了 Mybatis 也有很多的步骤,要读配置文件,创建工厂,创建 Session.... 这是 Mybatis 出于灵活,才这样设计的,我们可以简化为一行代码:
//1.读取配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSession session = new SqlSessionFactoryBuilder().build(in).openSession();
//4.使用SqlSession创建Dao接口的代理对象
IUserDao userDao = session.getMapper(IUserDao.class);
//5.使用代理对象执行方法
List<User> users = userDao.findAll();
for(User user : users){
System.out.println(user);
}
//6.释放资源
session.close();
in.close();
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 总结
本文使用 Mybatis 做了一个简单的查询,步骤如下;
- 读取配置文件
- 创建 SqlSessionFactory 工厂
- 使用工厂生成 SqlSession 对象
- 使用 SqlSession 创建 Dao 接口的代理对象
- 使用代理对象执行方法
- 释放资源
虽然步骤看上去还是挺复杂,但后续使用注解后,会变的很简单,敬请期待。
本文所有代码已上传到了 GitHub (opens new window) 和 Gitee (opens new window) 上,并且创建了分支 demo1,读者可以通过切换分支来查看本文的示例代码。