2024/10/20
通过Java程序来完成数据库的操作,(Mybatis)
持久层,即数据访问层,与数据库打交道,该框架(MyBatis)就是在持久层中操作数据库的

*引入:Mybatis
·MyBatis是一款优秀的 持久层框架,用于简化JDBC的开发。
·MyBatis本是Apache的一个开源项目iBatis,2010年这个项目由apache迁移到了google code,并且改名为MyBatis。2013年11月迁移到Github。
·官网: https://mybatis.org/mybatis-3/zh/index.html
一、Mybatis入门
(一)快速入门
1.使用Mybatis查询所有用户数据
1.准备工作:创建springboot工程、数据库表user、实体类User
(这个实体类就是用来封装用户信息的;在java中,SQL语句执行完成之后,会将结果返回给java程序,java程序就需要将这个结果封装起来,其中返回的每一条数据都会被封装为一个User对象,表中的字段会自动的封装到对应的属性里面,所以在入门程序阶段,我们需要将表中的字段名和类中的属性名保持一致,这样框架就可以完成自动封装)
(1)创建springboot工程
(2)数据库表user
(3)实体类user
*实体类:声明属性、get()和set()方法、tostring()方法、有参和无参构造
pojo.User连包带类创建:
2.引入Mybatis的相关依赖,配置Mybatis(数据库连接信息)
3.编写SQL语句(注解/XML)
(这里使用注解方式来定义)定义一个持久层接口UserMapper(在DAO层),并加上注解@Mapper
·mapper.UserMapper连包带类创建,这个包类似于三层架构中的DAO包
·首先在接口上加上一个注解@Mapper,代表当前是Mybatis当中的一个Mapper接口,此时在程序运行的时候,框架会自动生成该接口的实现类对象(SE中学的动态代理技术所生成的一个代理对象),并且会将该对象交给IOC容器管理
·接下来定义方法,来查询所有用户对象,用户的信息很多,每一条信息都会被封装为一个用户对象,多条记录封装在List集合当中,集合的泛型是User对象,再定义一个方法名list()
·在方法上加一个注解@Select,指明当下要完成的是一个查询操作,在注解的value属性中,指定要执行的SQL语句
要想执行这条SQL语句,只需要调用UsrMapper接口中的list()方法,框架就会自动执行这条SQL语句,并自动将返回的结果封装到方法的返回值当中
*注:
·在Mybatis开发中,我们只需要定义这个Mapper接口,不需要定义它的实现类,因为在程序运行时,框架底层会自动生产这个接口的实现类对象
·User报错,记得导包,如截图第二条导入代码所示
·若Mapper标红,可能是没有导入maven,如下查看:
4.测试
通过依赖注入的方式,用这个bean对象,在测试类上面声明一个UserMapper这个类型的对象,然后在上面加上一个注解@Autowired完成依赖注入,接下来就可以调用userMapper中list()方法来查询所有用户信息,获取返回值,并遍历输出
·这个单元测试springboot整合的单元测试,上面加了一个注解@SpringBootTest,一旦加了这个注解,那么其中的单元测试方法在运行的时候就会自动加载整个springboot的环境并且创建springboot的IOC容器,容器创建好之后,就可以通过依赖注入的形式从IOC容器当中获取UserMapper这个类型的bean对象,接下来就可以调用这个bean对象中的list()方法来查看所有用户信息
5.配置SQL语句提示
*注:要选中语句之后在进行配置:
*中文版设置提示方法:打开设置中的“语言和框架”选择“sql方言” 将全局方言和项目方言都设置为“mysql”即可
(二)JDBC介绍
1.JDBC
(Java DataBase Connectivity),就是使用java语言操作关系型数据库的API
*java通过JDBC提供的API来操作关系型数据库,JDBC仅仅是一套规范,一套接口而已,并没有提供具体的实现,而是由各个数据库厂商提供这些实现。总结 java提供了一些接口 各个数据库厂商去实现这些接口。我们要对数据库进行操作 只需要调用这些接口。
*我们最终在编写java程序的时候,直接使用面向接口编程,使用JDBC当中所提供的接口来操作就可以,最终通过我们引入进来的各个数据库厂商提供的JDBC的实现,来操作对应的数据库,各个厂商提供的JDBC规范的实现又称为数据库的驱动,例如入门程序中引入的mysql的驱动:
这个就是mysql厂商提供的JDBC的实现
2.本质
·sun公司官方定义的一套操作所有关系型数据库的规范,即接口
·各个数据库厂商去实现这套接口,提供数据库驱动jar包
·我们在java程序中使用JDBC,我们将采用面向接口的方式进行编程,我们使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类
3.演示
原始的JDBC程序操作数据库:
注册驱动,获取连接,获取预编译对象,执行SQL,封装结果集,关闭连接。
·弊端:
vs Mybatis:
spring.datasource:数据源
使用springboot整合Mybatis进行数据库操作时,主要关注两点:
·Mybatis的相关配置
·mapper接口 以及 定义的SQL语句
(三)数据库连接池
掌握:什么是数据库连接池、作用、如何切换不同的连接池产品
*类似于之前学的线程池,他也是一个容器,而这个容器存储的是一个一个数据库连接对象connection
1.介绍
·数据库是个容器,负责分配、管理数据库连接对象(Connection)
——资源重用,具有复用性
·允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个
——提升系统响应速度
·释放空闲时间超过最大空闲时间的连接,来避免因为没有释放连接而引起的数据库连接遗漏
——避免数据库连接遗漏
*数据库连接池简化JDBC的操作
2.接口
*所有的数据库连接池都要去实现这个标准的接口,并实现其中一个核心的功能方法
·标准接口:DataSource
·为实现数据库连接池,sun公司提供了一个标准的数据库连接池的接口,由第三方组织实现此接口
·功能:获取连接
Connection getConnection() throws SQLException;
数据库连接池不需要我们去实现,市面上有许多连接池技术:
C3P0、DBCP、Druid、Hikari
·在入门程序中,没有指定连接池,默认使用的是Hikari这个连接池这是springboot中自带的连接池
·其次,常用的数据库连接池是Druid:
Druid:(德鲁伊)
·Druid连接池是阿里巴巴开源的数据库连接池项目
·druid防sql注入,防御性高,功能多,hikari性能好,速度快
3.切换连接池Druid
官方地址:druid/druid-spring-boot-starter at master · alibaba/druid
·首先引入德鲁伊连接池的依赖
·其次配置连接信息
如下:
配置连接信息也可以写成:
(四)lombok
*问题分析:
入门程序中,显而易见,实体类中虽然只有5个属性,但是需要提供许多方法与构造,十分臃肿
-->引入lombok技术,直接引入注解即可
1.介绍
·LomBok是一个实用库的Java类库,能通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法,并可以自动生成日志变量,简化java开发、提高效率
·原理:
在编译时期,根据对应的注解生成对应的方法
2.使用
要想使用LomBok,首先引入其依赖:
在加入这项依赖的时候,不用指定version版本号,因为在springboot的父工程中,已经集成了lombok,已经将lombok的依赖版本统一进行了管理。
*注:初始化项目的时候,使用的URL是阿里云版的。官网的是采用继承的parent标签。阿里云是直接通过引用依赖,所以看不到parent标签(也就是父工程)。修改URL:http://start.spring.io/ 即可;或可以手动加入<parent>标签:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0</version>
<relativePath/>
</parent>
*注解的本质还是接口,所以还是面向接口编程
修改如下:
注解一键生成指路:
idea插件1秒生成get set方法(一图流)_ptg插件-优快云博客
*注:
LomBok会在编译时,自动生成对应的java代码。我们使用lombok时,还需要安装一个lombok的插件(idea自带)
二、Mybatis基础操作
通过mybatis来完成表结构中数据的增、删、改、查操作
案例:员工信息的增、删、改、查操作
*在查询中:
·根据主键ID查询:用于修改数据的时候,页面数据的回显(点击编辑按钮,首先查询到该数据,然后在表单中显示出来,展示出来之后,就可以在原有的数据基础之上来修改数据)
·条件查询:根据目标条件查询,并对查询的结果进行分页展示
1.环境准备
1.准备数据库表emp(员工表)
2.创建一个新的springboot工程,选择引入对应的起步依赖(mybatis、mysql驱动、lombok)
最终查看pom文件中引入的依赖:
mybatis的起步依赖、mysql驱动包、lombok、springboot进行单元测试的依赖
3.application.properties配置文件中引入数据库连接信息(即数据库连接四要素)
4.创建对应的实体类Emp(实体类属性采用驼峰命名)。实体类中的属性与表中的字段一一对应的
以下注意:
5.准备Mapper接口EmpMapper
*注:
·中文乱码点File->Setting->Editor->File Ecodeing 将三个属性都设置utf-8即可
2.删除
(1)根据主键删除
*介绍:点击删除操作,前端向服务端发送请求,然后将这条数据删除,而数据库在删除这条记录的时候,要告诉数据库删除的是哪一条记录,是需要这条记录的唯一标识的,所以在发送请求时,前端会将这条记录对应的唯一标识传递过来,这个唯一标识就是这条数据的主键id
示例图:
要求 动态 的删除某条数据:
我们在调用这条SQL语句的时候,动态的将这个id值传递进来,而什么时候会调用这条SQL语句——就是调用这个接口方法的时候。
·我们只需要在调用这个接口方法的时候,给这个接口方法传递一个参数,这个参数就是这个id,然后SQL语句在执行时,将这个参数传递进来即可
·加上参数之后,我们需要将这个id变成动态的,就需要在SQL语句当中获取这个方法在调用的时候传递进来的参数,如何动态获取——用到Mybatis当中提供的一个参数占位符,#{},大括号中写入的就是参数的名字
接口方法改写如下:
*注:
·delete语句在执行时是有返回值的,只不过目前不需要,设置成了void;如果有返回值,其返回值代表此次操作影响的记录数,将void改成int即可:
测试中:在控制台可看到数据
*问题:返回值为0是因为测试托管给maven,每次执行测试的时候,maven会先执行一遍,导致idea中又执行了一遍,而控制台输出的是idea执行的结果,在设置中把maven里的skip tests勾选就好了
对比在void的情况下test:
·如果mapper接口方法形参只有一个普通类型的参数,#{}里面的属性名可以随便写,如#{id}、#{value},因为这个方法传递进来的只有这一个参数,这个参数最终只能赋值给这个占位符
·找不到包:设置-构建-构建工具-Maven-运行程序-勾选委托给Maven
*问题:
·注释乱码可以打开设置->编辑器->文件编码,把三个地方的编码格式都改成utf-8,勾上自动转换成Ascii
(2)日志输出
*引入:根据主键删除员工信息操作中,可以看到在表结果中的数据被删除,但是mybatis这个框架底层到底执行了什么样的SQL语句,执行的结果是什么样,并不能直观看到,而在mybatis框架中,我们可以借助mybatis的日志来看到这些信息,而这些日志默认关闭。
1.根据入门程序实例
·可以在application.properties中,来打开mybatis的日志,并指定输出到控制台
*不用记配置项,因为未来会有很多,只需要记住关键字即可,会给出自动提示,此刻我们要看的是log,(网上搜也行)如:
·然后选择StdOutImpl,代表我们往控制台中输出日志:
·查看结果:
‘?’是一个参数占位符,最终SQL语句在运行的时候,会使用下面的参数‘16’来替换上面的参数(防注入),然后删除id为16的员工信息。
对于这条SQL语句有个专业名词:
2.预编译SQL
——优势:
——性能更高(就相当于如果太具体了每一次都要重新过一次但是如果像预编译那样就可以复用第一句)
*其中,编译就是将SQL语句编译成一些可执行的函数
——更安全(防止SQL注入)
3.SQL注入
·SQL注入是通过操作输入的数据来修改事先定义好的SQL语句,以达到执行代码对服务器进行攻击的方法
*可以登录,后面恒为真
密码部分:' or '1' = '1'
·通过预编译SQL的形式解决这个问题
从结果可知,在密码部分,不管输入怎样的字符串,他都会把整个字符串作为一个参数,传递给password,这样就避免了SQL注入这个问题
*总结,通过预编译的SQL可以防止SQL注入
·这里,我们选择mybatis的框架,应该选择怎样的预编译SQL——实际上,我们只需要在定义SQL语句时,使用 #{} 这个占位符,最终生成的就是预编译SQL语句:
mybatis还有其他的参数占位符:
对于#符号:
对于$符号:
直接将参数拼接在了SQL语句中,一旦拼接,那就不是预编译的SQL,性能低,且存在SQL注入问题
*注:
·另外:密码不要明文存储在数据库中,要进行加密后存储,登录时再加密比对,这样就算用拼接sql注入也没用
3.插入
(1)新增功能开发
*密码字段是有默认值的,在如上界面中录入员工信息的时候,并没有录入密码字段,因此也不需要插入。注意这里的password添加了default默认值为123456
同样,要将数据换成的动态的,由于参数多,在方法形参中声明每个参数,并一个个传递进来不利于维护,因此将多个参数封装到一个 对象 中,在调用insert()方法时就不用传递多个参数,只需要传递这一个对象即可;
这个对象可以选择Emp员工对象,即整个类。如下新增员工的接口方法:
(首先应该先写出SQL语句,再考虑在mybatis中应该怎么执行这条SQL语句——只需要定义这样一个接口方法,在接口方法上加上一个对应的注解,然后在注解的value属性中,来指定要执行的SQL语句。*属性名都是用驼峰命名的,不用写成字段名)
·测试:
我们只需要调用EmpMapper中的insert方法,然后里面传递一个员工对象,然后再为这个员工对象当中的各个属性进行赋值操作,就可以在最终执行insert方法时就会执行insert语句,在执行insert语句时,他就会自动的去获取emp对象中的各个属性值,从而完成数据插入操作
在测试类中,首先构造emp员工对象,然后再执行新增员工信息操作:
查看面板:
*注:
·查看emp表,添加Tom成功
(自增字段在设计上是为了确保主键的唯一性,一旦一个值被分配,即使该值对应的记录被删除,这个值也不会被再次使用。16和17已被作为例子在之前的测试中删除。)
·报错但是添加成功的可能是idea执行了两次,去setting里的runner勾上skip tests
·如果插入了但是报错的话,设置>构建,执行,部署>构建工具>maven>将IDE构建交给maven的√去掉就行
(2)主键返回
1.描述
在数据添加成功后,需要获取该插入数据库数据的主键值
(如:添加套餐数据时,还需要维护菜品关系表数据):
在该界面中,需要录入1.套餐的基本信息、2.套餐与菜品的关联信息
·套餐与菜品的关联信息就是往中间表中插入数据(套餐与菜品是多对多的关系),来维护他们之间的关系,中间表中,有两个外键字段,一个是菜品的id,另一个是套餐的id,套餐的id是指此次我所添加的这个套餐的id。因此在第一步保存完当前的套餐信息之后,需要将套餐的主键值返回回来,然后供第二步进行使用,这个时候就需要使用到主键返回功能
2.实现
·在之前我们所写的代码测试如下,返回值为null——没有拿到主键值(默认执行基础操作时不会返回主键值):
此时,在方法上加上注解@Options,并声明两个属性:
·useGeneratedKeys = true——代表我们需要拿到生成的主键值
·keyProperty = "id"——代表我们所获取到的主键最终会封装到emp对象的id属性中
此时:
4.,更新(修改)
*案例需求:点击 ‘编辑’ 按钮后,就会根据当前这条记录的主键id来查找这一条数据,并将该记录回显展示出来,然后就可以在原有数据基础上,对员工信息进行修改,然后点击 ‘保存’ 按钮,就会将这个表单的数据提交到服务端,最终再来修改表中的这些字段——回显、修改、更新
(1)查询——(本目录第五个查看)
(2)修改数据
1.首先写好SQL语句
2.基于mybatis完成更新操作
在Mapper接口中,定义一个接口方法:
测试:
结果:
*注:
·username值不能重复,因为是唯一值,否则会报错;相同数据重复添加会报错。报错可以试试把emp表的username的键和索引都删除
·id获取:id从前端页面提交获取
·改不了密码:这是管理员工的,密码要员工自己改
5.查询
(1)根据id查询
(1)首先写出SQL语句
(2)mybatis的实现:根据id去查询员工
*增删改 的返回值都是void,而查询是有返回值的——要将查询返回的那条数据封装起来;在入门程序中,查询返回的所有的数据我们是拿类似的集合来封装的,集合里面的泛型是User对象;
而此时返回一条记录就没必要封装到一个集合中,而是封装在一个员工对象中,然后在后面指定一个方法名getById(),代表根据id来查询,同样,要动态的传递数据:
测试:
结果:
·注:
后面三个值为null,这三个字段没有被封装进来,但在数据表结构中是有值的:
为什么没有封装?:
(2)数据封装
*(有测试人说明:新版IDEA名字不一样能自动封装)
1.实体类属性名 和 数据库表查询返回的字段名一致,mybatis会自动封装
2.如果实体类属性名 和 数据库表查询返回的字段名不一致,不会自动封装
*他们的名字不同Java中是驼峰命名数据库中是下划线,所以查询出来为null
1.方案一
给字段起别名,让别名与实体类属性一致:
2.方案二(不常用)
通过@Results,@Result注解手动映射封装
一个@Result注解就来映射一个字段和属性,在@Result注解中,指定两个属性column——表中的字段名,property——类中的属性名
3.方案三(推荐)
开启mybatis的驼峰命名自动映射开关——a_column——>aColumn
在application.properties中:
因此,放开原代码即可:
结果显示封装
*注:
·报错的看一下自己的update注解有没有删掉,一个方法上面不能有两个注解
·插入语句中数据直接插入预编译的SQL语句中,要的是数据 不管字段跟对象的实体属性匹不匹配
·数据库不区分大小写,在数据库用不了驼峰,如果你Java用了驼峰就映射不上
·配置文件注释乱码的去设置把编码格式全部设置为UTF-8
·*的查询效率低下,不提倡使用
·实际开发就是用xml文件来操作sql
·推荐一个插件,tabnine,一个tab键自动补全所有字段的映射代码
·使用mybatis-plus
(3)员工信息的列表条件查询
根据如下三条件查询:
1.SQL语句
根据页面原型,此处为模糊搜索:
*注:
·‘%’ 代表任意一个字符
·页面原型中,分页查询暂时不考虑实现
2.mapper接口方法
·可能产生多条数据——封装在集合中,集合里面的泛型就是Emp这个员工对象,并定义一个方法list()
·把这四个参数挨个传递进来。(若把这四个参数封装到一个对象中,比较麻烦,因为Emp中只有一个入职时间entrydate,而传递进来的既有入职时间的开始时间又有结束时间,这是一个范围,没办法封装两个时间)
·首先在这个方法中指定形参,为了动态传入数据,此时不能够使用#{},因为‘?’不能在引号内,应改为${}——$是字符串拼接符号,不会生成预编译的SQL,他会直接将传递过来的 ‘张’和两个字符串进行拼接 :
3.测试
4.问题
·提出:使用${},不是预编译的SQL,性能低、不安全、存在SQL注入问题
·解决:使用mysql提供的函数concat
该函数可以传入多个字符串,他将多个字符串拼接成一个字符串,例如:
于是解决示例问题:
测试:
*注:
·‘?’不能在引号内,可以把问号看成一个参数,如果参数出现在引号里,就变成字符了,无法继续传参
·查询不出来可能是因为中文的编码不一样,把你编译器的编码类型改成UTF8就行了
·若不用concat函数连接字符串,而用‘+’号,可能导致SQL注入或报错问题
·参数名说明:
*单独使用mybatis是指,不是基于springboot下
在下面这种情况,在对mapper接口进行编译时,他并不会保留方法的形参名称——name、gender、begin、end不会在编译后的字节码文件中保留,而是如下图所示(字节码文件):
此时#{name}去获取参数值时,不知道获取哪个参数,对应不起来,因此额外加上@Param注解来指定获取的是哪个参数
*据了解,3版本也是如此情况
三、XML映射文件
*上一章基于注解的方式完成了一套mybatis基础的增删改查操作,接下来讲解在入门程序中提到的mybatis中配置SQL语句的第二种方式——xml配置文件,通过xml配置文件的形式来配置SQL语句,在mybatis中也称为xml映射文件
*简单的业务逻辑,可以使用注解,有些需要动态sql,xml的可读性会更高;xml不如注解方便,注解本质也是xml
*知道如何在mybatis中如何定义一份xml映射文件
(一)规范
1.XML映射文件的名称要与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同包下(同包同名)(可以配置不在一个同名目录下)
包名都是com,itheima,mapper:
2.XML映射文件的namespace属性为Mapper接口全限定名一致
3.XML映射文件中SQL语句的id与Mapper接口中的方法名一致,并保持返回类型一致
*这个方法可以不用动源码而改变sql语句
(二)示例
1.定义xml映射文件
1.无package,选择目录,创建时用‘/’,而不是‘.’
错误:
正确:
2.创建文件
(1)文件名应与需要与mapper接口名字完全一致
在xml配置文件中都应该有约束——是固定的,不用去记忆,拷贝官方文档即可
(2)在xml配置文件中,有一个根标签——<mapper>,然后在里面选择配置怎样的SQL语句(增删改查)
2.xml配置文件的基本结构定义已好
·在<mapper>标签中,有一个唯一的属性——namespace命名空间,namespace属性需要与Mapper接口全类名一致
·获取全类名:
结果图:
3.定义SQL语句
利用xml的形式,实现条件查询员工的功能应该怎么配置:
·首先在接口中定义一个方法
·在xml配置文件中定义一对标签<select>,再把SQL语句粘贴进来
·(规范3)XML映射文件中SQL语句的id与Mapper接口中的方法名一致,并保持返回类型一致
*(这一块我们指定返回的单条记录封装的类型是Emp,与接口中所指定的类型一致),:
*这样这条SQL语句就配置好了
·resultType:单条记录所封装的类型——解释:整个查询的结果已经封装在集合中了,那单条记录所封装的类型就是Emp员工对象:
因此,resultType中需要配置的就是单条记录所封装的类型的全限定类名:
4.测试
结果:
*注:
·未配置sql方言解决办法:代码行右上角点感叹号,右键控制台位置显示的错误信息,将方言部分改为mySQL
·Invalid bound statement (not found)的你要保持resources下的com.xxx.mapper目录和java目录下的com.xxx.mapper目录名称一致
·如果报错(不允许有匹配 "[xX][mM][lL]")那就是xml文件顶格不能有空行
·记得把@Select注解注释掉
5.小结
*思考:在定义xml映射文件的时候为什么要遵守三条规范——通过mybatis这个框架来操作数据库,最终我们只需要调用mapper接口中的这个方法(list())就可以完成数据库操作,但是最终我们操作数据库并不是直接通过这个方法来操作的数据库,而是执行了与这个方法对应的SQL语句来完成数据库的操作
·所以现在的关键点在于通过这个接口当中类似的方法怎么找到与之关联的SQL语句——而在之前使用注解的方式在进行配置时不会存在这个问题——因为我们在执行这个接口方法,最终就是在执行这个SQL语句,如下(是绑定在一起的):
而如上面的(3.定义SQL语句可知),接口方法的定义与 xml配置文件中的SQL语句是分开的
·根据接口的方法,来找到对应的SQL语句——因此,我们按照三点规范定义xml配置文件之后,此时我们在调用EmpMapper这个接口中的list()方法时,mybatis框架就会自动的去查找namespace属性值与这个接口全类名相同的这份xml映射文件,并且在这份xml映射文件中找到id属性值与方法名相同的这条SQL语句,最终来运行这条SQL语句,从而就完成了数据库的操作——mybatis框架根据该思路定位到调用这个方法最终要执行的是哪一条SQL语句:
·关于这两种配置方法,在官网也有声明:mybatis – MyBatis 3 | 入门
6.MybatisX
Mybatis是一款基于IDEA的快速开发Mybatis的插件,为效率而生
·点击小鸟可以定位到方法对应的SQL语句,反正也可
·IDEA的误报:
若在当前工程中,我们有多个模块(多在学习阶段出现),小鸟可能关联到了其他模块同名字(Emp)的类里面这是一个IDEA语法检测的问题,代码是没有问题的——将另一个模块移除即可
四、Mybatis动态SQL
随着用户的输入或外部条件的变化而变化的SQL语句,称为动态SQL
在该员工查询表中,不想指定每个值:
在原有的代码上改,并不能实现想要的查询效果,如下,查询不到数据:
·因此,对于这种SQL语句,我们需要根据输入的条件动态来组装——可以通过动态SQL解决
·mybatis中,提供了一个动态SQL的标签——if,if就是用来作条件判断的,只有条件成立才会拼接这个SQL语句,不成立就不会拼接,如:
·我们学习动态SQL,就是学习动态SQL中的标签
(一)<if>
1.<if>
·作条件判断。使用test属性进行条件判断,若条件为true,则拼接
*首先 ctrl + alt + L 将SQL语句格式化,然后改写:
测试成功:
测试2:
2.引入<where>
<where>:where元素只会在子元素有内容的情况下才插入where子句。而且会自动去除子句的开头的AND或OR
问题:
·当只查询性别为男时,报错——SQL语句中,‘and’的错误——多余了,但是不能删
·因此,动态SQL为我们提供了一个标签——<where>,来替代where这个关键字的
·使用where标签将所有的查询条件包裹起来——作用:1.(动态生成where关键字)根据里面的这些子标签动态的判断里面的条件,若所有条件不成立,就不会生成where这个关键字,若有一个条件成立,就会生成where关键字;2.(自动去除的去除条件前面多余的‘and’或者‘or’):
测试成功:
测试2:将四个条件全设为null:
此时没有where关键字了
3.<if>案例
*完善更新员工功能,修改为动态更新员工数据信息,需求:
1.问题
在测试中直接修改时:
结果为,但是后面的值变成了null:
没有进行赋值的属性,都将被默认初始化,所以是null;发现问题——之前开发的更新员工信息功能并不灵活,如下:
2.需求
根据需求,解决问题:
·动态更新员工信息,如果更新时传递信息,则更新;如果更新时没有传递值,则不更新——动态SQL
·在xml映射文件中定义SQL语句,并指定为update2(若安装了mabatisX,就不用手动进行,直接alt + 回车,右键点击Generate statement,直接回车:)
在xml映射文件中可以看到生成了一个标签:
这个update2就是这个方法名(根据规范3:XML映射文件中SQL语句的id与Mapper接口中的方法名一致,并保持返回类型一致)
·然后在该标签中声明SQL语句,并格式化:
·修改为动态:
*注:要让xml的if语句里面的test后面的与实体类名字相同!不要与数据库相同
(1)问题
该实现无法进行,在SQL语句可以看到,where前面有一个逗号,错误写法
在我们写的动态更新的xml文件中,<if>前面的那个逗号——当只改变username这个值时,下面的不实现,那么就会多这个逗号,若删除逗号,下面的条件成立时,两个字段间又少一个逗号——在mybatis的动态SQL当中,提供了一个标签——<set>
(2)引入<set>
·动态地在行首插入SET关键字,并会删掉额外的逗号(用在update语句中)
用来替换set关键字——作用:1.set标签可以将所有的更新字段进行包裹;2.自动去除字段之后多余的逗号
修改如下:
测试成功:
*注:
·补充,可以使用<trim suffixOverrides=",">
·数据回显,每一次修改都会保留数据,点击修改之后,原来的数据还存在;例如,你修改个人信息,它会把你当前的信息给展示出来,这就是数据回显
·依赖前端传的数据是不安全的,别人知道服务端接口后就可以由此直接攻击服务端;一个合格的服务端,必须保证无论什么数据传过来,你都可以处理(返回/过滤/拦截)
(二)<foreach>
*根据需求引入
需求:在员工管理的页面原型中,有一个功能是批量删除:
点击后,就可以将选中的主键id发送给服务端,服务端就可以直接将这几条记录删除
1.编写SQL语句
2.基于mybatis完成
·一般使用数组或集合封装,这里使用List集合,泛型类型就是这个id的类型——Integer,然后指定方法形参名称——构建delete标签,将deleteById,alt + 回车---> Generate statement + 回车 + 回车:
·但是这三个id是固定死的,他们是封装在ids集合中传递进来的,接下来就要遍历这个集合,拿到每一个元素,再来拼接这条SQL语句
·标签<foreach>进行循环遍历操作——属性1:connection,遍历的集合,属性2:item,遍历出来的元素,属性3:separator,每次遍历出来的元素在拼接时用声明分隔,属性4:open,遍历开始前拼接的SQL片段,属性5:close,遍历结束后拼接的SQL片段:
·#{id}代表每一次遍历出来的元素
*有说把ids换成list,不然会报错,Java 编译器会擦除泛型信息,导致在运行时无法获取参数的具体类型和名称。具体指路:[已解决]报错:Parameter ‘ids‘ not found. Available parameters are [arg0, collection, list]_parameter 'ids' not found. available parameters ar-优快云博客
3.测试
该测试方法中,基于Arrays这个工具类,构造了这样一个asList集合,里面封装了三个元素:
结果返回:
(三)<sql> <include>
1.问题分析
在该xmlyswj中,配置了两条SQL——动态条件查询、根据id查询员工信息
·SQL语句重复,代码复用性差——在java中,解决方法是,定义一个方法,然后将这部分的代码封装在这个方法中,哪里需要就调用该方法——在mybatis的动态SQL同理——利用<sql> <include>标签解决
2.改写
·<sql>:定义可重用的SQL片段
负责抽取这个sql片段,抽取时,需要给该sql片段分配一个唯一标识,也就是定义一个id属性
·<include>:通过属性refid,指定包含的sql片段
负责在原来抽取的这个位置,将这个sql片段引用过来;通过reid这个属性来指定引入的哪一个sql片段
3.测试
测试成功,前面的这部分sql语句依然是已经拼接上了
*注:
·NoSuchMethod问题有可能是你的破解脚本路径有中文 或者你文件路径有空格 改了就行