上篇博客讲述了 Spring后端与前端进行交互的过程, 而这篇博客将讲述Spring与数据库的交互 , 众所周知 后端与数据库的关系是十分紧密的, 当然数据库也是有框架的 为 MyBits 是基于JDBC开发的
① 建立数据源 :DataSource
② 通过DataSource 与数据库进行链接 connection
③ 编写要执行的SQL语句 , 不确定的参数 用 ? 进行占位
④ 通过Connection 与 编写的SQL 语句 创建命令对象 Statement
⑤ 替换Statement 中的占位符 , 用指定的数据类型
⑥ 执行SQL语句 , 查询用 executeQuery(), 增加/ 删除 /修改用 executeUpdate()
⑦ 处理结果集
⑧ 关闭资源 ,从后往前关
MyBits 主要学习俩方面的内容 , 第一个是老生常谈的配置环境 ,第二个 是学习MyBits的语法 与模式
还记得上文中画的那张图五大类注解的图吗?如下 , 通过这张图 ,可以明显的看出来数据库是与持久层进行交互的 , 持久层主要有俩个 东西来进行交互 ,一个是接口 ,这里面提供给服务层可以调用的接口 , 一个是XML文件用来实现接口 ,同时操作数据库的SQL语句也是在这里面存放的,
我们学的MySQL数据库是关系型数据库 , 而Mybits 也是一个ORM 框架 ,
ORM 中文意思为 : 对象关系映射 ,意思 是在 : 面向对象的编程语言 中 , 将关系型数据库中的数据 与对象建立起映射关系 ,进而自动的完成 数据与对象的互相转换
MyBits 将输⼊数据(即传⼊对象)+SQL 映射成原⽣ SQL , 将结果集映射为返回对象,即输出对象
映射关系如下 :
数据库表(table)–> 类(class)
记录(record,⾏数据)–> 对象(object)
字段(field) --> 对象的属性(attribute)
① 创建一个SpringBoot项目 , 往项目中添加MyBits的框架 , 如下图
② 在application配置文件中,添加mysql的配置
③配置MyBits的xml的实现接口, 要与配置文件中写的一致
④创建接口类与实体类 :
实体类 相当于一张表 ,里面的属性要与数据库中的字段对应
接口内 相当于提供给服务层的使用接口 ,调用接口实际上调用的是XML中的语句
⑤构建Mapper层的代码实现
比如在接口类中写入什么 , 就必须在XML中构造出来 , ID要一致, 传过去的参数也要对应上
这是接口类中写入的
int getArtCountByUid(@Param("uid") Integer uid);
这是XML中写入的
其中 #{uid} 代表着动态接受传参 () 这个有俩种写法下面讲)
⑥在服务层调用接口
服务器只需要属性注入相对应的接口类的对象, 然后写一个普通方法提供给控制类使用, 普通方法中调用对应的接口方法即可
注 : 这里说一下, 在接口类中传递对象时 , 在XML中赋值使用的是对象的属性
结论: $ 有SQL注入的问题 , 而# 没有
原因: $ 是直接替换语句 ,而 # 是预处理语句
预编译处理是指:MyBatis 在处理#{}时,会将 SQL 中的 #{} 替换为?号
直接替换:是MyBatis 在处理 ${} 时,就是把 ${} 替换成变量的值。
比如 : 这个SQL语句
select count(*) from articleinfo where uid=#{uid} : 这是预处理的做法
select * from userinfo order by id ${sort} : 这是直接处理的做法
${} 是有好处的 : 使⽤ ${sort} 可以实现排序查询,⽽使⽤ #{sort} 就不能实现排序查询了,因为当使⽤ #{sort} 查询时,如果传递的值为 String 则会加单引号,就会导致 sql 错误
但是 ${}同样带来了SQL注入的问题 , 比如
select * from userinfo where username=‘ n a m e ′ a n d p a s s w o r d = ′ {name}' and password=' name′andpassword=′{pwd}’ 本来我想传递俩个参数来获取信息 ,但是如果传递过来前面路径一致, 后面加上 or 1= 1 , 由于${}是直接替换 , 那么就会绕开前面的判断 , 直接返回结果 , 但我们设置拦截器的想法就是 ,不能随意的返回数据, 这与我们最初的想法起了冲突
结论 : ⽤于查询的字段,尽量使⽤ #{} 预查询的⽅式
这里指出一点: 并不是#{} 就是完美无缺的了 , 它同样有着缺陷 , 比如 #{} 不能处理like 这种模糊匹配查询
select * from userinfo where username like ‘%#{username}%’;
这里面的替换后的效果为给username前后加上单引号, mysql不认这种组织方式 ,结果报错
select * from userinfo where username like ‘%‘username’%’
怎么解决 利用mysql内置的拼接函数解决concat , 用mysql自带的拼接函数不会加上单引号
select * from userinfo where username like concat('%',#{usernam
e},'%');
有时候 ,我们会遇到一种情况就是 , 当mysql中的字段名与程序中的属性值不一致该怎么办?
解决方案 : 利用resultMap 解决
这张图中 :
resultMap ID为该映射的标识 (名称) ,
type为 要映射的实体类所对应的路径
下面第一行 ID为主键 后面 property对应的是程序中的属性名
接下来的 result column 对应的都是普通的字段 , 后面代表映射的属性值
在映射结束后, 下面写SQL语句就不会出现问题了
还有一种比这更简单的处理方法就是
使用AS起别名的方式来 解决, 字段和属性值不对应的情况
使用方法 , 在SQL语句查询中 , 起别名为程序中对应的属性即可了,
比如说 id 与 username 是SQL语句中的字段名, 而ID与name 是Java程序中的属性名称
select id as ID , username as name from articleinfo where uid=#{uid}
当上路流程学完之后 , 已经学会了 如何写SQL语句 , 如何创建对应的实体类 , 如何创建一个使用MyBits的项目, 已经能简单写不复杂的SQL 与 Java程序之间的联动了 , 但是还有一种情况我们没有处理 那就是 : 上面解决了字段名称与属性名字不一致的写法 , 但是多对一的映射关系该如何解决
比如说 :在多表查询时,如果使⽤ resultType 标签,在⼀个类中包含了另⼀个对象是查询不出来被包含的对象类对象, 这种情况就要使用一些特殊的标签来表名 该resultMap的映射关系
比如
⼀对⼀映射要使⽤ 标签,具体实现如下(⼀篇⽂章只对应⼀个作者):association标签加到ResultMap中就可以了
<association property="user"
resultMap="com.example.demo.mapper.UserMapper.BaseMap"
columnPrefix="u_">
</association>
以上使⽤ 标签,表示⼀对⼀的结果映射:
property 属性:指定 Article 中对应的属性,即⽤户。
resultMap 属性:指定关联的结果集映射,将基于该映射配置来组织⽤户数据。
columnPrefix 属性:绑定⼀对⼀对象时,是通过反射来绑定的
⼀对多需要使⽤ 标签,⽤法和 相同,如下所示:
<collection property="alist" resultMap="com.example.demo.mapper.ArticleI
nfoMapper.BaseMap"
columnPrefix="a_">
</collection>
MyBits还支持动态SQL语句的编写, 这里给大家了官方网址
动态 SQL 是一种根据程序的当前需要来生成和执行 SQL 语句的方法。它允许在程序运行时动态创建 SQL 语句,根据不同的条件或者用户输入生成不同的 SQL 语句,从而满足不同的查询需求。动态 SQL 更加灵活,可以避免预编译 SQL 语句时固定的执行计划,提高查询效率和灵活性,并且可以防止 SQL 注入攻击。动态 SQL 可以在不同的编程语言和数据库系统中实现。
https://mybatis.org/mybatis-3/zh/dynamic-sql.html