MyBatis查询数据库

news2024/12/23 13:34:08

1.MyBatis 是什么?
MyBatis 是⼀款优秀的持久层框架,它⽀持⾃定义 SQL、存储过程以及⾼级映射。MyBatis 去除了⼏乎所有的 JDBC 代码以及设置参数和获取结果集的⼯作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接⼝和 Java POJO(Plain Old Java Objects,普通⽼式 Java 对象)为数据库中的记录。
简单来说 MyBatis 是更简单完成程序和数据库交互的⼯具,也就是更简单的操作和读取数据库⼯具
 

2.为什么学习MyBatis? 

对于后端开发来说,程序是由以下两个重要的部分组成的:

  • 后端程序
  • 数据库
     

⽽这两个重要的组成部分要通讯,就要依靠数据库连接⼯具,那数据库连接⼯具有哪些? JDBC, MyBatis,那已经有了 JDBC 了,为什么还要学习 MyBatis?这是因为 JDBC 的操作太繁琐了,我们回顾⼀下 JDBC 的操作流程:

  1. 创建数据库连接池 DataSource
  2. 通过 DataSource 获取数据库连接 Connection
  3. 编写要执⾏带 ? 占位符的 SQL 语句
  4. 通过 Connection 及 SQL 创建操作命令对象 Statement
  5. 替换占位符:指定要替换的数据库字段类型,占位符索引及要替换的值
  6. 使⽤ Statement 执⾏ SQL 语句
  7.  查询操作:返回结果集 ResultSet,更新操作:返回更新的数量
  8. 处理结果集
  9. 释放资源

 下⾯的⼀个完整案例,展示了通过 JDBC 的 API 向数据库中添加⼀条记录,修改⼀条记录,查询⼀条记录的操作。

  以下是 JDBC 操作的具体实现代码:

package com.example._20230103.javase;


import com.example._20230103.model.Book;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class SimpleJdbcOperation {
    private final DataSource dataSource;

    public SimpleJdbcOperation(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    //添加一本书
    public void addBook() {
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            //获取数据库连接
            connection = dataSource.getConnection();
            //创建语句
            statement = connection.prepareStatement("insert into soft_bookrack(book_name,book_author,book_isbn) values (?,?,?);");
            //参数绑定
            statement.setString(1, "Spring in Action");
            statement.setString(2, "Craig Walls");
            statement.setString(3, "9787115417305");
            //执行语句
            statement.execute();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if (statement != null) {
                    statement.close();
                }
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }

    //更行一本书
    public void updateBook() {
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            //获取数据库连接
            connection = dataSource.getConnection();
            //创建语句
            statement = connection.prepareStatement("update soft_bookrack set book_author=? where book_isbn=?");
            //参数绑定
            statement.setString(1, "张卫滨");
            statement.setString(2, "975646515645615");
            statement.execute();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if (statement != null) {
                    statement.close();
                }
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }

    //查询一本书
    public void queryBook() {
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        Book book = null;
        try {
            //获取数据库连接
            connection = dataSource.getConnection();
            //创建语句
            statement = connection.prepareStatement("select book_name,book_author,book_isbn from soft_bookrack where book_isbn = ?");
            //参数绑定
            statement.setString(1, "975646515645615");
            //执行语句
            resultSet = statement.executeQuery();
            if (resultSet.next()) {
                book = new Book();
                book.setName(resultSet.getString("book_name"));
                book.setAuthor(resultSet.getString("book_author"));
                book.setIsbn(resultSet.getString("book_isbn"));
            }
            System.out.println(book);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if (resultSet != null) {
                    resultSet.close();
                }
                if (statement != null) {
                    statement.close();
                }
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }
}


 

引入mysql依赖

从上述代码和操作流程可以看出,对于 JDBC 来说,整个操作⾮常的繁琐,我们不但要拼接每⼀个参数,⽽且还要按照模板代码的⽅式,⼀步步的操作数据库,并且在每次操作完,还要⼿动关闭连接等,⽽所有的这些操作步骤都需要在每个⽅法中重复书写。于是我们就想,那有没有⼀种⽅法,可以更简单、更⽅便的操作数据库呢?
答案是肯定的,这就是我们要学习 MyBatis 的真正原因,它可以帮助我们更⽅便、更快速的操作数据库。
 

 3.怎么学MyBatis?

MyBatis 学习只分为两部分:

  • 配置 MyBatis 开发环境;
  • 使⽤ MyBatis 模式和语法操作数据库。
     

 4.第⼀个MyBatis查询

开始搭建 MyBatis 之前,我们先来看⼀下 MyBatis 在整个框架中的定位,框架交互流程图:
 

MyBatis 也是⼀个 ORM 框架,ORM(Object Relational Mapping),即对象关系映射。在⾯向对
象编程语⾔中,将关系型数据库中的数据与对象建⽴起映射关系,进⽽⾃动的完成数据与对象的
互相转换:

  1. 将输⼊数据(即传⼊对象)+SQL 映射成原⽣ SQL
  2. 将结果集映射为返回对象,即输出对象

ORM 把数据库映射为对象:

  • 数据库表(table)--> 类(class)
  • 记录(record,⾏数据)--> 对象(object)
  • 字段(field) --> 对象的属性(attribute)

⼀般的 ORM 框架,会将数据库模型的每张表都映射为⼀个 Java 类。
也就是说使⽤ MyBatis 可以像操作对象⼀样来操作数据库中的表,可以实现对象和数据库表之间
的转换,接下来我们来看 MyBatis 的使⽤吧。

4.创建数据库和表

接下来我们要实现的功能是:使⽤ MyBatis 的⽅式来读取⽤户表中的所有⽤户,我们使⽤个⼈博
客的数据库和数据包,具体 SQL 如下。
 

-- 创建数据库
drop database if exists mycnblog;
create database mycnblog DEFAULT CHARACTER SET utf8;
-- 使⽤数据库
use mycnblog;
-- 创建用户表
drop table if exists userinfo;
create table userinfo
(
    id         int primary key auto_increment,
    username   varchar(100) not null,
    password   varchar(32)  not null,
    photo      varchar(500) default '',
    createtime datetime     default now(),
    updatetime datetime     default now(),
    `state`    int          default 1
);

-- 创建⽂章表
drop table if exists articleinfo;
create table articleinfo
(
    id         int primary key auto_increment,
    title      varchar(100) not null,
    content    text         not null,
    createtime datetime              default now(),
    updatetime datetime              default now(),
    uid        int          not null,
    rcount     int          not null default 1,
    `state`    int                   default 1
);

-- 创建视频表
drop table if exists videoinfo;
create table videoinfo
(
    vid        int primary key,
    `title`    varchar(250),
    `url`      varchar(1000),
    createtime datetime default now(),
    updatetime datetime default now(),
    uid        int
);

-- 添加⼀个⽤户信息
INSERT INTO `userinfo` (`id`, `username`, `password`, `photo`, `createtime`, `updatetime`, `state`)
VALUES (1, 'admin', 'admin', '', '2023-01-05 17:10:48', '2023-01-05 19:10:48', 1);

-- ⽂章添加测试数据
insert into articleinfo(title, content, uid)
values ('Java', 'Java正⽂', 1);

-- 添加视频
insert into videoinfo(vid, title, url, uid)
values (1, 'javatitle', 'http://www.baidu.com', 1);

5.添加MyBatis框架⽀持

这个插件用来管理依赖。

 6.配置连接字符串

如果是 application.yml 添加如下内容:


如果使⽤ MySQL 是 5.x 之前的使⽤的是“com.mysql.jdbc.Driver”,如果是⼤于 5.x 使⽤的
是“com.mysql.cj.jdbc.Driver”。

7.配置 MyBatis 中的 XML 路径


MyBatis 的 XML 中保存是查询数据库的具体操作 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 = 你要实现的接口的路径-->
<mapper namespace="com.example._20230103.mapper.UserMapper">
    
</mapper>

8.添加业务代码

下⾯按照后端开发的⼯程思路,也就是下⾯的流程来实现 MyBatis 查询所有⽤户的功能:



 

9.添加实体类

10.添加 mapper 接⼝
 

11.添加 UserMapper.xml
 

以下是对以上标签的说明:
<mapper>标签:需要指定 namespace 属性,表示命名空间,值为 mapper 接⼝的全限定
名,包括全包名.类名。


<select>查询标签:是⽤来执⾏数据库的查询操作的:id:是和 Interface(接⼝)中定义的⽅法名称⼀样的,表示对接⼝的具体实现⽅法。resultType:是返回的数据类型,也就是开头我们定义的实体类

12.添加 Service
 

13.添加 Controller


 

14.使⽤ postman 测试


15.增、删、改操作


接下来,我们来实现⼀下⽤户的增加、删除和修改的操作,对应使⽤ MyBatis 的标签如下:

  • <insert>标签:插⼊语句
  • <update>标签:修改语句
  • <delete>标签:删除语句
     

 1.插入功能的实现:

 运行结果:

 2.修改功能的实现:

运行结果:

3.删除功能的实现:

 

运行结果:

16.参数占位符 #{} 和 ${}

  • #{}:预编译处理.
  • ${}:字符直接替换.
     

预编译处理是指:MyBatis 在处理#{}时,会将 SQL 中的 #{} 替换为?号,使⽤ PreparedStatement 的set ⽅法来赋值。直接替换:是MyBatis 在处理 ${} 时,就是把 ${} 替换成变量的值。

17.${} 优点

 

 

 

 

运行结果:

 

使⽤ ${sort} 可以实现排序查询,⽽使⽤ #{sort} 就不能实现排序查询了,因为当使⽤ #{sort} 查询时,如果传递的值为 String 则会加单引号,就会导致 sql 错误。
 

 18.SQL 注⼊问题

 

 

 

 

运行结果:

 

 黑客能通过sql注入,能获得表中所有数据,还可以删库。

select * from userinfo where username= 'admin' and password='admin'
select * from userinfo where username= 'admin' and password='' or 1='1';

 使用${}存在安全隐患(SQL注入问题),而#{}不存在SQL注入问题。我们在满足特定场景下使用${}.

19.like查询

 

 

 

 运行结果:

 

 20.多表查询

如果是增、删、改返回搜影响的⾏数,那么在 mapper.xml 中是可以不设置返回的类型的,如下图所示:

 

 对于 <select> 查询标签来说⾄少需要两个属性:

  • id 属性:⽤于标识实现接⼝中的那个⽅法;
  • 结果映射属性:结果映射有两种实现标签:<resultMap> 和 <resultType>。
     

21.返回类型:resultType

绝⼤数查询场景可以使⽤ resultType 进⾏返回,如下代码所示:

<select id="getUserById" resultType="com.example._20230103.model.UserInfo">
        select * from userinfo where id=#{id}
</select>

它的优点是使⽤⽅便,直接定义到某个实体类即可.

22.返回字典映射:resultMap

resultMap 使⽤场景:

  • 字段名称和程序中的属性名不同的情况,可使⽤ resultMap 配置映射;
  • ⼀对⼀和⼀对多关系可以使⽤ resultMap 映射并查询数据

字段名和属性名不同的情况
 



 

 

 

运行结果:

 

可以明显看到查询不到titlename这个属性。这个时候就可以使⽤ resultMap 了,resultMap 的使⽤规则如下.

 

 

 

 

 运行结果:

 

23.⼀对⼀的表映射


 ⼀对⼀映射要使⽤ <association> 标签,具体实现如下(⼀篇⽂章只对应⼀个作者):

 

 

 

 

 

 

 

 

单元测试运行结果:

 

补充:把数据库文件发一下:

-- 创建数据库
drop database if exists mycnblog;
create database mycnblog DEFAULT CHARACTER SET utf8;
-- 使⽤数据库
use mycnblog;
-- 创建用户表
drop table if exists userinfo;
create table userinfo
(
    id         int primary key auto_increment,
    username   varchar(100) not null,
    password   varchar(32)  not null,
    photo      varchar(500) default '',
    createtime datetime     default now(),
    updatetime datetime     default now(),
    `state`    int          default 1
);

-- 创建⽂章表
drop table if exists articleinfo;
create table articleinfo
(
    id         int primary key auto_increment,
    title      varchar(100) not null,
    content    text         not null,
    createtime datetime              default now(),
    updatetime datetime              default now(),
    uid        int          not null,
    rcount     int          not null default 1,
    `state`    int                   default 1
);

-- 创建视频表
drop table if exists videoinfo;
create table videoinfo
(
    vid        int primary key,
    `title`    varchar(250),
    `url`      varchar(1000),
    createtime datetime default now(),
    updatetime datetime default now(),
    uid        int
);

-- 添加⼀个⽤户信息
INSERT INTO `userinfo` (`id`, `username`, `password`, `photo`, `createtime`, `updatetime`, `state`)
VALUES (1, 'admin', 'admin', '', '2023-01-05 17:10:48', '2023-01-05 19:10:48', 1);

-- ⽂章添加测试数据
insert into articleinfo(title, content, uid)
values ('Java', 'Java正⽂', 1);

-- 添加视频
insert into videoinfo(vid, title, url, uid)
values (1, 'javatitle', 'http://www.baidu.com', 1);

 

columnPrefix 如果省略,并且恰好两个表中如果有相同的字段,那么就会导致查询出错,示例如下:

这是原来的样子:

 删除columnPrefix:

测试运行结果:

这是因为userinfo 表中有 id 字段,articleinfo 中也有⼀个 id 字段,会导致查询出错,正确的做法是添加 columnPrefix.

24.⼀对多:⼀个⽤户多篇⽂章案例


 

 

 

 

 

 

单元测试junit5运行结果:

 

 

 

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

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

相关文章

计算机基础——计算机分类

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 前言 本章将会讲解计算机分类应用领域以及发展趋势 一.计算机分类 计算机并非只有日常所…

并行计算 Clion配置使用OpenMP

文章目录配置CMakeList.txt文件OpenMP之HelloWorld数据共享属性shared子句private子句default子句default(shared)default(none)配置CMakeList.txt文件 文件底部加入以下内容&#xff0c;即可支持OpenMP FIND_PACKAGE(OpenMP REQUIRED) if (OPENMP_FOUND)message("OPENM…

STM32MP157驱动开发——Linux DAC驱动

STM32MP157驱动开发——Linux DAC驱动0.前言一、DAC 简介二、驱动源码分析1.设备树下的 DAC 节点2.驱动源码分析1&#xff09;stm32_dac 结构体2&#xff09;stm32_adc_probe 函数3&#xff09;stm32_dac_iio_info 结构体三、驱动开发1.修改设备树2.使能DAC驱动四、 运行测试0.…

读书笔记 -公司改造 和 紧迫感

读书笔记 -公司改造 - 三枝匡 读书笔记 -公司改造 - 三枝匡 2022 年夏天的时候在微信读书上读了这本书&#xff0c;这是我们 CSDN 的创始人蒋涛推荐的&#xff0c;当时记了一些笔记如下。 总结&#xff1a; 每个有一定的历史&#xff0c;比较成功、或者尚未非常成功的公司遇…

基于Java+SpringBoot+vue+element实现毕业就业招聘系统

基于JavaSpringBootvueelement实现毕业就业招聘系统 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 文末获取源码…

用最简单的案例带你掌握C++中各种指针

1、前言 指针&#xff0c;作为C/C中最神秘、功能最强大的语法&#xff0c;着实是难以理解 、难以掌握、难以运用。&#x1f625; 但是&#xff0c;能灵活的使用指针&#xff0c;对利用C/C开发程序将有很大的帮助&#xff0c;让我们一起来了解了解吧。 2、啥是指针&#xff1f…

参加《2022 中国开发者影响力盛典》我的 4 重收获!

感谢 CSDN 邀请&#xff0c;西红柿有幸参加了 2022 中国开发者影响力盛典暨 CSDN 企业生态汇&#xff0c;让我有了一个不虚此行的下午&#xff0c;也跟大家分享一下我在会上的 4 重收获吧~第一重收获&#xff1a;互联网圈大佬 会议聚焦开发者生态建设主题&#xff0c;分享了 CS…

分布式基础篇4 —— 基础篇完结

分类维护一、三级分类后端实现准备工作跨域问题关闭 ESLint 检查前端实现二、分类删除前端完善分类列表后端实现——删除配置发送请求代码片段前端实现——删除三、分类增加前端实现四、分类修改五、拖拽菜单拖拽效果实现拖拽数据收集拖拽功能完成拖拽功能完善六、批量删除品牌…

JS知识补充-JS原型链

概述JS原型链别名&#xff1a;隐式原型链作用&#xff1a;根据一定路径查找属性&#xff08;方法&#xff09;作用举例&#xff1a;我们定义一个构造函数Fn&#xff0c;使用此构造函数创建一个对象fn1&#xff0c;接着使用创建的对象fn1去调用toString方法并打印&#xff0c;我…

【阶段三】Python机器学习03篇:机器学习中的函数、机器学习中的梯度下降、机器学习的数据结构:张量与机器学习概率与统计基础

本篇的思维导图: 机器学习中的函数 函数描述了输入与输出的关系。在函数中,一个事物(输出)随着另一个(或一组)事物(输入)的变化而变化,如下图所示。 输入与输出的关系一般情况下,用x(或x1,x2,x3,…)表示输入,用y表示输出,并把它们叫作变量,…

Java设计模式中的设计原则/开闭原则、里氏代换原则和依赖倒转原则又是什么,怎么用

继续整理记录这段时间来的收获&#xff0c;详细代码可在我的Gitee仓库SpringBoot克隆下载学习使用&#xff01; 3.设计原则 3.1 目的 提高软件系统可维护性与可复用性增加软件可扩展性与灵活性节约开发成本与维护成本 3.2 开闭原则 3.2.1 特点 对扩展开放&#xff0c;对修…

实战干货|自研数据存储迁移MySQL实战

背景 最近公司内部在做某自研数据存储的下线工作&#xff0c;这里我们暂且化名其为DistributeSQL&#xff0c;由于DistributeSQL不再进行服务支持&#xff0c;需要迁移项目中使用到该存储到其他数据存储中。 本篇来聊聊这次在数据存储迁移过程中的方案设计思路、实现的大致细节…

中老年服装电商小程序开发

近年来&#xff0c;随着网络的发展&#xff0c;中老年服装电商小程序开发有了很大的进步。这种平台不仅可以方便用户购买到最新最时尚的产品&#xff0c;而且还能帮助商家提高销售业绩。 1&#xff1a;中老年服装电商小程序开发的优势 中老年人对商品信息需求大、容易接受新鲜…

实验⼀:Windows主机漏洞利⽤攻击实践

永恒之蓝简介 永恒之蓝&#xff08;Eternal Blue&#xff09;爆发于2017年4月14日晚&#xff0c;是一种利用Windows系统的SMB协议漏洞来获取系统的最高权限&#xff0c;以此来控制被入侵的计算机。甚至于2017年5月12日&#xff0c; 不法分子通过改造“永恒之蓝”制作了wannacry…

【ROS】—— ROS重名问题(九)

文章目录前言1. ROS工作空间覆盖2. ROS节点名称重名2.1 rosrun设置命名空间与重映射2.1.1 rosrun设置命名空间2.1.2 rosrun名称重映射2.1.3 rosrun命名空间与名称重映射叠加2.2 launch文件设置命名空间与重映射2.3 编码设置命名空间与重映射2.3.1 重映射2.3.2 C 实现:命名空间3…

Maven基础学习——依赖配置(1):配置同一项目下的三个工程

依赖配置一、前言二、创建第一个工程三、新建第二个工程四、创建第三个工程五、配置1.每个工程的.xml文件2.文件配置六、结语一、前言 在讲述依赖配置时&#xff0c;需要使用实例来说明&#xff0c;在B站黑马课程&#xff08;第12小节&#xff09;中没有讲到如何配置基础的三个…

[Effective Objective] 熟悉Objective-C

了解 Objective-C Objective_C 是一种面向对象的语言。但与jave、C等语言不同&#xff0c;它使用了消息结构&#xff08;messaging structure&#xff09;而非函数调用&#xff08;function calling&#xff09;。Objective-C由Smalltalk演化而来&#xff0c;后者是消息语言的…

React 学习笔记总结(六)

文章目录1. redux 介绍2. redux 工作流程3. redux 的使用4. redux 完整结构补充5. redux的 异步action6. react-redux库 与 redux库7. react-redux库的 实战8. react-redux的connect 最精简写法9. react-redux的 Provider组件作用10. react-redux 整合UI组件 和 容器组件11. re…

webgl图形平移、缩放、旋转

文章目录前言平移图示代码示例缩放图示代码示例旋转公式推导代码示例总结前言 在webgl中将图形进行平移、旋转、缩放的操作称为变换或仿射变换&#xff0c;图形的仿射变换涉及到顶点位置的修改&#xff0c;通过顶点着色器是比较直接的方式。本文通过着色器实现对webgl图形的仿…

ArcGIS基础实验操作100例--实验65按字段调整点符号方向

本实验专栏参考自汤国安教授《地理信息系统基础实验操作100例》一书 实验平台&#xff1a;ArcGIS 10.6 实验数据&#xff1a;请访问实验1&#xff08;传送门&#xff09; 高级编辑篇--实验65 按字段调整点符号方向 目录 一、实验背景 二、实验数据 三、实验步骤 &#xff0…