【MyBatis】初识MyBatis 构建简单框架

目录

  • MyBatis
    • 前言
    • 搭建一个简单的MyBatis
      • 创建Maven项目
      • 引入必要依赖
      • 创建数据表结构
      • 创建User实体类
      • 创建Mapper接口
        • Mapper层
        • Dao层
      • 创建MyBatis的Mapper映射文件
      • 编写测试类
        • 传统测试类
        • JUnit测试

MyBatis

介绍:MyBatis是一款半自动的ORM持久层框架,具有较高的SQL灵活性,支持高级映射(一对一,一对多),动态SQL,延迟加载和缓存等特性,但它的数据库无关性较低

前言

我们先来看几个名词:

  1. ORM

    Object Relation Mapping,对象关系映射。对象指的是Java对象,关系指的是数据库中的关系模型,对象关系映射,指的就是在Java对象和数据库的关系模型之间建立一种对应关系,比如用一个Java的User类,去对应数据库中的一张user表,类中的属性和表中的列一一对应。User类就对应user表,一个User对象就对应user表中的一行数据。

  2. 持久层

    持久层指的是:将业务数据存储到磁盘,也具备长期存储能力,只要磁盘不损坏,如果在断电情况下,重启系统仍然可以读取数据。
    持久是相对于瞬时来说的,其实就是可以把数据固化在硬盘或者磁带一类可以保存很长时间的设备上,不像放在内存中一样断电就消失了。

  3. 为什么是半自动?

    MyBatis开发过程中,需要我们手动去编写SQL语句,所以称为半自动框架。而对于全自动框架,例如HIbernate,只需要定义好ORM关系,就可以直接进行CRUD操作(增删改查等等)。

由于MyBatis需要手写SQL语句,所以它有较高的灵活性,可以根据需要,自由地对SQL进行定制,也因为要手写SQL,当要切换数据库时,SQL语句可能就要重写,因为不同的数据库有不同的方言(Dialect),所以MyBatis的数据库无关性低。但是同时MyBatis 封装了 JDBC 的复杂操作,通过 XML 或注解配置 SQL 映射,简化了数据库访问代码,提高了开发效率和可维护性。它支持动态 SQL,提供了缓存机制和事务管理功能,能够更好地处理复杂业务逻辑,适用于大型项目和频繁修改 SQL 语句的场景。

搭建一个简单的MyBatis

这里简单介绍一下我用到的工具:

  • IDE:IntelliJ IDEA 2024.2.3

  • 项目构建:Maven3.9.8

  • 数据库:MySQL8.4.2

    这里提一下不同版本MySQL注意事项:

    1. 驱动类:驱动类driver-class-name (这个可以在添加依赖之后的依赖包中找到具体位置)

      MySQL 5版本使用jdbc5驱动,驱动类使用:com.mysql.jdbc.Driver

      MySQL 8版本使用jdbc8驱动,驱动类使用:com.mysql.cj.jdbc.Driver

    2. 连接地址url

      MySQL 5版本的url: jdbc:mysql://localhost:3306/ssm

      MySQL 8版本的url: jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC

创建Maven项目

这里不再过多介绍创建步骤,具体步骤可以看这篇博客:【Maven】一篇带你了解Maven项目管理工具-CSDN博客,打包方式我们直接选择jar即可:

在这里插入图片描述

引入必要依赖

引入我们的MyBatis核心、JUnit测试工具、MySQL驱动,可以在中央仓库中搜索MyBatis,选择对应版本并赋值对应代码即可:

在这里插入图片描述

如果你用的工具版本和我一样,可以直接复制下面这段代码到你pom.xml文件中:

<!-- 引入依赖 -->
    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.mysql/mysql-connector-j -->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>8.4.0</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

然后通过Maven重构你的项目

创建数据表结构

直接在你的NaviCat或者其他数据库管理工具中执行以下查询,或者你自己写一段查询语句创建一个差不多的表格:

CREATE DATABASE myfirstbatis;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(20) DEFAULT NULL COMMENT '用户名',
  `password` varchar(20) DEFAULT NULL COMMENT '密码',
  `age` int(11) DEFAULT NULL COMMENT '年龄',
  `sex` varchar(1) DEFAULT NULL COMMENT '性别',
  `email` varchar(50) DEFAULT NULL COMMENT '邮箱',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

# 随便加几条数据进去
insert into `user`(`id`,`username`,`password`,`age`,`sex`,`email`) values (1,'zhangsan','19732846','20','男','xxx@qq.com'),(2,'lisi','123456','23','男','xxx@gmail.com'),(3,'wangwu','123789','55','女','xxx@163.com'),(4,'zhaoliu','123456','30','女','xxx@gmail.com');

创建User实体类

上面我们创建的表名为user,如果我们想使用MyBatis对项目进行操作,需要一个对应的实体类User,这个实体类我将它放在项目的entities路径下:

在这里插入图片描述

你的表格中有几列就添加几条属性,属性名和列名对应,别照抄我的,然后添加对应的构造方法和Getter()、Setter()方法以及重写toString()方法:

public class User {
    private Integer id;
    private String username;
    private String password;
    private Integer age;
    private String sex;
    private String email;

    /**
     * 提供一个带参构造方法,同时提供一个无参构造方法
     * 提供Getter()和Setter()
     * 提供toString()
     */

    public User(Integer id, String username, String password, Integer age, String sex, String email) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.age = age;
        this.sex = sex;
        this.email = email;
    }

    public User() {
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                ", email='" + email + '\'' +
                '}';
    }
}

创建Mapper接口

Mapper 层和 DAO(Data Access Object)层是在持久层中用于处理数据访问的两个概念。虽然这两者的目的都是用于访问数据库,但它们之间有一些区别。在Java开发中,这两个概念通常与MyBatis(或其他ORM框架)结合使用。简单说一下这两个的区别:

Mapper层
  1. 定义:Mapper 是 MyBatis 中的一个术语,指的是用于描述如何映射数据库中的数据到 Java 对象的接口。每一个 Mapper 接口对应一个数据操作接口。
  2. 职责
    • 定义了数据访问的接口,提供了一组数据库操作的方法。
    • 包含了与具体数据访问有关的 SQL 语句和映射规则。
  3. 使用方法:通常使用 MyBatis 的注解或 XML 文件来描述 SQL 映射。
Dao层
  1. 定义:DAO(Data Access Object)是一个更通用的设计模式,用于封装与数据存储交互的逻辑。在Java中,通常指的是数据访问对象。
  2. 职责
    • 提供了一个抽象接口,定义了数据访问的方法。
    • 包含了数据访问的具体实现,可以是直接对数据库进行操作,也可以通过调用其他服务、API等方式进行数据访问。
  3. 使用方法:通常不涉及注解,而是通过实现接口的方式来定义数据访问方法。
// DAO 接口
public interface UserDao {
    User getUserById(int id);
    void insertUser(User user);
}
 
// DAO 实现
public class UserDaoImpl implements UserDao {
    // 数据库操作的具体实现
}

这里我们既然使用了MyBatis框架,就直接使用Mapper接口来映射数据库中的数据

public interface UserMapper { // Mapper不需要实现类
    /**
     * 添加用户信息
     * @return Integer
     */
    Integer insertUser();
}

创建MyBatis的Mapper映射文件

上面我们提到Mapper可以通过注解或者是XML 文件来描述 SQL 映射,所以我们需要这样一个XML文件去实现我们接口中的方法,但是要注意:映射文件在resources文件夹的路径要和Mapper接口的路径一致,比如这里我的Mapper接口在com/qcby/mybatis/mappers,这个路径下,那么我的XML文件就需要在:resources文件夹的com/qcby/mybatis/mappers路径下,保持一致

在这里插入图片描述

然后Mapper.xml文件里面也要保持两个一致:

  1. Mapper接口中的全类名和映射文件的命名空间(namespace)保持一致
  2. Mapper接口中的方法名和映射文件中编写SQL的标签的id属性保持一致

在这里插入图片描述

<?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中的全类名保持一致 -->
<mapper namespace="com.qcby.mybatis.mappers.UserMapper">
    <!-- mapper接口中的方法名和映射文件中编写sql的标签的id属性保持一致 -->
    <insert id="insertUser">
        insert into user values (null, 'Ray', '928322', 23, '男', 'Ray@qq.com')
    </insert>
</mapper>

编写测试类

上面的架构搭好之后,我们来进行功能测试:

传统测试类

传统测试功能一般在main()方法中实现,有以下的步骤:

  1. 获取核心配置文件
  2. 获取SqlSessionFactoryBuilder对象
  3. 获取SqlSessionFactory对象
  4. 获取SqlSession对象
  5. 获取代理实现类对象
  6. 调用方法,实现对应功能
  7. 关闭流

我们来看看具体实现代码:

public class mybatisTest {
    // 传统的测试方法:
    public static void main(String[] args) throws IOException {
        // 1. 获取核心配置文件
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        // 2. 获取SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        // 3. 获取SqlSessionFactory对象
         SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
        // 4. 获取SqlSession对象(不会自动提交事务)
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 5. 获取代理实现类对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        // 6. 调用方法实现添加功能
        Integer num = userMapper.insertUser();
        if (num > 0) {
            System.out.println("插入成功!!");
        } else {
            System.out.println("插入失败!!");
        }
        sqlSession.close();
        inputStream.close();
    }
}

但是我们执行之后会发现,虽然提示插入成功,但是数据库中其实并没有添加们前面设定好的数据——(null, 'Ray', '928322', 23, '男', 'Ray@qq.com'),如下图:

在这里插入图片描述

在这里插入图片描述

数据库中并没有更新

这是因为数据库在获取到添加或者是更新这种命令的时候需要确认事务是否提交,这里我们并没有提交事务,所以数据库自动回滚到插入之前的状态,也就是不作出改变。下面介绍三种事务提交的方式:

  1. 在执行插入方法之后手动提交事务

    sqlSession.commit(); 提交事务
    

在这里插入图片描述

  1. 自动提交事务

    SqlSession sqlSession = sqlSessionFactory.openSession(true); 
    

    我们在创建SqlSession对象的时候添加参数true,可以实现事务的自动提交

  2. 传统方法提交事务(最不常用)

    我们用命名空间+id的方式来实现接口中的方法,同样需要手动提交事务

    int num = sqlSession.insert("com.qcby.mybatis.mappers.UserMapper.insertUser");
    sqlSession.commit(); 提交事务
    

提交事务之后,我们就可以正常的插入数据了,

在这里插入图片描述

但是我们发现新插入的数据id并不是连续的,这是因为虽然数据库虽然回滚到插入之前的状态,但是id已经自增了一个,下次插入就会继续自增,导致了不连续。

JUnit测试

我们可以发现传统测试类我们如果想测试一个新方法就需要重新创建各种对象,执行很多重复的步骤来实现测试功能,那么我们使用JUnit测试,来简化这一过程。

首先我们将重复的步骤都写在一个公共类——SqlSessionUtil中,如:SqlSession对象的创建过程以及执行完测试之后的销毁过程:

public class SqlSessionUtil {
    private static InputStream inputStream = null;
    public static SqlSession getSqlSession() {
        SqlSession sqlSession = null;
        try {
            // 1. 获取核心配置文件
            inputStream = Resources.getResourceAsStream("mybatis-config.xml");
            // 2. 获取SqlSessionFactoryBuilder对象
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            // 3. 获取SqlSessionFactory对象
            SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
            // 4. 获取SqlSession对象
            sqlSession = sqlSessionFactory.openSession(true);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return sqlSession;
    }

    // 关闭输入流
    public static void closeInputStream() {
        try {
            inputStream.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

这样我们只需要在测试类中通过这个公共类初始化我们的SqlSession对象,然后重复使用这个对象就可以了。JUnit为我们提供了这个功能,我们使用注解来实现:初始化、测试、销毁等功能,下面我结合代码简单介绍一下三种常用的JUnit注解:

  1. @Before:在@Before注解下的代码块会自动在执行其他代码块的时候执行,通常用于初始化操作,比如我们就可以通过此注解实现我们的SqlSession对象的创建:

        @Before
        public void init(){
            // 通过公共类获取SqlSession对象
            sqlSession = SqlSessionUtil.getSqlSession();
            // 5. 获取代理实现类对象
            userMapper = sqlSession.getMapper(UserMapper.class);
        }
    
  2. @After:这个也好理解,此注解下的代码会在其他代码块执行完毕之后自动执行,通常用于销毁操作,比如关闭各种输入输出流:

        @After
        public void destroy(){
            sqlSession.close();
            SqlSessionUtil.closeInputStream();
        }
    
  3. @Test@Test注解算是我们JUnit测试的核心注解,他可以让我们的代码块摆脱main()方法执行,我们只需要定义方法执行逻辑,然后就可以直接运行,执行测试功能:

        @Test
        public void userInsertTest() throws IOException {
            // 6. 调用方法实现添加功能
            Integer num = userMapper.insertUser();
            if (num > 0) {
                System.out.println("插入成功!!");
            } else {
                System.out.println("插入失败!!");
            }
        }
    

至此我们就搭建好了一个简单的MyBatis框架,用于各种功能的测试

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/896924.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux下ClamAV源代码安装与使用说明

Linux下ClamAV源代码安装与使用说明 ClamAV(Clam AntiVirus)是一款开源的防病毒工具,广泛应用于Linux平台上的网络安全领域。它以其高效的性能和灵活的配置选项,成为网络安全从业人员的重要工具。ClamAV支持多线程扫描,可以自动升级病毒库,并且支持多个操作系统,包括Li…

NGINX 保护 Web 应用安全之基于 IP 地址的访问

根据客户端的 IP 地址控制访问 使用 HTTP 或 stream 访问模块控制对受保护资源的访问&#xff1a; location /admin/ { deny 10.0.0.1; allow 10.0.0.0/20; allow 2001:0db8::/32; deny all; } } 给定的 location 代码块允许来自 10.0.0.0/20 中的任何 IPv4 地址访问&#xf…

可视化大屏中运用3D模型,能够带来什么好处。

现在你看到的可视化大屏&#xff0c;大都会在中间放置一些3D模型&#xff0c;比如厂房、园区、设备等等&#xff0c;那么这些3D模型的放置的确给可视化大屏带来了不一样的视觉冲击&#xff0c;本文将从以下四个方面来分析这个现象。 一、可视化大屏中越来越多使用3D模型说明了…

Linux工具的使用-【git的理解和使用】【调试器gdb的使用】

目录 Linux工具的使用-031.git1.1git是什么1.2git在linux下的操作1.2.1创建git仓库1.2.2 .gitignore1.2.3 .git&#xff08;本地仓库&#xff09;1.2.4 add (添加)1.2.5 commit(提交)1.2.6push(推送)对两个特殊情况的处理配置免密码push 1.2.7 log(获取提交记录)1.2.8 status(获…

Java项目-基于springboot框架的逍遥大药房管理系统项目实战(附源码+文档)

作者&#xff1a;计算机学长阿伟 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、ElementUI等&#xff0c;“文末源码”。 开发运行环境 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBoot、Vue、Mybaits Plus、ELementUI工具&#xff1a;IDEA/…

Linux运维篇-误操作已经做了pv的磁盘导致pv异常

目录 故障场景排错过程小结 故障场景 在对/dev/vdb1创建了pv并扩容至vg(klas)之后&#xff0c;不小心对/dev/vdb进行了parted操作&#xff0c;删除了/dev/vdb1导致pvs查看显示异常。具体过程如下所示&#xff1a; 正常创建pv 将创建好的pv添加到系统现有的卷组中 不小心又对…

Golang | Leetcode Golang题解之第491题非递减子序列

题目&#xff1a; 题解&#xff1a; var (temp []intans [][]int )func findSubsequences(nums []int) [][]int {ans [][]int{}dfs(0, math.MinInt32, nums)return ans }func dfs(cur, last int, nums []int) {if cur len(nums) {if len(temp) > 2 {t : make([]int, len(…

【计网】理解TCP全连接队列与tcpdump抓包

希望是火&#xff0c;失望是烟&#xff0c; 生活就是一边点火&#xff0c;一边冒烟。 理解TCP全连接队列与tcpdump抓包 1 TCP 全连接队列1.1 重谈listen函数1.2 初步理解全连接队列1.3 深入理解全连接队列 2 tcpdump抓包 1 TCP 全连接队列 1.1 重谈listen函数 这里我们使用…

颜色交替的最短路径

题目链接 颜色交替的最短路径 题目描述 注意 返回长度为n的数组answer&#xff0c;其中answer[x]是从节点0到节点x的红色边和蓝色边交替出现的最短路径的长度图中每条边为红色或者蓝色&#xff0c;且可能存在自环或平行边 解答思路 可以使用广度优先遍历从0开始找到其相邻…

Java.6--多态-设计模式-抽象父类-抽象方法

一、多态 1.定义--什么是多态&#xff1f; a.同一个父类的不同子类对象&#xff0c;在做同一行为的时候&#xff0c;有不同的表现形式&#xff0c;这就是多态。&#xff08;总结为&#xff1a;一个父类下的不同子类&#xff0c;同一行为&#xff0c;不同表现形式。&#xff0…

leetcode day1 910+16

910 最小差值 给你一个整数数组 nums&#xff0c;和一个整数 k 。 在一个操作中&#xff0c;您可以选择 0 < i < nums.length 的任何索引 i 。将 nums[i] 改为 nums[i] x &#xff0c;其中 x 是一个范围为 [-k, k] 的任意整数。对于每个索引 i &#xff0c;最多 只能 …

Excel中如何进行傅里叶变换(FT),几步完成

在 Excel 中&#xff0c;虽然没有像 MATLAB 那样专门的函数库来直接进行傅里叶变换&#xff0c;但可以使用 Excel 内置的分析工具库提供的傅里叶变换&#xff08;FT &#xff0c;Fourier Transform&#xff09;功能。这个工具可以对数据进行频域分析。以下是如何在 Excel 中进行…

开源表单生成器OpnForm

什么是 OpnForm &#xff1f; OpnForm 是一个开源的表单构建工具&#xff0c;旨在简化创建自定义表单的过程&#xff0c;特别适合无编码知识的用户。它通过人工智能优化表单创建流程&#xff0c;支持多种用途&#xff0c;如联系人表单、调查表等。OpnForm 提供了一个直观的拖放…

semi-Naive Bayesian(半朴素贝叶斯)

semi-Naive Bayesian&#xff08;半朴素贝叶斯&#xff09; 引言 朴素贝叶斯算法是基于特征是相互独立这个假设开展的&#xff08;为了降低贝叶斯公式: P ( c ∣ x ) P ( c ) P ( x ∣ c ) P ( x ) P(c|x) \frac {P(c)P(x|c)}{P(x)} P(c∣x)P(x)P(c)P(x∣c)​中后验概率 P …

【Linux】进程优先级进程切换

文章目录 进程优先级查看进程优先级进程优先级的修改 进程切换进程切换的概念 总结 进程优先级 进程优先级是操作系统中用于决定进程调度顺序的重要属性。它表示一个进程在系统资源分配和 CPU 调度中的相对重要性。优先级越高的进程通常会获得更多的 CPU 时间和资源&#xff0…

若依项目学习---【数据字典】

数据字典 若以内置的数据字典&#xff0c;用于维护系统中常见的静态数据。例如&#xff1a;性别、状态……如下&#xff1a; 简单描述&#xff1a;一个地方定义&#xff0c;多个地方使用。 只需要修改数据字典&#xff0c;而不需要修改每一个使用该数据的地方。 常见静态数据&…

【C++】创建TCP客户端

目录 一、实现发送字符串功能 二、实现接收字符串功能 三、客户端接收乱码问题 四、客户端发送乱码问题 五、客户端接收到数据时进行回调 六、子线程接收数据 七、发送Json格式数据 源码 一、实现发送字符串功能 头文件 #pragma once #include <iostream> #inc…

.net framework 3.5sp1插件怎么安装

以下是在不同操作系统电脑上安装.NET Framework 3.5 SP1 的几种常见方法&#xff1a; 一、Windows 10 及以上操作系统&#xff1a; 1.在线安装&#xff08;需要网络连接稳定&#xff09;&#xff1a; 按键盘上的 Windows 键&#xff0c;键入 “Windows 功能”&#xff0c;然…

15分钟学Go 第3天:编写第一个Go程序

第3天&#xff1a;编写第一个Go程序 1. 引言 在学习Go语言的过程中&#xff0c;第一个程序通常是“Hello, World!”。这个经典的程序不仅教会你如何编写代码&#xff0c;还引导你理解Go语言的基本语法和结构。本节将详细介绍如何编写、运行并理解第一个Go程序&#xff0c;通过…