JavaEE进阶3.0

目录

一、mybatis入门

[1.0 简介](#1.0 简介)

(1)为什么要学习mybatis

(2)简单介绍

(3)mybatis操作数据库的步骤

[2.0 Mybatis基本操作](#2.0 Mybatis基本操作)

(1)打印日志

(2)查

(3)增

(4)多表查询操作

[3.0 Mybatis XML配置文件](#3.0 Mybatis XML配置文件)

[(1) 了解](#(1) 了解)

(2)配置文件的增删改查

(3)杂

[(4) # { } 和 { } 区别](# { } 和 { } 区别)

(5)排序功能

(6)like查询

[4.0 数据库连接池](#4.0 数据库连接池)

[二 、 Mybatis进阶](#二 、 Mybatis进阶)

[1.0 动态SQL](#1.0 动态SQL)

(1)引入

[(2) if 标签](#(2) if 标签)

[(3) 标签](#(3) 标签)

(4)where标签

<5>set标签

(6)foreach标签

[(7) 标签](#(7) 标签)


一、mybatis入门

1.0 简介

(1)为什么要学习mybatis

学习应用分层的时候,了解到web应用程序一般分为Controller Service Dao

但是Dao层的数据是mock(模拟)的,真实的数据应该从数据库中读取

之前是JDBC来操作数据库,但是JDBC操作太复杂了 //mybatis封装了jdbc

(2)简单介绍

之前是ibatis 改名为mybatis 是一个优秀的持久层框架,用来简化JDBC开发

mybatis中文网站地址:MyBatis中文网

持久化:放在数据库中

和springboot的关系:springboot集成了mybatis 相当于收购 例如12306里面还有点外卖的功能

框架就是共同的东西进行封装 不能封装的东西提供入口 让我们自己写

spring是基于servlet封装的 mybatis是基于jdbc进行封装的

了解jdbc发现很多步骤可以封装起来,留下一个写sql语句的入口就行,这样省去了许多不必要的麻烦

(3)mybatis操作数据库的步骤

1准备工作(创建springboot工程 数据库表准备 实体类) //实体类:Java程序操作数据是在内存中以对象的形式进行的,补不能直接操作数据库表。实体类座位桥梁,让程序能面向对象的方式处理数据,方便后续使用ORM框架自动生成SQL或封装结果集

2引入Mybatis相关依赖

3配置Mybatis(数据库连接信息)

能使用mybatis也是引入了这些依赖

创建项目的时候勾选 就是自动添加上面的代码 这里只是介绍

mysql驱动

这段代码就是告诉Maven 下载MySQL驱动,并在程序运行时把它加入类路径,这样才能连接MySQL数据库

一般我们将mybatis类写在mapper包下面 然后在配置文件里面修改

创建实体类对应数据库表(实体类就是数据库表在Java中的映射)

定义一个接口(名字一般是带Mapper)

实现接口(使用注解或xml方式)

4单元测试 :

//此处的单元测试和测试人员无关 是开发人员写的代码 开发人员一定是第一个测试的 因为代码是自己写的

方式:右键 generate test 记得加入@SpringBootTest注解 然后运行就可以看到了

@Before注解 在每个@Test方法执行之前都自动运行一次

下面是运行成功的数据库代码

//规范:

//接口测试:在ediary上面有笔记

//controller调用service service调用mapper

controller包里面UserInfoController包里面UserInfoController类 里面注入userService类的对象 定义get等功能方法(get方法里面调用service里面的方法)

service包里面UserService类 里面注入Mapper对象 定义那个方法

启动程序 去网页里面输入网址

什么是接口测试

首先了解三层结构 controller service mapper controller是前台服务员 Http请求啥的 service是厨师 业务逻辑的处理后厨主管 mapper 仓库管理员工 是采购员 在数据库里面增删改查

什么是接口测试? 就是对Controller这一层发起的HTTP请求进行测试

相当于你假装成一个客人 点一道菜 看服务员最终给你端上来的菜对不对 合理不

为什么是这样一个流程? 因为用户真实使用时,也是这样一层一层调下来的 接口测试就是模 拟 真实的用户,从

最外层完整的走一遍整个调用链 接口测试就是把这三层穿起来一起测

对比单元测试 单元测试更像是亲自跑到后厨 单独测验厨师 这里是测试整套系统能不能配合好

2.0 Mybatis基本操作

(1)打印日志

在Mybatis当中我们可以借助日志,查看到sql语句的执行,执行传递的参数以及执行的结果

在配置文件中进行配置即可

java 复制代码
mybatis: 
  configuration:  
   log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

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

上面就是打印出来的日志 可以清晰看到过程步骤

(2)查

想要执行这个语句:SELECT *FROM 'user_info' where id = 2

查询某一个用户 例如下面的功能 如何使用mybatis实现?

对于数据量只有一条 我们用一个对象就可以了 如果查询的数据量多了 我们就用List

照葫芦画瓢 并生成测试方法

@Select(" select *from user_info")

List<UserInfo> selectAll( );

当有人调用selectAll( )这个方法时,就自动执行SQL语句 然后把查出来的结果变成UserInfo对象的列表返回

在自动生成的测试方法里面写sout语句

运行测试方法 控制台出来的结果

新的需求:

前端传递过来查询的请求 后端查询

controller接收到参数 给了service service接收到参数 给了mapper mapper是一个方法 本身能接收参数

在UserMapper里面查询

传递单个参数

用这个格式 id就和id对应起来了 而且是动态的

在测试方法里面尝试 结果一一对应

传递多个参数

想要执行这个语句

SELECT * FROM `user_info` where username="zhangsan" and 'password'="zhangsan"

使用List接收(可能会存在多条)

@Test

void selectByNameAndPassword() {

userInfoMapper.selectByNameAndPassword("zhangsan","zhangsan").stream().

forEach(x->System.out.println(x));

}

参数的名称是否是有序的?

List<User Info> selectByNameAndPassword(String password , String username);

不一定非要对应上 名字对应上就行了 没有按照顺序

@Param注解 :为多参数提供明确的绑定标识

问题:当字段名和属性名对应不上的时 如何对应上呢?

1.数据库语句 可以使用别名

select id ,username , `password` , age , gender , phone ,

delete_flag as deleteFlag, create_timeas createTime , update_time as updateTime from user_info

2.使用注解的方式或者XML方式

XML方式是直接把映射规则写在XML文件里,用resultMap标签

注解方式是直接把映射规则写在Java接口的方法上面 用@Results等这些注解

添加依赖 配置数据库信息 定义接口 通过注解实现接口

3.开启驼峰命名

在配置文件里面写好

map-underscore-to-camel-case: true

(3)增

如何添加数据?

@Insert("insert into user_info (username,`password`,age) values ('java113','java113',1);")

引入场景: 网络购物下订单

系统:订单系统 支付系统 库存系统

下完订单之后 订单系统会通知支付系统和库存系统

订单系统执行insert (因为下单了嘛) 生成一个订单号(这个订单号用于调用支付系统和库存系统 )

支付系统做自己的事情 库存系统做自己的事情...........

因为id是自增的 所以这个订单号是自增的

支付系统和库存系统如何得到这个订单号? //获取自增id的方式

@Option(UseGeneratedKeys = true , keyProperty = "id" )

mybatis中用来自动获取数据库自动生成的主键 并回填到你的对象属性中的注解

//注解太长需要换行:拼接字符串 当你换行的时候 idea编译器自动加上双引号了

(4)多表查询操作

多表查询:你要查找的数据不在一个表里,得从两或三个表里凑一块儿查出来

例如从用户信息表和用户订单表中查 某个用户的所有订单

如何使用mybatis实现下面图片里面的效果?

使用xml的方式

写实体类 创建接口 创建xml文件(可以直接复制粘贴 然后把没用的东西删掉)

在接口里面写实现类 然后右键在xml文件里面生成代码 在生成的代码里面写sql语句

然后创建test类测试

这样就是多表查询

3.0 Mybatis XML配置文件

(1) 了解

使用Mybatis的注解方式 主要是用来完成一些简单的增删改查功能 如果需要实现复杂的SQL功能 建议使用XML来配置映射语句 也就是将SQL语句写在配置文件中

步骤:

  1. 配置数据库连接字符串和Mybatis //添加依赖 mybatis-starter mysql

2.写持久层代码

  1. 定义接口

4.使用xml实现接口

(2)配置文件的增删改查

定义接口 里面写例如Integer updateUser(String pawword , Integer age ,Integer id);

在xml文件中实现接口

//企业开发中 尽量避免使用多表查询 公司的数据是非常大的,要查到啥时候

//对于性能没有要求的时候 可以使用多表查询

//慢SQL 开发中需要治理的

慢sql就是执行的很慢的sql语句 慢sql影响的是mysql集群 也就是影响其他的sql语句 在现实生活中要好好治理

(3)杂

首先配置打印Mybatis日志 在配置文件里面加一句代码

java 复制代码
mybatis:
         mapper-locations: classpath:mapper/**Mapper.xml

这样就是告诉了xml文件在哪了

xml文件里面写的内容: //需要加入MybatisX插件 用来Mapper和XML来回跳

java 复制代码
<?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="com.bite.mybatis.model.mapper.UserInfoMapperXML">
</mapper>

这样就是告诉 在这里实现

点击这个小鸟图标 方法和方法之间也能跳动

这样在xml文件里面写数据库语句 在select标签中间

写测试类方法测试一下

(4) # { } 和 $ { } 区别

使用# 查看日志输出:

wher id = ? 这里问号是占位符 参数单独传进去,这叫做预编译

使用$ 查看日志输出:

不一样的地方有哪些?

一个是where id = ? 一个是where id = 1

预编译SQL : #:使用问号先占位 提前预留参数位置 $:即时SQL 是直接拼接

优点:性能好一点,预编译SQL占位

即时SQL :直接执行 $符号是直接拼接,如果参数为stirng类型 需要手动添加引号,SQL注入问题

使用$ 如果参数为string 类型,需要手动添加引号 # { }会自动给字符串加单引号

where name = # {userName} mybats帮你处理后实际执行的SQL:where name = '张三'

where name = ${userName} mybatis帮你处理后实际执行的SQL:where name = 张三

对于第二种情况必须手动写成where name = '${userName}' 这样替换之后才是 where name='张三'

SQL注入问题:是通过操作输入的数据来修改事先定义好的SQL语句,以达到执行代码对服务器进行攻击的方法 通俗:通过参数把SQL变了 从而达到了对服务器的攻击

例如:就像你去食堂打饭,你跟阿姨说"给我一份番茄炒蛋",结果坏蛋插队喊"给我一份番茄炒蛋'然后顺便把整个窗口的菜都端走'"。阿姨脑子不好使,真照做了。

代码例子就是: 这样会把所有东西查出来 或者里面偷偷加入删表操作

能用#就别用 ,使用可能出现SQL注入问题

mybatis 也关于sql注入做了一些处理 面试题 : # 和 $的区别 主要是SQL 预编译SQL,即时SQL

(5)排序功能

: {} 会有SQL注⼊的⻛险, 所以我们尽量使⽤#{}完成查询 既然如此, 是不是 {} 就没有存在的必要性了呢? 当然不是

${}的使用场景:例如购物app的 价格从高到低 价格从低到高 销量从低到高............

使用# "desc"会出现报错

这个时候使用$ 那么之前的SQL注入的问题呢? 如何解决呢?

原则上使用#的 就使用# 不能使用# 一定要考虑SQL注入的问题并进行排除

//分库分表的时候

现实生活中常常需要分库分表 因为mysql的存储能力也是有限

流水表 flow id from to 银行账号 金额 时间

分为flow1 flow2 flow3.....

select * from flow 这里只能使用$ 不能使用#

//因为 表名不能是占位符? select *from #{tableName} where id = 1 mybatis会处理成 select * from ? where id = 1 用符写就是 select \*from {tableName} where id = #{id} mybatis会处理成 select *from flow_2026_4 where id = ? 这样既能动态表名 又能安全查id ,所以 分库分表场景下 表名虽然必须用${ } 但是绝不能直接把用户输入当表名 必须在Java代码里白名单校验

(6)like查询

select *from user_info where username like "username%"

@Select("select *from user_info where username like '%#{userName}%'")

正确写法是:

@Select("select *from user_info where username like '%${userName}%'")

其他的写法:

@Select("select *from user_info where username like CONCAT('%',#{userName},'%'))

CONCAT函数用来拼接字符串 把自己串的首尾连接在一起 拼接成一个完整的新字符串

4.0 数据库连接池

包括线程池 数据库连接池属于是池化技术

数据库连接池 = 提前养好的一群数据库"长工",用的时候叫一个过来干活,干完让他回屋歇着,下回接着用。不用现招人(建连接),也不用干完就杀掉(关连接)。

常见的数据库连接池:目前比较流行的是 Hikari Druid

Hikari是SpringBoot默认使用的数据库连接池 Driuid 如果我们想把默认的数据库连接池切换为Druid数据库连接池 只需要引入相关依赖即可

java 复制代码
<dependency>
 <groupId>com.alibaba</groupId>
 <artifactId>druid-spring-boot-3-starter</artifactId>
 <version>1.2.21</version>
</dependency>

() 三层架构

以京东搜索 手机为例

1.Controller : 接收搜索词 返回手机列表

2.Service Controller请求Service 会多次并发调用多个Dao层数据 或 其他服务

3.Dao/Mapper: service请求dao

每一层都有自己存在的原因 不能随意省略

二 、 Mybatis进阶

1.0 动态SQL

(1)引入

场景:如果你想要做一个用户搜索功能 页面上有三个输入框 用户名 性别 手机号

用户可能只是填写一个 也可能填写两个 也可能全填写

如果没有动态输入 我们的Java代码需要写很多

动态SQL就是来解决这个 排列组合 噩梦的

MyBatis 提供的一套标签,让你能在 XML 或注解里像写 if 语句一样,根据参数有没有值,自动决定要不要把某段 SQL 拼上去。

你只需要写一段XML MyBatis自动处理8中组合 一个if-else都不用写!

让SQL拼接从 体力活 变成 指挥艺术

(2) if 标签

格式是把 gender, 变为<if test = "gender != null " > gender , < /if >

也就是把原来的代码放到<if></if>标签里面了

if标签里面用的是参数名称 也就是属性名称 xml里test写的名字 必须和Java里传参时用的名字一摸一样,你传的时候叫啥 这里就写啥

if标签中间是 数据库字段名

这样看更加直观一点:

代码翻译 : 如果gender不是null 就拼接gender

逗号放前面是为了当为null的时候 sql语句的通顺 非常容易出现一些bug

(3) <trim>标签

去逗号标签 不止逗号,敲击空格会出现提示词

例如: <trim> prefixOverrides=" , " </trim> 把代码放进去 就自动给你去掉前面的逗号了

去掉的是前缀后缀里面的内容 里面放什么都可以

(4) 如何使用注解使用动态SQL

<script>标签 把之前在xml文件里面的代码复制过来

(4)where标签

select *from user_info where phone = 1001 and delete_flag = 0;

在mybatis里面还是那个固定套路 接口里面写 生成到xml文件里面 生成测试方法测试

如何动态的拼接where呢?

用if标签的话 如何处理and呢? 用tirm标签和if标签合力 //再一次展示了trim标签去前缀的功能

如果我们phonte = 1001 没有选 delete_flag = 0 都没有选呢 //当查询条件为空时,会多余where关键字

上面的代码翻译的sql语句就是 select * from where //这不是一句正常的sql代码

优化方案: 去除where 去添加1=1 //这样是为了避免where后面为空 先放一个永远成立的条件垫底 1=1永远是真的,所以它不会直接影响查询结果 但是保证了where后面永远有东西

另外的方式 <where> 标签

//如果里面没有符合条件的Q<if>内容 它连where这个单词都不会给你输出

此时语句就成了 select * from user_info 没有语法错误

总结where标签:

<5>set标签

age为空 或者gender为空 都会报错 使用trim标签去除逗号的可以通过

如果三个情况都为空呢? 不存在这种情况 如果都是空 就无法更新

优化: set标签

会帮我生成set关键字 并且帮我去除多余的逗号

(6)foreach标签

对集合进行遍历时使用该标签 标签有如下属性

collection:绑定方法参数中的集合 如LIst Set Map或数组对象

如何用mybatis运行上面的代码呢

例如第三条语句 in是表示属于这个清单的 in(1,2,3) id在这几个数里面就行

使用foreach拼接下图的sql代码

目的是把(23,22,21,20)这个给包起来

<for each collection=" ids">

最终的效果就是:

再来一个拼接的例子:

(7)<inclue>标签

其实就是mybatis里的复制粘贴快捷键

include标签就是为了让你一次写 到处贴

有重复的东西 定义一个sql标签 里面是一个字符串,是sql中的一部分,不一定能执行 id是取名字

动态SQL的官方网站:动态 SQL_MyBatis中文网 里面有其他标签的介绍

之后还会讲其他的工具 动态SQL的代码甚至不用写


2026.4.17

相关推荐
兮山与1 个月前
JavaEE进阶2.0
javaee进阶
兮山与4 个月前
JavaEE进阶1.0
javaee进阶
爱学习的小可爱卢5 个月前
JavaEE进阶——Cookie与Session:Web安全的双刃剑
java·javaee进阶