MyBatis 中使用 Mapper 简化代码

Posted by 暮夏有五 on 2021-01-18
Estimated Reading Time 6 Minutes
Words 1.3k In Total
Viewed Times

前面文章所写的增删改查是存在问题的。主要问题就是冗余代码过多,模板化代码过多。

例如,我想开发一个 UserDao,可能是下面这样。此时,我们分析这个 UserDao,发现它有很多可以优化的地方。每个方法中都要获取 SqlSession,涉及到增删改的方法,还需要 commit,SqlSession 用完之后,还需要关闭,sqlSession 执行时需要的参数就是方法的参数,sqlSession 要执行的 SQL ,和 XML 中的定义是一一对应的。这是一个模板化程度很高的代码。

简化前的 UserDao.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
38
39
40
41
42
43
44
45
46
47
48
49
50
public class UserDao {

private SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getInstance();

public User getUserById(Integer id) {
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = (User) sqlSession.selectOne("com.antonio.hello.mybatis.mapper.UserDao.getUserById", id);
sqlSession.close();
return user;
}

public Integer addUser(User user) {
SqlSession sqlSession = sqlSessionFactory.openSession();
int insert = sqlSession.insert("com.antonio.hello.mybatis.mapper.UserDao.addUser", user);
sqlSession.commit();
sqlSession.close();
return insert;
}

public Integer addUser2(User user) {
SqlSession sqlSession = sqlSessionFactory.openSession();
int insert = sqlSession.insert("com.antonio.hello.mybatis.mapper.UserDao.addUser2", user);
sqlSession.commit();
sqlSession.close();
return insert;
}

public Integer deleteUserById(Integer id) {
SqlSession sqlSession = sqlSessionFactory.openSession();
int delete = sqlSession.delete("com.antonio.hello.mybatis.mapper.UserDao.deleteUserById", id);
sqlSession.commit();
sqlSession.close();
return delete;
}

public Integer updateUser(User user) {
SqlSession sqlSession = sqlSessionFactory.openSession();
int delete = sqlSession.delete("com.antonio.hello.mybatis.mapper.UserDao.updateUser", user);
sqlSession.commit();
sqlSession.close();
return delete;
}

public List<User> getAllUser() {
SqlSession sqlSession = sqlSessionFactory.openSession();
List<User> users = sqlSession.selectList("com.antonio.hello.mybatis.mapper.UserDao.getAllUser");
sqlSession.close();
return users;
}
}

对应的 UserMapper.xml


然后,和这个 UserDao 对应的,还有一个 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
<?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.antonio.hello.mybatis.mapper.UserDao">

<select id="getUserById" resultType="com.antonio.hello.mybatis.entity.User">
select * from user where id=#{id};
</select>

<insert id="addUser" parameterType="com.antonio.hello.mybatis.entity.User">
insert into user (username,address) values (#{username},#{address});
</insert>

<insert id="addUser2" parameterType="com.antonio.hello.mybatis.entity.User">
<selectKey resultType="java.lang.String" keyProperty="id" order="BEFORE">
select uuid();
</selectKey>
insert into user (id,username,address) values (#{id},#{username},#{address});
</insert>

<delete id="deleteUserById" parameterType="java.lang.Integer">
delete from user where id=#{id}
</delete>

<update id="updateUser" parameterType="com.antonio.hello.mybatis.entity.User">
update user set username = #{username} where id=#{id};
</update>

<select id="getAllUser" resultType="com.antonio.hello.mybatis.entity.User">
select * from user;
</select>
</mapper>

简化后的 UserDao.java


既然模板化程度很高,我们就要去解决它,原理很简单,就是前面 Spring 中所说的动态代理。我们可以将 UserDao 简化成一个接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.antonio.hello.mybatis.mapper;

public interface UserDao {

User getUserById(Integer id);

Integer addUser(User user);

Integer addUser2(User user);

Integer deleteUserById(Integer id);

Integer updateUser(User user);

List<User> getAllUser();
}

使用这个接口,完全可以代替上面的 UserDao,为什么呢?因为这个接口提供了 UserDao 所需要的最核心的东西,根据这个接口,就可以自动生成 UserDao:

  • 首先,UserDao 中定义了 SqlSessionFactory,这是一套固定的代码
  • UserMapper 所在的包 + UserMapper 类名 + UserMapper 中定义好的方法名,就可以定位到要调用的 SQL
  • 要调用 SqlSession 中的哪个方法,根据定位到的 SQL 节点就能确定

配置并使用


因此,我们在 MyBatis 开发中,实际上不需要自己提供 UserDao 的实现,我们只需要提供一个 UserMapper 即可。然后,我们在 MyBatis 的全局配置中,配置一下 UserMapper:

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 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:///test01?serverTimezone=Asia/Shanghai"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>

<mappers>
<package name="com.antonio.hello.mybatis.mapper"/>
</mappers>
</configuration>

然后,加载配置文件,获取 UserMapper,并调用它里边的方法:

1
2
3
4
5
6
7
8
9
public class Main2 {
public static void main(String[] args) {
SqlSessionFactory instance = SqlSessionFactoryUtils.getInstance();
SqlSession sqlSession = instance.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> allUser = mapper.getAllUser();
System.out.println(allUser);
}
}

注意,在 Maven 中,默认情况下,Maven 要求我们将 XML 配置、properties 配置等,都放在 resources 目录下,如果我们强行放在 java 目录下,默认情况下,打包的时候这个配置文件会被自动忽略掉。对于这两个问题,我们有两种解决办法:

不忽略 XML 配置:

我们可以在 pom.xml 中,添加如下配置,让 Maven 不要忽略我在 java 目录下的 XML 配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
</build>

按照 Maven 的要求来

按照 Maven 的要求来,将 xml 文件放到 resources 目录下,但是,MyBatis 中默认情况下要求,UserMapper.xml 和 UserMapper 接口,必须放在一起,所以,我们需要手动在 resources 目录下,创建一个和 UserMapper 接口相同的目录存放 UserMapper.xml。这样,我们就不需要在 pom.xml 文件中添加配置了,因为这种写法同时满足了 Maven 和 MyBatis 的要求。

更多干货请移步:https://antoniopeng.com


If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them. Thank you !