MyBatis实战项目测试
项目要求
后台:
使用Mybatis框架
数据库简述:
- 学生
- 姓名、学号、性别、所属班级、创建时间
- 班级
- 名称、备注、创建时间
- 老师
- 名称、性别、工号、创建时间
- 老师和班级多对多
功能
学生模块
- 添加、删除、批量删除、修改
- 查询
- 分页
- 根据姓名(模糊)、学号、班级中的一个或多个进行查询
教师模块
- 添加、删除、修改
- 查询
- 分页
- 返回所有授课班级信息
班级模块
- 添加
- 添加班级时可以同时选择添加多个教师
- 教师如果不存在插入数据并维护好关联表
- 删除
- 修改
- 查询
- 分页
- 返回所有教师信息
具体实现
一、数据库设计
数据库的设计很简单,根据要求设置好相应的字段即可
教师与班级表之间为多对多关系,故设计了一个中间表
表的sql语句如下:
/*Navicat Premium Data TransferSource Server : 本地数据库Source Server Type : MySQLSource Server Version : 80031Source Host : localhost:3306Source Schema : train1017Target Server Type : MySQLTarget Server Version : 80031File Encoding : 65001Date: 30/10/2024 17:34:26
*/SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for class
-- ----------------------------
DROP TABLE IF EXISTS `class`;
CREATE TABLE `class` (`c_id` int(0) NOT NULL AUTO_INCREMENT COMMENT '班级id',`c_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '班级名称',`c_remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '班级备注',`c_createtime` timestamp(0) NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '班级创建时间',PRIMARY KEY (`c_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 22 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of class
-- ----------------------------
INSERT INTO `class` VALUES (1, '软工1', '软工1备注', '2024-10-27 15:03:43');
INSERT INTO `class` VALUES (2, '软工2', '软工2备注', '2024-10-16 15:05:52');
INSERT INTO `class` VALUES (3, '软工3', '软工3备注', '2024-10-09 15:05:55');-- ----------------------------
-- Table structure for relation
-- ----------------------------
DROP TABLE IF EXISTS `relation`;
CREATE TABLE `relation` (`r_id` int(0) NOT NULL AUTO_INCREMENT COMMENT '关系表id',`t_id` int(0) NULL DEFAULT NULL COMMENT '教师id',`c_id` int(0) NULL DEFAULT NULL COMMENT '班级id',PRIMARY KEY (`r_id`) USING BTREE,INDEX `relation_teacher`(`t_id`) USING BTREE,INDEX `relation_class`(`c_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 26 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of relation
-- ----------------------------
INSERT INTO `relation` VALUES (1, 1, 1);
INSERT INTO `relation` VALUES (2, 1, 2);
INSERT INTO `relation` VALUES (3, 2, 2);
INSERT INTO `relation` VALUES (4, 2, 3);
INSERT INTO `relation` VALUES (5, 3, 3);
INSERT INTO `relation` VALUES (6, 3, 1);
INSERT INTO `relation` VALUES (7, 4, 1);
INSERT INTO `relation` VALUES (8, 4, 2);-- ----------------------------
-- Table structure for student
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (`s_id` int(0) NOT NULL AUTO_INCREMENT COMMENT '学生id',`s_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '学生姓名',`s_no` int(0) NULL DEFAULT NULL COMMENT '学生学号',`s_sex` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '学生性别',`c_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '学生所属班级',`s_createtime` timestamp(0) NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '学生创建时间',PRIMARY KEY (`s_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 20 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES (1, '学生1', 111, '男', '1', '2024-10-16 15:07:38');
INSERT INTO `student` VALUES (2, '学生2', 222, '女', '1', '2024-10-15 15:11:17');
INSERT INTO `student` VALUES (3, '学生3', 333, '男', '2', '2024-10-24 15:11:22');
INSERT INTO `student` VALUES (4, '学生4', 444, '女', '2', '2024-10-16 15:11:27');
INSERT INTO `student` VALUES (5, '学生5', 555, '男', '3', '2024-10-15 15:11:31');-- ----------------------------
-- Table structure for teacher
-- ----------------------------
DROP TABLE IF EXISTS `teacher`;
CREATE TABLE `teacher` (`t_id` int(0) NOT NULL AUTO_INCREMENT COMMENT '教师id',`t_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '教师姓名',`t_sex` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '教师性别',`t_no` int(0) NULL DEFAULT NULL COMMENT '教师工号',`t_createtime` datetime(0) NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '教师创建时间',PRIMARY KEY (`t_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of teacher
-- ----------------------------
INSERT INTO `teacher` VALUES (1, '老师1', '男', 1111, '2024-10-22 15:14:21');
INSERT INTO `teacher` VALUES (2, '老师2', '女', 2222, '2024-10-23 15:14:17');
INSERT INTO `teacher` VALUES (3, '老师3', '男', 3333, '2024-10-16 15:14:24');
INSERT INTO `teacher` VALUES (4, '老师4', '女', 4444, '2024-10-17 15:14:27');SET FOREIGN_KEY_CHECKS = 1;
设计好的表如下:
学生表
教师表
班级表
教师与班级中间表
MyBatis代码实现
二、环境准备
1.创建Maven项目,添加相应的依赖
<dependencies><!--mybatis核心包--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.5</version></dependency><!--mysql驱动包--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version></dependency><!-- 单元测试 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.10</version></dependency><!-- 日志 --><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency></dependencies>
2.创建相应的实体类,dao层接口,相应的mapper文件
完整的项目结构如下
实体类(提供相应getter、setter、有参无参构造方法、重写toString方法)
public class Student {private Integer s_id;private String s_name;private Integer s_no;private String s_sex;private Integer c_id;/*创建时间*/private LocalDateTime s_createtime;
}
public class Teacher {private Integer t_id;private String t_name;private String t_sex;private Integer t_no;/*创建时间*/private LocalDateTime t_createtime;
}
public class Class {private Integer c_id;private String c_name;private String c_remark;/*创建时间*/private LocalDateTime c_createtime;
}
public class Relation {private Integer r_id;private Integer t_id;private Integer c_id;
}
dao层接口
public interface StudentDao {}
public interface TeacherDao {}
public interface ClassDao {}
public interface RelationDao {}
相关mapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qcby.dao.StudentDao"></mapper><?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qcby.dao.TeacherDao"></mapper><?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qcby.dao.ClassDao"></mapper><?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qcby.dao.RelationDao"></mapper>
相关测试文件
public class StudentTest {private InputStream in = null;private SqlSession session = null;private StudentDao mapper = null;@Before //前置通知, 在方法执行之前执行public void init() throws IOException {//加载主配置文件,目的是为了构建SqlSessionFactory对象in = Resources.getResourceAsStream("SqlMapConfig.xml");//创建SqlSessionFactory对象SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);//通过SqlSessionFactory工厂对象创建SqlSesssion对象session = factory.openSession();//通过Session创建v接口代理对象mapper = session.getMapper(StudentDao.class);}@After //@After: 后置通知, 在方法执行之后执行 。public void destory() throws IOException {//释放资源session.close();in.close();}
}public class TeacherTest {private InputStream in = null;private SqlSession session = null;private TeacherDao mapper = null;@Before //前置通知, 在方法执行之前执行public void init() throws IOException {//加载主配置文件,目的是为了构建SqlSessionFactory对象in = Resources.getResourceAsStream("SqlMapConfig.xml");//创建SqlSessionFactory对象SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);//通过SqlSessionFactory工厂对象创建SqlSesssion对象session = factory.openSession();//通过Session创建UserDao接口代理对象mapper = session.getMapper(TeacherDao.class);}@After //@After: 后置通知, 在方法执行之后执行 。public void destory() throws IOException {//释放资源session.close();in.close();}
}public class ClassTest {private InputStream in = null;private SqlSession session = null;private ClassDao mapper = null;@Before //前置通知, 在方法执行之前执行public void init() throws IOException {//加载主配置文件,目的是为了构建SqlSessionFactory对象in = Resources.getResourceAsStream("SqlMapConfig.xml");//创建SqlSessionFactory对象SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);//通过SqlSessionFactory工厂对象创建SqlSesssion对象session = factory.openSession();//通过Session创建UserDao接口代理对象mapper = session.getMapper(ClassDao.class);}@After //@After: 后置通知, 在方法执行之后执行 。public void destory() throws IOException {//释放资源session.close();in.close();}
}
3.mybatis配置文件SqlMapConfig.xml如下
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!--seetings 控制mybatis的全局行为--><settings><!--设置mybatis输出日志--><setting name="logImpl" value="STDOUT_LOGGING"/></settings><environments default="mysql"><environment id="mysql"><!--配置事务的类型,使用本地事务策略--><transactionManager type="JDBC"></transactionManager><!--是否使用连接池 POOLED表示使用链接池,UNPOOLED表示不使用连接池--><dataSource type="POOLED"><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/train1017"/><property name="username" value="root"/><property name="password" value="t123456"/></dataSource></environment></environments><mappers><mapper resource="mapper/StudentMapper.xml"></mapper><mapper resource="mapper/TeacherMapper.xml"></mapper><mapper resource="mapper/ClassMapper.xml"></mapper><mapper resource="mapper/RelationMapper.xml"></mapper></mappers>
</configuration>
三、学生模块
注意除了查询,其他操作都需要commit才能生效
(1)添加
StudentDao.java
// 添加
int insert(Student student);
StudentMapper.xml
<!--添加int insert(Student student);--><insert id="insert" parameterType="com.qcby.entity.Student">insert into student(s_name, s_no, s_sex, c_id, s_createtime)values (#{s_name}, #{s_no}, #{s_sex}, #{c_id}, #{s_createtime,jdbcType=TIMESTAMP})</insert>
StudentTest.java
//插入@Testpublic void insert() {Student student = new Student();student.setS_name("学生7");student.setS_no(11116666);student.setS_sex("女");student.setC_id(3);student.setS_createtime(LocalDateTime.now());mapper.insert(student);session.commit();}
(2)删除
StudentDao.java
// 删除int delete(Integer id);
StudentMapper.xml
<!--删除int delete(Integer id);--><delete id="delete" parameterType="integer">delete from student where s_id = #{id}</delete>
StudentTest.java
//删除@Testpublic void delete() {mapper.delete(21);session.commit();}
(3)批量删除
StudentDao.java
// 批量删除int deleteBatch(List<Integer> ids);
StudentMapper.xml
<!--批量删除int deleteBatch(List<Integer> ids);--><delete id="deleteBatch" parameterType="list">delete from studentwhere s_id in<foreach item="id" collection="list" open="(" separator="," close=")">#{id}</foreach></delete>
foreach标签相关用法
StudentTest.java
// 批量删除@Testpublic void deleteBatch() {List<Integer> ids = Arrays.asList(26, 25);mapper.deleteBatch(ids);session.commit();}
(4)修改
StudentDao.java
// 更新int updateById(Student student);
StudentMapper.xml
<!-- 更新int updateById(Student student); --><update id="updateById" parameterType="com.qcby.entity.Student">update student<set><if test="s_name != null">s_name = #{s_name},</if><if test="s_no != null">s_no = #{s_no},</if><if test="s_sex != null">s_sex = #{s_sex},</if><if test="c_id != null">c_id = #{c_id},</if><if test="c_createtime != null">c_createtime = #{c_createtime},</if></set>where s_id = #{s_id}</update>
StudentTest.java
// 更新@Testpublic void updateById() {Student student = new Student();student.setS_id(23); //要修改的学生的idstudent.setS_name("kaka"); //要修改的内容mapper.updateById(student);session.commit();}
(5)分页查询
sql语句
-- 分页查询语句
select * from student limit 3 offset 0 # 查询第1页,每页3条数据
select * from student limit 3 offset 3 # 查询第2页,每页3条数据
select * from student limit 3 offset 6 # 查询第3页,每页3条数据
# pageIndex ---> 当前页面为第几页 1 2 3
# pageSize ---> 每页查询数据条数 每一页3条数据
SELECT * FROM student LIMIT pageSize OFFSET pageSize*(pageIndex-1)
StudentDao.java
// 分页查询,每页3条记录List<Student> selectByPage(Integer pageSize, Integer offset);
StudentMapper.xml
<!-- 分页查询,每页3条记录List<Student> selectByPage(Integer pageSize, Integer offset);param1对应pageSize param2对应offset 入参都为相同的数据类型才能使用--><select id="selectByPage" parameterType="java.lang.Integer" resultType="com.qcby.entity.Student">select * from studentlimit #{param1} offset #{param2}</select>
StudentTest.java
//分页查询@Testpublic void selectByPage() {int pageSize = 3;int pageIndex = 1; // 查询第1页int offset = (pageIndex - 1) * pageSize;List<Student> students = mapper.selectByPage(pageSize, offset);for (Student student : students) {System.out.println(student);}}
(6)根据姓名(模糊)、学号、班级中的一个或多个进行查询
StudentDao.java
//根据姓名模糊查询、学号查询,班级查询List<Student> selectByNameSnoClass(Student student);
StudentMapper.xml
<!--根据姓名模糊查询、学号查询,班级查询List<Student> selectByNameSnoClass(Student student); --><select id="selectByNameSnoClass" parameterType="com.qcby.entity.Student" resultType="com.qcby.entity.Student">select * from student<where><if test="s_name != null and s_name != ''">and s_name like CONCAT('%', #{s_name}, '%')</if><if test="s_no != null and s_no != ''">and s_no = #{s_no}</if><if test="c_id != null and c_id != ''">and c_id = #{c_id}</if></where></select>
StudentTest.java
//根据姓名模糊查询、学号查询,班级查询@Testpublic void selectByNameSnoClass() {Student student = new Student();student.setS_name("学生");student.setS_no(444);mapper.selectByNameSnoClass(student);System.out.println(student.toString());}
四、老师模块
(1)添加
TeacherDao.java
// 添加int insert(Teacher teacher);
TeacherMapper.xml
<!--添加int insert(Teacher teacher);--><insert id="insert" parameterType="com.qcby.entity.Teacher">insert into teacher(t_name, t_no, t_sex, t_createtime)values (#{t_name}, #{t_no}, #{t_sex}, #{t_createtime})</insert>
TeacherTest.java
//插入@Testpublic void insert() {Teacher teacher = new Teacher();teacher.setT_name("huhuhu");teacher.setT_sex("男");teacher.setT_no(3456);teacher.setS_createtime(LocalDateTime.now());mapper.insert(teacher);session.commit();}
(2)删除
TeacherDao.java
// 删除int delete(Integer id);
TeacherMapper.xml
<!--删除int delete(Integer id);--><delete id="delete" parameterType="integer">delete from teacher where t_id = #{id}</delete>
TeacherTest.java
//删除@Testpublic void delete() {mapper.delete(9);session.commit();}
(3)修改
TeacherDao.java
// 更新int updateById(Teacher teacher);
TeacherMapper.xml
<!-- 更新int updateById(Teacher teacher); --><update id="updateById" parameterType="com.qcby.entity.Teacher">update teacher<set><if test="t_name != null ">t_name = #{t_name},</if><if test="t_no != null">t_no = #{t_no},</if><if test="t_sex != null">t_sex = #{t_sex},</if><if test="t_createtime != null">t_createtime = #{t_createtime},</if></set>where t_id = #{t_id}</update>
TeacherTest.java
// 更新@Testpublic void updateById() {Teacher teacher = new Teacher();teacher.setT_id(10);teacher.setT_name("kakakak");teacher.setT_createtime(LocalDateTime.now());mapper.updateById(teacher);session.commit();}
(4)分页查询
TeacherDao.java
// 分页查询,每页3条记录List<Teacher> selectByPage(Integer pageSize, Integer offset);
TeacherMapper.xml
<!-- 分页查询,每页3条记录List<Teacher> selectByPage(Integer pageSize, Integer offset); --><select id="selectByPage" parameterType="java.lang.Integer" resultType="com.qcby.entity.Teacher">select * from teacherorder by t_idlimit #{param1} offset #{param2}</select>
TeacherTest.java
//分页查询@Testpublic void selectByPage() {int pageSize = 3;int pageIndex = 1; // 查询第1页int offset = (pageIndex - 1) * pageSize;List<Teacher> teachers = mapper.selectByPage(pageSize, offset);for (Teacher teacher : teachers) {System.out.println(teacher);}}
(5)查询返回所有授课班级信息
Teacher实体类中加入Class属性(以及相应get、set方法),class不止一个,故使用List
private List<Class> classList;
TeacherDao.java
// 通过分步查询查询教师及其相关联的班级信息第一步:查询老师信息Teacher selectTeachersWithClassesStep1(Integer t_id);
TeacherMapper.xml
<!-- 通过分步查询查询教师及其相关联的班级信息第一步:查询老师信息Teacher selectTeachersWithClassesStep1(Integer t_id); --><select id="selectTeachersWithClassesStep1" resultMap="TeachersWithClassesStep">SELECT * FROM teacher where t_id = #{t_id}</select><resultMap id="TeachersWithClassesStep" type="com.qcby.entity.Teacher"><id property="t_id" column="t_id"/><result property="t_name" column="t_name"/><result property="t_sex" column="t_sex"/><result property="t_no" column="t_no"/><result property="t_createtime" column="t_createtime"/><collection property="classList" column="t_id" ofType="com.qcby.entity.Class"select="com.qcby.dao.ClassDao.selectTeachersWithClassesStep2"></collection></resultMap>
ClassDao.java
// 通过分步查询查询教师及其相关联的班级信息第二步:查询班级信息List<Class> selectTeachersWithClassesStep2(Integer c_id);
ClassMapper.xml
<!-- 通过分步查询查询教师及其相关联的班级信息第二步:查询班级信息List<Class> selectTeachersWithClassesStep2(Integer c_id);--><select id="selectTeachersWithClassesStep2" parameterType="integer" resultType="com.qcby.entity.Class">SELECT * FROM class WHERE c_id in (SELECT c_id FROM relation WHERE t_id = #{t_id})</select>
TeacherTest.java
// 查询教师及其相关联的班级信息@Testpublic void selectTeachersWithClassesStep() {Teacher teacher = mapper.selectTeachersWithClassesStep1(4);System.out.println(teacher);}
班级模块后续更新