增删改查

查询单个实体对象

1
User getUserById(@Param("id") int id);
1
2
3
<select id="getUserById" resultType="User">
SELECT * FROM t_user WHERE id = #{id}
</select>

查询单个List集合

1
List<User> getAllUsers();
1
2
3
<select id="getAllUser" resultType="User">
SELECT * FROM t_user
</select>

注意:当查询的数据为多条时,不能使用实体类作为返回值,否则会抛出异常 TooManyResultsException;但是若查询的数据只有一条,可以使用实体类或集合作为返回值

查询单个数据

1
int getCount();
1
2
3
<select id="getCount" resultType="java.lang.Integer">
SELECT COUNT(id) FROM t_user
</select>

查询单条数据到map集合

1
Map<String, Object> getUserToMap(@Param("id") int id);
1
2
3
<select id="getUserToMap" resultType="java.util.Map">
SELECT * FROM t_user WHERE id = #{id}
</select>

注意:将一条数据查询到map集合中时,map的键是表中的字段名,map的值是表中数据

查询多条数据到map集合

方式1

1
List<Map<String,Object>> getAllUserToMap();
1
2
3
<select id="getAllUserToMap" resultType="java.util.Map">
SELECT * FROM t_user
</select>

每条查出来的数据都对应一个Map集合,然后再利用List集合将这些Map集合组织起来 [{,},{,},...]

方式2

1
2
@MapKey("id")
Map<String,Object> getAllUserToMap();
1
2
3
<select id="getAllUserToMap" resultType="java.util.Map">
SELECT * FROM t_user
</select>

每条查出来的数据都存放在一个Map集合中,但是这个Map集合的键由映射方法上方的@MapKey注解指定,而Map集合的值又是另外一个Map集合,作为值的Map集合中键对应表中字段名,值对应表中数据

1
2
3
4
5
{
1={password=123456, sex=男, id=1, age=23, username=admin},
2={password=123456, sex=男, id=2, age=23, username=张三},
3={password=123456, sex=男, id=3, age=23, username=张三}
}

模糊查询

1
List<User> getUserByLike(@Param("mohu") String mohu);
1
2
3
4
5
6
7
8
<select id="getUserByLike" resultType="User">
<!--方式1-->
SELECT * FROM t_user WHERE username LIKE '%${mohu}%'
<!--方式2-->
SELECT * FROM t_user WHERE username LIKE concat("%",#{mohu},"%")
<!--方式3-->
SELECT * FROM t_user WHERE username LIKE "%"#{mohu}"%"
</select>

注意:不能使用like '%#{mohu}%'的方式,因为#{}会被解析成占位符?,这个问号会被当成字符串的一部分造成参数获取失败

批量删除

1
void deleteSomeUser(@Param("ids") String ids);
1
2
3
<delete id="deleteSomeUser">
DELETE FROM t_user WHERE id IN(${ids})
</delete>

注意:这里获取参数的方式是${},因为#{}会自动添加引号,如果使用#{}的方式会造成SQL语句解析成delete from t_user where id in('ids')从而报错

insert

1
int addUser(User user);
1
2
3
<insert id="addUser" parameterType="com.cyan.pojo.User">
INSERT INTO `user` (`id`, `name`, `pwd`) VALUES (#{id}, #{name}, #{pwd});
</insert>

增删改需要提交事务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public void testAddUser() {

// 构建SqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();

// 调用
UserDao userDao = sqlSession.getMapper(UserDao.class);

int res = userDao.addUser(new User(4, "哈七","123456"));

if (res > 0) {
System.out.println("Add Success");
}

//提交事务
sqlSession.commit();
sqlSession.close();

}

delete

1
int deleteUser(int id);
1
2
3
<delete id="deleteUser" parameterType="int">
DELETE FROM `user` WHERE `id` = #{id};
</delete>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void testDeleteUser() {

// 构建SqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();

// 调用
UserDao userDao = sqlSession.getMapper(UserDao.class);

userDao.deleteUser(4);

// 提交事务
sqlSession.commit();
sqlSession.close();
}

update

1
int updateUser(User user);
1
2
3
<update id="updateUser" parameterType="com.cyan.pojo.User">
UPDATE `user` SET `name` = #{name}, `pwd` = #{pwd} WHERE `id` = #{id};
</update>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void testUpdateUser() {

// 创建SqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();

// 准备调用
UserDao userDao = sqlSession.getMapper(UserDao.class);

userDao.updateUser(new User(4,"小羊", "147257"));

// 提交事务
sqlSession.commit();
sqlSession.close();
}

select

1
2
List<User> getUserList();
User getUserById(int id);
1
2
3
4
5
6
7
<select id="getUserList" resultType="com.cyan.pojo.User">
SELECT * FROM `user`
</select>

<select id="getUserById" parameterType="int" resultType="com.cyan.pojo.User">
SELECT * FROM `user` WHERE `id` = #{id}
</select>
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 void testGetUserList() {

// 获取SqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();

// 执行SQL
UserDao userDao = sqlSession.getMapper(UserDao.class);
List<User> userList = userDao.getUserList();

for (User user : userList) {
System.out.println(user);
}

sqlSession.close();
}

public void testGetUserById() {

SqlSession sqlSession = MybatisUtils.getSqlSession();

UserDao userDao = sqlSession.getMapper(UserDao.class);
User user = userDao.getUserById(1);

System.out.println(user);

sqlSession.close();
}

动态设置表名

1
List<User> getUserList(@Param("table") String table);
1
2
3
<select id="getUserList" resultType="User">
select * from ${table}
</select>

注意:这里使用${}是因为使用#{}时会自动添加引号,而表名不允许添加表名

列字段和实体类属性名不一致

方法1 字段名取别名

  • 如果表中字段名和实体类属性名不一致,可以在SQL语句中给字段名取别名
  • 给字段取得别名必须和实体类属性名一致

方法2 配置驼峰映射

使用前提:表字段符合Mysql命名规范(使用下划线_分割单词),而实体类属性符合驼峰命名规范

1
2
3
<settings>
<setting name="mapUnderscoreToCamelCase" value="true" />
</settings>

在核心配置文件使用了如上配置后,在SQL语句中可以使用表的字段名而不用考虑表字段名和实体类属性名不一致的情况

方法3 自定义映射

<resultMap> 标签含有 id 属性和 type 属性,其中 id 属性是设置当前自定义映射的 标识,type 属性是映射的实体类

resultMap子标签 说明
<id>标签 设置主键字段的映射关系,使用column属性设置映射关系中表的字段名,使用property属性设置映射关系中实体类的属性名
<result>标签 设置普通字段的映射关系,使用column属性设置映射关系中表的字段名,使用property属性设置映射关系中实体类的属性名
1
2
3
4
5
6
7
8
9
10
<resultMap id="empResultMap" type="Emp">
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
</resultMap>

<select id="getEmpByEmpId" resultType="Emp" resultMap="empResultMap">
select * from t_emp where emp_id = #{empId}
</select>

关联映射应用

实体类中某个属性是以表中多个字段为属性构成的实体类,如员工类的部门属性,部门属性的类型是部门类,这个部门类有部门id,部门名称

1
2
3
4
5
6
7
8
class Employee {
private Dept dept;
...
}
class Dept {
private Integer id;
private String name;
}

方法1 使用级联

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<resultMap id="getEmpAndDeptByEmpIdResultMap" type="Emp">
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
<result column="dept_id" property="dept.deptId"></result>
<result column="dept_name" property="dept.deptName"></result>
</resultMap>

<select id="getEmpAndDeptByEmpId" resultMap="getEmpAndDeptByEmpIdResultMap">
SELECT emp_id,emp_name,age,gender,t_dept.dept_id,dept_name
FROM t_emp left join t_dept
on t_emp.dept_id = t_dept.dept_id where emp_id = #{empId}
</select>

方法2 使用关联标签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<resultMap id="getEmpAndDeptByEmpIdResultMap" type="Emp">
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
<association property="dept" javaType="Dept">
<id column="dept_id" property="deptId"></id>
<result column="dept_name" property="deptName"></result>
</association>
</resultMap>

<select id="getEmpAndDeptByEmpId" resultMap="getEmpAndDeptByEmpIdResultMap">
select emp_id,emp_name,age,gender,t_dept.dept_id,dept_name
from t_emp left join t_dept
on t_emp.dept_id = t_dept.dept_id where emp_id = #{empId}
</select>
1
2
3
4
<association property="dept" javaType="Dept">
<id column="dept_id" property="deptId"></id>
<result column="dept_name" property="deptName"></result>
</association>

association标签中

property属性是指映射实体类中属性的名称,javaType是实体类的类型

association标签内

id标签和result标签中的property属性是指javaType指定的类中的属性名称,column属性指表中的字段名

方法3 分步查询

查询员工信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<resultMap id="getEmpAndDeptByEmpIdResultMap" type="Emp">
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
<association
property="dept"
select="com.cyan.mapper.DeptMapper.getDeptByDeptId"
column="dept_id">
</association>
</resultMap>

<select id="getEmpAndDeptByEmpId" resultMap="getEmpAndDeptByEmpIdResultMap">
select * from t_emp where emp_id = #{empId}
</select>

根据员工的部门id查询部门信息:

1
2
3
4
5
6
7
8
<resultMap id="getDeptByDeptIdResultMap" type="Dept">
<id column="dept_id" property="deptId"></id>
<result column="dept_name" property="deptName"></result>
</resultMap>

<select id="getDeptByDeptId" resultMap="getDeptByDeptIdResultMap">
select * from t_dept where dept_id = #{deptId}
</select>

案例分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
CREATE TABLE `teacher` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO teacher(`id`, `name`) VALUES (1, '秦老师');

CREATE TABLE `student` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
`tid` INT(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fktid` (`tid`),
CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '小明', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小红', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小张', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', '1');

关联的嵌套Select查询

1
2
3
4
5
public interface StudentMapper {

// 查询学生的信息以及对应的老师的信息
List<Student> getStudent();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<select id="getStudent" resultMap="StudentTeacher">
SELECT * FROM `student`
</select>
<resultMap id="StudentTeacher" type="Student">
<!--常规映射-->
<result property="id" column="id"/>
<result property="name" column="name"/>

<!--关联Teacher-->
<!--复杂属性 单独处理
对象:association
集合:collection
-->
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>

<!--mybatis会先查询teacher信息,封装到StudentTeacher该Map中,供getStudent查询-->
<select id="getTeacher" resultType="Teacher">
SELECT * FROM `teacher` WHERE `id` = #{id};
</select>

关联的嵌套结果映射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<select id="getStudent" resultMap="StudentTeacher">
SELECT s.`id` sid, s.`name` sname, t.`name` tname
FROM `student` s, `teacher` t
WHERE s.tid = t.id
</select>

<resultMap id="StudentTeacher" type="Student">
<!--常规映射-->
<result property="id" column="sid"/>
<result property="name" column="sname"/>

<!--表连接-->
<association property="teacher" javaType="Teacher">
<result property="name" column="tname"/>
</association>
</resultMap>

集合映射应用

指实体类中某个属性是由许多实体类构成的集合,如部门类中员工属性是一个List集合

1
2
3
4
class Dept {
...
private List<Employee> employees;
}

方法1 使用集合标签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<resultMap id="getDeptAndEmpByDeptIdResultMap" type="Dept">
<id column="dept_id" property="deptId"></id>
<result column="dept_name" property="deptName"></result>
<collection property="emps" ofType="Emp">
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
</collection>
</resultMap>

<select id="getDeptAndEmpByDeptId" resultMap="getDeptAndEmpByDeptIdResultMap">
select *
from t_dept left join t_emp
on t_dept.dept_id = t_emp.dept_id
where t_dept.dept_id = #{deptId}
</select>

方法2 分步查询

查询部门信息:

1
2
3
4
5
6
7
8
9
10
11
12
<resultMap id="getDeptAndEmpByDeptIdResultMap" type="Dept">
<id column="dept_id" property="deptId"></id>
<result column="dept_name" property="deptName"></result>
<collection property="emps"
select="com.cyan.mapper.EmpMapper.getEmpByDeptId"
column="dept_id">
</collection>
</resultMap>

<select id="getDeptAndEmpByDeptId" resultMap="getDeptAndEmpByDeptIdResultMap">
select * from t_dept where dept_id = #{deptId}
</select>

根据部门id查询员工信息:

1
2
3
4
5
6
7
8
9
10
<resultMap id="getEmpByDeptIdResultMap" type="Emp">
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
</resultMap>

<select id="getEmpByDeptId" resultMap="getEmpByDeptIdResultMap">
select * from t_emp where dept_id = #{deptId}
</select>

案例分析

1
2
3
4
5
6
7
8
9
10
11
12
public class Student {
private int id;
private String name;

private int tid;
}
public class Teacher {
private int id;
private String name;

private List<Student> students;
}

集合的嵌套结果映射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<select id="getTeacher" resultMap="TeacherStudentMap">
SELECT s.id `sid`, s.name `sname`, t.name `tname`, t.id `tid`
FROM student s, teacher t
WHERE s.tid = t.id AND t.id = #{tid}
</select>

<resultMap id="TeacherStudentMap" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<collection property="students" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>

集合的嵌套Select查询

1
2
3
4
5
6
7
8
9
10
11
<select id="getTeacher" resultMap="TeacherStudentMap">
SELECT * FROM teacher WHERE id = #{tid}
</select>

<resultMap id="TeacherStudentMap" type="Teacher">
<collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTeacherId" column="id"/>
</resultMap>

<select id="getStudentByTeacherId" resultType="Student">
SELECT * FROM `student` WHERE tid = #{tid}
</select>

分步查询的优点

  • 分步查询的优点是可以实现延迟加载

  • 延迟加载可以避免在分步查询中执行所有的SQL语句,节省资源,实现按需加载

1
2
3
4
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
属性 说明
lazyLoadingEnabled 表示全局的延迟加载开关,true表示所有关联对象都会延迟加载,false表示关闭
aggressiveLazyLoading 表示是否加载该对象的所有属性,如果开启则任何方法的调用会加载这个对象的所有属性,如果关闭则是按需加载

由于这个配置是在核心配置文件中设定的,所以所有的分步查询都会实现延迟加载

如果某个查询不需要延迟加载,可以在collection标签或者association标签中的fetchType属性设置是否使用延迟加载,属性值lazy表示延迟加载,属性值eager表示立即加载

分页功能

MySQL 分页

1
SELECT * FROM user LIMIT startIndex,pageSize;

Mybatis 分页

1
List<User> getUserByLimit(Map<String, Integer> params);
1
2
3
<select id="getUserByLimit" parameterType="map" resultMap="UserMap">
SELECT * FROM `user` LIMIT #{startIndex}, #{pageSize}
</select>
1
2
3
4
5
6
7
8
9
10
11
12
13
public void getUserByLimit() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);

HashMap<String, Integer> params = new HashMap<>();
params.put("startIndex", 0);
params.put("pageSize", 2);

List<User> userList = mapper.getUserByLimit(params);
for (User user : userList) {
System.out.println(user);
}
}