MyBatis-03 动态sql
一、实现动态sql的元素
- if 利用if实现简单的条件选择
- choose 相当于Java中的switch语句,通常与when、otherwise搭配
- where 简化sql语句中的where条件判断
- set 解决动态更新语句
- trim 可以灵活的去除多余的关键字
- foreach 迭代一个集合,通常用于in条件
二、使用动态sql完成多条件查询
注: 以下代码中主要显示sql映射文件中语句,其他环境配置等代码见初始MyBatis-1
1、使用if+where实现多条件查询
UserMapper.java
/**
* 查询用户列表(对象入参)
* @param user
* @return
* @throws Exception
*/
public List<User> getUserList(User user)throws Exception;
UserMapper.xml
<select id="getUserList" resultMap="userList" parameterType="user">
select * from smbms_user
<where>
<!-- if元素判断是否符合test属性中的条件 符合条件进行追加-->
<if test="userRole!=null">
and u.userRole=#{userRole}
</if>
<if test="userName!=null and userName!=''">
and u.userName like CONCAT('%',#{userName},'%')
</if>
</where>
</select
UserMapperTest.java
/**
* 查询用户列表
*/
@Test
public void testGetUserList() {
SqlSession sqlSession = null;
List<User> ulist = null;
try {
// 3.创建sqlSession
sqlSession = MyBatisUtil.createSqlSession();
// 对象入参
User user = new User();
user.setUserName("赵");
user.setUserRole(3);
ulist = sqlSession.getMapper(UserMapper.class).getUserList(user);
for (User u : ulist) {
logger.info("用户编码:"+u.getUserCode()+",用户姓名:"+u.getUserName()+", 用户角色:"+u.getUserRoleName()+",用户地址:"+u.getAddress());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
MyBatisUtil.closeSqlSession(sqlSession);
}
}
2、使用if+trim实现多条件查询
注: 只对UserMapper.xml做修改,其他不做更改。
<!--根据角色id和用户姓名模糊查询用户列表 -->
<select id="getUserList" resultType="user" parameterType="user">
select * from smbms_user
<trim prefix="where" prefixOverrides="and | or">
<if test="userName!=null and userName!=''">
and userName like CONCAT('%',#{userName},'%')
</if>
<if test="userRole!=null">
and userRole=#{userRole}
</if>
</trim>
</select>
讲解:
- trim 元素作用: trim元素会自动识别其标签内是否有返回值,若有返回值,会在自己包含的内容前加上某些前缀,也可在其后加上某些后缀;也可把包含的内容的首部某些内容覆盖(即忽略),或者把尾部内容忽略。
-
trim 元素属性:
- prefix:前缀,通过自动识别是否有返回值后,在trim包含的内容前加上前缀。如where
- suffix:后缀,作用是在trim包含的内容上加上后缀
- prefixOverrides:对于trim包含内容的首部进行执行内容的忽略(如 and | or)
- stuffixOverrides:对于trim包含内容的尾部进行执行内容的忽略(如 and | or)
三、使用动态sql实现更新操作
1、使用if+set改造更新操作
UserMapper.java
/**
* 修改用户
* @param user
* @return
*/
public int modify(User user)throws Exception;
UserMapper.xml
<!--修改指定用户的信息-->
<update id="modify" parameterType="user">
UPDATE smbms_user
<set>
<if test="userCode!=null">userCode=#{userCode},</if>
<if test="userName!=null">userName=#{userName},</if>
<if test="userPassword!=null">userPassword=#{userPassword},</if>
<!--省略属性-->
</set>
where id=#{id}
</update>
2、使用if+trim改造修改操作
注: 只对UserMapper.xml做修改,用法与上述demo相同,此处不做演示
四、使用foreach完成复杂查询
1、foreach基本属性
- item:表示集合中每一个元素进行迭代时的别名
- index:指定一个名称,用于表示在迭代过程中,每次迭代到的位置(可有可无)
- open:表示该语句是以什么开始
- separator:表示在每次进行迭代时以什么符号作为分隔符
- close:表示该语句以什么结束
- collection:该属性必须指定,
- 若入参为单参数且参数类型是一个list时,collection=“list”
- 若入参为单参数且参数类型是一个数组时,collection=“array”
- 若入参为多参数,就需要封装为一个Map处理,collection就为一个map
2、MyBatis入参为数组类型的foreach迭代
Demo演示
需求: 根据传入的角色列表获取角色列表
UserMapper.java
/**
* 根据用户角色列表,获取该角色列表下用户列表信息foreach_array
* @param roleIds
* @return
*/
public List<User> getUserByRoleId_foreach_array(List<Integer> roleIds)throws Exception;
UserMapper.xml
<!--根据角色列表获取用户列表 -->
<select id="getUserByRoleId_foreach_array" resultMap="userMapByRole">
select * from smbms_user where userRole in
<foreach collection="array" item="roleIds" open="(" separator="," close=")">
#{roleIds}
</foreach>
</select>
<resultMap type="User" id="userMapByRole">
<id property="id" column="id"/>
<result property="userCode" column="userCode"/>
<result property="userName" column="userName"/>
</resultMap>
UserMapperTest.java 测试类
/**
* 根据角色列表获取用户列表
*/
@Test
public void testGetUserByRoleId_foreach_array(){
SqlSession sqlSession=null;
List<User> list=new ArrayList<User>();
Integer[] roleIds={2,3};
try {
sqlSession=MyBatisUtil.createSqlSession();
//单参数 类型为数组
list=sqlSession.getMapper(UserMapper.class).getUserByRoleId_foreach_array(roleIds);
} catch (Exception e) {
e.printStackTrace();
}finally
{
MyBatisUtil.closeSqlSession(sqlSession);
}
for (User u : list) {
logger.info("用户编码:"+u.getUserCode()+",用户姓名:"+u.getUserName()+",用户角色:"+u.getUserRole());
}
}
执行结果:
3、MyBatis入参为List类型的foreach迭代
UserMapper.java
/**
* 根据用户角色列表,获取该角色列表下用户列表信息foreach_array
* @param roleIds
* @return
*/
public List<User> getUserByRoleId_foreach_list(List<Integer> roleIds)throws Exception;
UserMapper.xml
<!--根据角色列表获取用户列表 -->
<select id="getUserByRoleId_foreach_list" resultMap="userMapByRole">
select * from smbms_user where userRole in
<foreach collection="list" item="roleList" open="(" separator="," close=")">
#{roleList}
</foreach>
</select>
<resultMap type="User" id="userMapByRole">
<id property="id" column="id"/>
<result property="userCode" column="userCode"/>
<result property="userName" column="userName"/>
</resultMap>
UserMapperTest.java
/**
* 根据角色列表获取用户列表
*/
@Test
public void testGetUserByRoleId_foreach_array(){
SqlSession sqlSession=null;
List<User> list=new ArrayList<User>();
//将多个角色id封装为list集合
List<Integer> roleList=new ArrayList<Integer>();
roleList.add(2);
roleList.add(3);
try {
sqlSession=MyBatisUtil.createSqlSession();
//单参数 list入参
list=sqlSession.getMapper(UserMapper.class).getUserByRoleId_foreach_list(roleList);
} catch (Exception e) {
e.printStackTrace();
}finally
{
MyBatisUtil.closeSqlSession(sqlSession);
}
for (User u : list) {
logger.info("用户编码:"+u.getUserCode()+",用户姓名:"+u.getUserName()+",用户角色:"+u.getUserRole());
}
}
4、MyBatis入参为Map类型的foreach迭代
Demo演示
需求: 获取该角色列表下指定性别的用户列表信息
分析: 多条件查,条件为rolesId 角色列表与gender 性别
编码:
UserMapper.java
/**
* 根据用户角色列表和性别(多参数),获取该角色列表下指定性别的用户列表信息
* @param conditionMap
* @return
* @throws Exception
*/
public List<User> getUserByConditionMap_froeach_map(Map<String,Object> conditionMap)throws Exception;
UserMapper.xml
<!-- 根据角色列表和性别获取用户列表-->
<select id="getUserByConditionMap_froeach_map" resultMap="userMapByRole">
<!--此处#{gender}与map集合中的key对象,value为值;#{roleMap同理}-->
select * from smbms_user where gender=#{gender} and userRole in
<foreach collection="roleIds" item="roleMap" open="(" separator="," close=")">
#{roleMap}
</foreach>
</select>
<resultMap type="User" id="userMapByRole">
<id property="id" column="id"/>
<result property="userCode" column="userCode"/>
<result property="userName" column="userName"/>
</resultMap>
UserMapperTest.java
/**
* 根据用户角色列表和性别(多参数),获取该角色列表下指定性别的用户列表信息
*/
@Test
public void getUserByConditionMap_froeach_mapTest(){
SqlSession sqlSession=null;
List<User> ulist=new ArrayList<User>(); //存放查询出的用户列表
Map<String,Object> conditionMap=new HashMap<String, Object>(); //存放角色列表和性别条件
List<Integer> roleList=new ArrayList<Integer>(); //存放查询条件角色列表
roleList.add(2);
roleList.add(3);
conditionMap.put("roleIds", roleList);
conditionMap.put("gender", 1);
try {
sqlSession=MyBatisUtil.createSqlSession();
ulist=sqlSession.getMapper(UserMapper.class).getUserByConditionMap_froeach_map(conditionMap);
} catch (Exception e) {
e.printStackTrace();
}finally
{
MyBatisUtil.closeSqlSession(sqlSession);
}
for (User u : ulist) {
logger.info("用户编码:"+u.getUserCode()+",用户姓名:"+u.getUserName());
logger.info("用户角色:"+u.getUserRole()+",用户性别:"+u.getGender());
}
}
运行结果:
5、choose(when、otherwise)
基本元素:
- when元素:当其test属性条件满足的时候,就会输出when元素中的内容,当when中一旦有条件满足时,就会跳出choose,即所有的when和otherwise中,只有一个条件会输出。
- otherwise元素:当when中的所有条件都不满足时,就会自动输出otherwise元素中的内容
需求:
根据用户名称、角色id、用户编码、创建日期查询用户列表,如果前三个条件都为空,则默认根据创建日期查询用户。
UserMapper.java
/**
* 根据用户名称、角色id、用户编码、创建日期查询用户列表
* @param userName 用户名称
* @param roleId 角色id
* @param userCode 用户编码
* @param creationDate 创建日期
* @return
* @throws Exception
*/
public List<User> getUserList_choose(@Param("userName")String userName,
@Param("userRole")Integer roleId,@Param("userCode")String userCode,
@Param("creationDate")Date creationDate)throws Exception;
UserMapper.xml
<!-- 根据用户名称、角色id、用户编码、创建日期查询用户列表 -->
<select id="getUserList_choose" resultType="User">
select * from smbms_user where 1=1
<choose>
<!--判断用户名是否为空 -->
<when test="userName!=null and userName!=''">
and userName like CONCAT('%',#{userName},'%')
</when>
<!--判断用户编码是否为空 -->
<when test="userCode!=null and userCode!=''">
and userCode like CONCAT('%',#{userCode},'%')
</when>
<!--判断用户角色是否为空 -->
<when test="userRole!=null">
and userRole=#{userRole}
</when>
<!-- 如果都为空 则默认根据创建日期查询 -->
<otherwise>
and YEAR(creationDate)=YEAR(#{creationDate})
</otherwise>
</choose>
</select>
UserMapperTest.java
/**
* 查询用户列表(choose)
*/
@Test
public void getUserList_chooseTest(){
SqlSession sqlSession=null;
List<User> ulist=new ArrayList<User>(); //存放查询出的用户列表
try {
sqlSession=MyBatisUtil.createSqlSession();
Date date=new SimpleDateFormat("yyy-MM-dd").parse("2016-1-1");
ulist=sqlSession.getMapper(UserMapper.class).getUserList_choose("", null, "", date);
} catch (Exception e) {
e.printStackTrace();
}finally
{
MyBatisUtil.closeSqlSession(sqlSession);
}
for (User u : ulist) {
logger.info("-----------用户列表-----------");
logger.info("用户编码:"+u.getUserCode()+",用户姓名:"+u.getUserName());
logger.info("用户角色:"+u.getUserRole()+",用户性别:"+u.getGender());
}
}
运行结果:
五、MyBatis入参小结
1、MyBatis接收的参数类型:基本类型、对象、list、数组、map
2、无论MyBatis的入参是哪种类型,MyBatis都会将参数放入一个Map中。
对于单参入参的情况
- 若入参为基本类型:变量名作为key,变量值为value,此时生成的map中只有一个元素
- 若参数为对象:对象的属性名作为key,属性值为value
- 若入参为list:默认"list"为key,该List即为value
- 若入参为数组:默认"array"作为key,该数据即为value
- 若入参为Map:键值不变
六、MyBatis补充
1、为实体类起别名
mybatis-config.xml
<typeAliases>
<!--第一种方式:逐个配置->
<!-- <typeAlias type="cn.smbms.pojo.User" alias="user"/> -->
<!--将pojo包下所有javaBean统一配置->
<package name="cn.smbms.pojo"/>
</typeAliases>
Demo结构如图
2、在核心配置文件为mapper做映射
<mappers>
<!-- 第一种方式:使用类资源路径获取资源-->
<mapper resource="cn/smbms/dao/user/UserMapper.xml"></mapper>
<mapper resource="cn/smbms/dao/provider/ProviderMapper.xml"></mapper>
<!-- 第二种方式:使用url获取资源 -->
<!-- <mapper url="file:///D:/UserMapper.xml"></mapper> -->
<!--第三方式 映射接口 -->
<!-- <mapper class="cn.smbms.dao.user.UserMapper"></mapper> -->
<!-- 第4种方式 配置指定包下的文件 -->
<package name="cn.smbms.dao"/>
</mappers>
3、log4j在config.xml文件中的配置方式
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
4、适用于项目与数据库中存在包含下划线的字段,故无法映射的情况(解决方式之一)
<configuration>
<!--设置启用数据库字段下划线映射到java对象的驼峰式命名属性,默认为false-->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
</configuration>