【毕业实习总结】(2)mybatis框架的基本使用

前言

大三暑假有个毕业实习,是企业的人来我们学校带我们做项目,为期三周。

前半部分是教我们一些框架的基本使用,后面几天就是组成小组利用前面学习的知识开发一个商城项目。感觉和课设其实没有差的太多。

学习到的框架有 mybatis、springmvc、spring、springboot、shiro、mybatis-plus,还在一开始学习了如何建立 maven 项目。

2020 年 7 月 15 日,我们小组完成了答辩。在之前因为要学习框架、做项目,甚至中间夹杂着几场考试,所以抽不出空来写博客,现在结束了,我现在通过 git 提交记录以及幕布学习笔记、工作日报等记录来尝试还原这一次经历以及学习到的技术。

一开始想的是本系列先整理学习笔记,最后对本次项目进行总结。不过碍于时间不足,可能会直接将以前的旧项目改为 springboot 架构,实习最终完成的商城项目就不进行分析了,项目开源链接:SpringBootMall

笔者也是刚刚才学习这些东西,所以如果有问题可以给我留言。

仓库链接

本文的练习项目已在码云开源,链接如下:

导入方式见本系列的第一篇文章。

mybatis 框架的基本使用

mybatis 官网文档

什么是 mybatis

下面是 mybatis 官网的说明:

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

它可以将 sql 语句和业务代码分开,从而方便修改。

本学期我做的另外几个课设中,sql 语句都是直接写在代码中的,类似于下面这样:

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/**
* 添加考试信息
* @param exam
* @return 是否添加成功
*/
public static boolean addExam(ExamBean exam)//单个考试添加函数
{
SimpleDateFormat sdf =new SimpleDateFormat("yyyy-MM-dd");//用于日期格式化
String date =sdf.format(exam.getDate());
String applyDate = sdf.format(exam.getApplyDate());
//添加exam表相关的属性
String sql = String.format("insert into "
+ "exam(exam_id,term_id,course_id,exam_wl,exam_date,location,period,teacherNeed,exam_status,`comment`,teacher_id,apply_date,refuse_reason)"
+ "values('%s','%s','%s',%d,'%s','%s','%s',%d,'%s','%s','%s','%s','%s');"
,exam.getExamNo()
,exam.getTerm()
,exam.getCourseNo()
,exam.getWorkload()
,date
,exam.getLocation()
,exam.getTime()
,exam.getNeed()
,exam.getStatus()
,exam.getComment()
,exam.getApplierNo()
,applyDate
,exam.getRefuseReason()
);

boolean success = databaseBean.executeUpdate(sql);
if(!success) return false;

//添加考试-班级表的记录
String[] classNoList = exam.getClassNo();
if(classNoList!=null) {
for(String classNo :classNoList) {
sql = String.format("insert into examclasses(exam_id,class_id)"
+ "values('%s','%s');"
, exam.getExamNo(),classNo);
success = databaseBean.executeUpdate(sql);
if(!success) return false;
}
}

//添加监考记录
InvigilatorBean[] invigilatorList = exam.getInvigilator();
if(invigilatorList!=null) {
boolean isMain = true;
for(InvigilatorBean invigilator:invigilatorList) {
success = InvigilatorBean.arrange(exam.getExamNo(), invigilator.getStaffNo(), isMain);
isMain=false;
if(!success) return false;
}
}

return true;
}

这是考务管理系统的 ExamBean 类中的内容(jsp+servlet+javabean 的架构,将业务逻辑写在了 javabean 中),可以看到,它需要手动进行日期的转换、多表查询的 sql 语句的拼接,而且 sql 语句是直接写在代码里面的,如果需要改动 sql 语句,会非常麻烦。

想要连接数据库,还需要自己写一个 DatabaseBean 来将数据库的用户名、密码、驱动名写在里面,提供获取数据库连接的类方法。

而使用了 mybatis 之后,sql 语句写在专门的 xml 文件当中,代码和 sql 语句分开,更方便管理。下文会展示如何简单地使用它,不作深入讲解(哈哈,因为更深的我也还不会)。

配置 mybatis

添加 mybatis 依赖

前往maven 中央仓库的官网,搜索 mybatis,选择版本,并将其依赖的配置代码添加到pom.xml中:

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
<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>com.test</groupId>
<artifactId>TestMaven</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<!--这里就是新添加的依赖-->
<!--和servlet相关的依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.0</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<!--这个才是mybatis的依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!--这里就是新添加的依赖-->
</dependencies>
</project>

文件保存后,等待 eclipse 把这个依赖自动下载到本地仓库,就可以使用 mybatis 了。

新建 mybatis 配置文件

在工程的src/main/resources目录下新建一个 xml 文件mybatis-config.xml,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?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>
<environments default="dev">
<environment id="dev">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<!--数据库相关配置-->
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://127.0.0.1:3306/test" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
<mappers>
<!--指定sql映射文件位置,此文件现在还没有创建,见下文-->
<mapper resource="mapper/StudentMapper.xml"/>
</mappers>
</configuration>

里面的驱动名(mysql5 以后的驱动名变了,请注意。本例中的 mysql 是 5.1 版本的)、url、用户名和密码都改成自己的。

在同目录下新建一个文件夹mapper,用于存放 SQL 映射文件。

增删改查举例

以教务管理系统的学生信息的增删改查为例。本地 mysql 的test数据库中的student表中存放着学生信息,grade表中存放着班级信息。

为了便于讲解,本例中的代码和上文给出的码云仓库的代码可能会有所不同。

目录结构一览

  • src/main/java
    • com.test
      • bean
        • Student.java:用于存储学生信息的 javabean
      • utils
        • MybatisUtils.java:用于获取 SqlSession 的工具类
      • dao
        • StudentMapper.java:用于处理对学生信息的
  • src/main/resource
    • mapper
      • StudentMapper.xml:SQL 映射文件,SQL 语句写在这里
    • mybatis-config.xml:mybatis 配置文件

新建包

com.test.bean

在你自己的工程包下(这里以com.test为例),新建一个bean包,存放的就是 javabean,用于将数据库的数据封装为类。

在其中新建一个学生 javabean,名为Student,其属性与数据库的学生信息表的字段一一对应(比如表中的sname字段对应 javabean 的sname属性)。

com.test.utils

utils 包存放一些工具类或者说是公共类。在此包下新建MybatisUtils类,内容如下:

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
package com.test.utils;

import java.io.IOException;
import java.io.Reader;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

/**
* @author 憧憬少
*/
public class MybatisUtils {

private static SqlSessionFactory factory=null;

static{
Reader reader;
try {
reader = Resources.getResourceAsReader("mybatis-config.xml");
factory = new SqlSessionFactoryBuilder().build(reader);
} catch (IOException e) {
e.printStackTrace();
}
}

public static SqlSession getSqlSession(){
return factory.openSession();
}

public static void close(SqlSession sqlSession){
if(sqlSession!=null){
sqlSession.close();
}
}

}

这里涉及到 mybatis 如何进行 sql 映射,来看看官网文档是怎么说的:

每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。

SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。

而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。

这个类在静态块里面读取了我们刚刚写的配置文件,并将其传给SqlSessionFactoryBuilder以创建SqlSessionFactory对象。

这个类的主要作用就是读取 mybatis 配置文件,并提供获取SqlSession对象的静态方法。我们可以使用SqlSession对象的方法,来使用 sql 映射文件中的 sql 语句。

com.test.dao

再新建一个名为dao的包,它的含义为 DAO(Data Access Object)数据访问对象,它是这个项目的数据访问层,业务代码通过它对数据库进行访问,有了这一层抽象,业务逻辑和数据访问就分开了。

dao包中新建一个StudentMapper类,它用来和 SQL 映射文件产生联系。它的代码如下:

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
package com.test.dao;

import java.io.IOException;

import org.apache.ibatis.session.SqlSession;

import com.bean.Student;
import com.utils.MybatisUtils;

public class StudentMapper {


public static int save(Student student) throws IOException{
SqlSession session = MybatisUtils.getSqlSession();
int flag = session.insert("saveStudent",student);
session.commit();
MybatisUtils.close(session);
return flag;
}

public static int update(Student student) throws IOException{
SqlSession session = MybatisUtils.getSqlSession();
int flag = session.update("updateStudent",student);
session.commit();
MybatisUtils.close(session);
return flag;
}

public static int delete(int id) throws IOException{
SqlSession session = MybatisUtils.getSqlSession();
int flag = session.delete("deleteStudent",id);
session.commit();
MybatisUtils.close(session);
return flag;
}

}

可以看到,这里面调用了SqlSession对象的三个方法insertupdatedelete,并且第一个参数是一个字符串,第二个参数就是操作的对象,操作对象中打包了用于增删改数据库的参数。

由于查询相比增删改要复杂一些,所以先写增删改的内容,等会儿再加上查询的代码。

操作完成后,使用 commit 方法进行事务提交,并关闭 SqlSession 对象。

那么第一个参数是什么呢?是 SQL 映射文件里面的 sql 语句的标识,接下来来看看 sql 映射文件吧~

新建 sql 映射文件

在刚刚新建的mapper文件夹中新建一个 xml 文件StudentMapper.xml,大体框架如下

1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.test.dao.StudentMapper">

</mapper>

其中,mapper 标签的namespace的属性值为与此文件绑定的映射类的包括类名在内的包路径,eclipse 按住 ctrl+左键可以跳转到对应的类(如果没有跳转说明可能是拼写错误)

在这里编写 sql 语句:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dao.StudentMapper">
<insert id="saveStudent">
insert into student(sname)
values(#{sname})
</insert>
<update id="updateStudent">
update student
set sname=#{sname}
where sid=#{sid}
</update>
<delete id="deleteStudent">
delete from student
where sid=#{sid}
</delete>

</mapper>

其中,标签对应的是 sql 语句所进行的操作,id 则是上文中调用SqlSession对象的方法时所传入的第一个字符串参数,在 sql 语句中夹杂着这样的内容:#{sname},它在映射后会作为一个占位符,类似 JDBC 的预编译。mybatis 会将传入的第二个 Object 参数的属性设置进去。

增改操作传入的都是Student对象,这个对象的属性就包含sname

这就是增删改操作,可以新建一个测试类来测试一下

测试用建表语句

为了简单起见,删除了一些字段

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
CREATE DATABASE IF NOT EXISTS test;

USE test;

# 删除表
DROP TABLE IF EXISTS student;
DROP TABLE IF EXISTS grade;

# 创建班级表
CREATE TABLE grade
(
gid INT AUTO_INCREMENT primary key,
gname char(30),
deleted INT DEFAULT 0# 删除标记
);


# 创建学生信息表
create table student
(
sid INT AUTO_INCREMENT primary key,
snum char(30),# 学号
sname char(30),# 姓名
deleted INT DEFAULT 0,# 删除标记
gid INT,
FOREIGN KEY(gid) REFERENCES grade(gid)
);

INSERT INTO grade(gname)
VALUES
('软件工程六班'),
('软件工程七班');

insert
into student(snum,sname,gid)
values
('2017901006','张三',1),
('2017901007','李四',2),
('2017901008','王五',1),
('2017901009','赵六',2),
('2017901026','张三',1);

增删改测试

示例测试类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.test;
import com.bean.Student;
import com.dao.StudentMapper;

public class TestStudentCRUD {

public static void main(String[] args){
try {
Student student = new Student();
student.setSname("张三");
int flag=0;
flag = StudentMapper.insert(student);
//flag = StudentMapper.update(student);
//flag = StudentMapper.delete(student.getId());

System.out.println(flag);
} catch (Exception e) {
e.printStackTrace();
}

}
}

如果插入成功,那么可以看到控制台输出了 1,这是影响的行数。如果是 0,那么就是插入失败,看一下报错信息,检查一下数据库用户名和密码是否正确,检查一下 javabean 和数据库字段对应情况

查询操作

再创建一个班级信息的 bean,字段如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.bean;
import java.io.Serializable;
import java.util.*;

public class Grade implements Serializable {

private static final long serialVersionUID = 1L;

private Integer gid;//班级主键
private String gname;//班级
private List<Student> list = new ArrayList<Student>();//学生列表
//省略setter和getter
}
1
2
3
4
5
6
7
8
9
10
11
12
13
package com.bean;

import java.io.Serializable;

public class Student implements Serializable {

private static final long serialVersionUID = 1L;

private Integer sid;
private String sname;
private Grade grade;//学生所属的班级
//省略setter和getter
}

下面的代码都是在StudentMapper.xml中写的。

单表查询

最简单的方式是单表查询,也就是仅仅查询一个表中的字段,不涉及另一个表。

以下的 sql 映射可以实现单表查询,不过有一定的限制,那就是查询结果中的字段名必须和 resultType 所指定的 javabean 的属性名一一对应,比如说数据库表中的字段名为sname,那么com.bean.Student这个 javabean 中的字段也必须有一个sname,否则会报错。

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dao.StudentMapper">
<!--省略增删改语句-->
<select id="selectStudent" resultType="com.bean.Student" >
select * from student
</select>

</mapper>

结果集映射

如果数据库表字段名和 javabean 的属性名不一样,那么可以使用结果集映射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dao.StudentMapper">
<!--省略增删改语句-->
<select id="selectStudent" resultMap="StudentMapper" >
select * from student
</select>
<resultMap type="com.bean.Student" id="StudentMapper">
<id property="sid" column="ID"/>
<result property="sname" column="Sname"/>
</resultMap>

</mapper>

select标签中的resultMap属性指定所使用的resultMap标签(结果集标签),resultMap标签由id属性所指定。

结果集标签中嵌套了id标签和result标签,前者指定结果集中的主键,而后者则是其他普通类型的属性,它们的property属性对应 javabean 的属性名,column对应数据库表的列名也就是字段名。

多表查询

如果要实现多表查询,那么就必须使用上述的结果集映射了。多表查询即涉及到多个表的字段的查询,需要进行连接操作。

在本例中,学生表中有一个班级字段,指明学生属于哪个班级。在查询学生的班级名时,需要连接学生表和班级表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dao.StudentMapper">
<!--省略增删改语句-->
<select id="selectStudent" resultMap="StudentMapper" >
select s.*,g.* from student s left join grade g on s.gid= g.gid
</select>
<resultMap type="com.bean.Student" id="StudentMapper">
<id property="sid" column="sid"/>
<result property="sname" column="sname"/>
<association property="grade" javaType="com.bean.Grade">
<id property="gid" column="gid"/>
<result property="gname" column="gname"/>
</association>
</resultMap>

</mapper>

这里多了一个association标签,它用于把结果集中的其他表的字段映射到本 javabean 的字段,本例中就是将查询结果中的gidgname字段映射到Student类的grade对象的对应属性中。

一对多查询

除了表的字段和类的属性的一一映射之外,有时还需要进行一对多的映射。

比如班级类中有一个列表,想要将所有属于该班级的学生都加入到这个列表当中,那么可以按照上文的方式新建对应的GradeMapper类和GradeMapper.xml,在映射文件中这样写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dao.GradeMapper">
<select id="getStudentListById" resultMap="GradeMapper">
select grade.*,student.* from grade left join student
on grade.gid=student.gid
where grade.gid=#{gid}
</select>
<resultMap type="com.bean.Grade" id="GradeMapper">
<id property="gid" column="gid" />
<result property="gname" column="gname" />
<collection property="list" ofType="com.bean.Student">
<id property="sid" column="sid"/>
<result property="sname" column="sname"/>
</collection>
</resultMap>
</mapper>

用的是collection标签,它的ofType属性是集合类中所装元素的类型,其他的和上面差不多

【毕业实习总结】(2)mybatis框架的基本使用

https://yxchangingself.xyz/posts/graduate_internship_2/

作者

憧憬少

发布于

2020-08-10

更新于

2020-08-10

许可协议