9.4 深入Mapper XML映射文件 示例 测试select,insert,update和delete操作

9.4 深入Mapper XML映射文件 示例 测试select,insert,update和delete操作

本示例直接使用第8章创建的TB_USER表,数据库脚本,User.javalog4j.xml,具体请参考第8章内容,此处不再赘述。
在实际项目开发中,连接数据库的参数信息不会直接写在mybatis-config.xml中,而是通过一个properties文件来定义连接数据库的参数信息,并在mybatis-config.xml中引用。

项目结构

展开/折叠
D:\Desktop\随书源码\Spring+Mybatis企业应用实战(第2版)\codes\09\DMLTest
├─src\
│ ├─db.properties
│ ├─log4j.xml
│ ├─mybatis-config.xml
│ └─org\
│   └─fkit\
│     ├─domain\
│     │ └─User.java
│     ├─factory\
│     │ └─FKSqlSessionFactory.java
│     ├─mapper\
│     │ └─UserMapper.xml
│     └─test\
│       ├─DeleteTest.java
│       ├─InsertTest.java
│       ├─SelectTest.java
│       └─UpadeTest.java
└─WebContent\
  ├─META-INF\
  │ └─MANIFEST.MF
  └─WEB-INF\
    ├─lib\
    │ ├─ant-1.9.6.jar
    │ ├─ant-launcher-1.9.6.jar
    │ ├─asm-5.2.jar
    │ ├─cglib-3.2.5.jar
    │ ├─commons-logging-1.2.jar
    │ ├─javassist-3.22.0-CR2.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
    │ ├─ognl-3.1.15.jar
    │ ├─slf4j-api-1.7.25.jar
    │ └─slf4j-log4j12-1.7.25.jar
    └─web.xml

db.properties

1
2
3
4
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/mybatis
username=root
password=root

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
43
44
45
46
47
48
49
50
<?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>
<!-- 引入properties资源文件,以便后面使用 -->
<properties resource="db.properties"/>
<!-- 指定 MyBatis 所用日志的具体实现 -->
<settings>
<setting
name="logImpl"
value="LOG4J"/>
</settings>
<!-- 设置别名 -->
<typeAliases>
<typeAlias
alias="user"
type="org.fkit.domain.User"/>
</typeAliases>
<!-- 环境配置,即连接的数据库。 -->
<environments default="mysql">
<environment id="mysql">
<!-- 指定事务管理类型,type="JDBC"指直接简单使用了JDBC的提交和回滚设置 -->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!-- 使用配置文件db.properties中设置的driver属性值给该driver属性赋值 -->
<property
name="driver"
value="${driver}"/>
<!-- 使用配置文件db.properties中设置的url属性值给该url属性赋值 -->
<property
name="url"
value="${url}"/>
<!-- 使用配置文件db.properties中设置的username属性值给该username属性赋值 -->
<property
name="username"
value="${username}"/>
<!-- 使用配置文件db.properties中设置的password属性值给该password属性赋值 -->
<property
name="password"
value="${password}"/>
</dataSource>
</environment>
</environments>
<!-- mappers告诉了MyBatis去哪里找持久化类的映射文件 -->
<mappers>
<mapper resource="org/fkit/mapper/UserMapper.xml"/>
</mappers>
</configuration>

引入properties配置文件

mybatis-config.xml中的

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

配置表示引入db.properties资源配置文件,

1
2
3
<property
name="driver"
value="${driver}"/>

引用properties配置文件中的值

表示driver的值引用db.properties文件中的名称为driver的值com.mysql.jdbc.Driver
同理:

1
2
3
${url}
${username}
${password}

引用db.properties文件中对应的url,usernamepassword的值。

UserMapper.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
<?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">
<!-- insert操,
parameterType="user"表示该插入语句需要一个user对象作为参数
useGeneratedKeys="true"表示使用自动增长的主键 -->
<insert
id="saveUser"
parameterType="user"
useGeneratedKeys="true"
keyProperty="id"> insert into tb_user(name,sex,age) values(#{name},#{sex},#{age})
</insert>
<!-- select操作
parameterType="int"表示该查询语句需要一个int类型的参数
resultType="user"表示返回的是一个user对象 -->
<select
id="selectUser"
parameterType="int"
resultType="user"> select * from tb_user where id = #{id}
</select>
<!-- update操作
parameterType="user"表示该更新语句需要一个user对象作为参数 -->
<update
id="modifyUser"
parameterType="user"> update tb_user set name = #{name},sex = #{sex},age = #{age} where id = #{id}
</update>
<!-- delete操作 parameterType="int"表示该查询语句需要一个int类型的参数 -->
<delete
id="removeUser"
parameterType="int"> delete from tb_user where id = #{id}
</delete>
</mapper>

UserMapper.xml中定义了insertupdatedeleteselect4个元素,分别对应插入、更新、删除和查询4个数据库操作。

FKSqlSessionFactory.java

因为每次测试都需要读取mybatis-config.xml根配置文件,根据根配置文件信息创建SqlSessionFactory对象,再获取Sqlsession对象,使得该操作比较频繁,所以开发一个FKSqlSessionFactory工厂类封装以上操作的重复代码。

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
package org.fkit.factory;

import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class FKSqlSessionFactory
{
private static SqlSessionFactory sqlSessionFactory = null;

// 初始化创建SqlSessionFactory对象
static
{
try (// 读取mybatis-config.xml文件
InputStream is = Resources
.getResourceAsStream("mybatis-config.xml"))
{
// 创建SqlSessionFactory实例
sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
} catch (Exception e)
{
e.printStackTrace();
}
}

// 获取SqlSession对象的静态方法
public static SqlSession getSqlSession()
{
return sqlSessionFactory.openSession();
}

// 获取SqlSessionFactory的静态方法
public static SqlSessionFactory getSqlSessionFactory()
{
return sqlSessionFactory;
}
}

测试insert标签

InsertTest.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
public class InsertTest {
public static void main(String[] args)
{
// 定义SqlSession变量
SqlSession sqlSession = null;
try
{
// 1.创建SqlSession实例
sqlSession = FKSqlSessionFactory.getSqlSession();
// 2.创建User对象
User user = new User("jack", "男", 22);
// 3.插入数据
sqlSession.insert("org.fkit.mapper.UserMapper.saveUser", user);
// 4.提交事务
sqlSession.commit();
} catch (Exception e)
{
// 回滚事务
sqlSession.rollback();
e.printStackTrace();
} finally
{
// 关闭SqlSession
if (sqlSession != null)
sqlSession.close();
}
}
}

运行InsertTest类的main方法,创建User对象,并将User对象作为参数调sqlSessioninsert方法,

Mybatis如何找到要执行的SQL语句

insert方法的第一个参数是org.fkit.mapper.UserMapper.saveUser,MyBatis会找到org.fkit.mapper.UserMapper命名空间下id="saveUser"元素,执行该元素中的SQL语句。

1
2
3
4
5
6
7
8
9
10
11
<mapper namespace="org.fkit.mapper.UserMapper">
......
<insert
id="saveUser"
parameterType="user"
useGeneratedKeys="true"
keyProperty="id">
insert into tb_user(name,sex,age) values(#{name},#{sex},#{age})
</insert>
......
</mapper>

insert元素属性解释

insert元素的属性:

  • parameterType="user"表示该插入语句需要一个User对象作为参数
  • useGeneratedKeys="true"表示使用数据库的自动增长的主键,该操作需要底层数据库的支持;
  • keyProperty="id"表示将插入数据生成的主键设置到user对象的id当中。

MyBatis表达式

insert元素中的SQL语句是一条标准的insert into语句,需要注意的是,#{name}使用了MyBatis的表达式,其会查找参数user当中的name属性作为值,并将该值设置到SQL语句中;如果传入的参数是一个Map,则会以name作为key查找Map当中的值,并将该值设置到SQL语句中#{sex}#{age}#{name}操作相同.
运行InsertTest类的main方法,将会插入一条数据到数据库当中。控制台结果如下所示:

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

插入数据后数据库表中的数据如下图所示:
这里有一张图片

测试select标签

SelectTest.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
public class SelectTest {
public static void main(String[] args)
{
// 定义SqlSession变量
SqlSession sqlSession = null;
try
{
// 1.创建SqlSession实例
sqlSession = FKSqlSessionFactory.getSqlSession();
// 2.根据id查询User对象
User user = sqlSession.selectOne("org.fkit.mapper.UserMapper.selectUser", 1);
System.out.println(user);
// 3.提交事务
sqlSession.commit();
} catch (Exception e)
{
// 4.回滚事务
sqlSession.rollback();
e.printStackTrace();
} finally
{
// 5.关闭SqlSession
if (sqlSession != null)
sqlSession.close();
}
}
}

如何找到要执行的SQL语句

运行SelectTest类的main方法,调用SqlSessionselectOne方法, selectOne方法的第个参数是org.fkit.mapper.UserMapper.selectUser, MyBatis会找到org.fkit.mapper.UserMapper命名空间下id="selectUser"的元素,执行该元素中的SQL语句:

1
2
3
4
5
6
7
8
9
10
<mapper namespace="org.fkit.mapper.UserMapper">
......
<select
id="selectUser"
parameterType="int"
resultType="user">
select * from tb_user where id = #{id}
</select>
......
</mapper>

属性解释

select元素中的

  • parameterType="int"表示该插入新语句需要一个int类型的值作为参数;
  • resultType="user"表示该条查询语句需要返回一个User对象。
  • 元素中的SQL语句是一条标准的select语句,该语句需要的参数id的值,就是我们是调用时传入的int值。

运行效果

运行SelectTest类的main方法,程序将会到数据库当中查询id为1的一条数据并封装成User类型的对象返回。控制台结果如下所示:

1
2
3
4
DEBUG [main] ==>  Preparing: select * from tb_user where id = ? 
DEBUG [main] ==> Parameters: 1(Integer)
DEBUG [main] <== Total: 1
User [id=1, name=admin, sex=男, age=26]

测试update元素

UpadeTest.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
public class UpadeTest {
public static void main(String[] args)
{
// 定义SqlSession变量
SqlSession sqlSession = null;
try
{
// 1.创建SqlSession实例
sqlSession = FKSqlSessionFactory.getSqlSession();
// 2.根据id查询User对象
User user = sqlSession.selectOne("org.fkit.mapper.UserMapper.selectUser", 1);
// 3.修改User对象的属性值
user.setName("tom");
user.setAge(25);
// 4.修改User对象
sqlSession.update("org.fkit.mapper.UserMapper.modifyUser", user);
// 5.提交事务
sqlSession.commit();
} catch (Exception e)
{
// 6.回滚事务
sqlSession.rollback();
e.printStackTrace();
} finally
{
// 关闭SqlSession
if (sqlSession != null)
sqlSession.close();
}
}
}

运行UpdateTest类的main方法,首先调用SqlSessionselectOne方法,查询出id1的数据返回给User对象。接下来修改该User对象的属性值,最后调用SqlSessionupdate方法修改该User对象。update方法的第一个参数是org.fkit.mapper.UserMapper.modifyUser,MyBatis会找到org.fkit.mapper.UserMapper命名空间下id="modifyUser"的元素,执行该元素中的SQL语句。

1
2
3
4
5
6
7
8
9
<mapper namespace="org.fkit.mapper.UserMapper">
......
<update
id="modifyUser"
parameterType="user">
update tb_user set name = #{name},sex = #{sex},age=#{age} where id = #{id}
</update>
......
</mapper>
  • update元素的属性:parameterType="user"表示该更新语句需要一个User对象作为参数。
  • update元素中的SQL语句是一条标准的update语句,该语句根据传入的User对象的属性更新表数据。

运行效果

运行UpdateTest类的main方法,我们将会看到数据库中的更新数据。控制台结果如下所示:

1
2
3
4
5
6
DEBUG [main] ==>  Preparing: select * from tb_user where id = ? 
DEBUG [main] ==> Parameters: 1(Integer)
DEBUG [main] <== Total: 1
DEBUG [main] ==> Preparing: update tb_user set name = ?,sex = ?,age = ? where id = ?
DEBUG [main] ==> Parameters: tom(String), 男(String), 25(Integer), 1(Integer)
DEBUG [main] <== Updates: 1

更新数据后数据库表数据如下图所示:
这里有一张图片

测试delete元素

DeleteTest.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
public class DeleteTest {
public static void main(String[] args)
{
// 定义SqlSession变量
SqlSession sqlSession = null;
try
{
// 1.创建SqlSession实例
sqlSession = FKSqlSessionFactory.getSqlSession();
// 2.删除id为1的User对象
sqlSession.delete("org.fkit.mapper.UserMapper.removeUser", 1);
// 3.提交事务
sqlSession.commit();
} catch (Exception e)
{
// 4.回滚事务
sqlSession.rollback();
e.printStackTrace();
} finally
{
// 5.关闭SqlSession
if (sqlSession != null)
sqlSession.close();
}
}
}

运行DeleteTest类的main方法,调用SqlSessiondelete方法。
delete方法的第一个参数是org.fkit.mapper.UserMapper.removeUser,MyBatis会找到org.fkit.mapper.UserMapper命名空间下的 id="removeUser"的元素,执行该元素中的SQL语句:

1
2
3
4
5
6
7
8
<mapper namespace="org.fkit.mapper.UserMapper">
......
<delete
id="removeUser"
parameterType="int"> delete from tb_user where id = #{id}
</delete>
......
</mapper>
  • delete元素中的parameterType="int"表示该删除语句需要一个int类型的值作为参数。
  • 元素中的SQL语句是一条标准的delete语句,该语句需要的参数id值是调用时传入的int值。

运行结果

1
2
3
DEBUG [main] ==>  Preparing: delete from tb_user where id = ? 
DEBUG [main] ==> Parameters: 1(Integer)
DEBUG [main] <== Updates: 1

删除后数据库表数据如下图所示:

image-20220814180400264