MyBatis框架一些知识

    技术2026-02-10  21

    MyBatis

    MyBatis简介什么是MyBatis 为什么要使用MyBatis1、使用传统方式JDBC访问数据库:`2、使用mybatis框架访问数据库: MyBatis快速入门1.先准备一个数据库,数据库中的表中有数据2.创建一个Maven工程3.在pom.xml中导入相关依赖 4.添加mybatis-config.xml文件1、在src/main/resources目录下,创建mybatis-config.xml文件 MyBatis中的占位符动态SQL标签if、where标签foreach元素

    MyBatis简介

    什么是MyBatis

    MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。

    MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注SQL本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。

    Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。

    总之,Mybatis对JDBC访问数据库的过程进行了封装,简化了JDBC代码,解决JDBC将结果集封装为Java对象的麻烦。

    下图是MBatis架构图 (1)mybatis-config.xml是Mybatis的核心配置文件,通过其中的配置可以生成SqlSessionFactory,也就是SqlSession工厂

    (2)基于SqlSessionFactory可以生成SqlSession对象

    (3)SqlSession是一个既可以发送SQL去执行,并返回结果,类似于JDBC中的Connection对象,也是Mybatis中至关重要的一个对象。

    (4)Executor是SqlSession底层的对象,用于执行SQL语句

    (5)MapperStatement对象也是SqlSession底层的对象,用于接收输入映射(SQL语句中的参数),以及做输出映射(即将SQL查询的结果映射成相应的结果)

    为什么要使用MyBatis

    思考:在开始之前,思考下如何通过JDBC查询Emp表中的所有记录,并封装到一个List集合中返回。(演示:准备数据、导包、导入JDBC程序)

    1、使用传统方式JDBC访问数据库:`

    (1)使用JDBC访问数据库有大量重复代码(比如注册驱动、获取连接、获取传输器、释放资源等,执行一次SQL语句就需要连接一次数据库);

    (2)JDBC自身没有连接池,会频繁的创建连接和关闭连接,效率低;

    (3)SQL是写死在程序中,一旦修改SQL,需要对类重新编译;

    (4)对查询SQL执行后返回的ResultSet对象,需要手动处理,有时会特别麻烦(未尝试过,不过会有这样的现象);

    2、使用mybatis框架访问数据库:

    (1)Mybatis对JDBC对了封装,可以简化JDBC代码;

    (2)Mybatis自身支持连接池(也可以配置其他的连接池),因此可以提高程序的效率;

    (3)Mybatis是将SQL配置在mapper文件中,修改SQL只是修改配置文件,类不需要重新编译。 如果是简单语句可以通过注解加配置文件

    (4)对查询SQL执行后返回的ResultSet对象,Mybatis会帮我们处理,转换成Java对象。 底层会根据相对应的POJO对象的getXxx()方法或者根据POJO对象的属性(数据库表的列名需与POJO对象的属性名一致)将返回的ResultSet对象封装到POJO对象中 …

    总之,JDBC中所有的问题(代码繁琐、有太多重复代码、需要操作太多对象、释放资源、对结果的处理太麻烦等),在Mybatis框架中几乎都得到了解决!!

    MyBatis快速入门

    1.先准备一个数据库,数据库中的表中有数据

    2.创建一个Maven工程

    3.在pom.xml中导入相关依赖

    <dependencies> <!-- junit单元测试 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.9</version> </dependency> <!-- mysql驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.32</version> </dependency> <!-- mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.2.8</version> </dependency> <!-- 整合log4j --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.6.4</version> </dependency> </dependencies>

    4.添加mybatis-config.xml文件

    1、在src/main/resources目录下,创建mybatis-config.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值应该保证唯一 在程序中通过[ namespace + id ]定位到要执行哪一条SQL语句 --> <mapper namespace="EmpMapper"> <!-- 通过select、insert、update、delete标签声明要执行的SQL --> <!-- 练习1: 查询emp表中的所有员工信息 resultType指定查询的结果将会封装到什么类型中 即使最终返回的结果是集合(List<Emp>),resultType也只需要指定集合中的泛型即可! --> <select id="findAll" resultType="com.tedu.pojo.Emp"> select * from emp </select> </mapper>

    这个是通过配置xml文件来执行SQL语句的方式

    MyBatis中的占位符

    在增删改查操作中,SQL语句中的值是写死在SQL语句中的,而在实际开发中,此处的值往往是用户提交过来的值,因此这里我们需要将SQL中写死的值替换为占位符。

    在mybatis中占位符有两个,分别是 #{} 占位符 和 ${} 占位符:

    #{}:相当于JDBC中的问号(?)占位符,是为SQL语句中的参数值进行占位,大部分情况下都是使用#{}占位符; 并且当#{}占位符是为字符串或者日期类型的值进行占位时,在参数值传过来替换占位符的同时,会进行转义处理(在字符串或日期类型的值的两边加上单引号) 例如:查询指定name的员工信息,SQL语句为: select * from emp where name=#{name}

    其实就等价于JDBC中:

    select * from emp where name=?,

    如果传过来的参数值为:张三,那么最终执行的SQL语句为:

    -- 在参数替换占位符的同时进行了转义处理(在值的两边加上了单引号) select * from emp where name='张三' ${}:是为SQL片段进行占位,将传过来的SQL片段直接拼接在${}占位符所在的位置,不会进行任何的转义处理。(由于是直接将参数拼接在SQL语句中,因此可能会引发SQL注入攻击问题) 那么如果我们在传递的时候不是一个参数值,而是一个SQL片段呢?

    例如:在查询时,我们想动态的传递查询的列:

    select #{columns} from emp

    此时传递过来的应该是一个SQL片段,不同于上面的参数值,如果此时还用#{},也会像上面一样被转译处理:

    select 'id,name,job' from emp

    这不是我们希望看到的!

    如果不想让传过来的SQL片段被转译处理,而是直接拼接在SQL语句中,那么这里可以使用${},例如:

    select ${columns} from emp

    拼接之后:

    select id,name,job from emp

    使用哪种方式要看你实际SQL语句

    动态SQL标签

    if、where标签

    <if>标签:是根据test属性中的布尔表达式的值,从而决定是否执行包含在其中的SQL片段。如果判断结果为true,则执行其中的SQL片段;如果结果为false,则不执行其中的SQL片段

    <where>标签:用于对包含在其中的SQL片段进行检索,在需要时可以生成where关键字,并且在需要时会剔除多余的连接词(比如and或者or)

    练习:根据薪资查询员工信息(if标签)

    <if>标签:是根据test属性中的布尔表达式的值,从而决定是否执行包含在其中的SQL片段。如果判断结果为true,则执行其中的SQL片段;如果结果为false,则不执行其中的SQL片段

    在mapper文件中编写SQL语句:

    <!-- 练习: 根据薪资查询员工信息 * 如果没有参数, 则不执行where子句, 默认查询所有员工: * select * from emp * 如果参数中只有minSal(即minSal不为null), 则: * ... where salary > minSal * 如果参数中只有maxSal(即maxSal不为null), 则: * ... where salary < maxSal * 如果参数有 minSal、maxSal(即minSal、maxSal不为null), 则: * ... where salary > minSal and salary < maxSal --> <select id="findAllBySal" resultType="com.tedu.pojo.Emp"> select * from emp where 1=1 <if test="minSal != null"> and salary>#{minSal} </if> <if test="maxSal != null"> and salary <![CDATA[ < ]]> #{maxSal} </if> </select>

    练习:根据薪资查询员工信息(where标签)

    <where>标签:用于对包含在其中的SQL片段进行检索,在需要时可以生成where关键字,并且在需要时会剔除多余的连接词(比如and或者or) <!-- 练习: 根据薪资查询员工信息 * 如果没有参数, 则不执行where子句, 默认查询所有员工: * select * from emp * 如果参数中只有minSal(即minSal不为null), 则: * ... where salary > minSal * 如果参数中只有maxSal(即maxSal不为null), 则: * ... where salary < maxSal * 如果参数有 minSal、maxSal(即minSal、maxSal不为null), 则: * ... where salary > minSal and salary < maxSal --> <select id="findAllBySal" resultType="com.tedu.pojo.Emp"> select * from emp <where> <if test="minSal != null"> and salary>#{minSal} </if> <if test="maxSal != null"> and salary <![CDATA[ < ]]> #{maxSal} </if> </where> </select>

    foreach元素

    foreach标签:可以对传过来的参数数组或集合进行遍历,以下是foreach标签上的各个属性介绍:

    属性属性描述collection必需,值为遍历的集合类型,例如:如果参数只是一个数组或List集合,则collection的值为array或list;如果传的是多个参数,用map封装,collection则指定为map中的key。item必需,若collection为数组或List集合时,item表示其中的元素,若collection为map中的key,item表示map中value(集合或数组)中的元素open可选,表示遍历生成的SQL片段以什么开始,最常用的是左括号’(’close可选,表示遍历生成的SQL片段以什么结束,最常用的是右括号’)’separator可选,每次遍历后给生成的SQL片段后面指定间隔符

    练习: 根据员工的id批量删除员工信息 在mapper文件中编写SQL语句:

    <!-- 练习14: 根据员工的id批量删除员工信息 delete from emp where id in (1,3,5,7) collection: 如果传的参数仅仅是一个数组或者List集合, collection可以指定为 array或list; 如果传的是多个参数,用map封装,collection则指定为map中的key open: 指定生成的SQL片段以什么符号开始 close: 指定生成的SQL片段以什么符号结束 item: 指定变量接收数组或集合中的元素 separator: 指定一个间隔符, 在将数组或集合中的每个元素拼接到SQL片段之后, 在后面拼接一个间隔符 --> <delete id="deleteByIds"> delete from emp where id in <foreach collection="array" open="(" item="id" separator="," close=")"> #{id} </foreach> </delete>
    Processed: 0.009, SQL: 9