当前位置: 首页 > news >正文

Spring-MyBatis基本操作

目录

一.什么是MyBtais

 二.第一个MyBatis程序

        1.构建数据库表

                企业建表的规范:

        2.创建项目引入依赖

        3.编写代码   

        4.创建单元测试

三.使用MyBatis

        1.通过注解使用Mybatis和Mysql数据库进行交互

                a.@Insert(增)

                 b.@Delete(删)

                c.@Update(改) 

                 d.@Select(查)

                        对象中的成员属性和待查表中自动名称不匹配解决方法:

         2.通过XML文件的方式使用MyBatis和MySQL数据库进行交互

                使用前的配置:

                        a.增加

                        b.删除 

                        c.修改

                        d.查找

三.多表查询

        1.MySQL中的多表查询的SQL语句

        2.MyBatis中的多表查询 

四.#{} 和 ${}

        1.相同之处

        2.不同之处

                使用#查询:

                使用$查询:

                        $存在的漏洞:SQL注入 

                总结#和$的区别:

五.池化


一.什么是MyBtais

        MyBatis是一款优秀的持久层(Dao层)框架,用于简化JDBC的开发。

        MyBatis本是Apache的一个开源项目iBatis,2010年这个项目由apache迁移到goole code,并且改名为MyBatis。2013年11月迁移到GitHub。

        官网:MyBatis中文网

        持久层:指的是持久化操作的层,通常指的是操作数据的层(Dao层),用来操作数据库的。

        简单来说MyBatis是更简单完成程序与数据库交互的框架,也就是更简单的操作和读取数据库的工具。 
        接下来,我们就通过一个入门程序,让大家感受一下通过MyBatis如何来操作数据库的。       

 二.第一个MyBatis程序

        1.构建数据库表
-- 创建数据库
DROP DATABASE IF EXISTS mybatis_test;CREATE DATABASE mybatis_test DEFAULT CHARACTER SET utf8mb4;
-- 使⽤数据数据
USE mybatis_test;-- 创建表[⽤⼾表]
DROP TABLE IF EXISTS user_info;
CREATE TABLE `user_info` (`id` INT ( 11 ) NOT NULL AUTO_INCREMENT,`username` VARCHAR ( 127 ) NOT NULL,`password` VARCHAR ( 127 ) NOT NULL,`age` TINYINT ( 4 ) NOT NULL,`gender` TINYINT ( 4 ) DEFAULT '0' COMMENT '1-男 2-⼥ 0-默认',`phone` VARCHAR ( 15 ) DEFAULT NULL,`delete_flag` TINYINT ( 4 ) DEFAULT 0 COMMENT '0-正常, 1-删除',`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now() ON UPDATE now(),PRIMARY KEY ( `id` ) ) ENGINE = INNODB DEFAULT CHARSET = utf8mb4; -- 添加⽤⼾信息INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )VALUES ( 'admin', 'admin', 18, 1, '18612340001' );INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )VALUES ( 'zhangsan', 'zhangsan', 18, 1, '18612340002' );INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )VALUES ( 'lisi', 'lisi', 18, 1, '18612340003' );INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )VALUES ( 'wangwu', 'wangwu', 18, 1, '18612340004' );
                企业建表的规范:

                        字段名/表名全部小写

                        表中必备的三个字段:id、gmt_create、gmt_modified 

                        delete_flag是用来标记这个数据是否被删除了

                                逻辑删除:从逻辑的角度上删除了数据,但是数据依然保存在数据库中,只是在查找的时候不打印这个数据了。

                                物理删除:从硬盘的角度上将数据彻底的删除。(开发中很少用到这种删除)

        2.创建项目引入依赖

                这里下面的MariaDB Driver引入错误了,应该是MySQL Driver 

                配置数据库的相关信息:

       配置文件中的代码https://blog.csdn.net/weixin_52159554/article/details/148771292?spm=1001.2014.3001.5502

                 试运行

        3.编写代码   

                创建用于接收数据库中字段信息的对象

import lombok.Data;import java.util.Date;@Data
public class UserInfo {private Integer id;private String username;private String password;private Integer age;private Integer gender;private String phone;private Integer deleteFlag;private Date createTime;private Date updateTime;
}

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.example.springmabatisdemo.model.UserInfo;import java.util.List;@Mapper
public interface UserInfoMapper {@Select("select * from user_info")List<UserInfo> selectAll();
}

        4.创建单元测试

import lombok.extern.slf4j.Slf4j;
import org.example.springmabatisdemo.model.UserInfo;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.util.List;import static org.junit.jupiter.api.Assertions.*;@SpringBootTest
@Slf4j
class UserInfoMapperTest {@Autowiredprivate UserInfoMapper userInfoMapper;@BeforeEachvoid setUp() {log.info("setUp");}@AfterEachvoid tearDown() {log.info("tearDown");}@Testvoid selectAll() {List<UserInfo> userInfos = userInfoMapper.selectAll();log.info("userInfos:"+ userInfos.toString());}
}

                方便对比引入配置 :

                        配置文件中内容,在上面的链接中

                        打印日志是一个很消费性能的行为,因为在实际开发中,需要打印的日志非常的多,如果不进行筛选的情况下,会对系统性能造成一个很大的影响,所以在开发中只在关键的地方进行日志的打印,而且打印日志只在项目的开发阶段用于程序员开发使用。

                        开发环境:本地开发,一些公司也会有单独的服务器上员工进行开发测试,开发环境一般有专属于开发环境的数据库。

                        测试环境:给测试人员用于测试项目搭建的环境,包括测试数据库。

                        预发布环境:和发布环境一样的配置,但是不对外提供服务只是用于内部测试。在这个环境中和发布环境公用一个数据库服务器。

                        发布环境 :用户可以访问到项目的环境。

                        灰度发布:项目在完成测试和开发后不会一下子发布到全部的线上服务器中,而是只发布到少量的服务器中,也就是控制访问的流量,用于小面积的测试,判断项目是否有问题,然后一点一点的增大流量,直到发布到所有服务器中。

三.使用MyBatis

        1.通过注解使用Mybatis和Mysql数据库进行交互
                a.@Insert(增)

                        新增之前的数据表:

    //1.指定新增的数据@Insert("insert into user_info (username,password,age,gender,phone)" +"values (\"张三\",\"123456\",\"18\",\"1\",\"15678881542\")")Integer insertOne();//2.通过接收对象来新增数据,并获取自增id@Options(useGeneratedKeys = true, keyProperty = "id")@Insert("insert into user_info (username,password,age,gender,phone)" +"values (#{username},#{password},#{age},#{gender},#{phone})")Integer insertTwo(UserInfo userInfo);//3.参数为对象时对参数进行重命名@Options(useGeneratedKeys = true, keyProperty = "id")@Insert("insert into user_info (username,password,age,gender,phone)" +"values (#{userInfo.username}," +"#{userInfo.password}," +"#{userInfo.age}," +"#{userInfo.gender}," +"#{userInfo.phone})")Integer insertThree(@Param("userInfo") UserInfo userInfo);

                        单元测试中的代码: 

   @Testvoid insertOne() {log.info(userInfoMapper.insertOne().toString());}@Testvoid insertTwo() {UserInfo userInfo = new UserInfo();userInfo.setUsername("李四");userInfo.setPassword("9874566");userInfo.setAge(25);userInfo.setGender(2);userInfo.setPhone("1345678912");log.info(userInfoMapper.insertTwo(userInfo).toString() + " " + "id:" + userInfo.getId());}@Testvoid insertThree() {UserInfo userInfo = new UserInfo();userInfo.setUsername("李四");userInfo.setPassword("9874566");userInfo.setAge(25);userInfo.setGender(2);userInfo.setPhone("1345678912");log.info(userInfoMapper.insertThree(userInfo).toString() + " " + "id:" + userInfo.getId());}

                        新增之后的数据表: 

                 b.@Delete(删)

                        删除前的数据表:

 //删除指定数据@Delete("delete from user_info where id=#{id}")Integer deleteOne(@Param("id") Integer id);
 @Testvoid deleteOne() {log.info(userInfoMapper.deleteOne(1).toString());}

                        删除后的数据表: 

                c.@Update(改) 

                        修改前的数据表:

//修改指定id的数据@Update("update user_info set age=#{age} where id=#{id}")Integer updateOne(UserInfo userInfo);
@Testvoid updateOne() {UserInfo userInfo = new UserInfo();userInfo.setId(2);userInfo.setAge(30);log.info(userInfoMapper.updateOne(userInfo).toString());}

                        修改后的数据表: 

                 d.@Select(查)
  @Select("select * from user_info")List<UserInfo> selectAll();
 @Testvoid selectAll() {List<UserInfo> userInfos = userInfoMapper.selectAll();log.info("userInfos:"+ userInfos.toString());}

                        运行后发现有些成员为空: 

                        原因是对象中的成员属性和待查表中自动名称不匹配: 

                        对象中的成员属性和待查表中自动名称不匹配解决方法:

                                对mysql查询结果进行重命名: 

                                        这里一定要注意换行写的情况下,需要留意空格,不然会导致SQL语句错误

 @Select("select id, username, password, age, gender, phone," +" delete_flag as deleteFlag, create_time as createTime, update_time as updateTime" +" from user_info")List<UserInfo> selectAll();

                                使用@Results注解

 @Results(id="BaseMap", value={@Result(column = "delete_flag", property = "deleteFlag"),@Result(column = "create_time", property = "createTime"),@Result(column = "update_time", property = "updateTime")})@Select("select * from user_info")List<UserInfo> selectAllTwo();@ResultMap(value = "BaseMap")@Select("select * from user_info")List<UserInfo> selectAllThree();
@Testvoid selectAllTwo() {List<UserInfo> userInfos = userInfoMapper.selectAllTwo();log.info("userInfos:"+ userInfos.toString());}@Testvoid selectAllThree() {List<UserInfo> userInfos = userInfoMapper.selectAllThree();log.info("userInfos:"+ userInfos.toString());}

                                通过配置来实现自动转驼峰: 
  MyBatis自动转驼峰配置代码https://blog.csdn.net/weixin_52159554/article/details/148771292?spm=1001.2014.3001.5502                                        此时只需要将配置代码导入到properties或yml文件中,就可以不需要上面的操作,只使用最原始是@Select,就就可以让MyBatis自动完成映射。

         2.通过XML文件的方式使用MyBatis和MySQL数据库进行交互
                使用前的配置:

                通过XML文件的方式和通过注释的方式第一步都是一样的,在properties或yml文件中配置连接mysql服务器的相关信息。

                指明XML文件的路径 


固定格式的XML文件代码https://blog.csdn.net/weixin_52159554/article/details/148797089?sharetype=blogdetail&sharerId=148797089&sharerefer=PC&sharesource=weixin_52159554&spm=1011.2480.3001.8118

import org.apache.ibatis.annotations.Mapper;
import org.example.springmabatisdemo.model.UserInfo;@Mapper
public interface UserInfoXMLMapper {}

                        a.增加
Integer insertOne(UserInfo userInfo);Integer insertTwo(@Param("userInfo")UserInfo userInfo);
<?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="org.example.springmabatisdemo.mapper.UserInfoXMLMapper"><insert id="insertOne" useGeneratedKeys="true" keyProperty="id">insert into user_info (username,password,age,gender,phone)values (#{username},#{password},#{age},#{gender},#{phone})</insert><insert id="insertTwo" useGeneratedKeys="true" keyProperty="id">insert into user_info (username,password,age,gender,phone)values (#{userInfo.username},#{userInfo.password},#{userInfo.age},#{userInfo.gender},#{userInfo.phone})</insert>
</mapper>
import lombok.extern.slf4j.Slf4j;
import org.example.springmabatisdemo.model.UserInfo;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import static org.junit.jupiter.api.Assertions.*;@SpringBootTest
@Slf4j
class UserInfoXMLMapperTest {@Autowiredprivate UserInfoXMLMapper userInfoXMLMapper;@BeforeEachvoid setUp() {log.info("setUp");}@AfterEachvoid tearDown() {log.info("tearDown");}@Testvoid insertOne() {UserInfo userInfo = new UserInfo();userInfo.setUsername("李四");userInfo.setPassword("9874566");userInfo.setAge(25);userInfo.setGender(2);userInfo.setPhone("1345678912");log.info(userInfoXMLMapper.insertOne(userInfo).toString() + " " + "id:" + userInfo.getId());}@Testvoid insertTwo() {UserInfo userInfo = new UserInfo();userInfo.setUsername("李四");userInfo.setPassword("9874566");userInfo.setAge(25);userInfo.setGender(2);userInfo.setPhone("1345678912");log.info(userInfoXMLMapper.insertTwo(userInfo).toString() + " " + "id:" + userInfo.getId());}
}

                        b.删除 
Integer deleteOne(@Param("id")Integer id);
 <delete id = "deleteOne">delete from user_info where id = #{id}</delete>
 @Testvoid deleteOne() {log.info(userInfoXMLMapper.deleteOne(5).toString());}
                        c.修改
Integer updateOne(@Param("id")Integer id,@Param("username")String username);
 <update id = "updateOne">update user_info set username = #{username}where id = #{id}</update>
@Testvoid updateOne() {UserInfo userInfo = new UserInfo();userInfo.setId(2);userInfo.setUsername("wuhuwhuwhuw");log.info(userInfoXMLMapper.updateOne(userInfo.getId(),userInfo.getUsername()).toString());}
                        d.查找

                                使用XML文件进行查找,也会遇到字段名称和Java属性名称不匹配的情况,解决办法同注释的方法一样。 

 List<UserInfo> selectOne();List<UserInfo> selectTwo();
<resultMap id="XmlBaseMap" type="org.example.springmabatisdemo.model.UserInfo"><id column="id" property="id"></id><result column="delete_flag" property="deleteFlag"></result><result column="create_time" property="createTime"></result><result column="update_time" property="updateTime"></result></resultMap><select id = "selectOne" resultType="org.example.springmabatisdemo.model.UserInfo">select * from user_info</select><select id = "selectTwo" resultMap="XmlBaseMap">select * from user_info</select>

三.多表查询

        在项目开发中最好尽量避免使用多表查询,尤其是在对性能有很高要求的项目中。因为多表查询是MySQL服务器帮我们进行的优化,我们无法选择是何种优化,这样在进行大量数据查询的时候会非常占用性能,所以使用多表查询必然很慢。

a.select * from ta
b.select * from tb
c.select * from ta left join tb ta.xx=tb.xx

        对于上面的SQL代码,假设a,b代码的运行时间分别是10ms,则c代码的运行时间肯定会大于10ms,此时虽然a,b代码分别执行后的总时间是20ms,看似使用多表查询是更省时间的选择,但是对于a,b代码的运行,在实际的项目开发中我们是会对这样的操作进行优化的,比如引入多线程,此时就会比多表查询更加节省时间,但是多表查询是MySQL服务器帮我们进行的优化,我们无法直接选择。

        而且通常情况下,数据库集群是很多项目一起使用的,当出现慢查询时,会影响整个数据库集群,从而也就影响了所有使用该集群的项目。

        同时比如在执行很多类似于a,b代码的操作时,虽然会导致Java服务器的吞吐量变大,造成系统卡顿,但是此时我们只需要很简单的将Java服务器扩容就好了,这种服务器扩容的方式是非常简单的,但是如果你想要扩容数据库集群的话就不是很方便了,此时就需要让DBA(数据库管理员,是另一个团队)来做扩容,自己本来可以通过别的方法解决的事情,此时引入第三方,就不会那么方便了。

        但是虽然多表查询在性能上的开销很大,但是多表查询会自动帮我们拼接我们需要查的多个表,帮我们对数据进行一些操作。

        1.MySQL中的多表查询的SQL语句

                添加新的数据表:

CREATE TABLE article_info (id INT PRIMARY KEY auto_increment,title VARCHAR ( 100 ) NOT NULL,content TEXT NOT NULL,uid INT NOT NULL,delete_flag TINYINT ( 4 ) DEFAULT 0 COMMENT '0-正常, 1-删除',create_time DATETIME DEFAULT now(),update_time DATETIME DEFAULT now() ) DEFAULT charset 'utf8mb4';-- 插⼊测试数据INSERT INTO article_info ( title, content, uid ) VALUES ( 'Java', 'Java正⽂', 1
);
select ta.*,tb.username,tb.age from article_info taLEFT JOIN user_info tb on ta.uid = tb.idwhere ta.id=1

        2.MyBatis中的多表查询 

                在项目中,我们获取多表查询数据的时候,并不在乎是多少个表组成的数据,所以只需要将需要数据构建成一个对象,将数据保存到这个对象中就可以了。

                构建用于接收数据的对象:

import lombok.Data;import java.util.Date;@Data
public class ArticleInfo {private Integer id;private String title;private String content;private Integer uid;private Integer deleteFlag;private Date createTime;private Date updateTime;//接收用户信息private String userName;private Integer age;
}

                使用使用注释的方法使用MyBatis操作数据库: 

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.example.springmabatisdemo.model.ArticleInfo;@Mapper
public interface ArticleInfoMapper {@Select("select ta.*,tb.username,tb.age from article_info ta" +" LEFT JOIN user_info tb on ta.uid = tb.id\n" +" where ta.id= #{id}")ArticleInfo getArticleInfoById(Integer id);
}

                单元测试代码: 

import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import static org.junit.jupiter.api.Assertions.*;@SpringBootTest
@Slf4j
class ArticleInfoMapperTest {@Autowiredprivate ArticleInfoMapper articleInfoMapper;@BeforeEachvoid setUp() {log.info("setUp");}@AfterEachvoid tearDown() {log.info("tearDown");}@Testvoid getArticleInfoById() {log.info(articleInfoMapper.getArticleInfoById(1).toString());}
}

四.#{} 和 ${}

        1.相同之处

                #{}和${}都是用来获取传入变量的值的。、

        2.不同之处
                使用#查询:

                        会自动根据传入的类型进行匹配: 

                                会自动根据传入的数据的类型进行匹配的原因是,#是预编译SQL: 

                        涉及排序操作的时候,不能使用# ,因为如果使用#会自动为其添加' ':

                                使用$就可以了: 

                        进行模糊查询的时候也不可以使用#: 

                                使用$就可以了:  

                使用$查询:

                        使用$并不会自动转换,给什么它就传什么,但是以username为条件的时候,需要' '引起来的字符串,#会自动添加,$不会。 

                        解决办法:不论传输何种数据,都手动加上' ',这样MySQL服务器会自动帮我们进行优化,但是会产生一定的性能问题。 

                                以下方法选其一:

                        $存在的漏洞:SQL注入 

                                此时因为or也是SQL关键词,MySQL也就同时将or 1='1' 给执行了,'1'MySQL会自动优化为1,但是这并不是想要的结果。

                                因为$是即时的SQL,所以给它啥它就会立马赋值为啥,此时就会有问题,这是一个非常严重的问题,如果想上面的代码这样直接写,如果有人这样访问数据库,带上了DROP操作,此时损失就非常的大了。

                                 此时使用#就可以了。

                总结#和$的区别:

                                #是预编译SQL而$是即时SQL

                                        预编译SQL性能高

                                        预编译SQL不存在SQL注入问题

                                        排序时不能用#,即时使用$时也要在代码中进行参数检查,防止代码注入的问题

                                        表名,字段名等作为参数时,也不能使用#

                                        模糊查询时,如果非要使用#,需要搭配mysql的内置函数concat

                                        一般在项目开发中,能用#的先用#,实在不行了再用$。 

五.池化

        Hikari : SpringBoot默认使⽤的数据库连接池

        Druid
                如果我们想把默认的数据库连接池切换为Druid数据库连接池, 只需要引⼊相关依赖即可
<dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-3-starter</artifactId><version>1.2.21</version>
</dependency>
                如果果SpringBoot版本为2.X, 使⽤druid-spring-boot-starter 依赖        
<dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.17</version>
</dependency>

http://www.lryc.cn/news/573536.html

相关文章:

  • 软件工程期末试卷简答题版带答案(共21道)
  • Typora文档另存与图片迁移的一种思路
  • JAVA锁机制:对象锁与类锁
  • 【好用但慎用】Windows 系统中将所有 WSL 发行版从 C 盘迁移到 非系统 盘的完整笔记(附 异常处理)
  • 百度萝卜快跑携4颗禾赛激光雷达进军迪拜,千辆L4无人车开启全球化战略
  • IEC61850 通信协议测试验证方法详解
  • 人工智能学习51-ResNet训练
  • Spring AOP全面详讲
  • Python 爬虫案例(不定期更新)
  • 一,python语法教程.内置API
  • 【知识图谱提取】【阶段总结】【LLM4KGC】LLM4KGC项目提取知识图谱推理部分
  • Linux 内核中 TCP 协议栈的输出实现:tcp_output.c 文件解析
  • 【JAVA】数组的使用
  • 电子电气架构 --- 实时系统评价的概述
  • 基于YOLO的智能车辆检测与记录系统
  • Transformer架构每层详解【代码实现】
  • LangGraph--基础学习(工具调用)
  • 2025zbrush雕刻笔记
  • NW849NX721美光固态闪存NX745NX751
  • 微处理器原理与应用篇---计算机系统的结构、组织与实现
  • 给交叉工具链增加libelf.so
  • 操作系统内核态和用户态--2-系统调用是什么?
  • 嵌入式开发之嵌入式系统架构如何搭建?
  • 【软考高级系统架构论文】论面向服务架构设计及其应用
  • modelscope设置默认模型路径
  • python的校园兼职系统
  • Taro 跨端开发:从调试到发布的完整指南
  • 基于正点原子阿波罗F429开发板的LWIP应用(7)——MQTT
  • 华为OD机试-云短信平台优惠活动-完全背包(JAVA 2024E卷)
  • TodoList 案例(Vue3): 使用Composition API