
我们作为一个程序员,主要工作归根结底就是和数据打交道。而使用 java 操作数据库的原始方式就是 JDBC。
先看看使用 JDBC 方式是如何操作数据库的:
// 1. 加载配置文件
Properties pro=new Properties();
pro.load(new FileReader("resource/jdbc.properties"));
// 2. 获取配置文件中连接数据库的信息
String url=pro.getProperty("url");
String user=pro.getProperty("user");
String password=pro.getProperty("password");
String driver=pro.getProperty("driver");
// 3. 加载数据库的驱动
Class.forName(driver);
// 4. 创建数据库的连接
Connection conn = DriverManager.getConnection(url, user, password);
// 5. sql 语句
String sql = "select * from s_admin where username=? and password=?";
// 3. 创建执行sql的对象
ps = conn.prepareStatement(sql);
// 4. 给 ?赋值
ps.setString(1, username);
ps.setString(2, password);
// 5. 执行sql
ResultSet rs = ps.executeQuery();
// 6. 如果查询出数据,则返回该条数据
if (rs.next()) {
Admin admin = new Admin();
admin.setUsername(rs.getString("username"));
admin.setPassword(rs.getString("password"));
return admin;
// 7. 否则返回空
} else {
return null;
}
看完上面的代码,我们发现了 JDBC 存在的问题:
1.每次操作我们都要创建 connection、Statement 等一些对象,操作完还要关闭、销毁这些对象。
2.ResultSet 不能帮我们完成数据库和实体对象的自动转换,我们还要手动赋值。
3.代码冗余,而且业务操作竟然和数据库操作混在一起,开发效率太低了。
真是越来越不想用 JDBC 了,那有没有一个玩意能帮我解决上面 JDBC 遇到的问题呢?
有的,盖世英雄MyBatis踩着七彩祥云来了。
官网地址:
https://mybatis.org/mybatis-3/
MyBatis 是一个基于 java 的持久层框架,它内部封装了 jdbc。
开发人员只需要关注 sql 语句,不需要处理加载驱动、创建连接等繁琐的过程。
MyBatis 通过 xml 或注解两种方式配置 sql 语句,然后执行 sql 并将结果映射为 java 对象并返回。
名词解释:
框架:框架是系统中可复用的设计,其实就相当于一个封装了很多功能的工具。
持久层:就是和数据库打交道的那一层。
3. 环境搭建1.创建数据库和表
我们使用 Navicat 创建数据库 mybatis_demo,然后创建 user 表。
CREATE TABLE `user` ( `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '姓名', `sex` varchar(1) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '性别', `age` int DEFAULT NULL COMMENT '年龄', PRIMARY KEY (`id`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
2.创建 Maven 项目
File -> New -> Project -> Maven
引入依赖
junit junit 4.12 test mysql mysql-connector-java 8.0.27 org.mybatis mybatis 3.5.3
3.创建实体类
User 类:
public class User {
private int id;
private String name;
private String sex;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
4.创建 Dao 接口
public interface UserDao {
List getAll();
}
5.创建 sql 映射文件
这是一个 mybatis 使用的配置文件,专门用来写 sql 语句的。
它是一个 xml 文件,因为 sql 语句包含在 mapper 标签中,所以又叫 mapper 文件。一般来说一个表对应一个 xml 文件。
规定:文件名称要和接口保持一致。
UserDao.xml:
select * from user
6.创建 MyBatis 主配置文件
主配置文件也是 xml 文件。
mybatis-config.xml:
7.编写测试类
public class UserTest {
@Test
public void testUser() throws IOException {
// 1.读取配置文件
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
// 2.创建 SqlSessionFactory 工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
// 3.获取 SqlSession 对象
SqlSession session = factory.openSession();
// 4.使用 SqlSession 创建 Dao 接口的代理对象
UserDao userDao = session.getMapper(UserDao.class);
// 5.执行接口的方法
List userList = userDao.getAll();
userList.forEach(user ->{
System.out.println("姓名:"+user.getName()+",性别:"+user.getSex()+",年龄:"+user.getAge());
});
}
}
8.执行结果
9.完整目录结构
上面测试代码中读取配置文件、获取 sqlsession 对象等都是一些重复性的操作,我们可以将这些代码封装到一个工具类中。
MyBatisUtil:
public class MyBatisUtil {
// 定义 SqlSessionFactory
private static SqlSessionFactory factory;
// 使用静态块只创建一次 SqlSessionFactory
static {
try {
// 读取配置文件
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
// 创建 SqlSessionFactory 对象
factory = new SqlSessionFactoryBuilder().build(in);
} catch (Exception e) {
e.printStackTrace();
}
}
// 获取 SqlSession 对象
public static SqlSession getSqlSession() {
SqlSession sqlSession = factory.openSession();
return sqlSession;
}
// 提交事务
public static void commit(SqlSession sqlSession) {
if (null != sqlSession) {
sqlSession.commit();
}
close();
}
// 回滚事务
public static void rollBack(SqlSession sqlSession) {
if (null != sqlSession) {
sqlSession.rollback();
}
close();
}
// 关闭 SqlSession
public static void close() {
SqlSession sqlSession = getSqlSession();
if (null != sqlSession) {
sqlSession.close();
}
}
}
5. 增删改查
这里我们使用 MyBatisUtil 实现用户的增删改查操作。
UserDao:
public interface UserDao {
// 获取所有用户信息
List getAll();
// 新增用户
boolean add(User user);
// 修改用户
boolean update(User user);
// 删除用户
boolean delete(int id);
}
UserDao.xml:
1.查询用户
@Test
public void testGetAll(){
// 1.获取 SqlSession 对象
SqlSession session = MyBatisUtil.getSqlSession();
// 2.使用 SqlSession 创建 Dao 接口的代理对象
UserDao userDao = session.getMapper(UserDao.class);
// 3.执行接口的方法
List userList = userDao.getAll();
userList.forEach(user ->{
System.out.println("姓名:"+user.getName()+",性别:"+user.getSex()+",年龄:"+user.getAge());
});
// 4.关闭 SqlSession
MyBatisUtil.close();
}
2.新增用户
@Test
public void add(){
SqlSession session = null;
try{
// 1.获取 SqlSession 对象
session = MyBatisUtil.getSqlSession();
// 2.使用 SqlSession 创建 Dao 接口的代理对象
UserDao userDao = session.getMapper(UserDao.class);
// 3.执行接口的方法
User user = new User();
user.setName("张无忌");
user.setAge(31);
user.setSex("男");
userDao.add(user);
// 4.提交事务并关闭 SqlSession
MyBatisUtil.commit(session);
}catch (Exception e){
e.printStackTrace();
// 回滚事务
MyBatisUtil.rollBack(session);
}
}
3.修改用户
@Test
public void update(){
SqlSession session = null;
try{
// 1.获取 SqlSession 对象
session = MyBatisUtil.getSqlSession();
// 2.使用 SqlSession 创建 Dao 接口的代理对象
UserDao userDao = session.getMapper(UserDao.class);
// 3.执行接口的方法
User user = new User();
user.setId(3);
user.setName("张无忌");
user.setAge(31);
user.setSex("男");
userDao.update(user);
// 4.提交事务并关闭 SqlSession
MyBatisUtil.commit(session);
}catch (Exception e){
e.printStackTrace();
// 回滚事务
MyBatisUtil.rollBack(session);
}
}
4.删除用户
@Test
public void delete(){
SqlSession session = null;
try{
// 1.获取 SqlSession 对象
session = MyBatisUtil.getSqlSession();
// 2.使用 SqlSession 创建 Dao 接口的代理对象
UserDao userDao = session.getMapper(UserDao.class);
// 3.执行接口的方法
userDao.delete(3);
// 4.提交事务并关闭 SqlSession
MyBatisUtil.commit(session);
}catch (Exception e){
e.printStackTrace();
// 回滚事务
MyBatisUtil.rollBack(session);
}
}
6. MyBatist核心配置文件
mybatis-config.xml 是 mybatis 的主配置文件,所有的配置都在 configuration 标签里面。
它主要包括:定义别名、配置数据源、配置 mapper 文件等。
1.定义别名
前面我们在 mapper 文件里面设置的 resultType 是全路径名。
为了简化代码,MyBatis 允许我们给全路径名起一个简单的别名,一般是实体类的类名。我们可以在 mybatis-config.xml 里面这样配置:
上面 name 的值一般是实体类所在包的全路径,配置完之后我们就可以直接用 user 代替 com.xxl.model.User 了。
2.配置数据源
我们使用 dataSource 标签配置连接数据库的各种参数,其中 dataSource 的 type 表示使用连接池配置数据源。
为了便于维护数据库的连接参数,我们一般会将这些参数存放在一个专门的文件中,MyBatis 主配置文件再从这个文件中读取连接数据库的参数数据。
在 resources 目录下面新建 jdbc.properties 文件
在主配置文件使用 properties 标签引入 jdbc.properties 文件
修改 dataSource
3.配置查找 mapper 文件的路径
4.事务
Mybatis 框架是对 JDBC 的封装,所以 Mybatis 框架的事务控制方式,其实就是 JDBC 的 Connection 对象的 commit(), rollback() 。
type=“JDBC” : 表示使用 JDBC 的事务管理机制。但是 MyBatis 默认将自动提交功能关闭了,改为了手动提交。
所以上面的测试代码中,我们在做完增删改之后还要手动提交事务。
自动提交事务
我们在获取 sqlSession 的时候,只需要将
openSession 的参数设置为 true,就能将 MyBatis 设置为自动提交事务。
// 读取配置文件
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
// 创建 SqlSessionFactory 对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
// 获取 SqlSession 对象
SqlSession sqlSession = factory.openSession(true);
7. mapper 映射文件
我们之前定义完 Dao 接口之后,还要定义一个它的实现类 DaoImpl。
而 Mybatis 框架根据 mapper.xml 文件帮助我们自动为接口生成了一个代理对象。
// 使用 SqlSession 创建 Dao 接口的代理对象 UserDao userDao = session.getMapper(UserDao.class);
然后我们就可以调用接口中的方法了,所以这个 mapper 文件很重要。
1.约定格式
① DAO 的全类名必须和对应的 mapper 文件中的namespace一致。
② DAO 中的方法名称必须和 mapper 文件中增删改查操作的id一致。
③ DAO 中的方法的返回值必须和 mapper 文件中操作的返回值类型一致。
④ DAO 中的方法的参数类型必须和 mapper 文件中的输入参数的类型一致。
注: mapper 文件中的 sql 语句不要加分号,id 不能重复。
2.封装输出结果
① resultType
执行 sql 之后得到 ResultSet 转换后的结果类型,使用类型的完全限定名或别名。如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身。resultType 和 resultMap,不能同时使用。
简单类型
接口方法
String getName(int id);
mapper 文件:
对象类型
接口方法
User getUser(int id);
mapper 文件:
Map 类型
接口方法
@MapKey("id")
Map getUser();
mapper 文件:
② resultMap
当数据库表中的列名和实体类的属性名不一致的时候,我们可以使用 resultMap 定义 sql 的结果和 java 对象属性的映射关系。
例如:
3.模糊查询
方式一:{} 中的值必须是 value
方式二
4.添加/修改处理 null 值
Mybatis 在执行添加、修改操作时不允许出现空值,所以在添加修改
时,要想使某个列的值为空,必须添加 jdbcType 属性。
例如:
8. MyBatis 传参insert into user(name,sex,age) values(#{name,jdbcType=VARCHAR},#{sex,jdbcType=INTEGER},#{age,jdbcType=INTEGER})
在 Mapper 文件中,我们可以使用 #{param} 和 ${param} 获取接口中传递的参数。
#{param} 是使用占位符的方式,${param} 是采用拼接 sql 语句的方式。使用 $ 有 sql 注入的风险,所以下面的例子中都会采用 #{param} 的方式。
一个参数
#{}:可以以任意的名字获取参数值。
例如:
多个参数
1.传递多个参数
传输多个参数,Mybatis会将这些参数放到map集合里面,可以通过 @Param 指定mapper 文件中参数的名字。例如:
接口:
ListgetUser(@Param("userName") String name,@Param("userSex") int age);
mapper 文件:
2.传递对象
传输参数为 JavaBean,#{} 可以通过属性名获取属性值。
接口:
// 修改用户 boolean update(User user);
mapper 文件:
update user set name = #{name}, sex = #{sex},age = #{age} where id = #{id}
3.传递 Map
传递的参数为 map 时,mapper 文件使用 # { key } 获取参数值。
例如:
Mapdata = new HashMap (); data.put("userName","知否君"); data.put("userAge",21);
接口:
ListgetUser(Map map);
mapper 文件:
9. 动态 SQL动态 SQL 是 MyBatis 强大特性之一,主要用于解决查询条件不确定的情况,它可以极大的简化我们拼装 SQL 的操作。
1.if 标签
If 标签用于完成简单的判断,当标签中 test 的值为 true 时,会将其包含的 SQL 片段拼接到其所在的 SQL 语句中。
语法格式:
sql 片段
例如:
2.where 标签
上面的例子中如果 name 参数存在,为了保证 sql 语句的正确性,我们不得不添加 where 1=1 。
Where 标签就是为了解决 sql 语句中 where 关键字以及条件中第一个 and 或者 or 的问题。
例如:
3.trim 标签
trim 标签可以在条件判断完的 sql 语句前后添加或者去掉指定的字符。
例如:
4.choose(when、otherwise) 标签
choose 标签主要是用于分支判断,类似于 java 中的 switch case,只会满足所有分支中的一个。
例如:
5.set 标签
set 标签主要是用于解决修改操作中 sql 语句中可能多出逗号的问题。
例如:
update user where id = #{id} name = #{name}, sex = #{sex}, age = #{age}
6.foreach 标签
foreach 标签主要用于循环迭代。
例如:
7.sql 标签
sql 标签是用于抽取可重用的 sql 片段,将相同的、使用频繁的 sql 片段抽取出来,单独定义,方便多次引用。
例如:
10. 注解式开发id,name,age,sex
通过观察 Mapper 文件我们发现,Mapper 文件的核心就是与 Dao 做接口映射,然后里面写一些 sql 语句。
那我能不能不要 mapper 文件,直接在接口里面写 sql 语句?可以的,MyBatsi 为我们提供了注解式开发。
1.修改主配置文件
虽然不用写 mapper 文件了,但是我们要在接口里面写 sql 语句,你得让 MyBatis 知道吧。所以需要告诉 MyBatis 带有注解的接口在哪里。
public interface UserDao {
// 获取所有用户信息
@Select("select * from user")
List getUser();
// 新增用户
@Insert("insert into user(name,sex,age) values(#{name},#{sex},#{age})")
boolean add(User user);
// 修改用户
@Update("update user set name = #{name}, sex = #{sex},age = #{age} where id = #{id}")
boolean update(User user);
// 删除用户
@Delete("delete from user where id = #{id}")
boolean delete(int id);
}
3.测试
@Test
public void testGetAll(){
// 1.获取 SqlSession 对象
SqlSession session = MyBatisUtil.getSqlSession();
// 2.使用 SqlSession 创建 Dao 接口的代理对象
UserDao userDao = session.getMapper(UserDao.class);
// 3.执行接口的方法
List userList = userDao.getUser();
userList.forEach(user ->{
System.out.println("姓名:"+user.getName()+",性别:"+user.getSex()+",年龄:"+user.getAge());
});
// 4.关闭 SqlSession
MyBatisUtil.close();
}
执行结果:
一对一
例如:一个人对应一张身份证,一张身份证对应一个人。在 MyBatis 的 mapper 文件中使用 association 处理一对一关系。
创建表:
A 表的一条记录,对应 B 表的一条记录,且 A 的主键作为 B 表的外键。这主要看以哪张表为中心。
下面例子中将用户信息表的主键(id)作为用户表的外键(info_id)。
用户表:user
CREATE TABLE `user` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', `name` varchar(20) DEFAULT NULL COMMENT '姓名', `sex` varchar(1) DEFAULT NULL COMMENT '性别', `age` int(11) DEFAULT NULL COMMENT '年龄', `info_id` int(11) DEFAULT NULL COMMENT '用户信息id', PRIMARY KEY (`id`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
INSERT INTO `mybatis_demo`.`user`(`id`, `name`, `sex`, `age`, `info_id`) VALUES (1, '张三', '男', 18, 1); INSERT INTO `mybatis_demo`.`user`(`id`, `name`, `sex`, `age`, `info_id`) VALUES (2, '李四', '男', 19, 2);
用户信息表:user_info
CREATE TABLE `user_info` ( `id` int(11) NOT NULL AUTO_INCREMENT, `number` varchar(20) DEFAULT NULL COMMENT '身份证编号', `address` varchar(50) DEFAULT NULL COMMENT '家庭地址', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;
INSERT INTO `mybatis_demo`.`user_info`(`id`, `number`, `address`) VALUES (1, '411121200302174025', '上海外滩'); INSERT INTO `mybatis_demo`.`user_info`(`id`, `number`, `address`) VALUES (2, '411121200222154554', '北京三里屯');
用户实体类:User
public class User {
private int id;
private String name;
private String sex;
private int age;
// 用户信息属性
private UserInfo userInfo;
public UserInfo getUserInfo() {
return userInfo;
}
public void setUserInfo(UserInfo userInfo) {
this.userInfo = userInfo;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + ''' +
", sex='" + sex + ''' +
", age=" + age +
'}';
}
}
用户信息类:
public class UserInfo {
private int id;
private String number;
private String address;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "UserInfo{" +
"id=" + id +
", number='" + number + ''' +
", address='" + address + ''' +
'}';
}
}
UserDao:
public interface UserDao {
List getAll();
}
UserDao.xml:
测试代码:
@Test
public void testUserGetAll(){
// 1.获取 SqlSession 对象
SqlSession session = MyBatisUtil.getSqlSession();
// 2.使用 SqlSession 创建 Dao 接口的代理对象
UserDao userDao = session.getMapper(UserDao.class);
// 3.执行接口的方法
List userList = userDao.getAll();
userList.forEach(user ->{
System.out.println(user+" "+user.getUserInfo());
});
// 4.关闭 SqlSession
MyBatisUtil.close();
}
测试结果:
一对多
例如:一个部门对应多个员工,一个员工属于一个部门。在 MyBatis 的 mapper 文件中使用 collection 处理一对多关系。
创建表:
A 表的一条记录,对应 B 表的多条记录,且 A 的主键作为 B 表的外键。
下面例子中将部门表的主键(id)作为员工表的外键(dep_id)。
部门表:department
CREATE TABLE `department` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) DEFAULT NULL COMMENT '部门名称', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;
INSERT INTO `mybatis_demo`.`department`(`id`, `name`) VALUES (1, '研发部'); INSERT INTO `mybatis_demo`.`department`(`id`, `name`) VALUES (2, '人事部'); INSERT INTO `mybatis_demo`.`department`(`id`, `name`) VALUES (3, '销售部');
员工表:employee
CREATE TABLE `employee` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) DEFAULT NULL COMMENT '员工姓名', `age` int(11) DEFAULT NULL COMMENT '员工年龄', `sex` varchar(1) DEFAULT NULL COMMENT '员工性别', `dep_id` int(11) DEFAULT NULL COMMENT '部门id', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4;
INSERT INTO `mybatis_demo`.`employee`(`id`, `name`, `age`, `sex`, `dep_id`) VALUES (1, '张无忌', 21, '男', 1); INSERT INTO `mybatis_demo`.`employee`(`id`, `name`, `age`, `sex`, `dep_id`) VALUES (2, '周芷若', 19, '女', 2); INSERT INTO `mybatis_demo`.`employee`(`id`, `name`, `age`, `sex`, `dep_id`) VALUES (3, '赵敏', 19, '女', 3); INSERT INTO `mybatis_demo`.`employee`(`id`, `name`, `age`, `sex`, `dep_id`) VALUES (4, '小昭', 20, '女', 2); INSERT INTO `mybatis_demo`.`employee`(`id`, `name`, `age`, `sex`, `dep_id`) VALUES (5, '蛛儿', 19, '女', 1);
部门实体类:
public class Department {
private String id;
private String name;
private List employeeList;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List getEmployeeList() {
return employeeList;
}
public void setEmployeeList(List employeeList) {
this.employeeList = employeeList;
}
@Override
public String toString() {
return "Department{" +
"id='" + id + ''' +
", name='" + name + ''' +
'}';
}
}
员工实体类:
public class Employee {
private int id;
private String name;
private String sex;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + ''' +
", sex='" + sex + ''' +
", age=" + age +
'}';
}
}
DepartmentDao:
public interface DepartmentDao {
List getAll();
}
DepartmentDao.xml:
测试代码:
@Test
public void testDepartmentGetAll(){
// 1.获取 SqlSession 对象
SqlSession session = MyBatisUtil.getSqlSession();
// 2.使用 SqlSession 创建 Dao 接口的代理对象
DepartmentDao departmentDao = session.getMapper(DepartmentDao.class);
// 3.执行接口的方法
List departmentList = departmentDao.getAll();
departmentList.forEach(department ->{
System.out.println("部门:"+department+" 员工:"+department.getEmployeeList());
});
// 4.关闭 SqlSession
MyBatisUtil.close();
}
测试结果:
多对多
例如:例如一个学生可以有多门课程,一门课程可以属于多个学生。多对多可以理解为是一对多和多对一的组合。要实现多对多,一般都需要有一张中间表(也叫关联表),形成多对多的形式。
创建表:
学生表:student
CREATE TABLE `student` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', `name` varchar(20) DEFAULT NULL COMMENT '姓名', `sex` varchar(1) DEFAULT NULL COMMENT '性别', `age` int(11) DEFAULT NULL COMMENT '年龄', PRIMARY KEY (`id`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;
INSERT INTO `mybatis_demo`.`student`(`id`, `name`, `sex`, `age`) VALUES (1, '张三', '男', 18); INSERT INTO `mybatis_demo`.`student`(`id`, `name`, `sex`, `age`) VALUES (2, '李四', '女', 21); INSERT INTO `mybatis_demo`.`student`(`id`, `name`, `sex`, `age`) VALUES (3, '王五', '男', 19);
课程表:course
CREATE TABLE `course` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) DEFAULT NULL COMMENT '课程名称', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4;
INSERT INTO `mybatis_demo`.`course`(`id`, `name`) VALUES (1, 'java开发'); INSERT INTO `mybatis_demo`.`course`(`id`, `name`) VALUES (2, '数据结构'); INSERT INTO `mybatis_demo`.`course`(`id`, `name`) VALUES (3, '大数据开发'); INSERT INTO `mybatis_demo`.`course`(`id`, `name`) VALUES (4, '云原生开发');
学生-课程关联表:student_course
CREATE TABLE `student_course` ( `student_id` int(11) NOT NULL, `course_id` int(11) NOT NULL, PRIMARY KEY (`student_id`,`course_id`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `mybatis_demo`.`student_course`(`student_id`, `course_id`) VALUES (1, 2); INSERT INTO `mybatis_demo`.`student_course`(`student_id`, `course_id`) VALUES (1, 3); INSERT INTO `mybatis_demo`.`student_course`(`student_id`, `course_id`) VALUES (2, 1); INSERT INTO `mybatis_demo`.`student_course`(`student_id`, `course_id`) VALUES (2, 2); INSERT INTO `mybatis_demo`.`student_course`(`student_id`, `course_id`) VALUES (3, 3); INSERT INTO `mybatis_demo`.`student_course`(`student_id`, `course_id`) VALUES (3, 4);
学生实体类:
public class Student {
private int id;
private String name;
private String sex;
private int age;
private List courseList;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public List getCourseList() {
return courseList;
}
public void setCourseList(List courseList) {
this.courseList = courseList;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + ''' +
", sex='" + sex + ''' +
", age=" + age +
'}';
}
}
课程实体类:
public class Course {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Course{" +
"id=" + id +
", name='" + name + ''' +
'}';
}
}
StudentDao:
public interface StudentDao {
List getAll();
}
StudentDao.xml:
测试代码:
@Test
public void testStudentGetAll(){
// 1.获取 SqlSession 对象
SqlSession session = MyBatisUtil.getSqlSession();
// 2.使用 SqlSession 创建 Dao 接口的代理对象
StudentDao studentDao = session.getMapper(StudentDao.class);
// 3.执行接口的方法
List studentList = studentDao.getAll();
studentList.forEach(student ->{
System.out.println("学生:"+student+" 课程:"+student.getCourseList());
});
// 4.关闭 SqlSession
MyBatisUtil.close();
}
测试结果:
12. 分页插件我们之前在写分页的时候,不仅要自定义一个 Page 类,还要拼接 sql 语句,最后还要封装数据。真的是”恶心他妈妈给恶心开门——恶心到家了。“
为了解决这个问题,MyBatis 为我们提供了一个通用的分页工具:PageHelper。
使用步骤:
1.引入依赖
com.github.pagehelper pagehelper 5.1.4
2.修改主配置文件
在 environments 标签之前添加:
3.准备数据
4.测试代码
@Test
public void testGetAll(){
// 1.获取 SqlSession 对象
SqlSession session = MyBatisUtil.getSqlSession();
// 2.使用 SqlSession 创建 Dao 接口的代理对象
UserDao userDao = session.getMapper(UserDao.class);
// 3.执行接口的方法
Page page = PageHelper.startPage(2, 3);
List userList = userDao.getUser();
System.out.println("当前页:"+page.getPageNum());
System.out.println("每页条数:"+page.getPageSize());
System.out.println("总条数:"+page.getTotal());
System.out.println("总页数:"+page.getPages());
System.out.println("-------------------------");
userList.forEach(user ->{
System.out.println("姓名:"+user.getName()+",性别:"+user.getSex()+",年龄:"+user.getAge());
});
// 4.关闭 SqlSession
MyBatisUtil.close();
}
5.执行结果