本文章是关于本人在一次项目开发过程中遇到SQL语句的问题总结,并不全面,之后遇到新问题的会继续更新。
1、 ${}和#{}的区别
后端使用SQL语句时注意${}和#{}的区别,使用#{}可以防止SQL注入的问题,#{}是占位符(会自动加引号),${}是拼接符(需要自己加引号)。
如果你所传的参数是String类型,你在sql语句中使用${}就需要在外面加上单引号(双引号都行)。
表名作为变量时,必须使用${},当表名带有汉字时要用反引号``。
在后端开发中我使用了两次表名的动态变化
一次是动态改变表名插入数据
@Insert("INSERT INTO ${tablename}(id, name, signintime, state, subject) VALUES(#{id}, #{name}, #{signintime}, #{state}, #{subject})")
另一次是动态改变表名查询数据(使用了左连接)
@Select("SELECT l.id, l.name, s.state , s.signintime FROM login l LEFT JOIN `${tablename}` s ON l.id = s.id AND l.sclass = #{sclass} AND s.subject = #{subject} AND s.signintime = #{signintime}")
两条语句对比,发现在插入语句中我的表名没有加反引号,但在查询语句中表明上加上了反引号,我个人判断应该是SQL语句识别的问题,不过为了安全我建议都加上反引号,确保能正确识别。
2、@Param注解
当使用了@Param注解来声明参数的时候,SQL语句取值使用#{},${}取值都可以。
当不使用@Param注解声明参数的时候,必须使用的是#{}来取参数。使用${}方式取值会报错。
不使用@Param注解时,参数只能有一个,并且是Javabean(实体类)。在SQL语句里可以引用JavaBean的属性,而且只能引用JavaBean的属性。
注意依赖包为:
import org.apache.ibatis.annotations.Param;
与@Param相关的有三个,具体的区别不太清楚,上述依赖包是在SpringBoot框架下引入的
3、多表查询
2.3.1 内连接查询(INNER JOIN)
内连接查询返回两个表中满足连接条件的记录。如果某个记录在另一个表中没有匹配项,则不会出现在结果集中。
示例:查询学生表(students)和成绩表(scores)中,学生的姓名和对应的成绩。
SELECT students.name, scores.score
FROM students
INNER JOIN scores ON students.id = scores.student_id;
2.3.2左连接查询(LEFT JOIN 或 LEFT OUTER JOIN)
左连接查询返回左表中的所有记录和右表中满足连接条件的记录。如果左表中的某条记录在右表中没有匹配项,则结果集中右表的部分会显示为NULL。
示例:查询所有学生及其成绩,即使某些学生没有成绩。
SELECT students.name, scores.score
FROM students
LEFT JOIN scores ON students.id = scores.student_id;
2.3.3 右连接查询(RIGHT JOIN 或 RIGHT OUTER JOIN)
右连接查询返回右表中的所有记录和左表中满足连接条件的记录。如果右表中的某条记录在左表中没有匹配项,则结果集中左表的部分会显示为NULL。
示例:查询所有成绩及其对应的学生姓名,即使某些成绩没有对应的学生。
SELECT students.name, scores.score
FROM students
RIGHT JOIN scores ON students.id = scores.student_id;
我刚开始使用时在on后添加了两个表关联的判断条件后,继续使用了where连接其他的判断条件,发现了查询后的结果与预期不符,将where改为and连接后查询出正确解决。
注意SQL查询时使用,占位符的个数要与你方法中传入的参数个数一致
如下方
//sclasss参数使用了两次,但是只有一个,在运行时会报错
@Select("SELECT l.id, l.name, s.state , s.signintime FROM login l LEFT JOIN `${slass}` s ON l.id = s.id AND l.sclass = #{sclass} AND s.subject = #{subject} AND s.signintime = #{signintime}")
List<Result> findStudentAll(@Param("sclass") String sclass, @Param("subject") String subjecte ,@Param("signintime") String signintime);
//将第一个sclass改为tablename,并在方法中新增一个tablename参数
@Select("SELECT l.id, l.name, s.state , s.signintime FROM login l LEFT JOIN `${tablename}` s ON l.id = s.id AND l.sclass = #{sclass} AND s.subject = #{subject} AND s.signintime = #{signintime}")
List<Result> findStudentAll(@Param("tablename") String tablename,@Param("sclass") String sclass, @Param("subject") String subjecte ,@Param("signintime") String signintime);
4、SQL语句调试
在SpringBoot的配置文件application.properties文件中增加以下配置
logging.level.项目路径(com.xxx.Mapper)=debug
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
可以在控制台输出SQL语句执行时的插入的数据和执行情况
如下:
//表示执行的SQL语句,之前的占位符用?代替,个人信息用xxxxx代替
Preparing: SELECT l.id, l.name, s.state , s.signintime FROM login l LEFT JOIN `软件2130` s ON l.id = s.id AND l.sclass = ? AND s.subject = ? AND s.signintime = ?
//按顺序对应查询条件
==> Parameters: xxxxxx(String), SpringBoot(String), 2024-06-18(String)
//查询结果
<== Columns: id, name, state, signintime
<== Row: xxxxxxxx, xxx, null, null
<== Row: xxxxxxxx, xxx, null, null
<== Row: xxxxxxxx, xxx, null, null
<== Row: xxxxxxxx, xxx, 已签到, 2024-06-18
<== Row: xxxxxxxx, 张三, null, null
<== Row: xxxxxxxx, 李四, null, null
<== Total: 6