#{}实现的是向 prepareStatement 中的预处理语句中设置参数值,sql 语句中#{}表示一个占位 符即?。
<select id="findUserById" parameterType="int" resultType="user">
select * from user where id = #{id}
select>
使用占位符#{}可以有效防止 sql 注入,在使用时不需要关心参数值的类型,mybatis 会自动进行java类型和jdbc类型的转换。 #{}可以接收简单类型值或pojo属性值, 如果parameterType 传输单个简单类型值,#{}括号中可以是 value 或其它名称。
KaTeX parse error: Expected 'EOF', got '#' at position 4: {}和#̲{}不同,通过{}可以将 parameterType 传入的内容拼接在 sql 中且不进行 jdbc 类型转换, 可 以 接 收 简 单 类 型 值 或 p o j o 属 性 值 , 如 果 p a r a m e t e r T y p e 传 输 单 个 简 单 类 型 值 , {}可以接收简单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值, 可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,{} 括号中只能是 value。使用 不 能 防 止 s q l 注 入 , 但 是 有 时 用 {}不能防止 sql 注入,但是有时用 不能防止sql注入,但是有时用{}会非常方便,如下的例子:
<select id="selectUserByName" parameterType="string" resultType="user">
select * from user where username like '%${value}%'
select>
如果本例子使用#{}则传入的字符串中必须有%号,而%是人为拼接在参数中,显然有点麻烦, 如果采用${}在 sql 中拼接为%的方式则在调用 mapper 接口传递参数就方便很多。
//如果使用占位符号则必须人为在传参数中加%
List<User> list = userMapper.selectUserByName("%管理员%");
//如果使用${}原始符号则不用人为在参数中加%
List<User>list = userMapper.selectUserByName("管理员");
再比如 orderby 排序,如果将列名通过参数传入 sql,根据传的列名进行排序,应该写为: ORDERBY${columnName}
如果使用#{}将无法实现此功能。
参考上边的例子。
Mybatis 使用 ognl 表达式解析对象字段的值
<!—传递pojo对象综合查询用户信息 -->
<select id="findUserByUser" parameterType="user" resultType="user">
select * from user where id=#{id} and username like '%${username}%'
select>
#{id}和%${username}%中,id和username是user对象中的字段名称。
开发中通过 pojo 传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。
定义包装对象将查询条件(pojo)以类组合的方式包装起来。
public class QueryVo {
private User user;
//自定义用户扩展类
private UserCustom userCustom;
}
<select id="findUserList" parameterType="queryVo" resultType="user">
select * from user where username=#{user.username} and sex=#{user.sex}
select>
说明:mybatis 底层通过 ognl 从 pojo 中获取属性值:#{user.username},user 即是传入的包装对象的属性。queryVo 是别名,即上边定义的包装对象类型。
<select id="findUserByHashmap" parameterType="hashmap" resultType="user">
select * from user where id=#{id} and username like '%${username}%'
select>
其中id和username是hashmap的key
public void testFindUserByHashmap()throws Exception{
//获取session
SqlSession session = sqlSessionFactory.openSession();
//获限mapper接口实例
UserMapper userMapper = session.getMapper(UserMapper.class);
//构造查询条件Hashmap对象
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("id", 1);
map.put("username", "管理员");
//传递Hashmap对象查询用户列表
List<User>list = userMapper.findUserByHashmap(map);
//关闭session
session.close();
}
Mapper.xml:
<select id="findUserCount" parameterType="user" resultType="int">
select count(1) from user
select>
Mapper 接口:
public int findUserCount(User user) throws Exception;
调用:
public void testFindUserCount() throws Exception{
//获取session
SqlSession session = sqlSessionFactory.openSession();
//获取mapper接口实例
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = new User(); user.setUsername("管理员");
//传递Hashmap对象查询用户列表
int count = userMapper.findUserCount(user);
//关闭session
session.close();
}
输出简单类型必须查询出来的结果集有一条记录,最终将第一个字段的值转换为输出类型。 使用 session 的 selectOne 可查询单条记录。
Mapper.xml :
<select id="findUserById" parameterType="int" resultType="user">
select * from user where id = #{id}
select>
Mapper 接口:
public User findUserById(int id) throws Exception;
测试:
Public void testFindUserById() throws Exception {
//获取session
SqlSession session = sqlSessionFactory.openSession();
//获限mapper接口实例
UserMapper userMapper = session.getMapper(UserMapper.class);
//通过mapper接口调用statement
User user = userMapper.findUserById(1);
System.out.println(user);
//关闭session
session.close();
}
使用 session 调用 selectOne 查询单条记录。
Mapper.xml :
<select id="findUserByUsername" parameterType="string" resultType="user">
select * from user where username like '%${value}%'
select>
Mapper 接口:
public List<User> findUserByUsername(String username) throws Exception;
测试:
public void testFindUserByUsername()throws Exception{
//获取session
SqlSession session = sqlSessionFactory.openSession();
//获限mapper接口实例
UserMapper userMapper = session.getMapper(UserMapper.class);
//如果使用占位符号则必须人为在传参数中加%
//List list = userMapper.selectUserByName("%管理员%");
//如果使用${}原始符号则不用人为在参数中加%
List<User> list = userMapper.findUserByUsername("管理员");
//关闭session
session.close();
}
使用 session 的 selectList 方法获取 pojo 列表。
输出 pojo 对象和输出 pojo 列表在 sql 中定义的 resultType 是一样的。
返回单个 pojo 对象要保证 sql 查询出来的结果集为单条,内部使用 session.selectOne 方法调用,mapper 接口使用 pojo 对象作为方法返回值。
返回 pojo 列表表示查询出来的结果集可能为多条,内部使用 session.selectList 方法,mapper 接口使用 List对象作为方法返回值。
输出 pojo 对象可以改用 hashmap 输出类型,将输出的字段名称作为 map 的 key,value 为字段值。
resultType 可以指定 pojo 将查询结果映射为 pojo,但需要 pojo 的属性名和 sql 查询的列名一致方可映射成功。
如果 sql 查询字段名和 pojo 的属性名不一致,可以通过 resultMap 将字段名和属性名作一个对应关系 ,resultMap 实质上还需要将查询结果映射到 pojo 对象中。
resultMap 可以实现将查询结果映射为复杂类型的 pojo,比如在查询结果映射对象中包括 pojo 和 list 实现一对一查询和一对多查询。
<select id="findUserListResultMap" parameterType="queryVo" resultMap="userListResultMap">
select id id_,username username_,birthday birthday_ from user
<where>
<include refid="query_user_where" />
where>
select>
使用 resultMap 指定上边定义的 personmap。
由于上边的 mapper.xml 中 sql 查询列和 Users.java 类属性不一致,需要定义 resultMap: userListResultMap 将 sql 查询列和 Users.java 类属性对应起来
<resultMap type="user" id="userListResultMap">
<id column="id_" property="id" />
<result column="username_" property="username" />
<result column="birtyday_" property="birtyday" />
resultMap>
:此属性表示查询结果集的唯一标识,非常重要。如果是多个字段为复合唯一约束则定义多个。
Property:表示 person 类的属性。
Column:表示 sql 查询出来的字段名。
Column 和 property 放在一块儿表示将 sql 查询出来的字段映射到指定的 pojo 类属性上。
:普通结果,即 pojo 的属性。
public List<User> findUserListResultMap() throws Exception;
通过 mybatis 提供的各种标签方法实现动态拼接 sql。
<select id="findUserList" parameterType="user" resultType="user">
select * from user where 1=1
<if test="id!=null and id!=''">
and id=#{id}
if>
<if test="username!=null and username!=''">
and username like '%${username}%'
if>
select>
注意要做不等于空字符串校验。
上边的 sql 也可以改为:
<select id="findUserList" parameterType="user" resultType="user">
select * from user
<where>
<if test="id!=null and id!=''">
and id=#{id}
if>
<if test="username!=null and username!=''">
and username like '%${username}%'
if>
where>
select>
可以自动处理第一个 and。
向 sql 传递数组或 List,mybatis 使用 foreach 解析,如下:
传入多个 id 查询用户信息,用下边两个 sql 实现:
SELECT * FROM USERS WHERE username LIKE '%张%' AND (id=10 OR id=89 OR id=16)
SELECT * FROM USERS WHERE username LIKE '%张%' id IN(10,89,16)
在 pojo 中定义 list 属性 ids 存储多个用户 id,并添加 getter/setter 方法
public class QueryVo{
private User user;
//自定义用户扩展类
private UserCustom userCustom;
//传递多个用户id
private List<Integer> ids;
}
mapper.xml
<if test="ids!=null and ids.size>0">
<foreach collection="ids" open=" and id in(" close=")" item="id" separator="," > #{id} foreach>
if>
测试代码:
List<Integer> ids = new ArrayList<Integer>();
ids.add(1); //查询id为1的用户
ids.add(10); //查询id为10的用户
queryVo.setIds(ids);
List<User> list = userMapper.findUserList(queryVo);
传递 List 类型在编写 mapper.xml 没有区别,唯一不同的是只有一个 List 参数时它的参数名为 list。
Mapper.xml
<select id="selectUserByList" parameterType="java.util.List" resultType="user">
select * from user
<where>
<if test="list!=null">
#{item.id} foreach>
if>
where>
select>
Mapper 接口
public List<User> selectUserByList(List userlist) throws Exception;
测试
public void testselectUserByList()throws Exception{
//获取session
SqlSession session = sqlSessionFactory.openSession();
//获限mapper接口实例
UserMapper userMapper = session.getMapper(UserMapper.class);
//构造查询条件List
List<User> userlist = new ArrayList<User>();
User user = new User();
user.setId(1);
userlist.add(user);
user = new User();
user.setId(2);
userlist.add(user);
//传递userlist列表查询用户列表
List<User>list = userMapper.selectUserByList(userlist);
//关闭session
session.close();
}
Mapper.xml
<select id="selectUserByArray" parameterType="Object[]" resultType="user">
select * from user
<where>
<if test="array!=null">
#{item.id} foreach>
if>
where>
select>
sql 只接收一个数组参数,这时 sql 解析参数的名称 mybatis 固定为 array,如果数组是通过一 个 pojo 传递到 sql 则参数的名称为 pojo 中的属性名。
index:为数组的下标。
item:为数组每个元素的名称,名称随意定义
open:循环开始
close:循环结束
separator:中间分隔输出
Mapper 接口
public List<User> selectUserByArray(Object[] userlist) throws Exception;
测试
public void testselectUserByArray()throws Exception{
//获取session
SqlSession session = sqlSessionFactory.openSession();
//获限mapper接口实例
UserMapper userMapper = session.getMapper(UserMapper.class);
//构造查询条件
List Object[] userlist = new Object[2];
User user = new User();
user.setId(1); userlist[0]=user;
user = new User();
user.setId(2); userlist[1]=user;
//传递user对象查询用户列表
List<User>list = userMapper.selectUserByArray(userlist);
//关闭session
session.close();
}
Mapper.xml
<select id="selectUserByArray" parameterType="Object[]" resultType="user">
select * from user
<where>
<if test="array!=null">
#{item} foreach>
if>
where>
select>
如果数组中是简单类型则写为#{item},不用再通过 ognl 获取对象属性值了。
Mapper 接口
public List<User> selectUserByArray(Object[] userlist) throws Exception;
测试
public void testselectUserByArray()throws Exception{
//获取session
SqlSession session = sqlSessionFactory.openSession();
//获限mapper接口实例
UserMapper userMapper = session.getMapper(UserMapper.class);
//构造查询条件
List Object[] userlist = new Object[2];
userlist[0]=”1”;
userlist[1]=”2”;
//传递user对象查询用户列表
List<User>list = userMapper.selectUserByArray(userlist);
//关闭session
session.close();
}
Sql 中可将重复的 sql 提取出来,使用时用 include 引用即可,最终达到 sql 重用的目的
<select id="findUserList" parameterType="user" resultType="user">
select * from user
<where>
<if test="id!=null and id!=''">
and id=#{id}
if>
<if test="username!=null and username!=''">
and username like '%${username}%'
if>
where>
select>
将 where 条件抽取出来
<sql id="query_user_where">
<if test="id!=null and id!=''">
and id=#{id}
if>
<if test="username!=null and username!=''">
and username like '%${username}%'
if>
sql>
使用 include 引用
<select id="findUserList" parameterType="user" resultType="user">
select * from user
<where>
<include refid="query_user_where"/>
where>
select>
注意:如果引用其它 mapper.xml 的 sql 片段,则在引用时需要加上 namespace,如: