关于Mybatis框架中的l中SQL的编写⽅法
我们在mybatis框架中写sql语句的时候,分为静态语句和动态语句。
静态语句
就是在java中直接写⼊的SQL语句,在达到程序设计的节点时就会进⾏SQL语句的查询。
动态语句
相⽐静态语句来说,mybatis中⽤得多的是动态语句,因为业务中传过来的值是不⼀定的,是动态变化的,所以动态SQL是有很多东西需要学习的。
以⼀个例⼦来讲,使⽤Mybatis 动态表名,查询数据,⽐如最近项⽬中使⽤到根据时间进⾏查询表的需求(即表名是根据时间变化的)
mapper.java ⽂件:
public Gpsinfo selectGpsByPlateNo(@Param("tableName")String tableName,@Param("plateNo")String plateNo);
<select id="selectGpsByPlateNo" parameterType="String" resultMap="BaseResultMap" statementType="STATEMENT">
SELECT *FROM
${tableName}
where plateNo='${plateNo}'
order by createDate desc limit 1
</select>
serviceImpl.java⽂件:
@Override
public Gpsinfo selectGpsByPlate(String plateNo) {
Gpsinfo gpsinfo = new Gpsinfo();
Date date=new Date();
DateFormat format=new SimpleDateFormat("yyyyMMdd");
String tableName="gpsinfo"+format.format(date);
gpsinfo = myGpsMapper.selectGpsByPlateNo(tableName,plateNo);
return gpsinfo;
}
表名根据时间进⾏拼接
这是⼀次别⼈代码优化过程中发现的问题,在功能优化后发现部分数据查出来了,问题就在于⼀条sql上的#和$。
下图为两条sql:
从图上可以看出 wwlr.LabelId in(${showLabels}) 和 wwlr.LabelId in(#{showLabels}),其中showLabels是传进来⼀个字符串类型的参数,参数的样⼦是这样的“4,44,514”,问题就出在这个参数传进来后#和$处理的⽅式是不⼀样的。
区别
作⽤
应⽤场景缺点#{ }相当于占位符,预编译处
理,MyBatis在处理#{ }时,它会将
sql中的#{ }替换为?,然后调⽤
PreparedStatement的set⽅法来赋
值,传⼊字符串后,会在值两边加上
单引号,如值 “1,0”就会变成“
‘1,0’ ”;
获取DAO中的参数数据,在映射⽂件的SQL语句中出现#{}表达式,底层会创建预编译的SQL;${ }字符串拼接与替换, MyBatis在处
理${ }时,它会将sql中的${ }替换为变
量的值,传⼊的数据不会在两边加上
单引号。获取配置⽂件数据,DAO接⼝中的
参数信息,当$出现在映射⽂件的
SQL语句中时创建的不是预编译的SQL,⽽是字符串的拼接,有可能会导致SQL注⼊问题.所以⼀般使⽤$接收dao参数时,这些参数⼀般
是字段名,表名等,例如order by
${column}。 1.有时需要在${parameter}前后加上单引号;2.导致sql注⼊,不利于系统的安全性。
关于#{}底层调⽤的PreparedStatement中的set⽅法:
这⾥涉及到⼀个知识点叫做SQL注⼊,就是通过把SQL命令插⼊到Web表单提交或输⼊域名或页⾯请求的查询字符串,最终达到欺骗服务器执⾏恶意的SQL命令。常见的有匿名登录(在登录框输⼊恶意的字符串)、借助异常获取数据库信息等。因此有些情况下能使⽤#{}达到要求的情况下就尽量不要使⽤${}了。
模糊查询
mybatis中的模糊查询有3种⽅式:
1.⾸先个⼈推荐使⽤CONCAT函数(concat,合并多个数组、字符串):
public interface FoodMapper{
@Select("select * from table where name like CONCAT('%',#{name},'%')")
List<Food> fuzzySearchByName(String name);
}
对应的Controller类:
public class foodController{
@Autowired
FoodMapper foodMapper = new FoodMApper()
@Component("/fuzzySearch")
Public List<Food> fuzzySearch(String name){
return fuzzySearchByName(name)
}
}
2.#{}
public interface FoodMapper{
@Select("select * from table where name like '%#{name,jdbcType=VARCHAR}%')")
List<Food> fuzzySearchByName(String name);
}
3.${}
public interface FoodMapper{
@Select("select * from table where name like '%${name}%')")
List<Food> fuzzySearchByName(String name);
}
推荐使⽤前两种⽅法,因为前两种⽅法使⽤的是#{},所以不会引起SQL注⼊,风险较⼩。
条件查询:
假设有以下业务场景,根据3个条件查出符合的数据,但是这3个条件可以为任何值,空值也是被允许的,现在为了直接将空值过滤掉,只查有具体条件内容的属性,可以像下⾯这样写:
<select id="getByParams" resultMap="BaseResultMap" parameterType="string">
SELECT
*
from
xxx_t
where
1 = 1
<if test = "null != number ">
and xx_number = #{xxNumber}
</if>
<if test = "null != age">
and xx_age = #{xxAge}
</if>
<if test = "null != state">
sql语句替换表中内容and xx_state = #{xxState}
</if>
</select>
case并列判断:
<choose><when>跟<if>是有区别的,类似于java语法中case与if、else之间的关系。
使⽤‘if‘ ‘else ‘ 判断 when otherwise,when其实⾃带⼀个break,只要有⼀个条件符合,就⾃动break跳出。
<select id="getByParams" resultMap="BaseResultMap" parameterType="string">
SELECT
*
from
xxx_t
<where>
<choose>
<when test = "1 == number">
number = 100
</when>
<when test = "2 == number">
number = 200
</when>
<when test = "3 == number">
number = 300
</when>
</choose>
</where>
</select>
也可以使⽤when otherwise。when的意思就是和java 代码中switch 的case⼀样,只能进⼀个判断。在所有的when条件都不满⾜的情况下就是进的otherwise。⽐如说我此时传了sum=5 那sql就是的aaa=bbb。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论