目录
1. 区别
2. 使用注意
2.1 #{}中变量名写法的注意
2.2 ${}中变量名写法的注意
2.3 使用${}而不适用#{}的场景:字符串替换
3. 使用实例
3.1 #{}占位符
3.2 ${}占位符
1. 区别
#{}: 解析为一个 JDBC 预编译语句(prepared statement)的参数标记符,一个 #{ } 被解析为一个参数占位符 。
${}: 仅仅为一个纯碎的 string 替换,在动态 SQL 解析阶段将会进行变量替换。
例子:
eg 1: select id,name,age from student where name=#{name} ;
解析为:select id,name,age from student where name='cy';
eg 2: select id,name,age from student where name=${name};
解析为:select id,name,age from student where name=cy;
使用#{}可以有效的防止 SQL 注入,提高系统安全性。
在大多数情况下还是经常使用#,但在不同情况下必须使用$.
2. 使用注意
2.1 #{}中变量名写法的注意
- #{}占位符可以用来设置参数,如果传进来的是基本类型,也就是(
string
,long
,double
,int
,boolean
,float
等),那么#{}
里面的变量名可以随意写,什么abc
,xxx
等等,这个名字和传进来的参数名可以不一致。 - 如果传进来的是
pojo
类型,那么#{}
中的变量名必须是pojo
的属性名,可以写成属性名
,也可以写属性名.属性名
。
参数是int
,不需要设置parameterType
:
<delete id="deleteStudentById" >
delete from student where id=#{XXXdoukeyi}
</delete>
parameterType
是pojo
类,如果使用pojo
类型作为参数,那么必须提供get
方法,也就是框架在运行的时候需要通过反射根据#{}
中的名字,拿到这个值放到sql
语句中,如果占位符中的名称和属性不一致,那么报ReflectionException
。
<insert id="insertStudent" parameterType="Student">
insert into student(name,age,score) values(#{name},#{age},#{score})
</insert>
注意:不能这样写:
<insert id="insertStudent" parameterType="Student">
insert into student(name,age,score) values(#{Student.name},#{Student.age},#{Student.score})
</insert>
否则会报一个错误(会将Student
当成一个属性),所以我们类名就直接省略不写就可以了:
### Cause: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'Student' in 'class bean.Student'
2.2 ${}中变量名写法的注意
- 如果传进来的是基本类型,也就是(
string
,long
,double
,int
,boolean
,float
等),那么#{}
里面的变量名必须写value
。
<delete id="deleteStudentById" >
delete from student where id=${value}
</delete>
- 如果传进来的是
pojo
类型,那么#{}
中的变量名必须是pojo
的属性名,可以写成属性名
,也可以写属性名.属性名
。但是由于是拼接的方式,对于字符串我们需要自己加引号。
<insert id="insertStudent" parameterType="Student">
insert into student(name,age,score) values('${name}',${age},${score})
</insert>
与上面一样,不能将类名写进来:
<!--这是错误的-->
<insert id="insertStudent" parameterType="Student">
insert into student(name,age,score) values('${Student.name}',${Student.age},${Student.score})
</insert>
2.3 使用${}而不适用#{}的场景:字符串替换
默认情况下,使用 #{}
参数语法时,MyBatis 会创建 PreparedStatement
参数占位符,并通过占位符安全地设置参数(就像使用 ? 一样)。 这样做更安全,更迅速,通常也是首选做法,不过有时你就是想直接在 SQL 语句中直接插入一个不转义的字符串。 比如 ORDER BY 子句(Mybatis中Order By 不能使用#号.md_zhouwenjun0820的博客-,这时候你可以:
ORDER BY ${columnName}
这样,MyBatis 就不会修改或转义该字符串了。
当 SQL 语句中的元数据(如表名或列名)是动态生成的时候,字符串替换将会非常有用。 举个例子,如果你想 select
一个表任意一列的数据时,不需要这样写:
@Select("select * from user where id = #{id}")
User findById(@Param("id") long id);
@Select("select * from user where name = #{name}")
User findByName(@Param("name") String name);
@Select("select * from user where email = #{email}")
User findByEmail(@Param("email") String email);
// 其它的 "findByXxx" 方法
而是可以只写这样一个方法:
@Select("select * from user where ${column} = #{value}")
User findByColumn(@Param("column") String column, @Param("value") String value);
其中 ${column}
会被直接替换,而 #{value}
会使用 ?
预处理。 这样,就能完成同样的任务:
User userOfId1 = userMapper.findByColumn("id", 1L);
User userOfNameKid = userMapper.findByColumn("name", "kid");
User userOfEmail = userMapper.findByColumn("email", "noone@nowhere.com");
3. 使用实例
3.1 #{}占位符
#{}占位符用来设置参数,参数的类型可以有3种:基本类型,自定义类型,Map。
基本类型:
基本类型,参数名称与占位符中的名称无关。
#{} 传入值时,sql解析时,参数是带引号的
如果用了@Param("xxx") ,则mybatis会自动生成map作为入参,那么参数名称则必须与占位符一致
<select id="findById" parameterType="int" resultType="cn.wh.vo.Role">
select * from t_role where id = #{xxxid}
</select>
测试:
@Test
public void testSelectOne(){
Role role = (Role)session.selectOne("cn.wh.mapper.RoleMapper.findById",1);
System.out.println(role.getName());
}
自定义类型
自定义类型作为参数,自定义类中需要为为属性提供get方法,如果没有提供get方法,那么会根据占位符中的名称去反射获取值,如果占位符中的名称和属性不一致,那么报ReflectionException。
<select id="findListBypage" parameterType="cn.wh.util.PageUtil" resultType="Role">
select * from t_role limit #{index},#{size}
</select>
测试:
@Test
public void testPage1(){
PageUtil pu = new PageUtil();
pu.setIndex(3);
pu.setSize(3);
List<Role> list = session.selectList("cn.wh.mapper.RoleMapper.findListBypage", pu);
for(Role r:list){
System.out.println(r.getName());
}
}
Map
Map作为参数类型,key和占位符中的名称一致即可,如果名称不一致那么将会把null,传递到占位符中。
3.2 ${}占位符
<!-- 查询所有 -->
<select id="findAll" parameterType="map" resultType="cn.wh.vo.Role">
select * from ${tableName}
</select>
测试:
@Test
public void testSelectList(){
Map<String,String> map = new HashMap<String,String>();
map.put("tableName", "t_role");
List<Role> list = session.selectList("cn.wh.mapper.RoleMapper.findAll",map);
for(Role role:list){
System.out.println(role.getId()+"----"+role.getName());
}
}
作为连接符使用:
<select id="selectLike1" parameterType="map" resultType="Role">
select *from t_role where name like '${name}%';
</select>
测试:
@Test
public void testLike2(){
Map<String,String> map = new HashMap<String,String>();
map.put("name", "黄");
List<Role> list = session.selectList("cn.wh.mapper.RoleMapper.selectLike1",map);
for(Role r:list){
System.out.println(r.getName());
}
}