在使用Mybatis框架时,我们会使用Mapper配置文件来定义sql语句以实现我们所需要的增删改查。而对于sql语句中所需要的参数的传递,是一个非常常见的问题,在jdbc中我们可以使用PreparedStatement来传递我们所需要的参数。在Mybatis中,我们使用parameterType来传递输入参数(如果觉得此处唠叨,就当凑个字数)。
而对于参数来说,我们平常常见的就是八大基本类型+String。在Mapper中,我们利用书写 #{ }或者${ }来在SQL 中获取我们传来的参数,那么,二者有什么区别呢?接下来就是我个人对其的一些总结:
1.若传递的参数为8大基本类型或者String,如果使用#{ }的方式,在花括号中可以填入任意参数名都可以,例如
<mapper namespace="com.charles.mybatis.personMapper">
<select id="selectPersonById" resultType="com.charles.mybatis.person" parameterType="int">
select * from person where id = #{AnyParaName}
</select>
</mapper>
2.若传递的参数为8大基本类型或者String,如果使${ }的方式,在花括号中必须填入value,例如
<mapper namespace="com.charles.mybatis.personMapper">
<select id="selectPersonById" resultType="com.charles.mybatis.person" parameterType="int">
select * from person where id = #{value}
</select>
</mapper>
3.若传入参数为对象类型,使用#{ }和${ }都需要传入对象的属性名,例如
<mapper namespace="com.charles.mybatis.personMapper">
<select id="com.charles.mybatis.person" resultType="com.charles.mybatis.person" parameterType="int">
select * from person where id = #{id}
</select>
</mapper>
4.两者都可以支持对象的级联属性。
5.在使用String数据类型作为参数时,#{}自动为其添加双引号,${}原样输出,不添加任何东西。接下来,用一个小demo来具体操作一下,验证其正确性。
建立pojo person.java
package com.charles.mybatis;
public class person {
private int id;
private String name;
public person(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public person() {
super();
}
@Override
public String toString() {
return "person [id=" + id + ", name=" + name + "]";
}
}
建立mybatis配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="db.properties"></properties>
<typeAliases>
<package name="com.charles.pojo"/>
</typeAliases>
<typeHandlers>
<typeHandler handler="com.charles.converter.StringAndIntConverter" javaType="String" jdbcType="INTEGER"/>
</typeHandlers>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/charles/pojo/personMapper.xml"/>
</mappers>
</configuration>
建立数据库配置文件
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis
username=root
password=charles
建立mapper代理接口
package com.charles.mapper;
import java.util.List;
import com.charles.pojo.person;
public interface personMapper {
person queryByName(String name);
person queryByName1(String name);
person queryByName2(String name);
person queryByName3(String name);
}
之后,建立mapper配置文件,定义了四个查询语句,每一个的参数使用形式不同,观察其执行。
<?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.charles.mapper.personMapper">
<select id="queryByName" parameterType="String" resultType="person">
select * from person where name=#{name}
</select>
<select id="queryByName1" parameterType="String" resultType="person">
select * from person where name=${name}
</select>
<select id="queryByName2" parameterType="String" resultType="person">
select * from person where name=${value}
</select>
<select id="queryByName3" parameterType="String" resultType="person">
select * from person where name='${value}'
</select>
<resultMap type="person" id="personResultMap">
<id property="id" column="id" javaType="String" jdbcType="INTEGER"/>
<result property="name" column="name"/>
</resultMap>
</mapper>
最后,创建一个测试类,完成demo的测试,分别执行main方法里面的四个函数调用,观察执行结果
package com.charles.pojo;
import java.io.IOException;
import java.io.Reader;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.charles.mapper.personMapper;
public class test
{
public static void main(String[] args) throws IOException
{
// queryByName("charleschou");
// queryByName1("charleschou");
// queryByName2("charleschou");
// queryByName3("charleschou");
}
public static void queryByName(String name) throws IOException
{
Reader reader=Resources.getResourceAsReader("conf.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(reader);
SqlSession session=build.openSession();
personMapper mapper = session.getMapper(personMapper.class);
person queryByName = mapper.queryByName("charleschou");
System.out.println(queryByName);
}
public static void queryByName1(String name) throws IOException
{
Reader reader=Resources.getResourceAsReader("conf.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(reader);
SqlSession session=build.openSession();
personMapper mapper = session.getMapper(personMapper.class);
person queryByName = mapper.queryByName1("charleschou");
System.out.println(queryByName);
}
public static void queryByName2(String name) throws IOException
{
Reader reader=Resources.getResourceAsReader("conf.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(reader);
SqlSession session=build.openSession();
personMapper mapper = session.getMapper(personMapper.class);
person queryByName = mapper.queryByName2("charleschou");
System.out.println(queryByName);
}
public static void queryByName3(String name) throws IOException
{
Reader reader=Resources.getResourceAsReader("conf.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(reader);
SqlSession session=build.openSession();
personMapper mapper = session.getMapper(personMapper.class);
person queryByName = mapper.queryByName3("charleschou");
System.out.println(queryByName);
}
}
(我的数据库此时是有数据的),观察执行结果,第一个方法调用queryByName(),
查询数据正常,接下来,第二个方法调用 queryByName1(),
查询失败,观察我们mapper中第二个sql语句的书写
select * from person where name=${name}
在使用${}时,里面只能是value,否则报错;因此我们将其改为value,观察第三个方法的调用queryByName2(),
此处依旧报错,观察我们的mapper文件第三个语句,
select * from person where name=${value}
其报错原因是因为,当有参数传递进来时,mapper的${}接收到参数,然后将该sql语句转为:
select * from person where name=charleschou
很明显这是一条错误的语句,因为我们没单引号,因此程序依旧会报错,我们需要的sql语句应该是
select * from person where name='charleschou'
因此,观察第四个方法的调用queryByName3()
执行成功,观察mapper文件中的最后一个查询语句,我们手动添加了单引号,因此不报错
select * from person where name='${value}'
对于两种参数获取方式的使用, 这里再总结一点,使用#{}方式,可以防止sql注入,而${}方式,则不能防止sql注入。
那么,我们实际开发或者使用中,应该避免使用${}方式吗?答案是否定的,虽然这种方式不能防注入,也不能自动加单引号,但是它可以用作其他用途,比如在查询批量数据需要根据字段排序时,我们可以利用此方式动态的将字段传入到sql中从而达到我们想要的效果!