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

news2024/10/23 7:50:00

目录

  • 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框架,用于各种功能的测试

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

利用自定义 ref 实现函数防抖

今天来简单介绍一个新的方法&#xff0c;使用自定义 ref 实现函数防抖。 1. 自定义 ref 的来源 自定义 ref 防抖函数来自于前端开发中的两个概念&#xff1a;Vue 的响应式系统 和 数防抖&#xff08;Debounce&#xff09;。 1、Vue 响应式系统&#xff1a;Vue 提供了 ref 和…

Python学习的自我理解和想法(20)

#1024程序员节|征文# 学的是b站的课程&#xff08;千锋教育&#xff09;&#xff0c;跟老师写程序&#xff0c;不是自创的代码&#xff01; 今天是学Python的第20天&#xff0c;学的内容是面向对象中的私有属性&#xff0c;私有方法&#xff0c;多态&#xff0c;单例计模式。开…

【ubuntu18.04】ubuntu18.04升级cmake-3.29.8及还原系统自带cmake操作说明

参考链接 cmake升级、更新&#xff08;ubuntu18.04&#xff09;-CSDN博客 升级cmake操作说明 下载链接 Download CMake 下载版本 下载软件包 cmake-3.30.3-linux-x86_64.tar.gz 拷贝软件包到虚拟机 cp /var/run/vmblock-fuse/blockdir/jrY8KS/cmake-3.29.8-linux-x86_64…

spring源码中的,函数式接口,注解@FunctionalInterface

调用方 /org/springframework/beans/factory/support/AbstractBeanFactory.java:333sharedInstance getSingleton(beanName, () -> {try {return createBean(beanName, mbd, args);}catch (BeansException ex) {// Explicitly remove instance from singleton cache: It mi…

高级的SQL查询技巧有哪些?

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///C爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于高级SQL查询技巧方面的相关内容&#xf…

MATLAB人脸考勤系统

MATLAB人脸考勤系统课题介绍 该课题为基于MATLAB平台的人脸识别系统。传统的人脸识别都是直接人头的比对&#xff0c;现实意义不大&#xff0c;没有一定的新意。该课题识别原理为&#xff1a;先采集待识别人员的人脸&#xff0c;进行训练&#xff0c;得到人脸特征值。测试的时…

HomeAssistant自定义组件学习-【一】

#环境准备# 按官方的步骤准备就可以&#xff0c;我是在Windows下使用VS Code开发的&#xff0c;安装了WSL&#xff08;使用模板创建组件需要在WSL环境下完成&#xff09; 官方链接&#xff1a;https://developers.home-assistant.io/docs/development_environment 环境准备好…

力扣困难题汇总(14道)

题4&#xff08;困难&#xff09;&#xff1a; 思路&#xff1a; 找两数组中位数&#xff0c;这个看起来简单&#xff0c;顺手反应就是数第(mn)/2个&#xff0c;这个难在要求时间复杂度为log(mn)&#xff0c;所以不能这样搞&#xff0c;我的思路是&#xff1a;每次切割长度为较…

【K8s】Kubernetes 词汇表

微思网络 厦门微思网络 K8S认证工程师&#xff08;CKA&#xff09;备考与学习指南https://mp.weixin.qq.com/s/XsEVpU7dKnJDBopynWW3GQ K8S-CKA课程试听:Container 概述 词汇表 此术语表旨在提供 Kubernetes 术语的完整、标准列表。其中包含特定于 Kubernetes 的技术术语以及…

uniapp修改input中placeholder样式

Uniapp官方提供了两种修改的属性方法&#xff0c;但经过测试&#xff0c;只有 placeholder-class 属性能够生效 <input placeholder"请输入手机验证码" placeholder-class"input-placeholder"/><!-- css --> <style lang"scss" s…

redis的zset实现下滑滚动分页查询思路

常规zset查询 我们redis的数据为 我们知道 我们常规查询的话 我们假如 zset 表中 有7个元素&#xff0c;然后我们进行分页查询的话&#xff0c;我们一次查3个元素&#xff0c;然后查出来元素 和元素的分数 我们redis的语法应该这样写 zrevrangebyscore wang 1000 0 withsc…

kotlin实现viewpager

说明:kotlin tablayout viewpager adapter实现滑动界面 效果图 step1: package com.example.flushfragmentdemoimport androidx.appcompat.app.AppCompatActivity import android.os.Bundle import androidx.fragment.app.Fragment import androidx.viewpager2.adapter.…

【uni-app学习-2】

一、跳转 方法&#xff1a;在methods中去定义方法&#xff1a; 上述为直接跳转&#xff0c;但是当你要跳转页面是由多个可切换页面组成比如&#xff1a; 这个页面其实是由两个页面组成&#xff0c;一个主页&#xff0c;一个我的&#xff0c;两个页面 路由配置需要用到toob…

java--多态(详解)

目录 一、概念二、多态实现的条件三、向上转型和向下转型3.1 向上转型3.2 向下转型 四、重写和重载五、理解多态5.1练习&#xff1a;5.2避免在构造方法中调用重写的方法&#xff1a; 欢迎来到权权的博客~欢迎大家对我的博客提出指导这是我的博客主页&#xff1a;点击 一、概念…

EasyExcel自定义下拉注解的三种实现方式

文章目录 一、简介二、关键组件1、ExcelSelected注解2、ExcelDynamicSelect接口&#xff08;仅用于方式二&#xff09;3、ExcelSelectedResolve类4、SelectedSheetWriteHandler类 三、实际应用总结 一、简介 在使用EasyExcel设置下拉数据时&#xff0c;每次都要创建一个SheetWr…

韩语干货topik韩语考级柯桥外语培训韩语中的惯用表达

表示递进的词尾或惯用表达 1 -을/ㄹ 뿐만 아니라 接在动词和形容词词干后面&#xff0c;表示“不仅...而且...”。该语法需要注意前后会有两个动词或形容词&#xff0c;此时两个动词或形容词的时态应保持一致。 例: 한번 파괴된 자연은 되돌리기기 쉽지 않을 뿐만 아니라 지역…

Java项目实战II基于微信小程序的原创音乐平台{UNIAPP+SSM+MySQL+Vue}(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 在数字音乐…

《Order-Agnostic Data Augmentation for Few-Shot Named Entity Recognition》中文

文章汉化系列目录 文章目录 文章汉化系列目录摘要1 引言2 相关工作2.1 NER的数据增强2.2 少样本命名实体识别&#xff08;Few-Shot NER&#xff09; 3 无序数据增强3.1 公式化3.2 通过实体重排进行数据增强3.3 构建唯一的输入-输出对3.4 使用 OADA-XE 校准预测 4 实验4.1 不同D…

【ELK】初始阶段

一、logstash学习 安装的时候最好不要有中文的安装路径 使用相对路径 在 Windows PowerShell 中&#xff0c;如果 logstash 可执行文件位于当前目录下&#xff0c;你需要使用相对路径来运行它。尝试输入以下命令&#xff1a; .\logstash -e ‘input { stdin { } } output { s…

[软件工程]—嵌入式软件开发流程

嵌入式软件开发流程 1.工程文件夹目录 ├─00_Project_Management ├─00_Reference ├─01_Function_Map ├─02_Hardware ├─03_Firmware ├─04_Software ├─05_Mechanical ├─06_FCT └─07_Tools00_Project_Management 子文件夹如下所示&#xff1a; ├─00_需求导…