MyBatis

MyBatis优秀的持久层框架,用于简化JDBC开发

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

 官网:https://mybatis.org/mybatis-3/zh/index.html

一些持久层框架

持久层:

  • 负责将数据保存到数据库,操作数据库数据的那一层代码
  • javaee三成架构 :表现层,业务层,持久层

框架

  • 框架是一个半成品软件,一套可重用的,通用的,软件基础代码模型
  • 在框架的基础之上构建软件编写更加高效,规范,通用,可扩展

官网 mybatis-spring –

JDBC 的缺点

JDBC代码

 

  • 硬编码
    • 一些语句的改动不方便等等
    • 注册驱动,获取连接,SQL语句处的硬编码
  • 操作繁琐
    • 手动操作参数
    • 手动封装结果集 等等

MyBatis 入门

入门操构建一个查询所有的MyBatis模块

1创建数据库表单

2 安装

要使用 MyBatis, 只需将 mybatis-x.x.x.jar 文件置于类路径(classpath)中即可。

 

如果使用 Maven 来构建项目,则需将下面的依赖代码置于 pom.xml 文件中:

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>x.x.x</version>
</dependency>

3 编写MyBatis核心配置文件→替换连接信息解决硬编码问题

→→→→→→→→→→→→ 

 

 

<--指定sql映射配置文件的历经-->  
<mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>

 

4编写SQL映射文件→统一管理sql语句,解决硬编码问题

<?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">
<!--
    namespace:名称空间
    配合要执行的sql语句标签中的id使用
id是sql语句的唯一标识,resultType是返回值类型
--> <mapper namespace="com.yang.mapper.UserMapper"> <select id="selectAll" resultType="com.yang.Pojo.User"> SELECT * FROM tb_user </select> </mapper>

5编码

  • 设计pojo javabean封装类
  • 加载核心配置文件,获取SqlSessionFactory对象
  • 获得SqlSession对象,执行Sql语句
  • 释放资源
  //加载核心配置文件,获取SqlsessionFactory工厂对象
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获取sqlSession对象
        SqlSession sqlSession = build.openSession();
        //执行sql语句,并接受结果集
        List<User> list = sqlSession.selectList("com.yang.mapper.UserMapper.selectAll");//mapper的名称空间.select的id属性值
        sqlSession.close();
        for (User user : list) {
            System.out.println(user);
        }
sql语句爆红是没有连接数据库
6 了解了原生的开发,只是为了让我们更好的了解Mybatis的原理,上面代码仍然存在硬编码问题

在我们传递sql语句映射地址的时候仍然有硬编码问题所以我们又要使用Mapper代理开发

 我们只需要增加一个对应封装类的Mapper接口,如User的UserMapper接口,保证mapper的命名空间namespce为mapper接口的全类名。只需保证接口中的抽象方法返回值能接受你sql语句的返回值方法名保持sql的唯一标识相同即可,这样我们的MyBatis即可利用反射原理,替我们完成老本版方法的连接,这样能让你的代码不仅更清晰,更加类型安全,还不用担心可能出错的字符串字面值以及强制类型转换。但我们需要定义与SQL映射文件同名的Mapper接口,并且将Mapper接口和SQL映射文件放置在同一目录下。(编译后和对应皆苦的Class文件在同一地址下就可以)

  我们使用UserMapper.class对象能够得到该接口的全限定名,又因为SQL映射配置文件也是这个地址,我们执行该接口的方法,改方法和SQL id一致,我们便可以执行SQL语句,且该方法的返回值,也是和之前sqlSession直接执行SQL语句一样的,所以者样我们使用Mapper代理便实现了旧版本的升级。

使用了Mapper代理后,我们可以使用包扫描的方法完成sql映射文件的加载

<mappers>
        <!--加载映射配置文件-->
        <!--<mapper resource="UserMapper.xml"/>-->
        <!-- 更换为包扫描-->
        <package name="com.yang.mapper"/>
    </mappers>

 这样我们的项目结构就变成了这样   

 

public static void main(String[] args) throws IOException {
        //加载核心配置文件,获取SqlsessionFactory工厂对象
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获取sqlSession对象
        SqlSession sqlSession = build.openSession();
        //执行sql语句,并接受结果集
       //List<User> list = sqlSession.selectList("test.selectAll");//名称空间.id属性值
        //使用mapper代理 获得UserMapper接口的代理对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> users = mapper.selectAll();
        sqlSession.close();
        //for遍历集合,处理结果
        for (User user : users) {
            System.out.println(user);
        }

    }

7Mapper核心配置文件内容

 官网很详细(配置遵守顺序就可以)

 8注意

当数据库字段名,与实体类属性名称对应不上时,数据便不能自动封装,这会导致我们查询到结果为空
如 brand_name 与brandName
  • sql映射文件中的sql语句利用as关键字起别名 brand_name as brandName
        <select id="selectAll" resultType="Brand">
            select brand_name as brandName from tb_brand;
        </select>
  • 当很多sql语句需要起别名时,我们可以抽取sql片段 缺点不灵活
    <sql id="brand_cloum">
        brand_name as brandName
    </sql>
        <select id="selectAll" resultType="Brand>
            select <include refid="brand_cloum"/> from tb_brand;
        </select>
  • 使用resultMap映射
    <!--方案三:resultMap-->
    <!--
        resultMap标签:手动配置数据表字段和实体类的映射关系
        id属性:唯一标识
        type属性:映射的实体类类型,支持别名
    -->
<resultMap id="brand_mapper" type="Brand">
    <result column="brand_name" property="brandName"/>
</resultMap>

//resultType换为resultMap 值设为 resultMap映射ID
    <select id="selectAll" resultMap="brand_mapper">
        select * from tb_brand;
    </select>

9参数占位符和xml中sql语句的特殊字符

<!--
        1.参数占位符
            #{}:使用预编译,将参数替换为 ? 占位符。防止sql注入,安全!
            ${}:直接拼接sql语句,存在sql注入,不安全!
            使用场景:
                #{}:实际参数传递时使用
                ${}:表名或字段名不固定时使用
        2.参数类型:parameterType属性(可以省略不写)这里parameterType的属性设置为 int
        3.特殊字符处理:< > <>等等
            转义字符替换:SELECT * FROM tb_brand WHERE id &lt; #{id}
            CDATA区:
                SELECT * FROM tb_brand WHERE id
                 <![CDATA[
                    <
                 ]]>
                 #{id}
    -->
<select id="selectById" parameterType="int" resultMap="brandResultMap">
     SELECT * FROM tb_brand WHERE id = #{id}
</select>
<select id="selectById" resultMap="brand_mapper">
select * from tb_brand where id <![CDATA[
<
]]>#{num};
</select>
 

10 Mapper 映射接口中的sql方法多参数接收

 为保证我们sql映射文件中的sql语句的#{}里面的参数占位符,能与我们在Mapper接口中对应方法的形参对应起来我们可以使用三种方法

   <select id="selectByCodition" resultMap="brand_mapper">
        select * from tb_brand
        <where>
            <if test="status !=null">
                and status=#{status}
            </if>
            <if test="companyName !=null and companyName != ''">
                and company_name like #{companyName}
            </if>
            <if test="brandName !=null and brandName != ''">
                and brand_name like #{brandName}
            </if>
        </where>
    </select>
  •   散装参数使用Param注解 @Param("sql语句的参数占位符名称")
 List<Brand> selectByCodition(@Param("status") int status, @Param("brandName") String brandName,@Param("companyName") String companyName);
  •      实体类封装参数 要求sql语句的参数占位符与实体类的属性名一致就可以了,其他无需改动
    List<Brand> selectByCodition(Brand brand);
  • Map集合封装参数 sql语句占位符与Map 的 key保持一致
    List<Brand> selectByCondition(Map map);

11 动态多条件查询

          当我们需要多条件查询时我们会编写这样的sql语句

 <select id="selectByCodition" resultMap="brand_mapper">
        select * from tb_brand
        where
         status=#{status} and company_name like #{companyName}and brand_name like #{brandName}
    </select>

但是当用户只给一个company_name的值查询时,程序会报错

因为 会产生 where and sql语句的语法错误 可以在where后加恒等式 或者使用<where>标签 会帮我们去掉多余的and关键字

这时我们需要一个动态SQL语句,使得sql语句随着用户的输入或外部条件的变化而变化 。MyBatis为我们提供了很多sql标签来帮助我们完成动态SQL

 <select id="selectByCodition" resultMap="brand_mapper">
        select * from tb_brand
        <where>
            <if test="status !=null">
                and status=#{status}
            </if>
            <if test="companyName !=null and companyName != ''">
                and company_name like #{companyName}
            </if>
            <if test="brandName !=null and brandName != ''">
                and brand_name like #{brandName}
            </if>
        </where>
    </select>

12 动态单条件查询

Mabatis为我们提供了 <choose><when></when><when></when><otherwise></otherwise>动态单条件查询标签

choose相当于switch when相当于 case otherwise相当于 default

 

 <select id="selectByConnditionSingle" resultType="com.yang.pojo.Brand">
        select * from tb_brand
        <where>
            <choose>
                <when test="status!=null">
                    status=#{status}
                </when>
                <when test="brandName!=null and brandName!=''">
                    brand_name like #{brandName}
                </when>
                <when test="companyName!=null and companyName!=''">
                    company_name like #{companyName}
                </when>
            </choose>
        </where>
    </select>

13 提交事务

MaBatis事务:

  • openSession(): 默认开启事务,进行增删改查操作后需要使用sqlSession.commit();手动提交事务
  • openSession(true): 可以设置为自动提交事务(关闭事务)
//进行增删改 操作需要对事务进行设置   

try { brandMapper.add(brand); sqlSession.commit(); } catch (Exception e) { sqlSession.rollback(); e.printStackTrace(); }finally { sqlSession.close(); }

14 获取主键id

编写映射文件的sql
  • useGeneratedKeys属性:是否使用生成的主键

  • keyProperty属性:主键名称

<!--添加数据后、可以返回自增数据的主键-->
<insert id="add" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO tb_brand (brand_name,company_name,ordered,description,status)
        VALUES (#{brandName},#{companyName},#{ordered},#{description},#{status})
</insert>

15 动态修改字段

添加<if></if>标签判断(防止其他字段被修改为null),sql中的,会出现错误,我们需要使用<set>标签

<!--
        动态修改数据
            <set>标签:替换set关键字
    -->
<update id="update">
        UPDATE tb_brand
            <set>
                <if test="brandName != null and brandName != ''">
                    brand_name = #{brandName},
                </if>
                <if test="companyName != null and companyName != ''">
                    company_name = #{companyName},
                </if>
                <if test="ordered != null">
                    ordered = #{ordered},
                </if>
                <if test="description != null and description != ''">
                    description = #{description},
                </if>
                <if test="status != null">
                    status = #{status}
                </if>
            </set>
        WHERE
            id = #{id}
</update>

 16批量删除

   <!--

        批量删除
mybatis会将数组参数,封装为一个一个Map集合:
*默认 array=数组
*或者使用Param注解来改变Map集合的默认名称 <foreach>标签:循环 collection属性:获取容器的名称,数组默认是array,可以通过@Param()指定名称 item属性:接收每个元素的变量名 separator属性:连接符 open属性:开始符号 close属性:结束符号
--> <!--collection 数组或者集合名 item 数组元素 separater item之间的连接符 open 开始符号 close 结束符号--> <delete id="deleteByIds"> delete from tb_brand where id in <foreach collection="ids" item="id" separator="," open="(" close=")"> #{id} </foreach>
      ;
</delete>

17 MyBatis 参数传递

1.MyBatis参数封装原理

  • MyBatis接口方法中的形参可以是多种类型的,MyBatis底层会对这些参数自动进行不同的封装

  • 通过 ParamNameResolver 类进行封装参数

2.单个参数情况

  • POJO类型:直接使用,属性名 和 参数占位符名称 一致

  • Map集合:直接使用,键名 和 参数占位符名称 一致

  • Collection:封装为Map集合,可以使用@Param注解,替换Map集合中默认的arg键名

    • map.put("arg0",collection集合);

    • map.put("collection",collection集合);

  • List:封装为Map集合,可以使用@Param注解,替换Map集合中默认的arg键名

    • map.put("arg0",list集合);

    • map.put("collection",list集合);

    • map.put("list",list集合);

  • Array:封装为Map集合,可以使用@Param注解,替换Map集合中默认的arg键名

    • map.put("arg0",数组);

    • map.put("array",数组);

  • 其他类型:直接使用

3.多个零散参数情况

  • 封装为Map集合,可以使用@Param注解,替换Map集合中默认的arg键名

  • 未使用@Param注解

    • map.put("arg0",参数值1)

    • map.put("param1",参数值1)

    • map.put("param2",参数值2)

    • map.put("agr1",参数值2)

  • 使用@Param注解

    • map.put("username",参数值1)

    • map.put("param1",参数值1)

    • map.put("param2",参数值2)

    • map.put("agr1",参数值2)

4.建议

  • 以后都使用@Param()注解来修改指定的键名替换arg名(param键名不会被替换),方便记忆参数和提高可读性

 18 使用注解完成增删改查

 

1.注解开发介绍

  • 在接口方法上,通过不同的注解,将SQL语句直接给定,可以省去映射配置文件的编写!

  • 例如

@Select(value = "SELECT * FROM tb_brand WHERE id = #{id}")
public Brand select(int id);

 

 

 

 

 

 

posted @ 2021-11-04 11:57  互联.王  阅读(19)  评论(0编辑  收藏  举报