1、单个参数
mybatis不做特殊处理,只需要用 #{参数名} 取出参数值就可以了 。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.pjf.mybatis.dao.HotelMapper">
<!-- public Hotel getHotel(Integer i); -->
<select id="getHotel" resultType="com.pjf.mybatis.po.Hotel">
select * from hotel
where
<!-- 这里#{id}可以写成任何值如 #{abc}-->
id=#{id}
</select>
</mapper>
注:事实上这里#{id},参数名id可以写任何值,因为只有传了一个参数。
2、多个参数
mybatis会做特殊处理。 多个参数会被封装成 一个map。需要用 #{key} 取出参数值, key是param1, param2.....或者0、1、2索引值 。
首先举个例子,理所当然,很容易认为是这样去取参数值,直接写#{id}和#{price}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.pjf.mybatis.dao.HotelMapper">
<!-- public Hotel getHotel(Integer i,Integer j); -->
<select id="getHotel" resultType="com.pjf.mybatis.po.Hotel">
select * from hotel
where
id=#{id} and price =#{price}
</select>
</mapper>
这样是不对的,运行之后发现报错了
Caused by: org.apache.ibatis.binding.BindingException: Parameter 'id' not found. Available parameters are [arg1, arg0, param1, param2]
事实上,多个参数时,mybatis会做特殊处理,多个参数会被封装成map,需要用 #{key} 取出参数值, key是param1, param2.....或者0、1、2索引值 。
改成下面这样就正确了。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.pjf.mybatis.dao.HotelMapper">
<!-- public Hotel getHotel(Integer i,Integer j); -->
<select id="getHotel" resultType="com.pjf.mybatis.po.Hotel">
select * from hotel
where
id=#{param1} and price =#{param2}
</select>
</mapper>
3、命名参数
事实上,人们还是习惯使用#{id}和#{price}而不是#{param1}和#{param2},当然mybatis也提供了解决办法,通过@param("key")明确指定封装map中的key,就可以通过#{key}取出参数值了,@param("key")写在hotelMapper接口上。
public interface HotelMapper {
public Hotel getHotel(@Param("id")Integer i,@Param("price")Integer j);
}
这时候就可以通过#{id}和#{price}取出参数值了。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.pjf.mybatis.dao.HotelMapper">
<!-- public Hotel getHotel(@Param("id")Integer i,@Param("price")Integer j); -->
<select id="getHotel" resultType="com.pjf.mybatis.po.Hotel">
select* from hotel
where
id=#{id} and price =#{price}
</select>
</mapper>
4、POJO
如果多个参数正好是我们业务逻辑的数据模型,我们就可以直接传入pojo;#{属性名}:取出传入的pojo的属性值。
<insert id="insertUser" parameterType="User">
insert into users (id, username, password)
values (#{id}, #{username}, #{password})
</insert>
5、map
如果多个参数不是业务模型中的数据,没有对应的pojo,不经常使用,为了方便,我们也可以传入map。 #{key}:取出map中对应的值
hotelMapper接口
package com.pjf.mybatis.dao;
import java.util.Map;
import org.apache.ibatis.annotations.Param;
import com.pjf.mybatis.po.Hotel;
public interface HotelMapper {
public Hotel getHotel(Map<String,Integer> map);
}
hotelMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.pjf.mybatis.dao.HotelMapper">
<!-- public Hotel getHotel(@Param("id")Integer i,@Param("price")Integer j); -->
<select id="getHotel" resultType="com.pjf.mybatis.po.Hotel">
select * from hotel
where
id=#{id} and price =#{price}
</select>
</mapper>
测试类
public class TestHotel {
public SqlSessionFactory sqlSessionFactory() throws IOException {
String resource = "mybatis_config.xml";
InputStream is = Resources.getResourceAsStream(resource);
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
return sessionFactory;
}
@Test
public void getHotel() throws IOException {
SqlSessionFactory sessionFactory = sqlSessionFactory();
SqlSession session = sessionFactory.openSession();
HotelMapper hotelMapper = session.getMapper(HotelMapper.class);
System.out.println(hotelMapper.getClass());
//手动封装一个map传入
Map map =new HashMap<>();
map.put("id", 1001);
map.put("price", 997);
Hotel hotel = hotelMapper.getHotel(map);
System.out.println(hotel);
session.close();
}
}
6、对象参数
如果多个参数不是业务模型,但是有用的比较频繁时,这时候我们可以编写一个TO对象专门用来传递参数
package com.pjf.mybatis.po;
public class HotelTo {
private int id;
private int price;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
这时候接口就可以修改为
package com.pjf.mybatis.dao;
import java.util.Map;
import org.apache.ibatis.annotations.Param;
import com.pjf.mybatis.po.Hotel;
public interface HotelMapper {
//传入HotelTo 模型
public void insertHotel(HotelTo hotelTo);
}
7、复合型
public Employee getEmp(@Param("id")Integer id,String lastName);
取值:id==>#{id/param1} lastName==>#{param2}
public Employee getEmp(Integer id,@Param("e")Employee emp);
取值:id==>#{param1} lastName===>#{param2.lastName/e.lastName}
//如果是Collection(List、Set)类型或者数组,也会特殊处理。也是把传入的list或者数组封装在map中
key:Collection(collection),如果是List还可以使用这个key(list)
public Employee getEmpById(List<Integer> ids);
取值:取出第一个id的值:#{ids[0]}
8、${} 与 #{} 的区别
举例说明
1 select * from user where name = "dato"; 2 3 select * from user where name = #{name}; 4 5 select * from user where name = ${name};
一般情况下,我们都不会注意到这里面有什么不一样的地方。因为这些sql都可以达到我们的目的,去查询名字叫dato的用户。
区别
动态 SQL 是 mybatis 的强大特性之一,也是它优于其他 ORM 框架的一个重要原因。mybatis 在对 sql 语句进行预编译之前,会对 sql 进行动态解析,解析为一个 BoundSql 对象,也是在此处对动态 SQL 进行处理的。在动态 SQL 解析阶段, #{ } 和 ${ } 会有不同的表现
select * from user where name = #{name};
#{} 在动态解析的时候, 会解析成一个参数标记符。就是解析之后的语句是:
select * from user where name = ?;
那么我们使用 ${}的时候
select * from user where name = ${name};
${}在动态解析的时候,会将我们传入的参数当做String字符串填充到我们的语句中,就会变成下面的语句
select * from user where name = "dato";
预编译之前的 SQL 语句已经不包含变量了,完全已经是常量数据了。相当于我们普通没有变量的sql了。
综上所得, ${ } 变量的替换阶段是在动态 SQL 解析阶段,而 #{ }变量的替换是在 DBMS 中。
这是 #{} 和 ${} 我们能看到的主要的区别,除此之外,还有以下区别:
- #方式能够很大程度防止sql注入。
- $方式无法防止Sql注入。
- $方式一般用于传入数据库对象,例如传入表名.
- 一般能用#的就别用$.