MyBatis笔记(1)-MyBatis快速开始

快速开始

简介

MyBatis最初来源于Apache的开源项目iBatis,后续迁移到Google之后,更名为MyBatis,在后续的包名中,我们还可以看到iBatis的踪迹。

MyBatis是一个基于Java的持久层框架,它支持定制化SQL,存储过程以及高级映射。它避免了几乎所有的JDBC代码,手动拼接参数,结果集获取等操作,而是使用简单的XML或者注解来对应配置和映射,将接口与Java中的普通Java对象(Plain Old Java Objects)映射成数据库中的记录。

MyBatis的下载地址在此:mybatis/mybatis-3: MyBatis SQL mapper framework for Java (github.com)

持久层技术除了MyBatis还有很多,各个框架各有特点。

  • 对于JDBC,SQL会夹杂在Java代码中,导致耦合度高,维护不方便,需要频繁修改源代码;并且代码冗长,开发效率低
  • 对于Hibernate和JPA,它的操作简便,开发效率高,但是程序中无法直接使用复杂的SQL,并且内部自动产生的SQL不容易做特殊优化。这是一个基于全映射的全自动框架,如果一个实体类有大量字段,在进行映射的时候会比较困难,并且其中反射操作太多,会导致数据库性能下降
  • 对于MyBatis,它是一个轻量级,性能出色的持久层框架,在其中SQL与Java代码分离,分工明确。Java代码专注业务,SQL语句专注数据逻辑。虽然开发效率稍低于Hibernate,但是在接受范围内

入门案例

下面我们通过一个入门案例来快速学习MyBatis的使用。其中部分配置文件的内容可以参考:入门_MyBatis中文网

首先我们准备相关的数据库测试环境。这里我们在本地的MySQL数据库中创建一个表格users,其中的字段分别有idusernamepasswordagegenderemail

之后我们来添加相关依赖,除了MyBaits的依赖项,还包括其他一些相关的辅助依赖,需要注意的是这些依赖并不是MyBaits必须的,而是方便我们进行项目的开发。依赖项如下:

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
<!--MyBatis核心-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!--Junit测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!--MySQL驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<!--log4j日志-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>

其中log4j日志的使用还需要配合配置文件log4j.xml。我们需要将配置文件放在resources目录下,其中的内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?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>

在实际使用MyBatis之前,我们先简单了解一下它的工作原理。对于持久层,我们希望它能够完成通过Java语言来操作数据库,包括增删该查操作,同时关联Java对象与数据库中的表,同时完成SQL语句的查询。

在MyBatis中,一个实体类对应一张表,类的属性对应表的不同字段,表中的一行数据对应实体类的对象。我们需要两个重要的配置文件,一个是核心配置文件,用来准备数据库连接环境所需要的相关信息,另一个是映射文件。在MyBatis中,我们期望的操作通过Mapper接口的形式来提供,我们需要创建Mapper接口,在接口中声明我们需要的操作,然后一个Mapper接口对应一个映射文件,在映射文件中,我们会给接口的每一个方法准备对应的SQL语句,这样就实现了SQL语句与Java代码的分离。在Java代码中,MyBatis会为我们的接口生成对应的实现类,在调用接口中的方法时,MyBatis会找到映射文件中对应的SQL语句进行执行,并将结果返回。

那么我们先创建核心配置文件,在官方文档中提供了如下模板。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?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="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>

我们对其进行相应的修改,主要修改驱动类、连接、用户名、密码等。这里映射文件引入路径与实际情况有关。

注意这里的核心配置文件的名称没有强制要求,我们习惯上将其命名为mybaits-config.xml。核心配置文件主要用于配置连接数据库的环境以及MyBatis的全局配置信息,存放位置为resources目录。

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 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.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/ssm_data"/>
<property name="username" value="root"/>
<property name="password" value="123123"/>
</dataSource>
</environment>
</environments>
<!--引入映射文件-->
<mappers>
<mapper resource="mappers/UserMapper.xml"/>
</mappers>
</configuration>

前面我们提到,在MyBatis中,数据库中的一张表会对应一个实体类,同时会对应一个Mapper接口,而一个Mapper接口又会对应一个映射文件,那么接下来我们就要完成这些资源的准备。

先创建对应的实体类,这里我们的表为user,可以创建一个实体类User,其中的属性就是表中的字段。将实体类中的相关方法都进行实现,包括无参构造,有参构造,属性的getter和setter方法,toString方法等。

之后创建Mapper接口。在接口中,我们声明的方法后续都可以进行使用。这里我们声明一个insert方法,用于向表格中插入一条记录。

1
2
3
public interface UserMapper {
int insertUser();
}

然后我们需要创建映射文件,映射文件也放在resources目录下。我们同样可以参考官方文档中映射文件的书写方式:

1
2
3
4
5
6
7
8
9
<?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="org.mybatis.example.BlogMapper">
<select id="selectBlog" resultType="Blog">
select * from Blog where id = #{id}
</select>
</mapper>

在映射文件中,我们需要先指定其中的namespace,这表示该映射文件与哪个Mapper接口对应。然后,我们需要指定每个接口方法对应的SQL语句,例如这里的接口中的insertUser方法,它对应的SQL语句如下所示,使用了insert标签进行包裹,并且标签的id属性指定为insertUser。

1
2
3
4
5
6
7
8
9
10
<?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.syh.mapper.UserMapper">
<!--int insertUser()-->
<insert id="insertUser">
insert into users values(null, 'admin', '123123', 18, '女', '123456@haha.com')
</insert>
</mapper>

一般情况下,我们将映射文件命名为表所对应的实体类类名+Mapper.xml,表示一个映射文件对应一个实体类,对应一张表的操作。

MyBatis中可以面向接口操作数据,但是其中要保证两个一致:

  1. Mapper接口中的全类名和映射文件的namespace保持一致
  2. Mapper接口中方法的方法名和映射文件中编写SQL的标签的id属性保持一致

至此,我们就已经做好了准备工作,可以书写方法进行测试。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 读取MyBatis的核心配置文件
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
// 创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 获得SqlSessionFactory
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
// 创建SqlSession对象
// 如果使用无参构造,则需要进行事务的手动提交和回滚
// 如果使用带参构造,给定true则表示自动事务提交
SqlSession sqlSession = sqlSessionFactory.openSession(true);
// 通过代理模式创建UserMapper接口的代理实现类对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 调用接口中的方法,这样就可以通过全类名找到映射文件,通过方法名匹配SQL标签,执行标签中的SQL语句
int result = userMapper.insertUser();
// sqlSession.commit();
System.out.println("result: " + result);

其他操作

上面我们提供了简单的插入操作,当然我们还可以提供其他简单的增删查改的操作。增加操作的时候,需要在接口中声明对应的方法,同时在映射文件中指定对应的标签以及标签内的SQL语句。

在接口中分别增加删除操作、修改操作、查询一行以及查询多行的操作:

1
2
3
4
5
6
7
8
9
10
11
public interface UserMapper {
int insertUser(); // 增加一条记录

int deleteUser(); // 删除一条记录

int updateUser(); // 更新一条记录

User getUser(); // 查询一条记录

List<User> getUserList(); // 查询多条记录
}

映射文件中需要提供对应的SQL语句,内容如下:

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
<mapper namespace="com.syh.mapper.UserMapper">
<!--int insertUser()-->
<insert id="insertUser">
insert into users
values (null, 'admin', '123123', 18, '女', '123456@haha.com')
</insert>
<!-- int deleteUser()-->
<delete id="deleteUser">
delete
from users
where id = 1
</delete>
<!-- int updateUser()-->
<update id="updateUser">
update users
set password = 'normal'
where username = 'normal'
</update>
<!-- User getUser()-->
<select id="getUser" resultType="com.syh.bean.User">
select *
from users
where id = 3
</select>
<!-- List<User> getUserList()-->
<select id="getUserList" resultType="com.syh.bean.User">
select *
from users
</select>
</mapper>

在查询操作select中,我们需要指定属性resultType或者resultMap,用来设置实体类和数据库表中记录的映射关系。两种映射只能设置其中一种:

  • resultType:设置结果类型,即处理的数据要转换为的Java类型(一行数据需要转化为的类型)

  • resultMap:自定义映射,处理多对一或一对多的映射关系,或字段名和属性名不一致的情况

核心配置文件

在入门案例中,我们使用的核心配置文件中只有一些最基本的内容,完整的核心配置文件,其中还提供了其他相关的标签,这里进行相关说明。

在核心配置文件中提供有多种标签,但是这些标签必须按照固定的顺序进行书写,具体顺序如下:propertiessettingstypeAliasestypeHandlersobjectFactoryobjectWrapperFactoryreflectorFactorypluginsenvironmentsdatabaseIdProvidermappers。这里先介绍一些常见的标签,其他标签后续使用到的时候再进行介绍。

properties

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

properties标签允许我们引入配置文件。在引入过后,properties文件中的值可以在核心配置文件中进行使用,使用${key}的方式来访问value。

typeAliases

1
2
3
4
5
<typeAliases>
<typeAlias type="com.syh.bean.User" alias="abc"></typeAlias>
<typeAlias type="com.syh.bean.User"></typeAlias>
<package name="com.syh.bean"/>
</typeAliases>

typeAlias标签允许我们设置类型的别名。

基本的使用方式是在type中提供需要设置别名的类型,同时在alias中提供别名。如果不设置该属性,则该类型会使用默认的别名,即该类型的类名,这里默认的别名就是User,不过类名不区分大小写。

另一种方式是以包的形式引入别名,在name中提供包的路径。该包下的所有类型都会被设置默认的类型别名,即类名且不区分大小写

environments

1
2
3
4
5
6
7
8
9
10
11
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>

environments标签中会配置项目的环境,其中可以配置多个环境,但是生效的只会有一个,由default属性来指定。

具体的环境由标签environment来指定。在该标签中,我们需要设置事务管理方式以及数据源。

事务管理方式对应标签transactionManager,其中的需要提供type属性。type属性只有两个可选值,分别是JDBC和MANAGED:

  • JDBC:表示当前环境中,执行SQL时使用的是JDBC中原生的事务管理方式,事务的提交或者回滚需要手动处理
  • MANAGED:表示MyBatis被管理,例如Spring等

数据源的配置对应标签dataSource,其中需要提供数据源的属性type,可选值有POOLED、UNPOOLED以及JNDI:

  • POOLED:表示使用数据库连接池来缓存数据库连接
  • UNPOOLED:表示不使用数据库连接池
  • JNDI:表示使用上下文中的数据源

同时数据源中还需要配置连接数据库的驱动、连接地址、用户名和密码等。

mappers

1
2
3
4
<mappers>
<mapper resource="mappers/UserMapper.xml"/>
<package name="com.syh.mapper"/>
</mappers>

mappers标签中引入对应的映射文件。我们可以通过mapper标签的方式引入单个映射文件,在resource属性中指定对应的路径。另一种方式是以包为单位引入映射文件,使用package标签。引入后,包下所有的映射文件都会被引入,不过使用包引入需要满足下面的要求:

  1. Mapper接口所在的包要和映射文件所在的包一致
  2. Mapper接口要和映射文件的名称一致

所在的包一致,即目录结构相同。在IDEA中,则表现为在resouces目录下创建对应的目录结构来存放映射文件。在项目加载之后,java目录和resources目录下的内容会被放在同一个目录下。


MyBatis笔记(1)-MyBatis快速开始
http://example.com/2022/10/09/MyBatis笔记-1-MyBatis快速开始/
作者
EverNorif
发布于
2022年10月9日
许可协议