MyBatis-初识MyBatis并实现CRUD

MyBatis

一、MyBatis概述

1.1 JDBC的不足

  • 在我们以前使用的JDBC编程中,我们的sql语句都是直接写在java程序中的,如果我们后面要想进行修改,那么我们就要对java程序进行修改,这是不符合OCP原则的。
  • 给?传值非常的繁琐。
  • 将结果集封装成Java对象也非常的繁琐。

1.2 了解MyBatis

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。

持久层位于三层架构的数据访问层。

三层架构

ORM:对象关系映射

    • O(Object):Java虚拟机中的Java对象

    • R(Relational):关系型数据库

    • M(Mapping):将Java虚拟机中的Java对象映射到数据库表中一行记录,或是将数据库表中一行记录映射成Java虚拟机中的一个Java对象。

      ORM

MyBatis框架特点:

    • 支持定制化 SQL、存储过程、基本映射以及高级映射
    • 避免了几乎所有的 JDBC 代码中手动设置参数以及获取结果集
    • 支持XML开发,也支持注解式开发。【为了保证sql语句的灵活,所以mybatis大部分是采用XML方式开发。】
    • 将接口和 Java 的 POJOs(Plain Ordinary Java Object,简单普通的Java对象)映射成数据库中的记录
    • 体积小好学:两个jar包,两个XML配置文件。
    • 完全做到sql解耦合。
    • 提供了基本映射标签。
    • 提供了高级映射标签。
    • 提供了XML标签,支持动态SQL的编写。
  • MyBatis下载:

    • 从github上下载,地址:https://github.com/mybatis/mybatis-3image-20230318013856990

    image-20230318013931748

二、创建MyBatis程序

2.1 创建maven项目

image-20230321140412591

image-20230321140512444

image-20230321145336348

自行添加目录达到上面的效果,或者再开始不打勾,直接下一步。

解释:

  • Mapper:存放具体的业务接口
  • pojo:存放实体类
  • utils:存放封装好的工具类
  • resources:存放各种资源
    • 在resources下创建相同路径的Mapper【注意:不能直接写com.Mapper,而是com/Mapper】
  • test:存放测试类

2.2 配置pom.xml

【直接复制使用】

image-20230321140639087

在标签内部我们可以直接引入jar包,不在像以前一样自己去下载。

下面给出了单元测试驱动、mybatis驱动、mysql驱动、logback驱动

<?xml version="1.0" encoding="UTF-8"?>
<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.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>Mybatis-Test</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!--打包方法:jar和war,war是网页-->
    <packaging>jar</packaging>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
             
       <!--单元测试驱动-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
             
        <!--mybatis驱动-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.10</version>
        </dependency>
             
        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.37</version>
        </dependency>

        <!--logback驱动  日志-->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.11</version>
        </dependency>

             
    </dependencies>
</project>

解释:

  • junit
    • 单元测试,用于对某一部分的功能进行测试,不用我们从头开始运行。
  • logback
    • 日志,在控制台打印执行信息。

注意:如果我们刚写进去爆红,我们可以刷新一下,让它自动下载对应的依赖

image-20230321144118004

2.3 引入数据库配置资源

image-20230321142701286

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/数据库名
jdbc.username=账号
jdbc.password=密码

2.4 引入mybaits配置资源

【直接复制使用】

image-20230321142950386

注意1:mybatis核心配置文件的文件名不一定是mybatis-config.xml,可以是其它名字。

注意2:mybatis核心配置文件存放的位置也可以随意。这里选择放在resources根下,相当于放到了类的根路径下。

<?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>

<!-- 填写数据库配置路径-->
 <properties resource="jdbc.properties"/>

 <typeAliases>
    <!--别名机制,后面会讲解-->
    <!-- 填写pojo路径-->
     <package name=""/>
 </typeAliases>

 <environments default="development">
     <environment id="development">
         <transactionManager type="JDBC"/>
         <dataSource type="POOLED">
             <property name="driver" value="${jdbc.driver}"/>
             <property name="url" value="${jdbc.url}"/>
             <property name="username" value="${jdbc.username}"/>
             <property name="password" value="${jdbc.password}"/>
         </dataSource>
     </environment>
 </environments>

 <mappers>
     <!--填写Mapper路径-->
  <package name=""/>
 </mappers>

</configuration>

2.5 引入logback配置文件

【直接复制使用】

image-20230321150221703

<?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>[%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </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>

三、增删查改(CRUD)

3.1 准备过程

准备数据库,添加部分数据

CREATE TABLE t_car (
id bigint(20) NOT NULL AUTO_INCREMENT,
car_num varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT ‘汽车编号’,
brand varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT ‘品牌’,
guide_price decimal(10,0) DEFAULT NULL COMMENT ‘指导价’,
produce_time char(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT ‘生产日期’,
car_type varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT ‘汽车类型’,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

项目整体结构:

image-20230321151020450

创建Car实体类

package com.pojo;

public class Car {
    // 数据库表当中的字段应该和pojo类的属性一一对应。
    // 建议使用包装类,这样可以防止null的问题。
    private Long id;
    private String carNum;
    private String brand;
    private Double guidePrice;
    private String produceTime;
    private String carType;

    @Override
    public String toString() {
        return "Car{" +
                "id=" + id +
                ", carNum='" + carNum + '\'' +
                ", brand='" + brand + '\'' +
                ", guidePrice=" + guidePrice +
                ", produceTime='" + produceTime + '\'' +
                ", carType='" + 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 carType) {
        this.carType = carType;
    }

    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;
    }

    public Car() {
    }
}

创建CarMapper接口

这里面都是一些CRUD的抽象方法

package com.Mapper;
import com.pojo.Car;
import java.util.List;

public interface CarMapper {

}

引入SqlSession工具类(包含事务处理)

package com.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;

public class SqlSessionUtil {
    private static SqlSessionFactory sqlSessionFactory;

    /**
     * 类加载时初始化sqlSessionFactory对象
     */
    static {
        try {
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static ThreadLocal<SqlSession> local = new ThreadLocal<>();

    /**
     * 每调用一次openSession()可获取一个新的会话,该会话支持自动提交。
     *
     * @return 新的会话对象
     */
    public static SqlSession openSession() {
        SqlSession sqlSession = local.get();
        if (sqlSession == null) {
            sqlSession = sqlSessionFactory.openSession();
            local.set(sqlSession);
        }
        return sqlSession;
    }

    /**
     * 关闭SqlSession对象
     * @param sqlSession
     */
    public static void close(SqlSession sqlSession){
        if (sqlSession != null) {
            sqlSession.close();
        }
        local.remove();
    }
}

MyBatis核心对象的作用域

SqlSessionFactoryBuilder

这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。

SqlSessionFactory

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”。因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。

SqlSession

每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。

//自动关闭资源,不需要我们自己去写close方法
try (SqlSession session = sqlSessionFactory.openSession()) {
  // 应用逻辑代码
}

创建CarMapper映射文件

以后所有的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填写CarMapper的全限定名称-->
<mapper namespace="com.Mapper.CarMapper">
  
</mapper>

修改mybaits配置资源(mybatis-config.xml)

修改pojo路径
image-20230328141759808
修改Mapper路径
image-20230328141845579

3.2 增加数据

CarMapper接口int insert(Car car);
CarMapper.xmlimage-20230328142551303
   
<!--#{名字},是占位符,如果你传入的是pojo类,#{里面要写属性名}-->

<!-- id要写接口中对应的方法名 -->
<!-- useGeneratedKeys 设置添加操作是否需要回填生成的主键,可以不写 -->
<!-- keyProperty 设置回填的主键值赋值到参数对象的哪个属性,可以不写 -->
<!-- 这两个的参数作用在mybatis技巧中的插入数据获取主键具体讲解 -->
<insert id="insert" keyProperty="id" useGeneratedKeys="true">
        insert into t_car
            (id, car_num, brand, guide_price, produce_time, car_type)
        values (#{id}, #{carNum}, #{brand}, #{guidePrice}, #{produceTime}, #{carType});
</insert>

测试(在接口中alt+insert,添加测试,选中要测试的方法,就会生成测试类)

    @Test
    public void insert() {
        SqlSession sqlSession = SqlSessionUtil.openSqlSession();
        CarMapper carMapper = sqlSession.getMapper(CarMapper.class);
        Car car = new Car(null, "56665", "大众", 20000.00, "2022-12-12", "汽油车");
        int count = carMapper.insert(car);
        sqlSession.commit();
        sqlSession.close();
        if (count == 1) {
            System.out.println("插入成功");
        } else {
            System.out.println("插入失败");
        }
    }

运行结果:

image-20230328143739976

image-20230328143801810

3.3 删除数据

CarMapper接口int deleteById(Long id);
CarMapper.xmlimage-20230328144224659
<!--#{名字},是占位符,这里只有一个参数,可以随便写,但是最好是都写出pojo类的属性名-->

<!--id要写接口中对应的方法名--> 
<delete id="deleteById">
        delete
        from t_car
        where id = #{id};
</delete>

测试

    @Test
    public void deleteById() {
        SqlSession sqlSession = SqlSessionUtil.openSqlSession();
        CarMapper carMapper = sqlSession.getMapper(CarMapper.class);
        int count = carMapper.deleteById(29L);
        sqlSession.commit();
        sqlSession.close();
        if (count == 1) {
            System.out.println("删除成功");
        } else {
            System.out.println("删除失败");
        }
    }

运行结果

image-20230328145803105

3.4 修改数据

CarMapper接口int update(Car car);
CarMapper.xmlimage-20230328150329048

<!--id规则和#{}规则同前面一样-->
<update id="update">
    update t_car
    set car_num      = #{carNum},
        brand        = #{brand},
        guide_price  = #{guidePrice},
        produce_time = #{produceTime},
        car_type     = #{carType}
    where id = #{id};
</update>

测试

@Test
public void update() {
    SqlSession sqlSession = SqlSessionUtil.openSqlSession();
    CarMapper carMapper = sqlSession.getMapper(CarMapper.class);
    Car car = new Car(30L, "56665", "宝马", 20000.00, "2022-12-12", "电车");
    int count = carMapper.update(car);
    sqlSession.commit();
    sqlSession.close();
    if (count == 1) {
        System.out.println("修改成功");
    } else {
        System.out.println("修改失败");
    }
}

运行结果前后对比

image-20230328150527795

image-20230328150547148

3.5 查询数据

此处展示查询返回pojo类型的单条数据和所有数据的所有方法

查询返回Map、List、Map<String,Map>、总记录条数,放在后面的查询专题

根据id查询单条数据
CarMapper接口Car selectById(Long id);
CarMapper.xmlimage-20230328150853852

resultType

1)resultType填写select出来的结果要转成什么pojo类的全限定名称

2)在mybatis-config.xml配置别名机制之后,resultType就可以直接写pojo类名,并且不区分大小写,Car和car效果一样

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

由于数据库中的字段名和pojo类的属性名不同,查询出来的结果无法转换成pojo类,导致结果中部分属性全为null

解决办法:

1)使用as把字段名转成属性名

<select id="selectById" resultType="Car">
    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>

2)使用resultMap进行结果映射

<!--map结果映射-->
<resultMap id="carResultMap" type="Car">
    <!--如果有主键,加一个id-->
    <!--property对应属性名,column对应数据库字段名-->
    <id property="id" column="id"/>
    <result property="carNum" column="car_num"/>
    <result property="brand" column="brand"/>
    <result property="guidePrice" column="guide_price"/>
    <result property="produceTime" column="produce_time"/>
    <result property="carType" column="car_type"/>
</resultMap>
   <!--此处的resultMap填写resultMap的id-->
<select id="selectById" resultMap="carResultMap">
    select *
    from t_car
    where id = #{id}
</select>

3)开启驼峰命名自动映射

mybatis-config.xml



条件:pojo中的属性满足小写字母开头,后面每个单词首字母大写;数据库中的字段全小写,并且单词与单词之间使用_

<select id="selectById" resultType="Car">
    select *
    from t_car
    where id = #{id};
</select>

测试

    @Test
    public void selectById() {
        SqlSession sqlSession = SqlSessionUtil.openSqlSession();
        CarMapper carMapper = sqlSession.getMapper(CarMapper.class);
        Car car = carMapper.selectById(30L);
        sqlSession.close();
        System.out.println(car);
    }

运行结果:image-20230328153914045

查询所有数据(使用结果集自动映射)
CarMapper接口List selectAll();
CarMapper.xmlimage-20230404151206411
    <select id="selectAll" resultType="car">
        select *
        from t_car
    </select>

测试

    @Test
    public void selectAll() {
        SqlSession sqlSession = SqlSessionUtil.openSqlSession();
        CarMapper carMapper = sqlSession.getMapper(CarMapper.class);
        List<Car> cars = carMapper.selectAll();
        cars.forEach((car)->{
            System.out.println(car);
        });
        sqlSession.close();
    }

运行结果:image-20230404151341492

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值