MyBatis

一、简介

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

  • 持久层:负责将数据保存到数据库的那一层代码。(与数据库相关的都叫持久层)
  • 框架:就是一个半成品软件,是一套可重用的、通用的、软件基础代码模型。在框架的基础上编写软件更加高效、规范、通用、可扩展。
  • JavaEE三层架构:表现层、业务层、持久层。

(一)JDBC使用缺点

  1. 硬编码:有字符串的地方都叫硬编码,硬编码太多修改麻烦。
  2. 操作繁琐:手动设置SQL等参数,JDBC使用数据库步骤太多。
    解决办法:硬编码写到配置文件;操作繁琐利用自动完成
    MyBatis免除了几乎所有的JDBC代码以及设置参数和获取结果集的工作

二、快速入门

  1. 创建Maven项目,在pom导入MyBatis的jar包(MyBatis中文网),坐标内容如下:
<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>3.5.5</version>
</dependency>

另外附上格式化log日志格式的工具的坐标

        <!-- Junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>

        <!-- LogBack-classic -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <!-- LogBack-core -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>1.2.3</version>
        </dependency>

        <!-- slf4j日志API -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.20</version>
        </dependency>
  1. 在resources下新建MyBatis核心配置文件mybatis-config.xml,并添加如下内容,然后修改里面的两处配置项
<?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>

    <!--别名-->
    <typeAliases>
        <package name="cn.fn.pojo"/>
    </typeAliases>

    <environments default="development">
        <environment id="development">
            <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/db1?useSSL=false"/>
                <property name="username" value="root"/>
                <property name="password" value="000000"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <!--加载SQL映射文件,填写路径,映射文件在同目录下-->
<!--        <mapper resource="cn/fn/mapper"/>-->

        <package name="cn.fn.mapper"/>
    </mappers>

</configuration>

mappers区别-01
mappers区别-02

  1. 新建SQL映射文件XXXMapper.xml,约定是哪一个表就用表名代替XXX来命名,如User表就是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">
<!--
    namespace:接口的全称
    id:用于标识这一段的SQL语句
    resultType:返回结果的类型,如查询结果返回String类型,就填String
-->
<mapper namespace="test">
    <select id="selectAll" resultType="cn.fn.pojo.User">
        select * from tb_user;
    </select>
</mapper>
  1. 开始编码,获取SqlSessionFactory对象,用于加载核心配置文件。
  2. 使用SqlSessionFactory对象获取SqlSession对象,SqlSession对象用于执行SQL语句。
  3. 使用SqlSession对象执行SQL语句。
  4. 释放资源。
    以上四条条示例如下
		//1.加载核心配置文件
        String resource = "mybatis-config.xml";		//指定核心配置文件
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2.获取SqlSession对象,用于执行sql
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //3.执行sql语句,参数为namespace名.id名
        List<User> users = sqlSession.selectList("test.selectAll");

        System.out.println(users);

        //4.释放资源
        sqlSession.close();

最后整体结构如下:
在这里插入图片描述
logback.xml内容如下

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!--
        CONSOLE :表示当前的日志信息是可以输出到控制台的。
    -->
    <appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>[%level] %blue(%d{HH:mm:ss.SSS}) %cyan([%thread]) %boldGreen(%logger{15}) - %msg %n</pattern>
        </encoder>
    </appender>

    <logger name="com.itheima" level="DEBUG" additivity="false">
        <appender-ref ref="Console"/>
    </logger>
    <!--
      level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF
     , 默认debug
      <root>可以包含零个或多个<appender-ref>元素,标识这个输出位置将会被本日志级别控制。
      -->
    <root level="DEBUG">
        <appender-ref ref="Console"/>
    </root>
</configuration>

附加

使用IDEA连接MySQL数据库
在这里插入图片描述
maper.xml没有提示解决办法,SQL Dialect改为MySQL
在这里插入图片描述

MyBatisX插件,主要用于XML和接口方法相互跳转;以及根据接口方法生成statement
在这里插入图片描述

三、Mapper代理开发(重点)

  • 目的
    • 解决原生方式中的硬编码
    • 简化后期执行SQL
  1. 定义与SQL映射文件同名的Mapper接口,并将Mapper接口和SQL映射文件放在同一目录
    步骤:
    A. 在java目录下新建一个包和接口,接口名要和SQL映射文件同名,如cn.fn.mapper.UserMapper
    B. 在resources目录右键New Directory,name为cn/fn/mapper(用/分隔表示,后期Maven编译项目时候会将此目录下的文件编译到接口同目录下)
  2. 设置SQL映射文件的namespace为Mapper接口的全限定名(即包名.接口名),如cn.fn.mapper.UserMapper
  3. 在Mapper接口中定义方法,方法命名规则:
    A. 返回值为SQL映射文件查询后的返回值类型
    B. 方法名为映射文件的id。
  4. 编写代码:
        //3.执行sql语句
//        List<User> users = sqlSession.selectList("test.selectAll"); //原 SQL执行语句
        UserMapper mapper = sqlSession.getMapper(UserMapper.class); //新 Mapper代理执行SQL语句
        List<User> users = mapper.selectAll();
  1. MyBatis核心配置文件修改
    <mappers>
        <!--加载SQL映射文件-->
        
        <!--1.这种方式只指定一个映射文件 -->
<!--        <mapper resource="cn.fn.mapper/UserMapper.xml"/>-->
        
        <!--2.这种方式指定此路径下的所有映射文件,路径名就是映射文件上面的包名 -->
        <package name="cn.fn.mapper"/>
    </mappers>

四、核心配置文件

别名:在<configuration>的起始标签下添加

    <!--别名-->
    <typeAliases>
        <package name="cn.fn.pojo"/>
    </typeAliases>

那么SQL映射文件的resultType值就可以只指定类名就行

<!--原resultType值:cn.fn.pojo.User(严格使用大小写)-->
<!--别名后resultType值:user(大小写都可)-->
<mapper namespace="cn.fn.mapper.UserMapper">
    <select id="selectAll" resultType="user">
        select * from tb_user;
    </select>
</mapper>

参考视频

五、配置文件完成增删改查

(一)查询(select)

实体类成员变量名和数据库表的列明不一致时,MyBatis不能自动封装数据,需要使用<resultMap>标签手动调整,(在SQL映射文件中)如下:
在这里插入图片描述

(1)查询单条数据(占位符#{}、特殊字符处理)

  • 参数占位符:
    • #{}:防止SQL注入,会将SQL语句传参部分替换为?
    • ${}:拼接SQL语句,不能防止SQL注入
    <select id="selectById" resultMap="brandResultMap">
        select * from tb_brand where id = #{id}
    </select>
  • 特殊字符处理(两种处理方式):
    • 转义字符(以<为例):&lt;
    • CDATA区:在需要处理的地方敲CD生成,然后将小于号写到里面。
    <select id="selectById" resultMap="brandResultMap">
        select *
        from tb_brand where id &lt; #{id}   <!--1.转义字符的方式-->
        select *
        from tb_brand where id <![CDATA[
        <
        ]]> #{id}   <!--1.CDATA区的方式-->
    </select>

(2)条件查询

多条件查询

注:select的查询语句格式照写,变的是Mapper接口里的方法执行SQL时的传参

	<!-- BrandMapper.xml-->
    <!-- 多条件查询-->
    <select id="selectByCondition" resultMap="brandResultMap">
        select * from tb_brand
        where status=#{status}
        and company_name like #{companyName}
        and brand_name like #{brandName}
    </select>
  1. Mapper接口(三种方式)
    A. 方式1@Param(参数)里的参数必须要和select语句的查询条件一一对应(如#{status}对应就必须写@Param("status")
    B. 方式2参数接收brand对象
    C. 方式3参数接收map集合
//BrandMapper.java接口
public interface BrandMapper {
    //多条件查询一条数据 方式1,散装参数,@Param参数名称要和SQL语句占位符保持一致
    List<Brand> selectByCondition(@Param("status") int status,
                                  @Param("companyName") String companyName,
                                  @Param("brandName") String brandName);

    //多条件查询一条数据 方式2,对象参数
    List<Brand> selectByCondition(Brand brand);

    //多条件查询一条数据 方式3,map集合参数
    List<Brand> selectByCondition(Map map);

}
  1. 测试用例,编码传参
    注意:使用Map集合时,键的值必须和#{}内容一一对应
//MyBatisTest.java测试用例
        //接受参数
        int status = 1;
        String companyName = "谷歌";
        String brandName = "谷歌";
        //处理参数
        companyName = "%" + companyName + "%";
        brandName = "%" + brandName + "%";

        //方式1,散装参数
//        List<Brand> brands = mapper.selectByCondition(status, companyName, brandName);

        //方式2,对象参数,先new一个对象,传入需要查询的参数
        Brand brand = new Brand();
        brand.setStatus(status);
        brand.setCompanyName(companyName);
        brand.setBrandName(brandName);
//        List<Brand> brands = mapper.selectByCondition(brand);

        //方式3,map集合参数,先new一个集合,传入需要查询的参数键值对,其中键值必须和select中#{}里的内容一一对应
        Map<Object, Object> hashMap = new HashMap<>();
        hashMap.put("status", status);
        hashMap.put("companyName", companyName);
        hashMap.put("brandName", brandName);
        List<Brand> brands = mapper.selectByCondition(hashMap);
动态条件查询
动态多条件查询

SQL语句随用户的输入或外部条件的变化而变化,称为动态SQL。(只更改select所在xml文件)

  1. <where>SQL的WHERE语句后面内容</where>(where标签替换原来的where,作用是自动识别and和or等运算符)
  2. <if test="条件判断">SQL语句</if>
    <!-- 多条件查询之动态SQL-->
    <select id="selectByCondition" resultMap="brandResultMap">
        select * from tb_brand
        <where>
            <if test="status!=null">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>
动态单条件查询

解决如下问题
在这里插入图片描述
注:全部在where后面写
<choose></choose>标签相当于swith。
<when test="条件判断"></when>标签相当于case。

    <select id="selectByChoose" resultMap="brandResultMap">
        select * from tb_brand
        <where>
            <choose>
                <when test="status !=null">
                    status =#{status}
                </when>
                <when test="companyName!=null and companyName!=''">
                    company_name like #{companyName}
                </when>
                <when test="brandName !=null and brandName !=''">
                    brand_name like #{brandName}
                </when>
            </choose>
        </where>
    </select>

(二)添加(insert)

  1. SQL映射文件,使用添加数据标签<insert id=""></insert>
    <insert id="add">
        insert into tb_brand(brand_name, company_name, ordered, description, status) values
        (#{brandName},#{companyName},#{ordered},#{ordered},#{status})
    </insert>
  1. Mapper接口文件,返回值为void(通过是否异常来判断有没有添加成功)
    void add(Brand brand);
  2. 测试用例,可以传入一个实体类对象添加数据,特别注意:MyBatis默认关闭了提交事务,所以需要使用SqlSession的commit()方法手动提交事务sqlSession.commit()。或者在 SqlSession sqlSession = sqlSessionFactory.openSession(true);的时候传入true参数,表示开启自动提交事务
    @Test
    public void testAdd() throws IOException {
        //1.获取SqlSessionFactory,加载核心配置文件
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2.获取sqlSession对象,执行sql语句
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //3.执行sql语句
        BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);

        //接受参数
        int status = 1;
        String companyName = "波导手机";
        String brandName = "波导";
        int ordered = 60;
        String description = "手机中的战斗机";

        //方式2,对象参数,先new一个对象,传入需要查询的参数
        Brand brand = new Brand();
        brand.setStatus(status);
        brand.setCompanyName(companyName);
        brand.setBrandName(brandName);
        brand.setOrdered(ordered);
        brand.setDescription(description);

        mapper.add(brand);
        sqlSession.commit();

        sqlSession.close();
    }

主键返回

需求:在数据添加成功后,需要获取插入数据库数据的主键值。

  1. 在SQL映射文件中添加两个属性即可
    <insert id="add" useGeneratedKeys="true" keyProperty="id">
    	省略...
    </insert>
  1. 测试用例,在添加数据后,提交事务前获取ID
        //方式2,对象参数,先new一个对象,传入需要查询的参数
        Brand brand = new Brand();
        brand.setStatus(status);
        brand.setCompanyName(companyName);
        brand.setBrandName(brandName);
        brand.setOrdered(ordered);
        brand.setDescription(description);
        
        mapper.add(brand);
        
        //下面是在提交事务前获取ID
        Integer id = brand.getId();
        System.out.println(id);
        
        sqlSession.commit();

        sqlSession.close();

(三)修改(update)

(1)修改全部字段(需要提交事务)

在这里插入图片描述

(2)修改动态字段(动态SQL)

使用场景:不修改一行里所有的数据,只修改一部分,动态去判断。
使用<set></set><if test=""></if>标签实现

	<!-- 修改动态字段就是加入set和if标签 -->
    <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>

(四)删除(delete)

在这里插入图片描述

批量删除

使用<foreach>标签批量删除(在in里面使用)
在这里插入图片描述
接口里:

    //void deleteByids(int[] ids);
    //@Param名称要和SQL占位符名称保持一致
    void deleteByids(@Param("ids") int[] ids);

xml里:

    <!-- 批量删除 -->
    <delete id="deleteByids">
        delete from tb_brand
        where id in (
            
            <foreach collection="ids" item="id" separator=",">
            <!-- 不起别名就是<foreach collection="array" item="id" separator=","> -->
                #{id}
            </foreach>
            )
    </delete>

六、MyBatis参数封装

  • 单个参数

    • POJO类型(实体类):直接传入,属性名和参数占位符名称一致即可(这样里面就可以装多个参数,然后再整体作为一个对象传入)
    • Map集合:直接传入,键名和参数占位符名称一致
    • Collection:封装为Map集合,可以使用@Param注解,替换Map集合中默认的arg键名
    • List:封装为Map集合,可以使用@Param注解,替换Map集合中默认的arg键名
    • Array:封装为Map集合,可以使用@Param注解,替换Map集合中默认的arg键名(如上面那个例子,传入的是int数组,就要起别名)
    • 其他类型:直接使用
  • 多个参数:会封装为Map集合,可以使用@Param注解,替换Map集合中默认的arg键名

    • 默认:map.put(“arg0”,参数值1)
    • map.put(“param1”,参数值1)
    • map.put(“arg1”,参数值2)
    • map.put(“param2”,参数值2)
    • --------------------@Param(“username”)替换后
    • map.put(“username”,参数值1)
    • map.put(“param1”,参数值1)
    • map.put(“arg1”,参数值2)
    • map.put(“param2”,参数值2)

七、使用注解完成增删改查

注意:注解只适合完成简单功能,复杂功能还是要用xml配置文件完成
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值