实验一 mybatis操作
实验目的
- 掌握MyBatis环境搭建,MyBatis核心配置文件及其元素的使用,MyBatis映射文件及其元素的使用。
- 掌握MyBatis中动态SQL元素的使用,MyBatis的条件查询操作,MyBatis的复杂查询操作。
- 掌握MyBatis的关联映射和缓存机制。
- 掌握MyBatis的基于注解的多对多关联查询开发。
实验环境
- IntelliJ IDEA Ultimate2024
- jdk-17
- MySQL 8.0
实验内容
1 数据准备
- 创建学生表(student)、课程表(course)、成绩表(score)。
sql
CREATE DATABASE experiment;
USE experiment;
CREATE TABLE student (
id INT PRIMARY KEY AUTO_INCREMENT, -- 学生ID,主键,自动递增
name varchar(32), -- 学生姓名,最多32字符
sex VARCHAR(8), -- 性别,最多8字符,通常为"男"或"女"
age INT, -- 年龄,整数类型
sclass INT -- 班级编号,整数类型
);
CREATE TABLE course (
id INT PRIMARY KEY AUTO_INCREMENT, -- 课程ID,主键,自动递增
name varchar(32), -- 课程名称,最多32字符
semester char(10) -- 学期标识,例如'2024-1'表示2024年第一学期
);
CREATE TABLE score (
id INT PRIMARY KEY AUTO_INCREMENT, -- 成绩记录ID,主键,自动递增
student_id INT, -- 学生ID,外键引用student表的id
course_id INT, -- 课程ID,外键引用course表的id
score INT, -- 分数,整数类型
FOREIGN KEY(student_id) REFERENCES student(id),
FOREIGN KEY(course_id) REFERENCES course(id)
);
2.插入代表个人信息的真实数据。
sql
-- 插入学生信息
INSERT INTO student (name, sex, age, sclass)
VALUES ('lql', '女', 21, 1),
('大学生2', '男', 20, 2);
-- 插入课程信息
INSERT INTO course (name, semester)
VALUES ('程序设计基础', '2022-1'),
('管理学原理', '2022-1'),
('Java核心技术', '2023-1'),
('基于轻量型架构的WEB开发', '2024-1');
-- 插入学生成绩信息
INSERT INTO score (student_id, course_id, score)
VALUES (1, 1, 92),
(1, 2, 95),
(1, 3, 93),
(2, 1, 88),
(2, 2, 90);
2 环境准备
2.1安装和配置IntelliJ IDEA Ultimate 2024
- 下载和安装:
- 访问JetBrains官网,下载IntelliJ IDEA Ultimate 2024版。安装并启动IDEA。
- 配置JDK:
- 在IDEA中,打开"File" > "Project Structure" > "SDKs"。添加JDK 17,确保其为项目使用的JDK。
2.2 安装和配置MySQL 8.0
- 下载和安装:
- 访问MySQL官网,下载MySQL 8.0版本。安装MySQL并设置root用户密码。
- 配置MySQL:
- 运行MySQL服务。创建数据库。
- 配置数据库连接:
- 在IDEA中,打开"Database"视图。配置MySQL 8.0数据库连接,输入数据库地址、端口、用户名和密码。
2.3 创建Maven项目
- 创建项目:
- 在IDEA中,选择"File" > "New" > "Project..."。选择"Maven"项目,点击"Next"。输入项目名称,选择项目存储位置,点击"Finish"。
- 配置pom.xml:
添加MyBatis和MySQL驱动的依赖。
示例pom.xml配置:
XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>bigDataWeb</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.16</version>
</dependency>
<!-- MySQL Connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<!-- JUnit 5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.7.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.7.0</version>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!-- Connection Pool -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.4.5</version>
</dependency>
</dependencies>
</project>
2.4 配置MyBatis
- 创建MyBatis配置文件:
在src/main/resources目录下创建mybatis-config.xml。
示例配置:
XML
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="db.properties"/>
<typeAliases>
<package name="com.example.domain"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/StudentMapper.xml"/>
</mappers>
</configuration>
- 创建映射文件:
在src/main/resources/mapper目录下创建映射文件,如StudentMapper.xml。
2.5 创建实体类和Mapper接口
- 实体类:
- 创建Student.java、Course.java和Score.java。
- package com.example.domain;
- Mapper接口:
创建StudentMapper.java、CourseMapper.java和ScoreMapper.java。
3 动态SQL(使用xml配置文件方式)
1.学生信息多条件查询(条件之间存在制约)
a)当用户输入的学生姓名不为空时,则只根据学生姓名进行学生信息的查询;
b)当用户输入的学生姓名为空而学生班级不为空时,则只根据学生班级进行学生信息的查询;
c)当用户输入的学生姓名和班级都为空,则要求查询出所有学号不为空的学生信息。
java
@Test
public void testFindStudentsByConditions() {
try (SqlSession session = MyBatisUtil.getSqlSession()) {
StudentMapper mapper = session.getMapper(StudentMapper.class);
List<Student> students = mapper.findStudentsByConditions(null, null);
students.forEach(System.out::println);
}
}
2.学生信息多条件查询
可以通过学生的姓名和班级来查找学生,也可以只通过学生姓名或只通过学生班级来查找学生,还可以没有条件查找出所有学生。
3.单条件查询
a)查询出所有id值小于5的学生的信息。
java
@Test
public void testFindStudentsByIdLessThanFive() {
try (SqlSession session = MyBatisUtil.getSqlSession()) {
StudentMapper mapper = session.getMapper(StudentMapper.class);
List<Student> students = mapper.findStudentsByIdLessThanFive();
students.forEach(System.out::println);
}
}
4 关联映射(使用xml配置文件方式)
查询某个学生的所有课程成绩
要求输入学生姓名,输出学生信息和课程信息以及分数。
java
@Test
public void testFindStudentScoresByName() {
try (SqlSession session = MyBatisUtil.getSqlSession()) {
StudentMapper mapper = session.getMapper(StudentMapper.class);
List<Score> scores = mapper.findStudentScoresByName("lql");
scores.forEach(System.out::println);
}
}
5 缓存机制
1.一级缓存测试
对Course表根据id进行两次相同的查询。
java
@Test
public void testFirstLevelCache() {
try (SqlSession session = MyBatisUtil.getSqlSession()) {
StudentMapper mapper = session.getMapper(StudentMapper.class);
// 第一次查询
List<Student> students = mapper.findAll();
System.out.println("第一次查询结果: " + students);
// 修改数据
Student student = new Student();
student.setName("测试");
student.setAge(20);
student.setSex("男");
student.setSclass(1);
mapper.insert(student);
// 第二次查询,应该使用缓存数据
students = mapper.findAll();
System.out.println("第二次查询结果: " + students);
}
}
2.一级缓存的清空
在两次相同查询之间,使用插入、更新或删除语句对Course表中的信息进行修改,第二次查询时Mybatis依然会从数据库查询。
java
@Test
public void testClearFirstLevelCache() {
try (SqlSession session = MyBatisUtil.getSqlSession()) {
StudentMapper mapper = session.getMapper(StudentMapper.class);
// 查询
List<Student> students = mapper.findAll();
System.out.println("查询结果: " + students);
// 清空一级缓存
session.clearCache();
// 再次查询,这次不会使用缓存
students = mapper.findAll();
System.out.println("清空缓存后查询结果: " + students);
}
}
3.二级缓存测试
除了参照教材的方式开启二级缓存,还需要序列化对象,比如在CourseMapper开启了二级缓存,则Course这个POJO需要实现Serializable接口,即implements Serializable,否则程序会报错。
java
package com.example;
import com.example.domain.Course;
import com.example.mapper.CourseMapper;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;
import java.util.List;
public class CourseMapperTest {
@Test
public void testFindAll() {
try (SqlSession session = MyBatisUtil.getSqlSession()) {
CourseMapper mapper = session.getMapper(CourseMapper.class);
List<Course> courses = mapper.findAll();
courses.forEach(System.out::println);
}
}
}
4.二级缓存的清空
参照一级缓存的清空,区别在于使用不同的sqlsession进行查询和修改操作。
在 MyBatis 中,二级缓存是全局的,可以跨 SqlSession 使用。二级缓存的清空通常涉及到使用不同的 SqlSession 来执行查询和修改操作。这是因为二级缓存是全局的,所以它不受单个 SqlSession 的限制。
要清空二级缓存,可以在 MyBatis 配置文件中设置 eviction 策略。MyBatis 提供了几种不同的清空策略,例如 LRU(最近最少使用)、FIFO(先进先出)、SOFT(软引用) 和 NO(无)。这些策略决定了在什么情况下二级缓存会被清空。
java
@Test
public void testClearSecondLevelCache() {
try (SqlSession session1 = MyBatisUtil.getSqlSession()) {
CourseMapper mapper1 = session1.getMapper(CourseMapper.class);
List<Course> courses = mapper1.findAll();
session1.evict();
try (SqlSession session2 = MyBatisUtil.getSqlSession()) {
CourseMapper mapper2 = session2.getMapper(CourseMapper.class);
List<Course> coursesAfterEvict = mapper2.findAll();
System.out.println("二级缓存清空成功");
}
}
}
6 注解开发
使用注解的开发方式实现实验内容三的第1个任务:查询某个学生的所有课程成绩,要求使用面向接口的开发方式。
java
/**
* 根据姓名查询学生的课程与分数
*
* @param name 学生姓名
* @return 学生对象,包含课程和分数信息
*/
@Select("SELECT s.*, c.id AS cid, c.name AS cname, sc.score AS score " +
"FROM student s " +
"JOIN score sc ON s.id = sc.student_id " +
"JOIN course c ON sc.course_id = c.id " +
"WHERE s.name = #{name}")
@Results({
@Result(property = "id", column = "id"),
@Result(property = "name", column = "name"),
@Result(property = "age", column = "age"),
@Result(property = "sex", column = "sex"),
@Result(property = "sclass", column = "sclass"),
@Result(property = "courseList", column = "cid",
many = @Many(select = "com.example.domain.CourseMapper.findByStudentId"))
})
Student findByNameCourseAndScore(String name);
实验总结
在本次实验中,我通过一系列步骤掌握了
- 环境搭建与配置:我成功安装并配置了IntelliJ IDEA Ultimate 2024、JDK 17和MySQL 8.0,为后续的MyBatis开发打下了坚实的基础。通过配置IDEA和MySQL,我加深了对开发环境搭建的理解。
- MyBatis核心配置:我学会了如何编写MyBatis的核心配置文件,包括数据源配置、事务管理器配置以及映射文件的引用。这些配置是MyBatis工作的基础,通过实践我掌握了它们的具体含义和作用。
- 动态SQL与条件查询:通过实验,我掌握了MyBatis中动态SQL的使用,包括条件查询操作和复杂查询操作。我学会了如何使用<if>、<choose>、<when>等动态SQL元素来构建灵活的查询语句。
- 关联映射与缓存机制:我探索了MyBatis的关联映射功能,通过编写映射文件和Mapper接口,实现了学生与课程成绩的关联查询。此外,我还了解了MyBatis的一级缓存和二级缓存机制,并掌握了如何在实际开发中使用和配置缓存。
- 注解开发:我尝试了使用注解的方式进行MyBatis开发,这种方式简化了XML配置文件的编写,使我能够更专注于业务逻辑的实现。通过注解,我实现了查询某个学生的所有课程成绩的功能。
- 问题解决:在实验过程中,我遇到了一些问题,如SLF4J的警告和MyBatis的PersistenceException。通过查阅文档和资料,我成功解决了这些问题,这不仅提升了我的问题解决能力,也加深了我对MyBatis和相关技术的理解。