1 引入

1.1 作用

替我们生成常用增删改查操作的 SQL 语句。

1.2 代码官方发布地址

https://gitee.com/free

https://gitee.com/free/Mapper/wikis/1.1-java?parent=1.integration

2 快速入门

2.1创建测试数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
CREATETABLE`tabple_emp`( 
`emp_id` intNOTNULLAUTO_INCREMENT,
`emp_name` varchar(500)NULL,
`emp_salary` double(15,5)NULL,
`emp_age` intNULL,
PRIMARYKEY(`emp_id`)
);


INSERT INTO `tabple_emp` (`emp_name`,`emp_salary`,`emp_age`)VALUES('tom','1254.37','27');
INSERT INTO `tabple_emp` (`emp_name`,`emp_salary`,`emp_age`)VALUES('jerry','6635.42','38');
INSERT INTO `tabple_emp` (`emp_name`,`emp_salary`,`emp_age`)VALUES('bob','5560.11','40');
INSERT INTO `tabple_emp` (`emp_name`,`emp_salary`,`emp_age`)VALUES('kate','2209.11','22');
INSERT INTO `tabple_emp` (`emp_name`,`emp_salary`,`emp_age`)VALUES('justin','4203.15','30');

2.2 搭建开发环境(快速入门)

创建SpringBoot mapper工程


导入依赖

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
      <dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.0.2</version>
</dependency>


<!--其余依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
  • 通用mapper是在springboot集成了Mybatis的基础上进行使用的

如果你需要对通用 Mapper 进行配置,你可以在 Spring Boot 的配置文件中配置 mapper. 前缀的配置。

例如在 yml 格式中配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#端口配置
server:
port: 8088
#jdbc配置
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/jpa?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
username: root
password: 123456
#mybatis配置
mybatis:
#实体类所在包名
type-aliases-package:com.zzxx.mappertest.entity



#通用mapper配置
mapper:
#公用接口类路径
mappers: tk.mybatis.mapper.common.Mapper #通用基类配置
identity: MYSQL

注意:mybatis.mapper-locations=classpath:mapper/*.xml就不用配置了,因为不生成mapper.xml文件

@MapperScan 注解配置

你可以给带有 @Configuration 的类配置该注解,或者直接配置到 Spring Boot 的启动类上,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

package com.zzxx.mappertest;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import tk.mybatis.spring.annotation.MapperScan;

@SpringBootApplication
@MapperScan("com.zzxx.mappertest.mapper")
public class MapperTestApplication {

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

}

注意:这里使用的 tk.mybatis.spring.annotation.MapperScan !

Java 实体类 考虑到基本数据类型在 Java 类中都有默认值,会导致 MyBatis 在执行相关操作 时很难判断当前字段是否为 null,所以在 MyBatis 环境下使用 Java 实体类时尽量不 要使用基本数据类型,都使用对应的包装类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;


@Data
@AllArgsConstructor
@NoArgsConstructor
@Table(name="tabple_emp") //数据库表名为tabple_emp 默认是驼峰命名
public class Employee {

@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private Integer empId;//emp_id

private String empName;//emp_name

@Column(name="emp_salary")
private Double empSalary;//emp_salary

private Integer empAge;//emp_age
}

注意:Mybatis通用接口mapper依赖JPA,所以实体类得用JPA建立对象和表的映射关系

Dao层

1
2
3
4
5
6
7
8
9
import com.zzxx.mappertest.entity.Employee;
import org.springframework.stereotype.Repository;
import tk.mybatis.mapper.common.Mapper;

@Repository
public interface EmployeeMapper extends Mapper<Employee> {

}

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@SpringBootTest
class MapperTestApplicationTests {
@Autowired
EmployeeMapper employeeMapper;

@Test
public void testSelectOne() {

//1.创建封装查询条件的实体类对象
Employee employeeQueryCondition = new Employee(null, "bob", 5560.11, null);

//2.执行查询
Employee employeeQueryResult = employeeMapper.selectOne(employeeQueryCondition);

//3.打印
System.out.println(employeeQueryResult);
}


}

结果

1
2
Employee(empId=3, empName=bob, empSalary=5560.11, empAge=40)

注意:如果实体类上不加 @Table(name=”tabple_emp”)与数据库表名映射会报错(默认为驼峰命名映射)t同样字段上面默认也为驼峰命名,不匹配需要加注解@Column(name=”表字段”)

3. 常用注解

3.1 @Table 注解

作用:建立实体类和数据库表之间的对应关系。

默认规则:实体类类名首字母小写作为表名。Employee 类→employee 表。

用法:在@Table 注解的 name 属性中指定目标数据库表的表名

3.2 @Column 注解

作用:建立实体类字段和数据库表字段之间的对应关系。

默认规则: 实体类字段:驼峰式命名 数据库表字段:使用“_”区分各个单词

用法:在@Column 注解的 name 属性中指定目标字段的字段名
(假设诉数据库为emp_salary_apple)

3.3 @Id注解

通用 Mapper 在执行 xxxByPrimaryKey(key)方法时,有两种情况。

情况 1:没有使用@Id 注解明确指定主键字段

1
SELECT emp_id,emp_name,emp_salary_apple,emp_age FROM tabple_emp WHERE emp_id = ? ANDemp_name=?ANDemp_salary_apple=?ANDemp_age=? 

之所以会生成上面这样的 WHERE 子句是因为通用 Mapper 将实体类中的所有 字段都拿来放在一起作为联合主键。

情况 2:使用@Id 主键明确标记和数据库表中主键字段对应的实体类字段。

3.4@GeneratedValue 注解

作用:让通用 Mapper 在执行 insert 操作之后将数据库自动生成的主键值回写到实 体类对象中。

自增主键用法:

3.5@Transient主键

用于标记不与数据库表字段对应的实体类字段。

1
@Transient privateStringotherThings;//非数据库表中字段

4. 常用方法

4.1 selectOne 方法

通用 Mapper 替我们自动生成的 SQL 语句情况

1
2
3
 SELECT emp_id,emp_name,emp_salary,emp_age FROM tabple_emp WHERE emp_name = ? AND emp_salary = ? 
Parameters: bob(String), 5560.11(Double)
Total: 1

实体类封装查询条件生成 WHERE 子句的规则

  • 使用非空的值生成 WHERE 子句
  • 在条件表达式中使用“=”进行比较

要求必须返回一个实体类结果,如果有多个,则会抛出异常

4.2xxxByPrimaryKey 方法

需要使用@Id 主键明确标记和数据库表主键字段对应的实体类字段,否则通用 Mapper 会将所有实体类字段作为联合主键。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  @Test
public void testSelectByPrimaryKey() {

//1.提供id值
Integer empId = 3;

//2.执行根据主键进行的查询
Employee employee = employeeMapper.selectByPrimaryKey(empId);

//3.打印结果
System.out.println(employee);

// 结果:Employee(empId=3, empName=bob, empSalary=5560.11, empAge=40)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test
public void testExistsWithPrimaryKey() {

//1.提供主键值
Integer empId = 33;

//2.执行查询
boolean exists = employeeMapper.existsWithPrimaryKey(empId);

//3.打印结果
System.out.println(exists);
// 结果:false (如果存在为true)
}

4.insert 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
   @Test
public void testInsert() {

//1.创建实体类对象封装要保存到数据库的数据
Employee employee = new Employee(null, "emp03", 3000.00, 23);

//2.执行插入操作
System.out.println(employeeMapper.insert(employee));

//3.获取employee对象的主键字段值
Integer empId = employee.getEmpId();
System.out.println("empId="+empId);(主键回填)

}
//结果:
1
empId=7

实体类主键字段上必须有 @GeneratedValue(strategy= GenerationType.IDENTITY)注解才会主键回填

4.4xxxSelective 方法

非主键字段如果为 null 值,则不加入到 SQL 语句中。
这个很重要,尤其修改的时候。

1
2
3
4
5
6
7
8
9
10
11
12
13
//采用updateByPrimaryKey时
@Test
public void testUpdaet() {

//1.创建实体类对象封装要保存到数据库的数据
Employee employee = new Employee();
employee.setEmpName("zzxx");
employee.setEmpId(6);
System.out.println(employeeMapper.updateByPrimaryKey(employee));

//结果: 1
}

输出

1
2
3
4
5
6
7
8
9
10
@Test
public void testupdateByPrimaryKeySelective() {
Employee employee = new Employee();
employee.setEmpName("kkhh");
employee.setEmpId(5);
int i = employeeMapper.updateByPrimaryKeySelective(employee);
System.out.println();

//结果: 1
}

4.5 delete

1
2
3
4
5
6

//1.声明实体类变量作为查询条件 不加条件数据全部删除,使用要小心
Employee employee = null;

//2.执行删除
employeeService.removeEmployee(employee);

1
2
3
4
5
6
7
8
9
10
11
@Test
public void testDeleteByPrimaryKey() {

//1.提供主键值
Integer empId = 13;

//2.执行删除
int i= employeeService.removeEmployeeById(empId);
//结果: 1

}

5. QBC 查询

5.1概念

Query By Criteria

Criteria 是 Criterion 的复数形式。意思是:规则、标准、准则。在 SQL 语句中相当 于查询条件。

QBC 查询是将查询条件通过 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
@Test
public void testSelectByExample() {

//目标:WHERE (emp_salary>? AND emp_age<?) OR (emp_salary<? AND emp_age>?)
//1.创建Example对象
Example example = new Example(Employee.class);

//***********************
//i.设置排序信息
example.orderBy("empSalary").asc().orderBy("empAge").desc();

//ii.设置“去重”
example.setDistinct(true);

//iii.设置select字段
// example.selectProperties("empName","empSalary");

//***********************

//2.通过Example对象创建Criteria对象
Example.Criteria criteria01 = example.createCriteria();
Example.Criteria criteria02 = example.createCriteria();

//3.在两个Criteria对象中分别设置查询条件
//property参数:实体类的属性名
//value参数:实体类的属性值
criteria01.andGreaterThan("empSalary", 3000)
.andLessThan("empAge", 25);

criteria02.andLessThan("empSalary", 5000)
.andGreaterThan("empAge", 30);

//4.使用OR关键词组装两个Criteria对象
example.or(criteria02);

//5.执行查询
List<Employee> empList = employeeMapper.selectByExample(example);

for (Employee employee : empList) {
System.out.println(employee);
}
}

结果

1
2
3
4
5
6
#sql语句
SELECT distinct emp_id,emp_name,emp_salary,emp_age FROM tabple_emp WHERE ( emp_salary > ? and emp_age < ? ) or ( emp_salary < ? and emp_age > ? ) order by emp_salary ASC,emp_age DESC


Employee(empId=1, empName=tom, empSalary=3254.37, empAge=24)
Employee(empId=5, empName=kkhh, empSalary=4203.15, empAge=31)

分页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Test
public void testSelectByRowBounds() {

int pageNo = 1;
int pageSize = 5;

int index = (pageNo - 1) * pageSize;

RowBounds rowBounds = new RowBounds(index, pageSize);

List<Employee> empList = employeeService.getEmpListByRowBounds(rowBounds);
for (Employee employee : empList) {
System.out.println(employee);
}
}

结果

1
2
3
4
5
6
7
8
9
10
//sql语句 查询全部 在内存中分页 假分页 意义不大
SELECT emp_id,emp_name,emp_salary,emp_age FROM tabple_emp



Employee(empId=1, empName=tom, empSalary=3254.37, empAge=24)
Employee(empId=2, empName=jerry, empSalary=6635.42, empAge=38)
Employee(empId=3, empName=bob, empSalary=5560.11, empAge=40)
Employee(empId=4, empName=kate, empSalary=2209.11, empAge=22)
Employee(empId=5, empName=kkhh, empSalary=4203.15, empAge=31)