曹耘豪的博客

MyBatis入门

  1. 安装
  2. 使用
    1. 配置
    2. Spring 配置代码
    3. 创建Mapper
    4. 在Spring使用
    5. 常用代码段
      1. 批量插入insertAll
    6. 相关问题
      1. if标签字符串判断相等问题
      2. 模糊查询
  3. 原理分析
    1. 启动解析
      1. XMLConfigBuilder
      2. XMLMapperBuilder
      3. XMLStatementBuilder
    2. 结果处理
  4. 涉及到的技术
  5. 涉及的设计模式
    1. 建造者模式
    2. 工厂模式
    3. 模板方法模式
    4. 组合模式
    5. 装饰者模式
    6. 适配器模式
    7. 代理模式
    8. 策略模式

安装

Gradle 引用org.mybatis:mybatis:3.5.11

引用MySQL:mysql:mysql-connector-java

使用

配置

在resouces文件夹下先新建org/mybatis文件夹,再新建mybatis-config.xml文件和config.properties文件

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
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="org/mybatis/config.properties"/> // 下面的配置可以使用${xxx}代替硬编码

<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/> // 该属性可以开启自动映射
</settings>

<typeAliases>
<typeAlias type="com.cyh.server.domain.User" alias="User"/> // 类路径,简写
</typeAliases>

<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>
<package name="com.cyh.server.db.mapper"/> // resources下的路径
</mappers>
</configuration>

config.properties如下

1
2
3
4
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis_test?useUnicode=true&characterEncoding=utf8
username=root
password=

Spring 配置代码

1
2
3
4
5
6
7
8
9
10
11
@Configuration
public class MyBatisConfiguration {

@Bean
public SqlSessionFactory sqlSessionFactory() throws IOException {
String resource = "org/mybatis/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
return new SqlSessionFactoryBuilder().build(inputStream);
}

}

创建Mapper

开始创建方法,假设我们在com.cyh.server.db.mapper下创建mapper

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface UserMapper {

User selectUser(Long id);

Long insertUser(User user);

}

// User类如下
@Data
public class User {
Long id;
String name;
String hashedPassword;
}

则需要在resources文件下,创建同路径的mapper文件:

如下:resources/com/cyh/server/db/mapper/UserMapper.xml

⚠️注意:在创建resources下的文件夹时,和创建包路径不一样,不能简单填写”com.cyh.server.db.mapper”,否则会创建一个名为”com.cyh.server.db.mapper”的文件夹,可以填”com/cyh/server/db/mapper”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?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.cyh.server.db.mapper.UserMapper">
<resultMap id="usermap" type="User"> // 这里type可以简写,因为上述的typeAliases
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="hashed_password" property="hashedPassword"/>
</resultMap>
<select id="selectUser" resultMap="usermap"> // id和方法名一样,resultMap是结果映射
select * from User where id = #{id}
</select>

<insert id="insertUser" parameterType="User" useGeneratedKeys="true" keyColumn="id" keyProperty="id"> // 使用自增id,参数的类型是实体类
INSERT INTO `user` (`id`, `name`, `hashed_password`) VALUES (#{id}, #{name}, #{hashedPassword})
</insert>
</mapper>

在Spring使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Repository
public class UserRepository {

@Autowired
private SqlSessionFactory sessionFactory;

public User findById(Long id) {
try (SqlSession session = sessionFactory.openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
return mapper.selectUser(id);
}
}

public Long addUser(User user) {
try (SqlSession session = sessionFactory.openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
Long ret = mapper.insertUser(user); // 后续提交后,user就有id了
session.commit(); // 必须commit
return ret;
}
}

}

常用代码段

批量插入insertAll

1
2
3
4
5
6
7
<insert id="insertAll" useGeneratedKeys="true" keyColumn="id" keyProperty="id" parameterType="xxx">
INSERT INTO <include refid="TableName"/>
(c1, c2)
values <foreach collection="list" item="item" separator=",">
(#{item.f1}, #{item.f2})
</foreach>
</insert>

相关问题

if标签字符串判断相等问题

1
2
3
4
5
6
<if test="a == '1'.toString()">
AND db_field != '-1'
</if>
<if test='a == "2"'>
AND db_field = '-1'
</if>

模糊查询

1
name like concat("%", #{name}, "%")

原理分析

启动解析

XMLConfigBuilder

入口: XMLConfigBuilder#parseConfiguration

XMLMapperBuilder

解析Mapper.xml文件的mapper标签内容

XMLStatementBuilder

结果处理

涉及到的技术

涉及的设计模式

建造者模式

工厂模式

模板方法模式

组合模式

装饰者模式

适配器模式

代理模式

策略模式

   /