• 【零基础入门MyBatis系列】第三篇——使用MyBatis完成CRUD


    一、背景

    1、什么是CRUD?

    • 通常我们用CRUD代表增删改查四种操作。
    • C:Create、R:Relative、U:Update、D:Delete

    2、在本篇内容学习之前,需要一些准备工作:

    • 创建一个新的模块【利用Maven构建的普通Java模块】
    • 修改 pom.xml 中的一些配置信息
      • 添加一条语句,将打包方式定义为 jar 包 【因为我们当前不需要在web服务器上运行我们的项目】
      • 添加 mybatis、mysql驱动、junit、logback的依赖
    	<!--打了一个jar包-->
        <packaging>jar</packaging>
        <dependencies>
            <!--mybatis核心依赖-->
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.5.11</version>
                <scope>import</scope>
            </dependency>
    
            <!--mysql驱动依赖-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.30</version>
                <scope>import</scope>
            </dependency>
    
            <!--添加junit依赖-->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.13.2</version>
                <scope>test</scope>
            </dependency>
            
            <!--导入日志文件的依赖-->
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-classic</artifactId>
                <version>1.2.11</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • mybatis-config.xml、logback.xml 文件 放到根路径下

    (1) 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>
    	<!--日志配置-->
        <settings>
            <setting name="logImpl" value="SLF4J"/>
        </settings>
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                    <!--配置自己的数据库端口号和数据库-->
                    <property name="url" value="jdbc:mysql://localhost:3306/powernode"/>
                    <!--配置自己的数据库用户名和密码-->
                    <property name="username" value="root"/>
                    <property name="password" value="111111"/>
                </dataSource>
            </environment>
        </environments>
        <mappers>
            <!--sql映射文件创建好之后,需要将该文件路径配置到这里[对应的Mapper文件]-->
            <mapper resource="CarMapper.xml"/>
        </mappers>
    </configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    (2) logback.xml 文件的配置信息如下

    <?xml version="1.0" encoding="UTF-8"?>
    
    <configuration debug="false">
        <!-- 控制台输出 -->
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            </encoder>
        </appender>
        <!-- 按照每天生成日志文件 -->
        <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!--日志文件输出的文件名-->
                <FileNamePattern>${LOG_HOME}/TestWeb.log.%d{yyyy-MM-dd}.log</FileNamePattern>
                <!--日志文件保留天数-->
                <MaxHistory>30</MaxHistory>
            </rollingPolicy>
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            </encoder>
            <!--日志文件最大的大小-->
            <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
                <MaxFileSize>100MB</MaxFileSize>
            </triggeringPolicy>
        </appender>
    
        <!--mybatis log configure-->
        <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"/>
    
        <!-- 日志输出级别,logback日志级别包括五个:TRACE < DEBUG < INFO < WARN < ERROR -->
        <root level="DEBUG">
            <appender-ref ref="STDOUT"/>
            <appender-ref ref="FILE"/>
        </root>
    
    </configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 提供com.powernode.mybatis.utils.SqlSessionUtil工具类【方便创建会话】
    package com.powernode.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;
    
    /**
     * @author Bonbons
     * @version 1.0
     */
    public class SqlSessionUtil {
        private SqlSessionUtil(){}
    
        //定义一个SqlSession
        private static final SqlSessionFactory sqlSessionFactory;
        //在类加载的时候初始化SqlSessionFactory
        static {
            try {
            	//此处自己的 mybatis-config.xml 文件位置要配置正确
                sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        //通过一个公有的方法为外部提供会话的对象
        public static SqlSession openSession(){
            return sqlSessionFactory.openSession(true);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 最后一步就是创建测试用例

    二、Insert【添加数据】

    1、前情回顾:

    • 之前我们的 CarMapper.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先随便写-->
    <mapper namespace="car">
        <insert id="insertCar">
            insert into t_car(car_num,brand,guide_price,produce_time,car_type) values('103', '奔驰E300L', 50.3, '2022-01-01', '燃油车')
        </insert>
    </mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    插入数据的语句是固定的,如果想插入不同的数据,只能在这块自己调整参数 >> 很不方便

    2、改进方法1:

    (1)在MyBatis中可以将数据放到Map集合中,在使用Java程序处理业务时,将Map对象作为参数传递进来。
    (2)在sql语句中使用 #{map集合的key} 来完成传值,其中的 #{} 就是占位符
    (3)给出改进后的 CarMapper.xml 中的配置信息【可以看出此时占位符中的参数已经替换为Map实例的key】

    <?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先随意写一个-->
    <mapper namespace="com.powernode.CarMapperTest">
        <!--insert sql:保存一个汽车信息-->
        <insert id="insertCar">
        	insert into t_car (id,car_num,brand,guide_price,produce_time,car_type) values (null,#{car_num},#{brand},#{guide_price},#{produce_time},#{car_type})
    	</insert>
    </mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    (4)再看一下测试用例中的代码:

    @Test
    public void testInsertCar(){
        //利用工具类创建会话
        SqlSession session = SqlSessionUtil.openSession();
        //创建一个Map存储我们要传递的信息
        Map<String, Object> map = new HashMap<String, Object>();
    	// id,car_num,brand,guide_price,produce_time,car_type
    	// 对于key的选取应该见名知意
        map.put("car_num", 3);
        map.put("brand", "奥迪");
        map.put("guide_price", 50.0);
        map.put("produce_time", "2022-10-18");
        map.put("car_type", "燃油车");
        //调用我们的添加方法
        session.insert("insertCar", map);
        //提交事务
        session.commit();
        session.close();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    (5)运行后可以刷新 Navicat 查看结果
    在这里插入图片描述
    3、改进方法2:
    (1)设置一个普通的Java类,类的属性对应数据库中的字段,为外部提供GetSet方法【该系列将这种普通Java类称之为pojo

    (2)创建一个 com.powernode.pojo.Car 类,用于封装数据

    package com.powernode.mybatis.pojo;
    
    /**
     * @author Bonbons
     * @version 1.0
     */
    public class Car {
        // id,car_num,brand,guide_price,produce_time,car_type
        // 使用包装类,出现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;
        }
        //提供get和set方法
    
        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 carType) {
            this.carType = carType;
        }
        //重写toString方法
    
        @Override
        public String toString() {
            return "Car{" +
                    "id=" + id +
                    ", carNum='" + carNum + '\'' +
                    ", brand='" + brand + '\'' +
                    ", guidePrice=" + guidePrice +
                    ", produceTime='" + produceTime + '\'' +
                    ", carType='" + carType + '\'' +
                    '}';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90

    (2)要修改 CarMapper.xml 文件,更改 insert 方法中占位符中的内容

    • 这里面需要注意一个问题,占位符中的内容并不一定是Car类中的参数,它这个对应机制是这样的:

    #{parameter} --> getParemeter() 【也就是说会去Car类中寻找这个get方法来获取参数】

    <?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先随意写一个-->
    <mapper namespace="com.powernode.CarMapperTest">
        <!--insert sql:保存一个汽车信息-->
        <insert id="insertCar">
            insert into t_car (id,car_num,brand,guide_price,produce_time,car_type) values (null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
    	</insert>
    </mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    (3)原来的测试类中添加相关的的测试方法

    @Test
    public void testInsertCarByPOJO(){
        SqlSession session = SqlSessionUtil.openSession();
        //封装数据
        Car car = new Car(null, "4", "托马斯", 200.0, "2022-11-11","煤油车");
        //事务处理
        session.insert("insertCar", car);
        //提交事务
        session.commit();
        session.close();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    4、总结

    • 如果采用map集合传参,#{} 里写的是map集合的key,如果key不存在不会报错,数据库表中会插入NULL
    • 如果采用POJO传参,#{} 里写的是get方法的方法名去掉get之后将剩下的单词首字母变小写【getAge对应的是 #{age}

    三、delete 和 update【删除、更新数据】

    • 此处我们只涉及简单的删除和更新操作,重点在于了解基本语法
    • 我们根据 id 来完成数据的删除和更新
    • 此部分给出在 CarMapper.xml 中的配置信息以及测试类中的对应测试方法

    1、通过指定 id 删除数据
    (1)在CarMapper.xml 中的配置信息如下【为了看起来更简洁,只给出对应的SQL语句】

    • 有一件值得注意的事情:当只存在一个占位符时,可以自动识别,参数名不匹配也没有问题
    <!--根据id删除数据-->
    <delete id="deleteById">
        delete from t_car where id = #{id}
    </delete>
    
    • 1
    • 2
    • 3
    • 4

    它的外部代码是这样的

    <?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="balabala">
    <!--在这部分写我们的SQL语句-->
    </mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    (2)测试方法如下【也是只给出了完整方法,没去写类名】

    @Test
    public void testDeleteCarById(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        // count会记录操作实际影响数据库表中数据的条数
        int count = sqlSession.delete("deleteById", 15);
        //通过变量名.sout 可以快速生成输出指定变量的语句[在IDEA中]
        System.out.println(count);
        sqlSession.commit();
        sqlSession.close();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    (3)成功运行,删除了原来 id = 15 的数据
    在这里插入图片描述
    2、通过指定 id 更新数据
    (1)在CarMapper.xml 中的配置信息如下

    <!--根据id修改数据-->
    <update id="updateById">
        update t_car set car_num = #{carNum}, brand = #{brand}, guide_price = #{guidePrice}, produce_time = #{produceTime},car_type = #{carType} where id = #{id}
    </update>
    
    • 1
    • 2
    • 3
    • 4

    (2)测试方法如下

    @Test
    public void testUpdateCarById(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        Car car = new Car(17L, "1111", "奔驰大G", 200.0, "2020-01-01", "汽油越野车");
        int count = sqlSession.update("updateById", car);
        System.out.println(count);
        sqlSession.commit();
        sqlSession.close();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    (3)成功运行,修改了原来 id = 17 的数据
    在这里插入图片描述


    四、Select【查询数据】

    • 查询语句的重点在于:对于查询结果集的处理以及类属性名与数据库字段名的对应
    • 此处分别以查询一条数据和查询全部数据为例,来说明MyBatis中是如何完成数据查询的

    1、 根据 id 查询一条数据:

    (1)CarMapper中的配置信息

    <select id="selectById" resultType="com.powernode.mybatis.pojo.Car">
        <!--select * from t_car where id = #{id}-->
        select id, car_num as carNum, brand, guide_price as guidePrice, produce_time as produceTime, car_type as carType from t_car where id = #{id}
    </select>
    
    • 1
    • 2
    • 3
    • 4

    细心的盆友不难发现,查询语句与其他数据操作SQL语句不同:

    第一,多了resultType;第二为查询的字段设置了别名

    • 使用 resultType 是为了告诉 MyBatis 我们查询结果集是一个什么类型的数据【使用的是全限定类名(类的完整地址)】
    • 设置别名,是因为如果类属性与数据库表中字段对应不上,就无法正确传递参数值

    (2)测试方法

    @Test
    public void testSelectById(){
    	SqlSession sqlSession = SqlSessionUtil.openSession();
    	//用Car的实例接收返回值
    	Car car = sqlSession.selectOne("selectById",1);
    	//打印查询结果[之所以此处可以输出属性和值,是因为在Car类中重写了toString方法]
    	System.out.println(car);
    	//查询语句不需要提交事务
    	sqlSession.close();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    2、查询全部的数据

    • 与前者的区别在于:查询时不需要设置条件、返回的是一个结果的集合

    (1)CarMapper中的配置信息

    <!--查询数据库表中全部数据-->
    <select id="selectAll" resultType="com.powernode.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
    </select>
    
    • 1
    • 2
    • 3
    • 4

    (2)测试方法

    @Test
    public void testSelectAll(){
    	SqlSession sqlSession = SqlSessionUtil.openSession();
    	List<Car> cars = sqlSession.selectList("selectAll");
    	//使用Lamda表达式+forEach输出
    	cars.forEach(car -> System.out.println(car));
    	sqlSession.close();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述
    3、namespace 用法说明

    • 当出现两个 XxxMapper.xml 文件中出现同IDSQL语句时,可能会出现问题
    • 我们可以通过 namespace.SQL语句id 来指定使用哪个Mapper中的 SQL 方法
    • 简言之,命名空间 >> 防止 id 冲突
    • PS:如果设置了多个Mapper.xml 文件,要记得添加到核心配置文件中
  • 相关阅读:
    ActivitiListener
    164. 最大间距
    MySQL表的增查(进阶)
    SpringMvc--文件上传下载
    【免费Web系列】大家好 ,今天是Web课程的第十八天点赞收藏关注,持续更新作品 !
    CPU、MPU、MCU、SOC的理解
    创新前沿:Web3如何颠覆传统计算机模式
    迭代器设计模式
    C++实现Wlan自动连接(wpa2 enterprise)
    Java调用OpenDDS(3)-自己编写调用OpenDDS的程序
  • 原文地址:https://blog.csdn.net/qq_61323055/article/details/127571174