什么是 MyBatis?
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
MyBatis的优点
- 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件就可以了,易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
- 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
- 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
- 提供xml标签,支持编写动态sql。
Mybatis官网:mybatis – MyBatis 3 | 简介
MyBatis开发步骤
① 添加MyBatis,Mysql等相关依赖
<!--mybatis坐标-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.13</version>
</dependency>
<!--mysql驱动坐标-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.32</version>
</dependency>
<!--单元测试坐标-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
② 编写核心文件mybatis-config.xml
附代码:
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--实际开发中,习惯将数据源的配置信息单独抽取成一个properties文件,该标签可以加载额外配置的properties文件-->
<properties resource="db.properties"/>
<settings>
<!--配置驼峰命名映射-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!--使用扫描包的形式定义别名 -->
<typeAliases>
<package name="pojo" />
</typeAliases>
<environments default="development"> <!--指定默认的环境名称-->
<environment id="development"> <!--指定当前环境的名称-->
<transactionManager type="JDBC"/> <!--指定事务管理类型是JDBC-->
<dataSource type="POOLED"> <!--指定当前数据源类型是连接池-->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/example/mapper/UserMapper.xml"/>
</mappers>
</configuration>
③ 编写连接配置db.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/freshman?useUnicode=true&characterEncoding=utf-8
username=root
password=123456
④ 创建mapper接口
MyBatis中的mapper接口相当于以前的dao。但是区别在于,mapper仅仅是接口,我们不需要提供实现类
public interface UserMapper {
/**
* 添加用户信息
*/
int insertUser();
}
⑤ 编写映射文件xxxMapper.xml
- 映射配置文件文件名与Mapper接口名一致,且放在相同的包下(同包同名)。
⑥ 编写工具类MybatisUtils
因为在测试时需要多次的从 XML 中构建 SqlSessionFactory且从SqlSessionFactory 中获取 SqlSession,为了更方便的复用,把其封装到MybatisUtils工具类中。
/**
* 工具类
*/
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory = null;
// 初始化SqlSessionFactory对象
static {
try {
// 使用MyBatis提供的Resources类加载MyBatis的配置文件
Reader reader =
Resources.getResourceAsReader("mybatis-config.xml");
// 构建SqlSessionFactory工厂
sqlSessionFactory =
new SqlSessionFactoryBuilder().build(reader);
} catch (Exception e) {
e.printStackTrace();
}
}
// 获取SqlSession对象的静态方法
public static SqlSession getSession() {
//openSession() 会默认开启一个事务,但事务不会自动提交
return sqlSessionFactory.openSession();
}
}
⑦ 编写测试
public class DeptTest {
@Test
public void findInfoByDeptIdTest(){
//调用工具类MybatisUtils中的getSession()方法
SqlSession sqlSession = MybatisUtils.getSession();
Dept dept = sqlSession.selectOne
("com.example.mapper.DeptMapper.findInfoByDeptId",401);
System.out.println(dept.toString());
sqlSession.close();
}
association解决多对一的映射关系
- association:处理多对一的映射关系
- property:需要处理多对的映射关系的属性名
- javaType:该属性的类型
实体类Dept:
public class Dept {
private Integer deptId;//系别ID
private String deptName;//系名
private List<Major> majorList;
//构造方法....
}
实体类Major:
public class Major {
private String majorId;//专业ID
private String majorName;//专业
private Integer tuition;//学费
private Integer deptId;//系别ID
private Dept dept;
//构造方法....
}
MajorMapper.xml
<!--嵌套查询方式:根据专业名称模糊查找专业及相关的系部信息-->
<select id="findDeptByMajor" parameterType="String" resultMap="majorList">
select * from tb_major where major_name like concat('%',#{majorName},'%')
</select>
<resultMap id="majorList" type="Major">
<id property="majorId" column="major_id"/>
<result property="majorName" column="major_name"/>
<result property="tuition" column="tuition"/>
<!-- 方式一:嵌套查询 -->
<!-- 多对一:association使用select属性引入另外一条SQL语句 -->
<association property="dept" column="dept_id"
javaType="Dept"
select="com.example.mapper.DeptMapper.findDeptById"/>
</resultMap>
DeptMapper.xml
<!-- 根据系编号查询系信息-->
<select id="findDeptById" resultType="Dept">
select * from tb_dept where dept_id=#{deptId}
</select>
输出结果:
注:输出结果取决于实体类中构造方法toString()
collection解决一对多的映射关系
- collection:用来处理一对多的映射关系
- ofType:表示该属性对饮的集合中存储的数据的类型
DeptMapper.xml
<!--嵌套结果查询方式:根据系编号查询系部及相关专业信息-->
<!--根据系编号(dept_id)查询,要求使用嵌套结果查询指定系的所有专业信息(一对多)-->
<select id="findInfoByDeptId" resultMap="DeptWithMajorsResult">
SELECT d.dept_id,d.dept_name,m.major_id,m.major_name,m.tuition
from tb_dept d left join tb_major m on d.dept_id = m.dept_id
where d.dept_id = #{deptId}
</select>
<resultMap id="DeptWithMajorsResult" type="Dept">
<id property="deptId" column="dept_id"/>
<result property="deptName" column="dept_name"/>
<!--collection:一对多关联映射-->
<collection property="majorList" ofType="Major">
<id property="majorId" column="major_id"/>
<result property="majorName" column="major_name"/>
<result property="tuition" column="tuition"/>
</collection>
</resultMap>
输出结果:
注:输出结果取决于实体类中构造方法toString()
动态SQL
- <if>
- 用于判断条件是否成立,如果条件为true,则拼接SQL
- 形式:<if test = "name != null">..</if>
- <where>
- where元素只会在子元素有内容的情况下才插入where子句,而且会自动去除子句的开头的AND或OR
<!--resultType:单条记录所封装得类型-->
<select id="list" resultType="com.example.springbootmybatiscrudxml.pojo.Emp">
/*ctrl+alt+l 快速排列格式*/
<include refid="commonSelect"></include>
/*
mybatis动态sql:
where:where元素只会在子元素有内容的情况下才插入where子句。而且会自动去除子句的开头的AND或 OR
if:用于判断条件是否成立。使用test属性进行条件判断,如果条件为true,则拼接SQL
*/
<where>
<if test="name != null">
name like concat('%', #{name}, '%')
</if>
<if test="gender != null">
and gender = #{gender}
</if>
<if test="begin != null and end != null">
and entrydate between #{begin} and #{end}
</if>
</where>
order by update_time desc
</select>
- <set>
- 动态地在行首插入SET关键字,并会删掉额外的逗号。(用在update语句中)
<!--动态更新员工-->
<update id="update2">
update emp
/*set:
动态的在行首插入SET关键字,并会删掉额外的逗号。(用在update语句中)
*/
<set>
<if test="username != null">username = #{username},</if>
<if test="name != null">name = #{name},</if>
<if test="gender != null">gender = #{gender},</if>
<if test="image != null">image = #{image},</if>
<if test="job != null">job = #{job},</if>
<if test="entrydate != null">entrydate = #{entrydate},</if>
<if test="deptId != null">dept_id = #{deptId},</if>
<if test="updateTime != null">update_time = #{updateTime}</if>
</set>
where id = #{id}
</update>
- <foreach>
- <foreach collection="集合名称" item="集合遍历出来的元素/项" separator="每一次遍历使用的分隔符" open="遍历开始前拼接的片段" close="遍历结束后拼接的片段">
</foreach>
<delete id="deleteByIds">
delete from emp where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
- sql片段
- <sql>
- 定义可重用的SQL片段
<sql id="commonSelect">
select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time
from emp
</sql>
- <include>
- 通过属性refid,指定包含的sql片段
<include refid="commonSelect"></include>