MyBatis 操作数据库 - 2

目录

解决数据库字段和Java对象属性不同

起别名

结果映射

开启驼峰命名

MyBatis XML 配置文件

配置连接字符串和 MyBatis

写持久层代码

添加 mapper 接口

添加 UserInfoXmlMapper.xml

增删改查操作

增(Insert)

删(Delete)

改(Update)

查(Select)

多表查询

#{} 和 ${}

Integer 类型的参数

String 类型的参数

区别

排序功能

like 模糊查询

数据库连接池

使用

总结

MySQL 规范

#{} 和 ${} 区别

动态 SQL

if 标签

​编辑

trim 标签

where 标签

set 标签

foreach 标签

include 标签

完!


上篇文章中,对 MyBatis 操作数据库的基本知识,我们有了一些了解。

这篇文章,由增删改查中的 “查” 引出。

当我们执行 SQL 语句:select * from user_info

返回的结果中,有一些属性并未成功获取到值

进行观察,发现,如果数据库字段和 Java 对象属性一致,就会自动赋值,如果数据库字段中,出现下划线,而 Java 对象属性中用驼峰转换了,就会出现无法赋值的情况:

解决数据库字段和Java对象属性不同

解决办法:

1. 起别名

2. 结果映射

3. 开启驼峰命名

起别名

在 SQL 语句中,给列名起别名,保持别名和实体类属性名一样

结果映射

如果其他 SQL 语句,也希望可以复用这个映射关系,则可以给这个 Results 定义一个名称。

使用 Rsults 中的 id 属性来给 Results 定义别名,再使用 @ResultMap 注解来复用其他定义的 ResultMap

开启驼峰命名

我们可以直接在配置信息中配置,自动按照规范,将数据库使用的蛇形命名法,转换为 Java 属性规范遵循的驼峰命名法~~

然后 Java 代码中不需要做任何处理,就可以正常获得值了

MyBatis XML 配置文件

上面学习了注解的方式来使用 MyBatis 进行开发,还可以使用 XML 的方式来对 MyBatis 来进行开发。

配置连接字符串和 MyBatis

写持久层代码

1. 方法定义 Interface

2. 方法实现:XXX.xml

添加 mapper 接口

添加 UserInfoXmlMapper.xml

因为我们在配置文件中配置了路径,在 resources 下的 mapper 中的 **Mapper.xml

所以需要在 resources 下创建 mapper 文件夹,在 mapper 文件夹,创建名为 **Mapper.xml,** 表示多位模糊匹配~

UserInfoXmlMapper.xml 中,有 MyBatis 的固定 xml 格式:

在 <mapper> 双标签中实现查询所有用户的具体实现。

标签说明:

        <mapper>:需要指定 namespace 属性,值为 mapper 接口的全限定名。

        <select> 查询标签:用来执行数据库查询操作

                id:是和 Interface 中定义的方法名称一样的,表示对接口的具体方法实现。

                resultType:表示返回的数据类型,也就是我们最初在 model 包中定义的实体类~

进行单元测试发现符合预期~

增删改查操作

接下来,我们使用 XML 形式的 MyBatis 来实现用户的增删改查操作

增(Insert)

删(Delete)

改(Update)

查(Select)

在 xml 中,同样也存在数据封装问题。当数据库字段和 Java 对象属性不一致的时候,无法直接赋值。

解决办法和注解类似:

起别名,结果映射,开启驼峰命名

起别名就是在 sql 语句中进行操作即可,这里不做详解。

开启驼峰命名更加简单,在配置文件中配置即可,这里也不做详解。

我们学习在 xml 中写结果映射

注意,使用结果映射,select 标签中的属性为 resultMap,如果不使用结果映射,属性应该是 resultType

多表查询

再创建一张文章表,进行多表关联查询

-- 创建文章表
DROP TABLE IF EXISTS articleinfo;

CREATE TABLE articleinfo (
    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 articleinfo ( title, content, uid ) VALUES ( 'Java', 'Java正文', 1 );

对应 model:

sql 语句:

对 sql 语句的解释:

因为查询的语句涉及到了 UserInfo 中的属性,进行 model 补充:

接口定义:

#{} 和 ${}

Integer 类型的参数

我们输入的参数,并没有在后面拼接,id 的值使用 ?来进行占位。这种 SQL 我们称之为 “预编译 SQL”

把 #{ } 修改为 ${ } 再观察日志:

可以看到,我们的参数直接拼接在 SQL 语句中了

String 类型的参数

使用 #{} 接收参数

使用 ${} 接收参数

可以通过日志看到,此时的参数,是直接拼接到 SQL 语句中了,但是字符串作为参数的时候,需要添加引号 ‘ ’,当我们使用 ${} 的时候,不拼接 ‘ ’ ,会导致程序发生报错。

我们可以手动在 ${} 中添加引号

可以观察:

#{ } 使用的是预编译 SQL,通过 ? 占位的方式,提前对 SQL 语句进行了编译,将参数直接填充到 SQL 语句中,#{ } 会根据参数类型,自动拼接引号 ‘ ’

${ } 会直接字符替换,一起对 SQL 语句进行编译,如果参数为字符串,需要加上引号~

区别

两者一个是预编译 SQL,一个是即时 SQL。

当客户发送一条 SQL 语句给服务器后,大致会有如下流程:

1. 解析语法语义,校验 SQL 语句是否正确

2. 优化 SQL 语句,制定执行计划

3. 执行并返回结果

如果一条 SQL 语句经过如上流程的处理,我们就称之为 即时 SQL

预编译 SQL 语句的好处:

1. 性能更高

大部分情况下,某一条 SQL 语句可能会被重复的反复调用,或者每次执行的时候,只有个别的值不同(例如:select 中的 where 的 id 不同,update 的 set 字句不同...)如果每次都经过上面三个流程,进行语法语义解析,优化语句,则会降低效率。

预编译 SQL 语句,编译一次之后,会将编译后的 SQL 语句缓存起来,当后面再次执行这条语句的时候(如果只是参数不同),不会再进行编译,省去了解析优化过程,提高效率。

2. 更安全(防止 SQL 注入)

SQL 注入:在学习 JDBC 的时候,我们有所了解,是通过操作输入的数据,来将预先定义好的 SQL 语句进行修改,以达到执行代码对服务器进行攻击的方法。

sql 注入代码: ' or 1 = ' 1

正常情况:

SQL 注入:

排序功能

上面的区别中,我们将了 #{} 的好处,即也是 ${} 的缺点,会有 SQL 注入的风险。所以绝大部分情况下,我们尽量使用 #{} 完成 SQL 语句

但 ${} 存在,即有其合理性。

当我们要操作数据库,完成对数据的排序功能:

这时候,就需要使用 ${ } 来实现排序查询了,如果使用 #{ } 会当作参数,无法实现。

like 模糊查询

SQL 语句使用 like 进行模糊查询的时候,使用 #{} 会报错

可以将  #{} 改为 ${} 查询,但 ${} 存在 SQL 注入的问题,所以还不能直接使用 ${} 。

我们可以使用 mysql 的内置函数 concat()来进行处理。

数据库连接池

在 MyBatis 中,我们使用了数据库连接池的技术,避免了频繁的创建,销毁连接造成的性能消耗。

数据库连接池,分则分配,管理,释放数据库连接,允许程序对某一个现有的数据库来重复使用,而不是多次新建数据库连接。

使用数据库连接池的情况:程序启动时,会在数据库连接池中创建一定数量的 Connection 对象,当客户请求数据库连接池,会从数据库连接池中获取 Connecttion 对象,然后执行 SQL,SQL 语句执行完毕之后,再把 Connection 对象归还给数据库连接池,

使用

常见的数据库连接池:C3P0 DBCP Druid Hikari

SpringBoot 默认使用的是Hikari 数据库连接池

如果想把默认的数据库连接池切换为 Druid 数据库连接池,只需要引入相关依赖即可~

运行结果如下

总结

MySQL 规范

1. 表名,字段使用小写字母或者数字,单词之间以下划线分割。不允许出现数字开头或者两个下划线中间只出现数字的情况。

2. 建表必备三字段:id,create_time,update_time

3. 在表查询的时候,大部分情况,不使用 * 作为查询的字段列表。

#{} 和 ${} 区别

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

2. #{} 可以防止 SQL 注入,${} 存在 SQL 注入的风险

3. 一些情况下,必须使用 ${} 例如:排序功能,表名,字段名作为参数,需要使用 ${},但一定要考虑到 SQL 注入的风险,并提前进行规避。

4. 模糊查询虽然 ${} 可以完成,但存在 SQL 注入的风险,通常使用 mysql 的内置函数 concat 来完成。

动态 SQL

Mybatis 最强大特性之一 -- 动态 SQL,能够完成不同条件下的 SQL 拼接。

if 标签

举例:当用户在注册页面,可能出现如下情况:

注册表格中分为两种:必填和非必填字段,如果在添加用户的时候有不确定的字段传入,程序该如何实现呢???

比如:添加 gender 为非必填字段,具体实现如下:

Mapper.xml 实现:

trim 标签

上面的插入用户功能,只有一个 gender 字段可能是选填项。但如果有多个字段都是选填项,我们考虑使用标签结合标签,对多个字段都同时采用动态生成的方式。

如果继续单纯的使用 <if> 会导致最后拼接完的 sql 语句多出一个逗号,所以需要结合 <trim> 标签

<trim> 标签中有如下属性:

prefix:表示整个语句块,以 prefix 的值作为前缀。

suffix:表示整个语句块,以 suffix 的值作为后缀。

prefixOverrides:表示整个语句块要去除的前缀。

suffixOverrides:表示整个语句块要去除的后缀,

调整代码为:

where 标签

有如下需求:

系统需要根据用户的筛选条件,动态的组装 where 条件

需求:传入用户对象,根据属性做 where 条件查询。用户对象中属性不为 null 的,都为查询条件。

接口定义:

Mapper.xml 实现:

<where> 只会在子元素有内容的情况下,插入 where 字句,而且会自动去除字句的开头的 and 或 or。以上标签页可以使用 <trim prefix = "where" prefixOverrides = "and"> 代替,但是当子元素没有内容的时候,where 关键字仍然会保留。   

set 标签

需求:根据传入的用户对象属性来更新用户数据。

接口定义:根据传入的用户 id 属性,修改其他不为 null 的属性。

Mapper.xml:

<set>:会动态的在 SQL 语句中添加 set 关键字,并删除额外的逗号。

补充:Java 属性,数据库字 与 Java 代码对应

foreach 标签

对集合进行遍历的时候,可以使用该标签。标签有如下属性:

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

item:遍历时的每一个对象

open:语句块开头的字符串

close:语句块结束的字符串

separator:每次遍历之间间隔的字符串

需求:根据多个 userId,删除用户的数据

接口方法:

Mapper.xml 中增加 SQL 语句

include 标签

在 xml 映射文件中,配置的 SQL 语句,会出现很多重复的片段,较多的冗余代码。

我们可以对重复的代码片段进行抽取,将其通过 <sql> 标签封装到一个 SQL 片段,然后再通过 <include> 标签进行引用。

<sql>:定义可重用的 SQL 片段

<include>:通过属性 refid,指定包含的 SQL 片段

完!

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值