系列文章目录
文章目录
目录
一、前言
本系列为博主近期复习Mybatis相关知识时整合的书籍内容、相关练习例子以及个人的一些理解的分享,作为自己重温Mybatis操作的总结。希望能对在学习Mybatis或者在一些操作上遇到同样bug的同学给到一定的帮助。
本次的代码 链接: https://pan.baidu.com/s/13ebpuITEe5xY6_yY0hAeoA?pwd=fuu0 提取码:fuu0
二、回顾与补充
回顾:上一次与大家一起了解了Mybatis的基本使用步骤,用mybatis实现了简单学生增删改查的例子,这一次将和大家一起分享一下Mybatis的核心配置。
补充:在上一次的例子,每一次执行方法时都要读取配置->构建sqlSessionFactory->创建sqlSession对象,这样写的第一个问题就是重复代码。第二个是会多次实例化sqlSessionFactory对象,工厂对象一旦被创建,在整个应用执行期间都会存在。如果我们多次地创建同一个数据库的SqlSessionFactory,就造成了资源的浪费。
解决方法:对此我们可以封装一个工具类同时用上单例模式,简化了方法代码的简洁同时保证每次获取的Factory对象唯一。
- 1、创建MybatisUtils工具类
package com.mashang.util;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
public class MybatisUtils {
// 在这里使用的是饿汉式
// sessionFactory将会经常使用因此可以在项目启动时直接创建
private static SqlSessionFactory sessionFactory = null;
//使用静态代码块创建factory
static {
try {
// 读取配置文件
InputStream resource = Resources.
getResourceAsStream("mybatis-config.xml");
// 构建SqlSessionFactory工厂
sessionFactory = new SqlSessionFactoryBuilder()
.build(resource);
} catch (IOException e) {
e.printStackTrace();
}
}
// 获取sqlSession的静态方法
public static SqlSession getSession() {
return sessionFactory.openSession();
}
}
- 2、修改测试类代码:
/*
* 根据学生ID返回学生数据
* */
@Test
public void getStudentById() throws IOException {
//1.通过工具类获取sqlSession
SqlSession sqlSession = MybatisUtils.getSession();
Student student = sqlSession.selectOne("com.mashang." +
"mapper.StudentMapper.getStudentById", 1);
System.out.println(student);
sqlSession.close();
}
三、Mybatis核心配置
1.Mybatis的核心对象
Mybatis的核心对象有两个:SqlSessionFactory与SqlSession。工厂类是单个数据库映射关系经过编译后的内存镜像,主要作用是创建SqlSession,而SqlSession是应用程序与持久层之间执行交互操作的一个单线程对象,其主要作用是执行持久化操作。
在上一小节也说到:
通常每一个数据库都会只对应一个SqlSessionFactory,所以在构建SqlSessionFactory实例时,建议使用单列模式。
而对于sqlSession而言,每一个业务都应该有一个自己的SqlSession实例,并且该实例是不能被共享的。同时在使用完成后要及时关闭sqlSession。
sqlSession中封装了很多方法,比如我们上一次用到的selectOne、selectList、insert、update、delete等,想要具体了解所有的方法,我们可以点进sqlSession的源码中查看:

2.Mybatis配置文件
Mybatis的配置文件也就是我们先前配置的"mybatis-config.xml"文件,在上一章的入门案例中,我们在配置文件内只使用了<environments>和<mapper>等几个元素,但在实际开发时,通常还会对其他一些元素进行配置。对于xml文件来说配置项是要按照一定的顺序进行配置,这里附上mybatisConfig的配置顺序图供大家参考:

-
properties元素
<properties>是一个配置属性的元素,在面向配置开发时,我们通常在db.properties中配置好数据库相关的配置,再通过动态替换<enviroment>中数据库的配置。当我们修改数据库信息时,只需要修改配置文件而不用改动mybatisConfig代码,具体实现方式如下:
(1) 在项目目录下创建db.properties文件,编辑后的代码如下所示。
# 配置jdbc驱动
jdbc.driver=com.mysql.cj.jdbc.Driver
# 配置Jdbc url
# 其中userSSL指不使用SSL连接
# serverTimezone指的是数据库时区
jdbc.url=jdbc:mysql://localhost:3306/learn-mysql\
?userSSL=false&serverTimezone=Asia/Shanghai
# 配置用户名
jdbc.username=root
# 配置密码
jdbc.password=root
(2) 在MyBatis配置文件mybatis-config.xml中配置<properties... />属性,具体如下:
<!--获取配置文件-->
<properties resource="db.properties"/>
(3)使用"${value}" 修改配置文件中数据库连接的信息,具体如下:
<dataSource type="POOLED">
<!--配置驱动-->
<property name="driver" value="${jdbc.driver}"/>
<!--配置路径-->
<!--userSSL=false:不使用SSL协议链接数据库-->
<!--serverTimeZone=Asia/Shanghai:指明时区为亚洲上海-->
<property name="url"
value="${jdbc.url}"/>
<!--配置数据库用户名-->
<property name="username" value="${jdbc.username}"/>
<!--配置数据库密码-->
<property name="password" value="${jdbc.password}"/>
</dataSource>
以上便是properties比较常用的一种配置方式,那么其实还可以展开<properties>标签,配置其<property>子标签,单独为每一个属性配置。有兴趣的朋友可以自行查阅相关资料、博客。
-
settings元素
<settings>元素主要是开启Mybatis中的二级缓存、延迟加载等配置,在平常中使用的频率不是很高,因此这一块的内容博主给大家附上常用配置就不展开了。

-
typeAliases元素 (常用)
<typeAliases>元素是为映射文件中的java类型设置一个别名,在先前的mapper映射文件中我们是使用全类名来设置java类型,如:resultType="com.mashang.entity.Student"。而在我们配置了<typeAliases>之后就只需要配置短类名即可,如:resultType="student"。(博主测试过使用首字母大写类名也可以被识别)。
配置的方法如下:
- 使用<typeAlias> 单独配置别名:
<!--定义别名--> <typeAliases> <!-- type:指定需要被定义别名的类的全限定名 alias:自定义的别名 可以代替com.mashang.entity.Student 使用在映射文件的任何位置, 若省略alias则默认以类名首字母小写为别名 --> <typeAlias type="com.mashang.entity.Student" alias="student"/> </typeAliases> - 使用自动扫描包定义别名:
<typeAliases> <!-- 扫描com.mashang.entity下的所有包, 所有实体类以首字母小写的非限定类名来作为它的别名 --> <package name="com.mashang.entity"/> </typeAliases>
除了可以使用<typeAliases>元素自定义别名外,MyBatis框架还默认为许多常见的Java类型(如数值、字符串、日期和集合等)提供了相应的类型别名,如图:

-
typeHandler元素 (不常用)
typeHandler的作用就是将预处理语句中传入的参数从javaType(Java类型)转换为jdbcType(JDBC类型),或者从数据库取出结果时将jdbcType转换为javaType。为了方便转换,MyBatis框架提供了一些默认的类型处理器,如图:

当MyBatis框架所提供的这些类型处理器不能够满足需求时,还可以通过自定义的方式对类型处理器进行扩展。通过实现TypeHandler接口或者继承BaseTypeHandle类来定义。注册的方式与<typeAliases>元素类似,这里不做具体的处理器展示,若有需要的朋友可以自行查阅资料。
-
environments元素
<environments>元素用于对环境进行配置,实际上就是数据源的配置,我们可以通过<environments>元素配置多种数据源,即配置多种数据库。
<!--配置环境,默认环境id为mysql,
可以有多个environment,通过id选择-->
<environments default="mysql">
<!--配置id为mysql的数据库环境-->
<environment id="mysql">
<!--配置事务管理,它的type属性用于指定事务管理的方式-->
<transactionManager type="JDBC"/>
<!--数据源配置-->
<!--type为POOLED表示以连接池形式-->
<dataSource type="POOLED">
<!--配置驱动-->
<property name="driver" value="${jdbc.driver}"/>
<!--配置路径-->
<!--userSSL=false:不使用SSL协议链接数据库-->
<!--serverTimeZone=Asia/Shanghai:指明时区为亚洲上海-->
<property name="url"
value="${jdbc.url}"/>
<!--配置数据库用户名-->
<property name="username" value="${jdbc.username}"/>
<!--配置数据库密码-->
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
在MyBatis中,可以配置两种类型的事务管理器,分别是JDBC和MANAGED。不同点在于MANAGED从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期。
对于数据源的配置,MyBatis框架提供了UNPOOLED、POOLED和JNDI三种数据源类型,具体如下:
UNPOOLED:配置此数据源类型后,在每次被请求时会打开和关闭连接。它对没有性能要求的简单应用程序是一个很好的选择。
POOLED:此数据源利用“池”的概念将JDBC连接对象组织起来,这种方式使得并发Web应用可以快速地响应请求,是当前流行的处理方式
JNDI:此数据源可以在EJB或应用服务器等容器中使用。容器可以集中或在外部配置数据源,然后放置一个JNDI上下文的引用。
-
mappers元素
在配置文件中,<mappers>元素用于指定MyBatis映射文件的位置,一般可以使用以下4种方法引入映射器文件,具体如下所示。
- 使用类路径引入
<mappers> <mapper resource="com/mashang/mapper/StudentMapper.xml"/> </mappers> - 使用本地文件路径引入
<!--配置Mapper映射文件位置--> <mappers> <mapper url="file:\\\C:\Mybatis_02\src\ main\java\com\mashang\mapper\StudentMapper.xml"/> </mappers> - 使用接口类引入
使用接口类需要先创建一个与mapper文件相同名字的接口类,且配置对应的抽象方法:package com.mashang.mapper; import com.mashang.entity.Student; /* * StudentMapper.xml的mapper接口类 * */ public interface StudentMapper { /* * 对应StudentMapper.xml中的getStudentByI方法 <select id="getStudentById" parameterType="int" resultType="com.mashang.entity.Student"> select * from student where id = #{id} </select> * */ Student getStudentById(); }<!--配置Mapper映射文件位置--> <mappers> <mapper class="com.mashang.mapper.StudentMapper"/> </mappers> - 使用包名引入
<mappers> <!-- 注意:包扫描是扫描mapper包下的接口类 而不是*.xml文件 --> <package name="com.mashang.mapper"/> </mappers>
3.映射文件
-
select元素
<select>元素用于映射查询语句,它可以帮助我们从数据库中读取出数据,并组装数据给业务开发人员。使用<select>元素执行查询操作非常简单,其示例如下 :
<select id="getStudentById" parameterType="int"
resultType="com.mashang.entity.Student">
select *
from student
where id = #{id}
</select>
上述语句中的唯一标识为getStudentById,它接收一个Integer类型的参数(int为Integer的别名),并返回一个Student类型的对象。除了上述示例代码中的几个属性外,还有其他一些可以配置的属性,如图:

-
insert元素
<insert>元素用于映射插入语句,在执行完元素中定义的SQL语句后,会返回一个表示影响记录数的整数。<insert>元素的配置示例如下:
<!--添加学生-->
<!--因为我在数据库中设置了id自增,因此将id赋值设为null-->
<insert id="addStudent"
parameterType="com.mashang.entity.Student">
insert into student
values (null, #{name}, #{age}, #{sex})
</insert>
<insert>元素的属性与<select>元素的属性大部分相同,但还包含了3个特有属性,这3个属性的描述如表:
| 属性 | 说明 |
| keyProperty | (仅对insert和update有用)此属性的作用是将插入或更新操作时的主键值返回赋值给Entity类的某个属性,通常会设置为主键对应的属性(注意是实体类中的属性)。如果需要设置联合主键,可以在多个值之间用逗号隔开。 |
| keyColumn | (仅对 insert和 update有用)此属性用于设置第几列是主键,当主键列不是表中的第一列时需要设置。在需要主键联合时,值可以用逗号隔开。 |
| useGeneratedKeys | (仅对insert和 update有用)此属性会使 MyBatis使用JDBC的getGeneratedKeys()方法来获取由数据库内部生产的主键,如MySQL和SQL Server等自动递增的字段,其默认值为false |
对于三个属性,我们可以试验一把:
(1)首先添加一个<insert>元素
<insert id="addStudentWithReturn" parameterType="Student"
keyProperty="id" useGeneratedKeys="true">
insert into student(name, age, sex)
values (#{name}, #{age}, #{sex})
</insert>
(2)修改StudentMapper接口
package com.mashang.mapper;
import com.mashang.entity.Student;
/*
* StudentMapper.xml的mapper接口类
* */
public interface StudentMapper {
/*
* 对应StudentMapper.xml中的getStudentByI方法
<select id="getStudentById" parameterType="int"
resultType="com.mashang.entity.Student">
select *
from student
where id = #{id}
</select>
* */
Student getStudentById();
int addStudentWithReturn(Student student);
}
(3)编写测试类
/*
* 创建ID并返回主键id
* */
@Test
public void addStudentWithReturn() {
// 1.准备一个学生类
Student student = new Student();
student.setName("冯艳");
student.setAge(29);
student.setSex("女");
// 2.通过工具类获取sqlSession
SqlSession session = MybatisUtils.getSession();
// 3.通过getMapper传入mapper接口类的class对象获得mapper类
StudentMapper mapper = session.getMapper(StudentMapper.class);
// 4.通过mapper类调用接口方法
int row = mapper.addStudentWithReturn(student);
if (row > 0) {
System.out.println("添加学生成功");
session.commit();
} else {
System.out.println("添加学生失败");
}
// 5.打印返回的student主键
System.out.println(student.getId());
}
(4)运行结果:

-
update元素和delete元素
<update>和<delete>元素的使用比较简单,它们的属性配置也基本相同。<update>和<delete>元素的属性基本与<select>元素中的属性一致。与<insert>元素一样,<update>和<delete>元素在执行完之后,也会返回一个表示影响记录条数的整数,其使用示例如下:
<!--根据id修改学生信息-->
<!--
这里使用了mybatis中的set和if结合的动态sql,
根据传入参数动态生成sql语句,
具体的动态sql语法在后续会介绍
-->
<update id="updateStudent"
parameterType="com.mashang.entity.Student">
update student
<set>
<if test="name!=null and name!=''">
name=#{name},
</if>
<if test="age!=null and age!=''">
age=#{age},
</if>
<if test="sex!=null and sex!=''">
sex=#{sex},
</if>
</set>
where id=#{id}
</update>
<!--根据id删除学生-->
<delete id="deleteStudent" parameterType="int">
delete
from student
where id = #{id}
</delete>
-
sql元素
<sql>元素的作用就是定义可重用的SQL代码片段,然后在其他语句中引用这一代码片段。
例如,定义一个包含name、age和sex字段的代码片段如下:
<sql id="studentParamsWithoutId">name,age,sex</sql>
<select id="getStudentById" parameterType="int"
resultType="com.mashang.entity.Student">
select
<include refid="studentParamsWithoutId"></include>
from student
where id = #{id}
</select>
上面示例只是一个简单的引用查询。在实际开发中,可以更加灵活地定义SQL片段,这里的目的是想展示sql中可以多层嵌套、变量以及property的使用,其示例如下:
<!--定义要查询的表名-->
<sql id="tableName">
${tableName}
</sql>
<!--定义要查询的表-->
<sql id="fromTable">
from
<include refid="${table_target}"/>
</sql>
<!--定义查询的列-->
<sql id="columns">
id
,name,age,sex
</sql>
<!--根据Id查询学生-->
<select id="getStudentById" parameterType="int"
resultType="com.mashang.entity.Student">
select
<include refid="columns"/>
<include refid="fromTable">
<property name="table_target" value="tableName"/>
<property name="tableName" value="student"/>
</include>
where id = #{id}
</select>
-
resultMap元素
<resultMap>元素表示结果映射集,是MyBatis中最重要也是最强大的元素。它的主要作用是定义映射规则、级联的更新以及定义类型转化器等。
<!--resultMap的元素结构-->
<resultMap id="" type="">
<id/> <!--用于表示哪个列是主键-->
<result/> <!--注入到字段或实体类属性的普通结果-->
<association property=""/> <!--用于一对一关联-->
<collection property=""/> <!--用于一对多关联-->
</resultMap>
接下来,通过一个具体的案例来演示<resultMap>元素在此种情况的使用,具体步骤如下
(1) 在mybatis数据库中,创建一个user表,并插入几条测试数据。
| 属性名 | 类型 |
| uid | int |
| username | varchar |
| address | varchar |
数据如下:
| uid | username | address |
| 1 | 夏芳 | 湖南省 常德市 临澧县 |
| 2 | 郝明 | 湖南省 衡阳市 衡南县 |
| 3 | 邱洋 | 广西壮族自治区 贺州市 富川瑶族自治县 |
(2) 创建持久化类User,并在类中定义id、name和age属性,以及其getter/setter方法和toString()方法
package com.mashang.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer id;
private String username;
private String address;
}
(3) 创建映射文件UserMapper.xml,并在映射文件中编写映射查询语句
<?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.mashang.mapper.UserMapper">
<select id="findAllUser" resultMap="UserMap">
select uid as iiiiid, username, address
from user;
</select>
<!--resultMap的元素结构-->
<resultMap id="UserMap" type="user">
<!--其中property指的是实体类中的属性名,如id-->
<!--column指的是在sql语句中得到的结果,如上方select
语句返回结果为uid而我将其命名为iiiiid,则此处的
column应该写iiiiid,其意思为将sql语句得到的结果
iiiiid(uid)设置进User类的id属性中-->
<id property="id" column="iiiiid"/>
<!--result与id的属性值同理-->
<result property="username" column="username"/>
<result property="address" column="address"/>
</resultMap>
</mapper>
(4) 创建接口类UserMapper,并在接口类中编写抽象方法
package com.mashang.mapper;
import com.mashang.entity.User;
import java.util.List;
public interface UserMapper {
List<User> findAllUser();
}
(5) 在测试类中,编写测试方法findAllUserTest(),代码如下所示
/*
* 查询所有用户
* */
@Test
public void findAllUser() {
SqlSession session = MybatisUtils.getSession();
UserMapper mapper = session.getMapper(UserMapper.class);
List<User> user = mapper.findAllUser();
System.out.println(user);
}
(6) 测试结果为:

可以看出,虽然user表的列名与User对象的属性名完全不一样,但查询出的数据还是被正确地封装到了User对象中。
四、总结
本次主要对MyBatis中的核心对象和核心文件进行了介绍。首先讲解了MyBatis中的两个重要核心对象SqlSessionFactory和SqlSession;然后介绍了配置文件中的元素及其使用;最后对映射文件中的几个主要元素进行了介绍。

本文详细解读了Mybatis的核心配置,包括SqlSessionFactory与SqlSession对象,数据库配置、typeAliases、typeHandler、environments和mappers元素,以及映射文件中的select、insert、update、delete和resultMap。通过实例演示了如何简化配置和提高代码效率。
3259

被折叠的 条评论
为什么被折叠?



