• MyBatis 的在使用上的注意事项及其辨析


    1. MyBatis 的在使用上的注意事项及其辨析

    @


    2. 准备工作

    数据表结构的设计,数据表名为:t_car

    在这里插入图片描述

    t_car 表中的数据信息:

    在这里插入图片描述

    pom.xml 文件当中配置相关的依赖的 jar 包如下:

    在这里插入图片描述

    
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0modelVersion>
    
        <groupId>com.rainbowseagroupId>
        <artifactId>mybatis-005-crud-blogartifactId>
        <version>1.0-SNAPSHOTversion>
    
        <properties>
            <maven.compiler.source>17maven.compiler.source>
            <maven.compiler.target>17maven.compiler.target>
        properties>
    
        <dependencies>
            
            <dependency>
                <groupId>org.mybatisgroupId>
                <artifactId>mybatisartifactId>
                <version>3.5.10version>
            dependency>
    
            
            <dependency>
                <groupId>mysqlgroupId>
                <artifactId>mysql-connector-javaartifactId>
                <version>8.0.30version>
            dependency>
    
            <dependency>
                <groupId>junitgroupId>
                <artifactId>junitartifactId>
                <version>4.13.2version>
                <scope>testscope>
            dependency>
    
            
            <dependency>
                <groupId>ch.qos.logbackgroupId>
                <artifactId>logback-classicartifactId>
                <version>1.2.11version>
            dependency>
        dependencies>
    
    project>
    

    配置 logback 的配置文件,用于打印显示,我们的日志信息,方便我们查看我们的运行过程,效果。

    在这里插入图片描述

    
    
    <configuration debug="false">
        
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%npattern>
            encoder>
        appender>
    
        
        <logger name="com.apache.ibatis" level="TRACE"/>
        <logger name="java.sql.Connection" level="DEBUG"/>
        <logger name="java.sql.Statement" level="DEBUG"/>
        <logger name="java.sql.PreparedStatement" level="DEBUG"/>
    
        
        <root level="DEBUG">
            <appender-ref ref="STDOUT"/>
            <appender-ref ref="FILE"/>
        root>
    
    configuration>
    

    配置 MyBatis 的核心配置文件,

    在这里插入图片描述

    
    configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        
        <typeAliases>
            
            <package name="com.rainbowsea.mybatis.pojo"/>
        typeAliases>
        <environments default="mybatis">
    
            <environment id="mybatis">
                
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                    <property name="username" value="root"/>
                    <property name="password" value="MySQL123"/>
                dataSource>
            environment>
        environments>
        <mappers>
            
            <mapper resource="CarMapper.xml">mapper>
        mappers>
    configuration>
    

    对照 t_car 创建的ORM 映射的 Car 类

    注意:在MyBatis 当中对应的ORM ,一般在框架里对应的 Bean实体类,一定要实现该 set 和 get 方法以及无参数构造方法,无法框架无法使用反射机制,进行操作

    建议用包装类,这样可以防止 Null的问题,因为(简单类型 int num = null ,是不可以赋值为 null)的编译无法通过

    在这里插入图片描述

    package com.rainbowsea.mybatis.pojo;
    
    public class Car {
        // 数据库表当中的字段应该和pojo类的属性一一对应
        // 建议使用包装类,这样可以防止null的问题
        private Long id;
        private String carNum;
        private String brand;
        private Double guidePrice;
        private String produceTime;
        private String carType;
    
        public Car() {
        }
    
        public Car(Long id, String carNum, String brand, Double guidePrice, String produceTime, String carType) {
            this.id = id;
            this.carNum = carNum;
            this.brand = brand;
            this.guidePrice = guidePrice;
            this.produceTime = produceTime;
            this.carType = carType;
        }
    
        @Override
        public String toString() {
            return "Car{" +
                    "id=" + id +
                    ", carNum='" + carNum + '\'' +
                    ", brand='" + brand + '\'' +
                    ", guidePrice=" + guidePrice +
                    ", produceTime='" + produceTime + '\'' +
                    ", catType='" + carType + '\'' +
                    '}';
        }
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public String getCarNum() {
            return carNum;
        }
    
        public void setCarNum(String carNum) {
            this.carNum = carNum;
        }
    
        public String getBrand() {
            return brand;
        }
    
        public void setBrand(String brand) {
            this.brand = brand;
        }
    
        public Double getGuidePrice() {
            return guidePrice;
        }
    
        public void setGuidePrice(Double guidePrice) {
            this.guidePrice = guidePrice;
        }
    
        public String getProduceTime() {
            return produceTime;
        }
    
        public void setProduceTime(String produceTime) {
            this.produceTime = produceTime;
        }
    
        public String getcarType() {
            return carType;
        }
    
        public void setcarType(String catType) {
            this.carType = catType;
        }
    }
    
    

    对应操作实现CRUD(增删改查)的接口(这里是:CarMapper接口),在MyBtis 当中 ,关于 CRUD(增删改查)操作的接口/实现类,都是 mapper 结尾的作为持久层,而在 MVC的三层架构中,则是以 dao 为后缀作为CRUD(增删改查)操作的接口/实现类。

    在这里插入图片描述

    package com.rainbowsea.mybatis.mapper;
    
    import com.rainbowsea.mybatis.pojo.Car;
    
    import java.util.List;
    
    public interface CarMapper {
    
    
        /**
         * 新增 Car
         * @param car
         * @return
         */
        int insert(Car car);
    
    
        /**
         * 根据id 删除 Car
         * @param id
         * @return
         */
        int deleteById(Long id);
    
    
        /**
         * 修改汽车信息
         * @param car
         * @return
         */
        int update(Car car);
    
    
        /**
         * 根据id查询汽车信息
         * @param id
         * @return
         */
        Car selectById(Long id);
    
    
        /**
         * 获取所有的汽车信息
         * @return
         */
        List selectAll();
    }
    
    

    获取 Sqlsession 对象的工具类的编写。

    在这里插入图片描述

    package com.rainbowsea.mybatis.utils;
    
    
    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;
    
    public class SqlSessionUtil {
        // 工具类的构造方法一般都是私有话化的
        // 工具类中所有的方法都是静态的,直接类名即可调用,不需要 new 对象
        // 为了防止new对象,构造方法私有化。
    
        private SqlSessionUtil() {
    
        }
    
    
    
        private static SqlSessionFactory sessionFactory = null;
    
        // 静态代码块,类加载时执行
        // SqlSessionUtil 工具类在进行第一次加载的时候,解析mybatis-config.xml 文件,创建SqlSessionFactory对象。
        static {
            // 获取到  SqlSessionFactoryBuilder 对象
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    
            // 获取到SqlSessionFactory 对象
            // SQlsessionFactory对象,一个SqlSessionFactory对应一个 environment, 一个environment通常是一个数据库
            try {
                sessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"),
                        "mybatis");
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
    
        }
    
        /**
         * 获取会话对象
         * @return SqlSession
         */
        public static SqlSession openSession() {
            // 获取到 SqlSession 对象
            SqlSession sqlSession = sessionFactory.openSession();
            return sqlSession;
        }
    }
    
    

    3. #{ } 与 ${ } 的区别和使用

    • #{ } :先编译 SQL 语句,再对占位符传值,底层是 PrepareedStatement 实现,可以防止 SQL 注入,比较常用
    • ${ }:先进行SQL语句的拼接,然后再对SQL语句进行编译,底层是 Statement 实现,这种方式存在 SQL注入现象,SQL注入的风险,简单的说就是,直接将传入的值拼接为了SQL语句,然后再执行的)。只有在需要进行SQL语句关键字拼接的情况下才会用到。
    • 简单的说一个区别就是:#{} 传的值是带有 '' 单引号的,而 ${} 传的值是(直接就是值,没有单引号,或者是双引号,两个都没有)

    检验一下。

    这里我们根据汽车的 car_type 查询,为新能源汽车的。多条记录

    首先这里我们先使用 #{} ,传的是带有 '' 单引号的值 ——> '新能源'

    在这里插入图片描述

    在这里插入图片描述

    package com.rainbowsea.mybatis.mapper;
    
    import com.rainbowsea.mybatis.pojo.Car;
    
    import java.util.List;
    
    /**
     * 封装汽车相关信息的pojo类,普通的Java类
     */
    public interface CarMapper {
    
        /**
         * 根据汽车类型获取汽车信息
         * @param carType
         * @return
         */
        List selectByCarType(String carType);
    
    }
    
    
    
    mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    
    <mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">
    
        
        
        <select id="selectByCarType" resultType="com.rainbowsea.mybatis.pojo.Car">
            select id,
                   car_num      as carNum,
                   brand,
                   guide_price  as guidePrice,
                   produce_time as produceTime,
                   car_type     as carType
            from t_car
            where car_type = #{carType}
        select>
    
    mapper>
    

    运行Java程序:

    在这里插入图片描述

    在这里插入图片描述

    查询成功。

    下面我们再实验用 ${} ,直接就是新能源的值,没有单引号,也没有双引号,就是直接就是——》新能源的值。运行结果如下:

    在这里插入图片描述

    比较上述#{}和 ?{} 的运行结果:

    {}

    在这里插入图片描述

    ${}

    在这里插入图片描述

    通过执行可以清楚的看到,sql 语句中是带有 ? 的,这个 ? 就是大家在JDBC中所学的占位符,专门用来接收值的。

    把“新能源”以 String 类型的值,传递给 ? ,加上 '' 单引号,作为字符串传入进行,执行SQL语句

    这就是 #{},它会先进行sql语句的预编译,然后再给占位符传值。

    而 ${} 是直接将我们的 新能源 作为值,传入给SQL语句的,注意 ${} 的方式是不会加单引号/双引号的,而是作为值,直接拼接到 SQL语句当中去了,但是,在我们这个查询的SQL当中,新能源就是必须要为字符串才行的,不然是无法执行SQL语句,是无法识别出来的。

    在这里插入图片描述

    3.1 什么情况下必须使用 $

    当需要进行 sql 语句关键字拼接的时候,简单的说就是当我们要使用 SQL语句当中的关键字的时候,以及要传的值,不要单引号/双引号的值的时候,就必须使用${ }

    需求:通过向sql语句中注入asc或desc关键字,来完成数据的升序或降序排列。

    根据数据表中的 produce_time日期时间进行排序。

    因为这里我们使用到了 ASC / DESC 这两者都是 SQL语句当中的关键字,所以我们需要使用 ${} 的方式。

    在这里插入图片描述

    package com.rainbowsea.mybatis.mapper;
    
    import com.rainbowsea.mybatis.pojo.Car;
    
    import java.util.List;
    
    /**
     * 封装汽车相关信息的pojo类,普通的Java类
     */
    public interface CarMapper {
    
        /**
         * 查询所有的汽车信息,然后通过 asc 升序,desc 降序
         * @param ascOrDesc
         * @return
         */
        List selectAllByAscOrDesc(String ascOrDesc);
    
    
    }
    
    
    
    mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    
    <mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">
    
        
        
        <select id="selectAllByAscOrDesc" resultType="com.rainbowsea.mybatis.pojo.Car">
            select id,
                   car_num      as carNum,
                   brand,
                   guide_price  as guidePrice,
                   produce_time as produceTime,
                   car_type     as carType
            from t_car
            order by produce_time ${ascOrDesc}
        select>
    
    mapper>
    
    

    Java程序运行测试:

    在这里插入图片描述

    public class TestCarMapper {
    
        @Test
        public void testSelectAllByAscOrDesc() {
            SqlSession sqlSession = SqlSessionUtil.openSession();
            CarMapper mapper = sqlSession.getMapper(CarMapper.class);
            List cars = mapper.selectAllByAscOrDesc("asc");
            cars.forEach(car -> {
                System.out.println(car);
            });
    
            sqlSession.close();
        }
    
    }
    

    如果换成 #{} ,将SQL 语句的关键字 asc 作为字符串的形式拼接到 SQL语句当中是会编译失败的了。

    在这里插入图片描述

    3.1.1 拼接表名

    业务背景:实际开发中,有的表数据量非常庞大,可能会采用分表方式进行存储,比如每天生成一张表,表的名字与日期挂钩,例如:2022年8月1日生成的表:t_user20220108。2000年1月1日生成的表:t_user20000101。此时前端在进行查询的时候会提交一个具体的日期,比如前端提交的日期为:2000年1月1日,那么后端就会根据这个日期动态拼接表名为:t_user20000101。有了这个表名之后,将表名拼接到sql语句当中,返回查询结果。那么大家思考一下,拼接表名到sql语句当中应该使用#{} 还是 ${} 呢?

    使用#{}会是这样:select * from 't_car'

    使用${}会是这样:select * from t_car

    向SQL语句当中拼接表名,就需要使用${}
    现实业务当中,可能存在分表存储的数据的情况,因为一张表存的话,数据量太大了,查询效率比较低。
    可以将这些数据有规律的分表存储,这样在查询的时候效率就比较高,因为扫描的数据量变小了
    日志表,专门存储日志信息,如果t_long 只有一张表,这张表中每一天都会产生很多的log,慢慢的,这个表中数据会很多,
    怎么解决呢
    可以每天生成一个新表,每张表以当天日期作为名称,例如:
    t_log_202209801
    t_log_20220902
    你想知道某一天的日志信息怎么办呢?
    假设今天20220901,那么直接查:t_log-20220901的表即可。

    下面是我们的t_log_20220902 的数据表信息

    在这里插入图片描述

    在这里插入图片描述

    对应数据表的 POJO 类设计:

    在这里插入图片描述

    package com.rainbowsea.mybatis.pojo;
    
    
    public class Log {
        private Integer id;
        private String log;
        private String time;
    
        public Log() {
        }
    
    
        public Log(Integer id, String log, String time) {
            this.id = id;
            this.log = log;
            this.time = time;
        }
    
    
        @Override
        public String toString() {
            return "Log{" +
                    "id=" + id +
                    ", log='" + log + '\'' +
                    ", time='" + time + '\'' +
                    '}';
        }
    
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getLog() {
            return log;
        }
    
        public void setLog(String log) {
            this.log = log;
        }
    
        public String getTime() {
            return time;
        }
    
        public void setTime(String time) {
            this.time = time;
        }
    }
    
    

    对应的LogMapper 的接口信息编写。

    首先我们使用 ${} 的方式测试运行。

    在这里插入图片描述

    在这里插入图片描述

    package com.rainbowsea.mybatis.mapper;
    
    
    import com.rainbowsea.mybatis.pojo.Log;
    
    import java.util.List;
    
    public interface LogMapper {
    
        /**
         * 根据日期查询不同的表,获取表中所有的日志
         *
         * @param date
         * @return
         */
        List selectAllByTable(String date);
    }
    
    
    mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    
    <mapper namespace="com.rainbowsea.mybatis.mapper.LogMapper">
    
        
        
        <select id="selectAllByTable" resultType="com.rainbowsea.mybatis.pojo.Log">
            select * from t_log_${date};
        select>
    
    mapper>
    

    在这里插入图片描述

    package com.rainbowsea.test;
    
    import com.rainbowsea.mybatis.mapper.LogMapper;
    import com.rainbowsea.mybatis.pojo.Log;
    import com.rainbowsea.mybatis.utils.SqlSessionUtil;
    import org.apache.ibatis.session.SqlSession;
    import org.junit.Test;
    
    import java.util.List;
    
    public class LogMapperTest {
    
        @Test
        public void testSelectAllByTable() {
            SqlSession sqlSession = SqlSessionUtil.openSession();
            LogMapper mapper = sqlSession.getMapper(LogMapper.class);
            List logs = mapper.selectAllByTable("20220902");
            logs.forEach(log -> {
                System.out.println(log);
            });
        }
    }
    
    

    使用 ${} 拼接上的结果为:select * from t_log_20220902; 直接就是 20220902 的值,没有加单引号/双引号。

    使用 #{ } 的方式是会带上 ‘’ 单引号的。

    在这里插入图片描述

    使用 #{} 拼接上的结果为:select * from t_log_‘20220902’; 加上的单引号后拼接上去,t_log_20220902是一个数据表名的,加了单引号后,MySQL 就找不到该数据表了,编译无法通过了。

    3.1.2 批量删除

    业务背景:一次删除多条记录。

    在这里插入图片描述

    批量删除:一次删除多条记录
    批量删除的SQL语句有两种写法:

    第一种:or: delete form t_car where id =1 or id = 2 or id = 3
    第二种:delete from t_car where id in(1,2,3)
    

    假设现在使用in的方式处理,前端传过来的字符串:1, 2, 3

    如果使用mybatis处理,应该使用#{} 还是 ${}

    使用#{} :delete from t_user where id in('1,2,3') 会加上单引号, 执行错误:1292 - Truncated incorrect DOUBLE value: '1,2,3'

    使用${} :delete from t_user where id in(1, 2, 3),执行成功

    所以我们要采用 ${} ,不加单引号的形式。

    在这里插入图片描述

    在这里插入图片描述

    package com.rainbowsea.mybatis.mapper;
    
    import com.rainbowsea.mybatis.pojo.Car;
    
    import java.util.List;
    
    /**
     * 封装汽车相关信息的pojo类,普通的Java类
     */
    public interface CarMapper {
    
        /**
         * 批量删除,根据id
         * @param ids
         * @return
         */
        int deleteBath(String ids);
    }
    
    
    
    mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    
    <mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">
    
        
        <delete id="deleteBath">
            delete from t_car where id in(${ids})
        delete>
    
    mapper>
    

    Java程序测试,

    注意因为我们这里是对数据表进行的修改操作的,所以需要提交一下数据给数据库。

    这里我们删除 id为(121,122,123) 三条记录。

    在这里插入图片描述

    在这里插入图片描述

    package com.rainbowsea.test;
    
    import com.rainbowsea.mybatis.mapper.CarMapper;
    import com.rainbowsea.mybatis.pojo.Car;
    import com.rainbowsea.mybatis.utils.SqlSessionUtil;
    import org.apache.ibatis.session.SqlSession;
    import org.junit.Test;
    
    import java.util.List;
    
    public class TestCarMapper {
    
        @Test
        public void testDeleteBath() {
            SqlSession sqlSession = SqlSessionUtil.openSession();
            CarMapper mapper = sqlSession.getMapper(CarMapper.class);
            int count = mapper.deleteBath("121,122,123");
            sqlSession.commit();
            sqlSession.close();
    
        }
    
    }
    

    如果使用 #{} 是将 使用#{} :delete from t_user where id in('121,122,123') 会加上单引号, 执行错误:1292 - Truncated incorrect DOUBLE value: '121,122,123'

    在这里插入图片描述

    3.1.3 模糊查询

    需求:查询小米系列的汽车。【只要品牌brand中含有小米两个字的都查询出来。】

    关于模糊查询有四种方案:

    1. 方案一:'%${brand}%'
    2. 方案二: concat('%','${brand}','%')
    3. 方案三: count函数,这个是mysql数据库当中的一个函数,专门进行字符串拼接的 concat('%',#{brand},'%')
    4. 方案四: "%"#{brand}"%", 这种方式比较常用,也避免了SQL注入的问题。
    方案一:'%${brand}%'
    方案二: concat('%','${brand}','%')
    方案三: count函数,这个是mysql数据库当中的一个函数,专门进行字符串拼接的
            concat('%',#{brand},'%')
    方案四: "%"#{brand}"%"
    

    四种方式:总的来说,都是为了拼接成字符串,把不是字符串的想办法拼接成字符串

    3.1.3.1 使用 ${ }的方式

    方案一:'%${brand}%'

    在这里插入图片描述

    在这里插入图片描述

    package com.rainbowsea.mybatis.mapper;
    
    import com.rainbowsea.mybatis.pojo.Car;
    
    import java.util.List;
    
    /**
     * 封装汽车相关信息的pojo类,普通的Java类
     */
    public interface CarMapper {
    
    
    
    
        /**
         * 根据汽车品牌进行模糊查询
         * @param brand
         * @return
         */
        List selectByBrandLike(String brand);
    
    
    
    }
    
    
    
    mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    
    <mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">
        
        
        <select id="selectByBrandLike" resultType="com.rainbowsea.mybatis.pojo.Car">
            select
                id,
                car_num as carNum,
                brand,
                guide_price as guidePrice,
                produce_time as produceTime,
                car_type as carType
            from t_car
            where brand like '%${brand}%'
        select>
    
    mapper>
    

    Java程序运行结果:

    在这里插入图片描述

    方案二: concat('%','${brand}','%')

    在这里插入图片描述

    
    mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    
    <mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">
        
        
        <select id="selectByBrandLike" resultType="com.rainbowsea.mybatis.pojo.Car">
            select
                id,
                car_num as carNum,
                brand,
                guide_price as guidePrice,
                produce_time as produceTime,
                car_type as carType
            from t_car
            where brand like concat('%','${brand}','%')
        select>
    mapper>
    

    在这里插入图片描述

    3.1.3.2 使用 #{ } 的方式

    方案三: count函数,这个是mysql数据库当中的一个函数,专门进行字符串拼接的 concat('%',#{brand},'%')

    在这里插入图片描述

    
    mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    
    <mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">
        
        
        <select id="selectByBrandLike" resultType="com.rainbowsea.mybatis.pojo.Car">
            select
                id,
                car_num as carNum,
                brand,
                guide_price as guidePrice,
                produce_time as produceTime,
                car_type as carType
            from t_car
            where brand like concat('%',#{brand},'%')
        select>
    mapper>
    

    在这里插入图片描述

    方案四: "%"#{brand}"%", 这种方式比较常用,也避免了SQL注入的问题。

    在这里插入图片描述

    
    mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    
    <mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">
        
        
        <select id="selectByBrandLike" resultType="com.rainbowsea.mybatis.pojo.Car">
            select
                id,
                car_num as carNum,
                brand,
                guide_price as guidePrice,
                produce_time as produceTime,
                car_type as carType
            from t_car
            where brand like "%"#{brand}"%"
        select>
    mapper>
    

    测试运行:

    在这里插入图片描述

    4. typeAliases 别名定义的使用

    我们来观察一下CarMapper.xml中的配置信息:

    在这里插入图片描述

    resultType 属性用来指定查询结果集的封装类型,这个名字太长,可以起别名吗?可以。

    mybatis-config.xml 文件中使用 typeAliases 标签来起别名,包括两种方式:

    4.1 typeAliases 的第一种方式:typeAlias

    在这里插入图片描述

        
        <typeAliases>
            <typeAlias type="com.rainbowsea.mybatis.pojo.Car" alias="Car">typeAlias>
            <typeAlias type="com.rainbowsea.mybatis.pojo.Log" alias="Log">typeAlias>
        typeAliases>
    
    
    configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        
        <typeAliases>
            <typeAlias type="com.rainbowsea.mybatis.pojo.Car" alias="Car">typeAlias>
            <typeAlias type="com.rainbowsea.mybatis.pojo.Log" alias="Log">typeAlias>
        typeAliases>
    
        <environments default="mybatis">
    
            <environment id="mybatis">
                
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                    <property name="username" value="root"/>
                    <property name="password" value="MySQL123"/>
                dataSource>
            environment>
        environments>
        <mappers>
            
            <mapper resource="CarMapper.xml">mapper>
            <mapper resource="LogMapper.xml">mapper>
        mappers>
    configuration>
    
    • 首先要注意typeAliases标签的放置位置,如果不清楚的话,可以看看错误提示信息。

    • typeAliases标签中的typeAlias可以写多个。

    • typeAlias:

      • type属性:指定给哪个类起别名
      • alias属性:别名。
        • alias属性不是必须的,如果缺省的话,type属性指定的类型名的简类名作为别名。
        • alias是大小写不敏感的。也就是说假设alias="Car",再用的时候,可以CAR,也可以car,也可以Car,都行、

    注意:接口,一定要为全限定类名(带有包名),不可以用别名机制

    测试:

    在这里插入图片描述

    在这里插入图片描述

    特别的: 省略 alias 属性之后,别名就是类的简名了,比如 :com.rainbowsea.mybatis.pojo.Car 的别名就是 Car/CAR/cAR,不区分大小写的。

    在这里插入图片描述

        
        
        <typeAliases>
            <typeAlias type="com.rainbowsea.mybatis.pojo.Car" >typeAlias>
            <typeAlias type="com.rainbowsea.mybatis.pojo.Log">typeAlias>
        typeAliases>
    
    

    4.2 typeAliases 的第二种方式:package

    如果一个包下的类太多,每个类都要起别名,会导致 typeAlias 标签配置较多,所以mybatis用提供package的配置方式,只需要指定包名,该包下的所有类都自动起别名,别名就是简类名。并且别名不区分大小写。

    注意:接口,一定要为全限定类名(带有包名),不可以用别名机制

    这种方式是最常用的。

    在这里插入图片描述

    
        <typeAliases>
            
            <package name="com.rainbowsea.mybatis.pojo"/>
        typeAliases>
    
    

    测试:

    在这里插入图片描述

    注意:

    使用 还可以将这个包下的所有的类的全部自动起别名,别名就是简名,不区分大小写

    ,所有的别名不区分大小写。但是:namespace 不能使用别名机制

    同时需要按照一定的顺序放置,放到指定的顺序当中去

    5. mappers 路径设置的使用

    SQL映射文件的配置方式包括四种:

    • resource:从类路径中加载
    • url:从指定的全限定资源路径中加载
    • class:使用映射器接口实现类的完全限定类名
    • package:将包内的映射器接口实现全部注册为映射器

    5.1 mapper 标签下的 resource 属性的使用

    这种方式是从类路径中加载配置文件,所以这种方式要求SQL映射文件必须放在resources目录下或其子目录下。

    <mappers>
      <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
      <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
      <mapper resource="org/mybatis/builder/PostMapper.xml"/>
    mappers>
    

    在这里插入图片描述

    5.2 mapper 标签下的 url 属性的使用

    这种方式是一种绝对路径的方式,这种方式不要求配置文件必须放到类的路径当中,哪里都行,只要提供了一个绝对路径就行,这种方式使用极少,因为移植性太差了(并不是所以的系统都有盘符的说法的)。

    在这里插入图片描述

    **需要注意的是:要三个\\\ ,才表示两个 \\ **

    <mappers>
      <mapper url="file:///var/mappers/AuthorMapper.xml"/>
      <mapper url="file:///var/mappers/BlogMapper.xml"/>
      <mapper url="file:///var/mappers/PostMapper.xml"/>
    mappers>
    

    5.3 mapper 标签下的 class 属性的使用

    Class: 这位置提供的是 mapper 接口的全限定接口名,必须带有包名(就是要一定要和对应接口的路径是一致的,一致的,一致的)

    如果使用这种方式必须满足以下条件:

    • SQL映射文件和mapper接口放在同一个目录下。
    • SQL映射文件的名字也必须和mapper接口名一致。
            <mapper class="com.rainbowsea.mybatis.mapper.CarMapper"><mapper>
            如果你class指定是:com.rainbowsea.mybatis.mapper.CarMapper
            那么mybatis框架会自动去com/rainbowsea/mybatis/mapper/CarMapper/的目录下找,注意是 / 
    注意:也就是说,如果你采用这种方式,那么你必须保证:CarMapper.xml文件和CarMapper接口必须在同一个目录下,并且名字也是一致的
    
    CarMapper接口——》CarMapper.xml
    LogMapper接口——> LogMapper.xml
    
    

    提醒:
    在IDEA的resources 目录下新建多重目录的话,必须是这样创建:
    com/rianbowsea/mybatis/mapper/
    不然是
    com.rianbowsea.mybatis.mapper 这是建包了

    在这里插入图片描述

    在这里插入图片描述

    保持一致的同时,名称也要是一致的

    在这里插入图片描述

        <mappers>
            
           <mapper class="com.rainbowsea.mybatis.mapper.CarMapper">mapper>
           <mapper class="com.rainbowsea.mybatis.mapper.LogMapper">mapper>
        mappers>
    

    测试运行:

    运行程序:正常!!!

    在这里插入图片描述

    5.4 package 标签的使用

    如果class较多,可以使用这种package的方式,但前提条件和上一种(mapper 标签下的class 属性的使用)方式一样。

    如果使用这种方式必须满足以下条件:

    • SQL映射文件和mapper接口放在同一个目录下。
    • SQL映射文件的名字也必须和mapper接口名一致。

    这种方式是最常用的。

        
        <package name="com.rainbowsea.mybatis.mapper">package>
    

    在这里插入图片描述

    运行测试:

    在这里插入图片描述

    6. 在 IDEA 中自定义配置文件模板

    mybatis-config.xml 和 SqlMapper.xml ,logback 文件可以在IDEA中提前创建好模板,以后通过模板创建配置文件。

    在这里插入图片描述

    在这里插入图片描述

    mybatis 核心配置文件的模板内容

    
    
    <configuration debug="false">
        
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%npattern>
            encoder>
        appender>
    
        
        <logger name="com.apache.ibatis" level="TRACE"/>
        <logger name="java.sql.Connection" level="DEBUG"/>
        <logger name="java.sql.Statement" level="DEBUG"/>
        <logger name="java.sql.PreparedStatement" level="DEBUG"/>
    
        
        <root level="DEBUG">
            <appender-ref ref="STDOUT"/>
            <appender-ref ref="FILE"/>
        root>
    
    configuration>
    

    logback 的日志配置模板内容

    
    
    <configuration debug="false">
        
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%npattern>
            encoder>
        appender>
    
        
        <logger name="com.apache.ibatis" level="TRACE"/>
        <logger name="java.sql.Connection" level="DEBUG"/>
        <logger name="java.sql.Statement" level="DEBUG"/>
        <logger name="java.sql.PreparedStatement" level="DEBUG"/>
    
        
        <root level="DEBUG">
            <appender-ref ref="STDOUT"/>
            <appender-ref ref="FILE"/>
        root>
    
    configuration>
    

    SqLMapper的配置模板内容:

    
    mapper
    		PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    		"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    
    <mapper namespace="">
    
    
    	
    mapper>
    

    7. 补充:插入数据时获取自动生成的主键的值

    **前提是:主键是自动生成的。 **

    业务背景:一个用户有多个角色。

    在这里插入图片描述

    插入一条新的记录之后,自动生成了主键,而这个主键需要在其他表中使用时。

    插入一个用户数据的同时需要给该用户分配角色:需要将生成的用户的id插入到角色表的user_id字段上。

    第一种方式:可以先插入用户数据,再写一条查询语句获取id,然后再插入user_id字段。【比较麻烦】

    第二种方式:mybatis提供了一种方式更加便捷。

    
    	<insert id="insertCarUserGeneratedKey" useGeneratedKeys="true" keyProperty="id" >
    		insert into t_car values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
    	insert>
    
    

    userGeneratedKeys = "true" 使用自动生成的主键值,false 则是不使用自动生成的主键值了
    keyProperty="id" 指定主键值赋值给POJO类(ORM映射)对象的哪个属性,这个就表示将主键值给Car对象的 id属性。
    注意:这个 keyProperty 指定的值,一定要和对应上的 pojo 对象类上的属性一致,不然,不行的。

    在这里插入图片描述

    在这里插入图片描述

    package com.rainbowsea.mybatis.mapper;
    
    import com.rainbowsea.mybatis.pojo.Car;
    
    import java.util.List;
    
    /**
     * 封装汽车相关信息的pojo类,普通的Java类
     */
    public interface CarMapper {
    
        /**
         * 插入 Car 信息,并且使用生成的主键值
         * @param car
         * @return
         */
        int insertCarUserGeneratedKey(Car car);
    
    }
    
    
    
    mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    
    <mapper namespace="com.rainbowsea.mybatis.mapper.CarMapper">
        
        <insert id="insertCarUserGeneratedKey" useGeneratedKeys="true" keyProperty="id">
            insert into t_car
            values (null, #{carNum}, #{brand}, #{guidePrice}, #{produceTime}, #{carType})
        insert>
    mapper>
    

    运行测试:

    在这里插入图片描述

    在这里插入图片描述

    8. 总结:

    1. { } 与 ${ } 的区别和使用

    - #{ } :先编译 SQL 语句,再对占位符传值,底层是 PrepareedStatement 实现,可以防止 SQL 注入,比较常用
    - ${ }:先进行SQL语句的拼接,然后再对SQL语句进行编译,底层是 Statement 实现,这种方式存在 SQL注入现象,SQL注入的风险,简单的说就是,直接将传入的值拼接为了SQL语句,然后再执行的)。只有在需要进行SQL语句关键字拼接的情况下才会用到。
    - 简单的说一个区别就是:#{} 传的值是带有 '' 单引号的,而 ${} 传的值是(直接就是值,没有单引号,或者是双引号,两个都没有)
    
    
    1. 什么情况下必须使用 $
    拼接表名
    批量删除
    模糊查询
    
    1. typeAliases 别名定义的使用,注意:接口,一定要为全限定类名(带有包名),不可以用别名机制 ,建议采用第二种 package 方式,,同时注意:typeAliases 的正确顺序和位置,可以参考报错信息,进行修正。
    
        <typeAliases>
            
            <package name="com.rainbowsea.mybatis.pojo"/>
        typeAliases>
    
    1. mappers 路径设置的使用 ,建议采用 package 标签的方式,注意条件,两个条件的一致性。
    - SQL映射文件和mapper接口放在同一个目录下。
    - SQL映射文件的名字也必须和mapper接口名一致。
    
    1. 在 IDEA 中自定义配置文件模板
    2. 插入数据时获取自动生成的主键的值,**前提是:在对应数据表中的主键是自动生成的(自增的方式才行)。 **
    
    	<insert id="insertCarUserGeneratedKey" useGeneratedKeys="true" keyProperty="id" >
    		insert into t_car values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
    	insert>
    
    

    9. 最后:

    “在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。”

    在这里插入图片描述

  • 相关阅读:
    【IDEA 使用easyAPI、easyYapi、Apifox helper等插件时,导出接口文档缺少代码字段注释的相关内容、校验规则的解决方法】
    Docker镜像使用教程
    jenkins2.289.1版本远程命令执行漏洞
    面试题:如何测试App性能?
    【逆向】在程序空白区添加Shellcode
    考研数学05-12年真题总结
    windows改键软件——sharpkeys
    大型 APP 的性能优化思路
    python 提取红楼梦第一章得到五言律诗和七言律诗(正则表达式)
    【C++初阶】类和对象——构造函数&&析构函数&&拷贝构造函数
  • 原文地址:https://www.cnblogs.com/TheMagicalRainbowSea/p/18227167