对象关系映射模型Hibernate。用来实现非常轻量级的对象的封装。将对象与数据库建立映射关系。实现增删查改。
MyBatis与Hibernate非常相似。对象关系映射模型ORG。java对象与关系数据库映射的模型。

1 配置MyBatis

最佳实践

最佳实战:
● 引入mybatis-starter
● 配置application.yaml中,指定mapper-location位置即可
● 编写Mapper接口并标注@Mapper注解
● 简单方法直接注解方式
● 复杂方法编写mapper.xml进行绑定映射
● @MapperScan(“com.atguigu.admin.mapper”) 简化,其他的接口就可以不用标注@Mapper注解

添加MyBatis依赖

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>

配置数据库连接

在application.properties中配置mysql的链接配置

1
2
3
4
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

创建数据表

1
2
3
4
5
6
CREATE TABLE `User` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(100) COLLATE utf8mb4_general_ci DEFAULT NULL,
`age` int DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci

创建java对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Data
@NoArgsConstructor
public class User {

private Long id;

private String name;
private Integer age;

public User(String name, Integer age) {
this.name = name;
this.age = age;
}
}

MyBatis参数传递

使用@Param参数传递

1
2
@Insert("INSERT INTO USER(NAME, AGE) VALUES(#{name}, #{age})")
int insert(@Param("name") String name, @Param("age") Integer age);

使用map 传递参数

1
2
3
4
5
6
7
@Insert("INSERT INTO USER(NAME, AGE) VALUES(#{name,jdbcType=VARCHAR}, #{age,jdbcType=INTEGER})")
int insertByMap(Map<String, Object> map);
//调用
Map<String, Object> map = new HashMap<>();
map.put("name", "CCC");
map.put("age", 40);
userMapper.insertByMap(map);

使用普通java对象

1
2
@Insert("INSERT INTO USER(NAME, AGE) VALUES(#{name}, #{age})")
int insertByUser(User user);

2注解模式

创建数据表的操作接口

1
2
3
4
5
6
7
8
9
10
@Mapper
public interface UserMapper {

@Select("SELECT * FROM USER WHERE NAME = #{name}")
User findByName(@Param("name") String name);

@Insert("INSERT INTO USER(NAME, AGE) VALUES(#{name}, #{age})")
int insert(@Param("name") String name, @Param("age") Integer age);

}

增删改查操作

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

@Select("SELECT * FROM user WHERE name = #{name}")
User findByName(@Param("name") String name);

@Insert("INSERT INTO user(name, age) VALUES(#{name}, #{age})")
int insert(@Param("name") String name, @Param("age") Integer age);

@Update("UPDATE user SET age=#{age} WHERE name=#{name}")
void update(User user);

@Delete("DELETE FROM user WHERE id =#{id}")
void delete(Long id);
}

对增删查改的调用

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
@Transactional
@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTests {

@Autowired
private UserMapper userMapper;

@Test
@Rollback
public void testUserMapper() throws Exception {
// insert一条数据,并select出来验证
userMapper.insert("AAA", 20);
User u = userMapper.findByName("AAA");
Assert.assertEquals(20, u.getAge().intValue());
// update一条数据,并select出来验证
u.setAge(30);
userMapper.update(u);
u = userMapper.findByName("AAA");
Assert.assertEquals(30, u.getAge().intValue());
// 删除这条数据,并select验证
userMapper.delete(u.getId());
u = userMapper.findByName("AAA");
Assert.assertEquals(null, u);
}
}

3 XML方式

创建Mapper文件

在应用主类中增加mapper的扫描包配置:

1
2
3
4
5
6
7
8
9
@MapperScan("com.didispace.chapter36.mapper")
@SpringBootApplication
public class Chapter36Application {

public static void main(String[] args) {
SpringApplication.run(Chapter36Application.class, args);
}

}

Mapper包下创建User表

1
2
3
4
5
6
7
public interface UserMapper {

User findByName(@Param("name") String name);

int insert(@Param("name") String name, @Param("age") Integer age);

}

在配置文件中通过mybatis.mapper-locations参数指定xml配置的位置

1
mybatis.mapper-locations=classpath:mapper/*.xml

xml配置目录下创建User表的mapper配置

1
2
3
4
5
6
7
8
9
10
11
12
13
<?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.didispace.chapter36.mapper.UserMapper">
<select id="findByName" resultType="com.didispace.chapter36.entity.User">
SELECT * FROM USER WHERE NAME = #{name}
</select>

<insert id="insert">
INSERT INTO USER(NAME, AGE) VALUES(#{name}, #{age})
</insert>
</mapper>

对xml方式进行调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class Chapter36ApplicationTests {

@Autowired
private UserMapper userMapper;

@Test
@Rollback
public void test() throws Exception {
userMapper.insert("AAA", 20);
User u = userMapper.findByName("AAA");
Assert.assertEquals(20, u.getAge().intValue());
}

}

4 MyBatis-Plus

什么是MyBatis-Plus

MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
mybatis plus 官网
建议安装 MybatisX 插件

  • 通用Mapper能力
  • 增强单表查询能力
  • 多种主键策略,支持UUID和雪花算法
  • 基础代码生成器
  • 乐观锁

引入

1
2
3
4
5
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>

自动配置

● MybatisPlusAutoConfiguration 配置类,MybatisPlusProperties 配置项绑定。mybatis-plus:xxx 就是对mybatis-plus的定制
● SqlSessionFactory 自动配置好。底层是容器中默认的数据源
● mapperLocations 自动配置好的。有默认值。classpath*:/mapper/**/*.xml;任意包的类路径下的所有mapper文件夹下任意路径下的所有xml都是sql映射文件。 建议以后sql映射文件,放在 mapper下
● 容器中也自动配置好了 SqlSessionTemplate
● @Mapper 标注的接口也会被自动扫描;建议直接 @MapperScan(“com.atguigu.admin.mapper”) 批量扫描就行

优点

优点:
● 只需要我们的Mapper继承 BaseMapper 就可以拥有crud能力

进阶操作

  1. 设置表明和自增主键
  2. 使用条件构造器
    1. boolean condition表示该条件是否加入最后生成的sql中
    2. 支持多种条件表达式拼接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
31
32
33
34
35
36
37
38
39
40
41
AbstractWrapper
allEq
eq
ne
gt
ge
lt
le
between
notBetween
like
notLike
likeLeft
likeRight
notLikeLeft
notLikeRight
isNull
isNotNull
in
notIn
inSql
notInSql
groupBy
orderByAsc
orderByDesc
orderBy
having
func
or
and
nested
apply
last
exists
notExists
QueryWrapper
select
UpdateWrapper
set
setSql
lambda

CRUD实例

DAO层

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
 
public interface ArticleMapper extends BaseMapper<Article> {
}


public interface BaseMapper<T> extends Mapper<T> {
int insert(T entity);

int deleteById(Serializable id);

int deleteById(T entity);

default int deleteByMap(Map<String, Object> columnMap) {
return this.delete((Wrapper)Wrappers.query().allEq(columnMap));
}

int delete(@Param("ew") Wrapper<T> queryWrapper);

int deleteBatchIds(@Param("coll") Collection<?> idList);

int updateById(@Param("et") T entity);

int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);

default int update(@Param("ew") Wrapper<T> updateWrapper) {
return this.update((Object)null, updateWrapper);
}

T selectById(Serializable id);

List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);

void selectBatchIds(@Param("coll") Collection<? extends Serializable> idList, ResultHandler<T> resultHandler);

default List<T> selectByMap(Map<String, Object> columnMap) {
return this.selectList((Wrapper)Wrappers.query().allEq(columnMap));
}

default void selectByMap(Map<String, Object> columnMap, ResultHandler<T> resultHandler) {
this.selectList((Wrapper)Wrappers.query().allEq(columnMap), resultHandler);
}

default T selectOne(@Param("ew") Wrapper<T> queryWrapper) {
return this.selectOne(queryWrapper, true);
}

default T selectOne(@Param("ew") Wrapper<T> queryWrapper, boolean throwEx) {
List<T> list = this.selectList(queryWrapper);
int size = list.size();
if (size == 1) {
return list.get(0);
} else if (size > 1) {
if (throwEx) {
throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + size);
} else {
return list.get(0);
}
} else {
return null;
}
}

default boolean exists(Wrapper<T> queryWrapper) {
Long count = this.selectCount(queryWrapper);
return null != count && count > 0L;
}

Long selectCount(@Param("ew") Wrapper<T> queryWrapper);

List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);

void selectList(@Param("ew") Wrapper<T> queryWrapper, ResultHandler<T> resultHandler);

List<T> selectList(IPage<T> page, @Param("ew") Wrapper<T> queryWrapper);

void selectList(IPage<T> page, @Param("ew") Wrapper<T> queryWrapper, ResultHandler<T> resultHandler);

List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);

void selectMaps(@Param("ew") Wrapper<T> queryWrapper, ResultHandler<Map<String, Object>> resultHandler);

List<Map<String, Object>> selectMaps(IPage<? extends Map<String, Object>> page, @Param("ew") Wrapper<T> queryWrapper);

void selectMaps(IPage<? extends Map<String, Object>> page, @Param("ew") Wrapper<T> queryWrapper, ResultHandler<Map<String, Object>> resultHandler);

<E> List<E> selectObjs(@Param("ew") Wrapper<T> queryWrapper);

<E> void selectObjs(@Param("ew") Wrapper<T> queryWrapper, ResultHandler<E> resultHandler);

default <P extends IPage<T>> P selectPage(P page, @Param("ew") Wrapper<T> queryWrapper) {
page.setRecords(this.selectList(page, queryWrapper));
return page;
}

default <P extends IPage<Map<String, Object>>> P selectMapsPage(P page, @Param("ew") Wrapper<T> queryWrapper) {
page.setRecords(this.selectMaps(page, queryWrapper));
return page;
}
}

Service层

1
2
3
4
5
6
7
8
9
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {


}

public interface UserService extends IService<User> {

}

完整实例

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
package com.baomidou.mybatisplus.samples.crud;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.samples.crud.entity.User;
import com.baomidou.mybatisplus.samples.crud.entity.User2;
import com.baomidou.mybatisplus.samples.crud.mapper.User2Mapper;
import com.baomidou.mybatisplus.samples.crud.mapper.UserMapper;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;
import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;

/**
* <p>
* 内置 CRUD 演示
* </p>
*
* @author hubin
* @since 2018-08-11
*/
@SpringBootTest
public class CrudTest {
@Autowired
private UserMapper mapper;
@Autowired
private User2Mapper user2Mapper;

@Test
public void aInsert() {
User user = new User();
user.setName("小羊");
user.setAge(3);
user.setEmail("abc@mp.com");
assertThat(mapper.insert(user)).isGreaterThan(0);
// 成功直接拿回写的 ID
assertThat(user.getId()).isNotNull();
}


@Test
public void bDelete() {
assertThat(mapper.deleteById(3L)).isGreaterThan(0);
assertThat(mapper.delete(new QueryWrapper<User>()
.lambda().eq(User::getName, "Sandy"))).isGreaterThan(0);
}


@Test
public void cUpdate() {
assertThat(mapper.updateById(new User().setId(1L).setEmail("ab@c.c"))).isGreaterThan(0);
assertThat(
mapper.update(
new User().setName("mp"),
Wrappers.<User>lambdaUpdate()
.set(User::getAge, 3)
.eq(User::getId, 2)
)
).isGreaterThan(0);
User user = mapper.selectById(2);
assertThat(user.getAge()).isEqualTo(3);
assertThat(user.getName()).isEqualTo("mp");

mapper.update(
null,
Wrappers.<User>lambdaUpdate().set(User::getEmail, null).eq(User::getId, 2)
);
assertThat(mapper.selectById(1).getEmail()).isEqualTo("ab@c.c");
user = mapper.selectById(2);
assertThat(user.getEmail()).isNull();
assertThat(user.getName()).isEqualTo("mp");

mapper.update(
new User().setEmail("miemie@baomidou.com"),
new QueryWrapper<User>()
.lambda().eq(User::getId, 2)
);
user = mapper.selectById(2);
assertThat(user.getEmail()).isEqualTo("miemie@baomidou.com");

mapper.update(
new User().setEmail("miemie2@baomidou.com"),
Wrappers.<User>lambdaUpdate()
.set(User::getAge, null)
.eq(User::getId, 2)
);
user = mapper.selectById(2);
assertThat(user.getEmail()).isEqualTo("miemie2@baomidou.com");
assertThat(user.getAge()).isNull();
}


@Test
public void dSelect() {
mapper.insert(
new User().setId(10086L)
.setName("miemie")
.setEmail("miemie@baomidou.com")
.setAge(3));
assertThat(mapper.selectById(10086L).getEmail()).isEqualTo("miemie@baomidou.com");
User user = mapper.selectOne(new QueryWrapper<User>().lambda().eq(User::getId, 10086));
assertThat(user.getName()).isEqualTo("miemie");
assertThat(user.getAge()).isEqualTo(3);

mapper.selectList(Wrappers.<User>lambdaQuery().select(User::getId))
.forEach(x -> {
assertThat(x.getId()).isNotNull();
assertThat(x.getEmail()).isNull();
assertThat(x.getName()).isNull();
assertThat(x.getAge()).isNull();
});
mapper.selectList(new QueryWrapper<User>().select("id", "name"))
.forEach(x -> {
assertThat(x.getId()).isNotNull();
assertThat(x.getEmail()).isNull();
assertThat(x.getName()).isNotNull();
assertThat(x.getAge()).isNull();
});
}

@Test
public void orderBy() {
List<User> users = mapper.selectList(Wrappers.<User>query().orderByAsc("age"));
assertThat(users).isNotEmpty();
//多字段排序
List<User> users2 = mapper.selectList(Wrappers.<User>query().orderByAsc("age", "name"));
assertThat(users2).isNotEmpty();
//先按age升序排列,age相同再按name降序排列
List<User> users3 = mapper.selectList(Wrappers.<User>query().orderByAsc("age").orderByDesc("name"));
assertThat(users3).isNotEmpty();
}

@Test
public void selectMaps() {
List<Map<String, Object>> mapList = mapper.selectMaps(Wrappers.<User>query().orderByAsc("age"));
assertThat(mapList).isNotEmpty();
assertThat(mapList.get(0)).isNotEmpty();
System.out.println(mapList.get(0));
}

@Test
public void selectMapsPage() {
IPage<Map<String, Object>> page = mapper.selectMapsPage(new Page<>(1, 5), Wrappers.<User>query().orderByAsc("age"));
assertThat(page).isNotNull();
assertThat(page.getRecords()).isNotEmpty();
assertThat(page.getRecords().get(0)).isNotEmpty();
System.out.println(page.getRecords().get(0));
}

@Test
public void orderByLambda() {
List<User> users = mapper.selectList(Wrappers.<User>lambdaQuery().orderByAsc(User::getAge));
assertThat(users).isNotEmpty();
//多字段排序
List<User> users2 = mapper.selectList(Wrappers.<User>lambdaQuery().orderByAsc(User::getAge, User::getName));
assertThat(users2).isNotEmpty();
//先按age升序排列,age相同再按name降序排列
List<User> users3 = mapper.selectList(Wrappers.<User>lambdaQuery().orderByAsc(User::getAge).orderByDesc(User::getName));
assertThat(users3).isNotEmpty();
}

@Test
public void testSelectMaxId() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.select("max(id) as id");
User user = mapper.selectOne(wrapper);
System.out.println("maxId=" + user.getId());
List<User> users = mapper.selectList(Wrappers.<User>lambdaQuery().orderByDesc(User::getId));
Assertions.assertEquals(user.getId().longValue(), users.get(0).getId().longValue());
}

@Test
public void testGroup() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.select("age, count(*)")
.groupBy("age");
List<Map<String, Object>> maplist = mapper.selectMaps(wrapper);
for (Map<String, Object> mp : maplist) {
System.out.println(mp);
}
/**
* lambdaQueryWrapper groupBy orderBy
*/
LambdaQueryWrapper<User> lambdaQueryWrapper = new QueryWrapper<User>().lambda()
.select(User::getAge)
.groupBy(User::getAge)
.orderByAsc(User::getAge);
for (User user : mapper.selectList(lambdaQueryWrapper)) {
System.out.println(user);
}
}

@Test
public void testTableFieldExistFalse() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.select("age, count(age) as count")
.groupBy("age");
List<User> list = mapper.selectList(wrapper);
list.forEach(System.out::println);
list.forEach(x -> {
Assertions.assertNull(x.getId());
Assertions.assertNotNull(x.getAge());
Assertions.assertNotNull(x.getCount());
});
mapper.insert(
new User().setId(10088L)
.setName("miemie")
.setEmail("miemie@baomidou.com")
.setAge(3));
User miemie = mapper.selectById(10088L);
Assertions.assertNotNull(miemie);

}

@Test
public void testSqlCondition() {
Assertions.assertEquals(user2Mapper.selectList(Wrappers.<User2>query()
.setEntity(new User2().setName("n"))).size(), 2);
Assertions.assertEquals(user2Mapper.selectList(Wrappers.<User2>query().like("name", "J")).size(), 2);
Assertions.assertEquals(user2Mapper.selectList(Wrappers.<User2>query().gt("age", 18)
.setEntity(new User2().setName("J"))).size(), 1);
}
}