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

MyBatis 操作数据库(⼊⻔)

1.什么是MyBatis

MyBatis 是一款优秀的持久层框架,用于简化数据库操作。它通过 XML 或注解配置 SQL 语句,并将 Java 对象与数据库记录映射,避免了手动编写 JDBC 代码的繁琐。MyBatis 支持定制化 SQL、存储过程及高级映射,同时提供灵活的缓存机制。

2.MyBatis⼊⻔

数据准备

创建数据库:

-- 创建数据库
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' );

创建对应的实体类UserInfo:

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

配置数据库连接字符串

spring:datasource:url: jdbc:mysql://127.0.0.1:3306/mycnblog?characterEncoding=utf8&useSSL=falseusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Driver

写持久层代码

@Mapper
public interface UserMapper {//查询所有用户@Select("select * from user_info")List<UserInfo> selectAll();
}

单元测试

@SpringBootTest
class UserMapperTest {@Autowiredprivate UserMapper userInfoMapper;@Testvoid selectAll() {List<UserInfo> userInfoList = userInfoMapper.selectAll();System.out.println(userInfoList);//  userInfoMapper.selectAll().stream().forEach(x-> System.out.println(x));}
}

运⾏结果如下:

Service层

@Service
public class UserService {@Autowiredprivate UserMapper userInfoMapper;public List<UserInfo> getAllUser() {return userInfoMapper.selectAll();}
}

Contriller层

@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@RequestMapping("/getAllUser")public List<UserInfo> getAllUser(){return  userService.getAllUser();}
}

3. MyBatis的基础操作

打印⽇志

mybatis:configuration: # 配置打印 MyBatis 执行的 SQLlog-impl: org.apache.ibatis.logging.stdout.StdOutImpl

重新运⾏程序,可以看到SQL执⾏内容,以及传递参数和执⾏结果

测试前后置

测试前置

@BeforeEachvoid setUp() {System.out.println("before....");}

测试后置

@AfterEachvoid tearDown() {System.out.println("after....");}

参数传递(查)

查找单个参数的情况下:

Mapper接⼝

 @Select("SELECT * FROM `user_info` where id = #{num}")UserInfo selectById(Integer num);
//注意这里再对象这有一个的情况下可以用对象接收,如果不止一个的话用集合

测试代码:

 @Testvoid selectById() {UserInfo userInfo = userInfoMapper.selectById(4);System.out.println(userInfo);}

运行结果:

也可以通过 @Param ,设置参数的别名

  @Select("SELECT * FROM `user_info` where id = #{userId}")UserInfo selectById(@Param("userId") Integer num);

查找多个参数的情况下:

Mapper接⼝

//查找对象为多个参数的情况下@Select("SELECT * FROM `user_info` where username = #{username} and age = #{age} ")List<UserInfo> selectByNameAndAge(String username , Integer age);

测试代码:

 @Testvoid testSelectById() {List<UserInfo> userInfoList = userInfoMapper.selectByNameAndAge("wangwu",18);System.out.println(userInfoList);}

增(Insert)

Mapper接⼝

 //插入数据@Insert("insert into user_info (username, `password`, age) VALUES (#{username}, #{password}, #{age})")Integer insertUser(UserInfo userInfo);

测试代码:

@Testvoid insertUser() {UserInfo userInfo = new UserInfo();userInfo.setUsername("username3");userInfo.setPassword("password3");userInfo.setAge(4);userInfoMapper.insertUser(userInfo);}

运行结果:

返回主键

Insert 语句默认返回的是受影响的⾏数

但有些情况下,数据插⼊之后,还需要有后续的关联操作,需要获取到新插⼊数据的id

如果想要拿到⾃增id,需要在Mapper接⼝的⽅法上添加⼀个Options的注解

Mapper接⼝

 //插入数据@Options(useGeneratedKeys = true, keyProperty = "id")@Insert("insert into user_info (username, `password`, age) VALUES (#{username}, #{password}, #{age})")Integer insertUser(UserInfo userInfo);
//插入数据重命名的情况下@Options(useGeneratedKeys = true,keyProperty = "id")@Insert("insert into user_info (username, `password`, age)" +" VALUES (#{user.username}, #{user.password}, #{user.age})")Integer insertUser1(@Param("user") UserInfo userInfo);

测试代码:

@Testvoid insertUser() {UserInfo userInfo = new UserInfo();userInfo.setUsername("username3");userInfo.setPassword("password3");userInfo.setAge(4);Integer result = userInfoMapper.insertUser(userInfo);System.out.println("影响行数:"+ result + ", id:"+ userInfo.getId());}

运行结果:

删(Delete)

Mapper接⼝

//删除数据@Delete("DELETE from user_info WHERE id = #{id};")Integer deleteUserById(Integer id);

测试代码:

@Testvoid deleteUserById() {Integer result = userInfoMapper.deleteUserById(2);System.out.println(result);}

改(Update)

Mapper接⼝

//修改数据@Update("UPDATE user_info SET username = #{username} where id = #{id};")Integer updateById(UserInfo userInfo);

测试代码:

 @Testvoid testUpdateById() {UserInfo userInfo = new UserInfo();userInfo.setUsername("wqwwq");userInfo.setId(5);userInfoMapper.updateById(userInfo);}

4. MyBatis XML配置⽂件

配置连接字符串和MyBatis

mybatis:mapper-locations: classpath:mapper/*Mapper.xml

写持久层代码

mapper接⼝

public interface UserMapperXml {List<UserInfo> selectAll();
}

添加UserInfoXMLMapper.xml

<?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="cn.demo.demomybatis.mapper.UserMapperXml"><select id="selectAll" resultType="cn.demo.demomybatis.model.UserInfo">SELECT * FROM user_info</select></mapper>
  • id:与接口中定义的方法名称一致,表示对接口方法的具体实现。
  • resultType:指定返回的数据类型,通常是实体类的全限定名。

测试代码:

@SpringBootTest
class UserMapperXmlTest {@Autowiredprivate UserMapperXml userMapperXml;@Testvoid selectAll() {userMapperXml.selectAll().stream().forEach(x-> System.out.println(x));}
}

响应结果:

增删改查操作

增(Insert)

Mapper接⼝

 //增Integer insertUser(UserInfo userInfo);

测试代码:

@Testvoid insertUser() {UserInfo userInfo = new UserInfo();userInfo.setUsername("username3");userInfo.setPassword("password3");userInfo.setAge(4);Integer result = userMapperXml.insertUser(userInfo);System.out.println("影响行数:"+ result + ", id:"+ userInfo.getId());}

返回⾃增id

<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">insert into user_info (username, `password`, age) VALUES (#{username}, #{password}, #{age})</insert>

删改查也是用类似的方法就不具体演示

5.其他查询操作

多表查询

实体类:

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

接⼝定义:

@Mapper
public interface ArticleMapper {@Select("SELECT * FROM article_info left JOIN " +"user_info on user_info.id = article_info.uid WHERE user_info.id = 1;")ArticleInfo SelectArticle();}

测试代码:

@SpringBootTest
class ArticleMapperTest {@Autowiredprivate ArticleMapper articleMapper;@Testvoid selectArticle() {ArticleInfo articleInfo = articleMapper.SelectArticle();System.out.println(articleInfo);}
}

测试结果:

6.#{} 和${}

//查找对象只有一个的情况下@Select("SELECT * FROM `user_info` where id = #{userId}")UserInfo selectById(@Param("userId") Integer num);

运行结果:

我们发现日志中我们输出的sql语句为

 select username, `password`, age, gender, phone from user_info where id= ?

我们输⼊的参数并没有在后⾯拼接,id的值是使⽤ ? 进⾏占位. 这种SQL我们称之为"预编译SQL"

我们把 #{} 改成 ${} 再观察打印的⽇志:

可以看到,这次的参数是直接拼接在SQL语句中了,这种就是”即时SQL“

注意:String类型的参数需要添加引号’ ‘

#{} 和${}区别

性能更⾼

绝⼤多数情况下,某⼀条SQL语句可能会被反复调⽤执⾏,或者每次执⾏的时候只有个别的值不同(⽐ 如select的where⼦句值不同,update的set⼦句值不同,insert的values值不同).如果每次都需要经过上⾯的语法解析,SQL优化、SQL编译等,则效率就明显不⾏了

预编译SQL,编译⼀次之后会将编译后的SQL语句缓存起来,后⾯再次执⾏这条语句时,不会再次编译 (只是输⼊的参数不同),省去了解析优化等过程,以此来提⾼效率

更安全(防⽌SQL注⼊)

SQL注⼊:是通过操作输⼊的数据来修改事先定义好的SQL语句,以达到执⾏代码对服务器进⾏攻击的⽅法。

正常访问情况:

Mapper接⼝

@Select("SELECT * FROM `user_info` where id = '${username}'")List<UserInfo> selectByName(String username);

测试代码

 @Testvoid selectByName() {List<UserInfo> userInfoList = userInfoMapper.selectByName("lisi");System.out.println(userInfoList);}

运行结果

SQL注⼊场景:

@Testvoid selectByName() {List<UserInfo> userInfoList = userInfoMapper.selectByName("' or 1='1");System.out.println(userInfoList);}

运行结果

结果依然被正确查询出来了,其中参数or被当做了SQL语句的⼀部分,这也就发生sql注入的问题

http://www.dtcms.com/a/399879.html

相关文章:

  • [baka编程]初入C++,如何理解新概念——类和对象
  • 竞价网站做推广一款app是如何制作出来的
  • 北京建设银行网站广东官网网站建设平台
  • 淘宝客怎么在网站做推广网站每年续费费用
  • Pyside6 + QML - 多线程01 - QThread 基础(子线程执行耗时任务)
  • 农产品应该建设哪个网站屏幕分辨率 网站开发
  • 摄影作品展示网站flash全站源码山东住建部和城乡建设官网
  • 购物网站功能模块图使用div建设的网站
  • Python爬虫实战:获取上海石油天然气交易中心2025年液化天然气交易数据并做分析
  • springboot项目添加请求url及请求入参日志
  • Spring XML 配置简介
  • 阿里云虚拟主机如何上传网站国外flash网站
  • NXP - 安装后的MCUXpresso IDE里面有所有的支持包,不用另外去下载
  • 公司网站域名更改怎么做做美团旅游网站多少钱
  • 网站建设初稿wordpress 教學
  • 【nvm for windows安装问题】手动安装方案
  • 网站定制开发怎么写网站后台管理系统图片
  • 如何本地搭建网站贵阳市门户网站
  • 网站设计理念怎么写wordpress插件清理
  • 语义精炼技巧生成对抗网络(3)基于Wasserstein GAN 的特征生成
  • 3.算法——遗传算法
  • html怎么做网站版块网站空间购买官方
  • 成都建站网站软件开发涵盖网站开发吗
  • DDOS高防的优点是什么
  • 电子电气架构 --- 引导式诊断
  • 视觉大模型:Qwen-VL 技术报告解读
  • 给公司建立网站不可以做到的是素材下载网站开发文档
  • wordpress网站类型长春网页设计培训
  • 半精度浮点在AI推理中的应用:C++23新类型与性能测试
  • p-SCN-Bn-NOTA,1206475-68-4是一种双功能螯合剂用于金属离子螯合