java day16
继续学习网课
终于有空继续看视频了;
首先呢在写sql语句的时候呢,标明,比如,名字和密码对吧,选出来有几条那就是几条;因为你条件都限制这么死了,选出来的不都是你想要的吗;所以可以直接select count(*)
好,然后用户名和密码从哪来?就是用户在输入登录界面的时候拿来的;那就需要获取用户的登录;
sql注入
学一个sql注入的攻击,通过操作输入的数据修改事先定义好的sql语句,比如刚刚的要用户名和密码,我们就需要获取用户的输入吗;然后获取到输入了;才能实现查询, 在获取输入的时候,我们去篡改输入;比如直接在写密码的时候,咱们续写sql语句,直接加条件
相当于直接这样做 ,直接把sql改了,就是恶意sql
这样就把sql改啦,其实这意思就是,直接把where里面的条件作为更改;直接改为1的真条件,count一查全查到了;那肯定能上;
这样他就是把里面的字符串里面的东西做了更改;
但是用预编译sql就不会有这样的问题
所以说预编译sql可以防止sql的注入,可以直接设立好设立完整;
解决办法
可以使用mybatis这种方式,他自己会处理sql的拼接,这里也用过了;比如用wapper写sql;或者是根据这个:比如一个花括号这种类似模板字符串的东西吧;这里直接在mapper的映射的时候直接杜绝;标注一个delete的注解里面写好sql,这就是预编译。删除id等于输入的,动态sql;然后里面写方法返回;
如何防范 SQL 注入?
输入验证与过滤:对用户输入的特殊字符(如 '、;、OR 等)进行过滤或转义,限制输入格式(如手机号、邮箱的正则校验)。这种在用户输入的时候或者你建表的时候就可以规定;实在不行也可以去Impl层规定;
使用参数化查询(预编译语句):将 SQL 语句与用户输入分离,通过 ? 或命名参数传递数据,避免直接拼接 SQL(如 Java 的 PreparedStatement、Python 的 sqlite3 参数绑定)。就类似#{}这样的模板字符串;
示例(参数化查询):
java
String sql = “SELECT * FROM users WHERE username=? AND password=?”;//这种用问号传达参数的形式避免了很多攻击;
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, username); // 自动处理特殊字符
pstmt.setString(2, password);
授予权限
最小权限原则:数据库账号仅授予必要权限(如查询、插入),禁止使用 root 等高权限账号连接应用。
使用 ORM 框架:如 MyBatis、Hibernate 等,自动处理 SQL 拼接,减少手动编写 SQL 的风险。
定期审计与更新:检查代码中的 SQL 语句,及时修复漏洞;更新数据库和 Web 服务器版本,修补已知安全缺陷。
参数占位符
注意,写参数的时候
#{}写成这样的时候,参数是被问号替代的,这样的预编译sql,用?代替参数从而参数传进来就被替代;这种传参的时候比较方便;
${}这样传参的时候就是拼接sql,但是这种拼接会有注入问题;动态设置的时候用?
这是一个这样传参的例子,发现他也是直接拼接到where后面;也是很有风险,所以以后就用#{},更安全;
新增
用新增注解,里面写好新增的语句插入的字段和名字;但是看这样特别麻烦;我们不如封装起来,到一个地方去;
#{} 全部用这个参数形式替代,我们就可以预编译sql,对象就是员工对象;因为这些属性都是再员工表里面的;
主类里面就输入我们要传递的信息则可;给她设置一下传进来的参数;调用他的set方法;然后设置好传参;然后调用Insert方法,插入到这个对象里面去;
当输出这种一串的问号的时候这就对了;证明预编译没毛病;
有多个参数就用实体类封装;
新增主键返回
这里的意思好像是比如两个表有联系吧,比如套餐和菜品表,一个套餐里面多个菜,一个菜也可以进入多个套餐;所以说,他们就是有关系的;需要一个中间表来对应;再建立一张表,对他们进行关联;在这个mybatis里面,进行对 主键的返回,插入一个注解叫options这种;然后封装到这个实体类的id属性里面去;
更新
比如说这个更新吧;先在sql里面写就应该是
update 表名 set username=‘’ ,name=‘’,gender=‘’,image=‘’,…where id=''应该是这样的,一条更新的sql,然后变成动态预编译传参,再一个是条件肯定是id的条件,因为只有根据id是什么东西,才能查到是哪一条要更新,再一个是你更新了一些字段,也千万不可以忘掉你的更新时间要改;还是变成全部都是#{}的模式不要字符串是最好的;预编译sql的好处在这里,面试可能会问道#{}和${}有什么区别,一个是预编译sql直接替换成字符串,一个是直接把参数拼后面;
当然在mapper里面要用到更新的注解,现在就是更新的方法也安排完毕了;
最后就是crud里面的,增删改查的查了;
前几个可以直接封装完毕;或者是现在工作使用的若依框架;他有一套自动代码生成的东西;
增删改的返回值都是void,因为你是改动数据,你只是参数是实体类
但是查询不一样,查询是你要查出来然后吧返回结果作为一个集合还是一个列表返回出来,需要用户能看见
查询
然后比如类似这个,用查询的注解写了查询的信息以后;public 里面的方法的类型是emp,意思就是你这查出来的这么多条信息就没必要封装到集合里面了,可以封装到这个员工对象里面,然后逐步返回吗;然后再去主类里面给她动态返回参数;直接给她用emp对象调用mapper的方法获取id,给她里面设置好id是多少;然后传回去;select语句再根据这个传回去的查,然后给她封装到这个对象里面;
再一个就是,你命名的时候啊;比如有些表里面有下划线;比如部门id这个嘛有dept_id这种,在mybatis里面不对应就会报错
!所以呢;我们需要进行驼峰形式的命名;应该是大驼峰吧;前小写后大写;这个命名一定要规范,不然很容易被认为不专业;然后这样mybatis就可以正常读取啦;
还有正常读取的方法
就是这种,对其进行手动封装,先用results({把这几个都封装起来})里面是result注解,然后column=“表中的字段名”,property=“这里面是实际的字段名” 但是这种方式也过于繁琐;
还有就是每次调用方法的时候,调过来的是方法里面返回的东西,你需要找一个去接收他;必须接收过来了才可以用,才可以拿去写拿去作妖;
但是现在不止这一种解决方案,还可以去打开mybatis的自动映射的开关;
也就是说更改字段不匹配的映射问题,可以是用这三种解决方案,还有就是他的crud语句全部都是在mapper层里面写的;
初级需求业务
输入信息然后获取到信息的值,然后后端按这个去查找,查找出来的结果返回,然后用前端渲染出来;
现在区别就来了,首先你上面你按id查,肯定可以查到一个具体的人,因为id他就是不重复的主键的嘛,现在你要按多个条件查了,什么模糊匹配张三啊,性别男啊;入职时间between and啊,还有别的,多个条件查出来的不止一个,因为给的这几个条件都不是重复的;所以呢;你现在,一次有可能查出来一条,也有可能查出来多条,那么就不能封装到一个对象里面了,就可以封装到一个集合里面,这样才能包裹多调信息;所以方法,还是公开,但是返回值变成List 集合里面的对象是咱们这个类,然后方法名字是list();然后加上select语句则可,这也是现阶段覆盖了大部分的东西;
观察上面的他写的所有的mapper层,他都是上面的sql语句里面的where的条件里面的东西,需要我们的下面的方法里面也要有参数,要对应上,毕竟你是从前端获取,你获取到这些参数,然后传给sql,才能去查,然后sql要写成预编译,他就变成#{};这种类型最好;
就是这个意思,但是呢,比如name那里,他现在是模糊匹配,要写两个%但%又只能在‘’里面,但是预编译的sql不能让他在里面,所以怎么办?可以把#变成$,因为这个是拼接的意思;
然后去主类试调用,这里又是一个细节,因为mapper是接口没有对象,所以交给ioc容器管理,建立一个全局对象,然后咱们用这个对象调用mapper层的方法,然后用一个变量去接收;然后看到这个方法的返回值是个集合,所以要用集合去接收
大概就是这样;因为是单元测试就顺便传参了;这个变量类型就是集合的类型,这个集合是一个emp对象的集合;意思就是多条emp的信息;
但是又有问题了;
就是说,现在这样写也是出大问题的;
这是字符串拼接函数;就是用select concat (‘hello’,…)这几个语句,可以把他全部连接起来;
这里就有一个很机智的解决办法了
比如哈,因为之前你全部连在一起的时候 模糊匹配名字还是会暴露sql注入的风险,‘${name}’ 就是这种类型他也是一个字符串‘;他也是可以被编写替代的,所以啊,我们就应该写一个concat的方法,比如,用这个去连接那初始的两个百分号,如图所示,将这三个拼到一块,中间那个咱们单独变成#{}这种类型,可以被替换的参数,这样就防止了sql注入的风险;
这是mybatis基本的crud
现在来看xml文件;终于学到细的了;
发明这个主要是因为,你把所有crud语句都放到mapper里面了,那就非常的杂乱了;所以可以进行放到xml文件里面
这是xml文件的定义的规范;
与mapper层的名字要一样,只是后缀不一样,再一个是要放在同一个包下;他的namespace要完全和全类名一致;id和方法一致,然后呢resultType 和 map这两个有不同的写法和意义;就是如果sql语句太复杂,就用xml文件代替则可,一般的crud就直接标注解;