天天看点

Mybatis入门系列之(十)——动态sql之foreach

foreach标签

需求:

这样的sql在mybatis中如何实现??

1. foreach实现批量插入

语法如下:

从待处理的部分可以看出,后面时一个值的循环,可以通过foreach实现循环插入。

重新建表 emp:

CREATE TABLE `emp` (
  `id` BIGINT() NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  `user_name` VARCHAR() DEFAULT NULL COMMENT '用户名',
  `user_password` VARCHAR() DEFAULT NULL COMMENT '密码',
  `user_email` VARCHAR() DEFAULT NULL COMMENT '邮箱',
  `user_info` TEXT COMMENT '简介',
  `head_img` BLOB COMMENT '头像',
  `create_time` DATETIME DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT= DEFAULT CHARSET=utf8 COMMENT='用户表';
           

实体类Emp:

/**
 * @author snow
 */
public class Emp {
    /**
     * 用户ID
     */
    private Long id;

    /**
     * 用户名
     */
    private String userName;

    /**
     * 用户密码
     */
    private String userPassword;

    /**
     * 用户邮箱
     */
    private String userEmail;

    /**
     * 简介
     */
    private String userInfo;

    /**
     * 头像
     */
    private Byte[] headImg;

    /**
     * 创建时间
     */
    private Date createTime;
  //省去get和set方法
}
           

创建EmpMapper.java,并添加如下方法:

public interface EmpMapper {
    /**
     * 批量插入用户信息
     * @param emps
     * @return
     */
    int insertList(List<Emp> emps);
}
           

创建EmpMapper.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="tk.mybatis.simple.mapper.EmpMapper">
  <!--
    useGeneratedKeys:返回插入记录的自增主键
    keyProperty:指定属性为id
  -->
  <insert id="insertList" useGeneratedKeys="true" keyProperty="id">
          INSERT INTO emp
            (user_name,user_password,user_email,user_info,head_img,create_time)
          values
          <foreach collection="list" item="emp" separator=",">
              (#{emp.userName},#{emp.userPassword},#{emp.userEmail},
              #{emp.userInfo},#{emp.headImg,jdbcType=BLOB},
              #{emp.createTime,jdbcType=TIMESTAMP})
          </foreach>
    </insert>
</mapper>
           
foreach标签属性的说明:

foreach元素的属性主要有 item,index,collection,open,separator,close。 
    item表示集合中每一个元素进行迭代时的别名,
    index指定一个名字,用于表示在迭代过程中,每次迭代到的位置,
    open表示该语句以什么开始,
    separator表示在每次进行迭代之间以什么符号作为分隔符,
    close表示以什么结束。
           

测试代码如下:

public class EmpMapperTest extends BaseMapperTest{
      @Test
    public void testInsertList(){
        SqlSession sqlSession = getSqlSession();
        try {
            EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
            List<Emp> emps = new ArrayList();

            for(int i=;i<=;i++){
                Emp emp = new Emp();
                emp.setUserName("test "+i);
                emp.setUserPassword("123456");
                emp.setUserInfo("info "+i);
                emp.setUserEmail("email "+i);
                emp.setCreateTime(new Date());
                emps.add(emp);
            }
            int i = empMapper.insertList(emps);
            System.out.println(i);
            for(Emp e : emps){
                System.out.println(e.getId());
            }
        }finally {
            sqlSession.commit();
            sqlSession.close();
        }
    }
}
           

测试结果如下:

[DEBUG] -- ::, method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:)
==>  Preparing: INSERT INTO emp (user_name,user_password,user_email,user_info,head_img,create_time) values (?,?,?, ?,?, ?) , (?,?,?, ?,?, ?) , (?,?,?, ?,?, ?) , (?,?,?, ?,?, ?) , (?,?,?, ?,?, ?) 
[DEBUG] -- ::, method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:)
==> Parameters: test (String), (String), email (String), info (String), null, -- ::(Timestamp), test (String), (String), email (String), info (String), null, -- ::(Timestamp), test (String), (String), email (String), info (String), null, -- ::(Timestamp), test (String), (String), email (String), info (String), null, -- ::(Timestamp), test (String), (String), email (String), info (String), null, -- ::(Timestamp)
[DEBUG] -- ::, method:org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:)
<==    Updates: 






           

测试结果将主键值也返回了。。。

2. foreach实现in集合

在EmpMapper.java中添加如下代码

/**
     * 根据用户id集合查询
     * @param idList
     * @return
     */
    List<Emp> selectByIdList(@Param("idList") List<Long> idList);
           

对应的xml配置如下:

<select id="selectByIdList" resultType="tk.mybatis.simple.model.Emp">
    SELECT * from emp
    <where>
        id in
        <foreach collection="idList" separator="," open="(" close=")"
                 index="i" item="id">
            #{id}
        </foreach>
    </where>
</select>
           

测试代码略去…

如果参数传递的是数组,则代码修改如下:

/**
 * 根据用户id集合查询
 * @param idArray
 * @return
 */
List<Emp> selectByIdList(Long[] idArray);
           

xml配置如下:

<select id="selectByIdList" resultType="tk.mybatis.simple.model.Emp">
        SELECT * from emp
        <where>
            id in
            <foreach collection="array" separator="," open="(" close=")"
                     index="i" item="id">
                #{id}
            </foreach>
        </where>
    </select>
           

3. foreach实现动态update

在EmpMapper.java中添加如下代码:

/**
 * 通过Map更新列
 * @param maps
 * @return
 */
int updateByMap(Map<String,Object> maps);
           

对应的xml的配置

<!--
    这里使用key作为列名,对应的值作为该列的值,
    通过foreach将需要更新的字段拼接在SQL语句中

    由于java代码中没有使用@param注解,mybatis在内部的上下文中使用了默认值
    _parameter作为该参数的key,所以在xml文件中使用_parameter
-->
<update id="updateByMap">
    UPDATE emp
    SET
    <foreach collection="_parameter" item="val" index="key" separator=",">

        ${key} = #{val}
    </foreach>
    where id = #{id}
</update>
           

测试代码如下:

@Test
public void testUpdateByMap(){
    SqlSession sqlSession = getSqlSession();
    try {
        EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
        Map<String,Object> maps = new HashMap<>();
        maps.put("id",L);
        maps.put("user_password","qwwdwedawedaw");
        int i = empMapper.updateByMap(maps);
        System.out.println(i);
    }finally {
        sqlSession.commit();
        sqlSession.close();
    }

}
           

————————————————————————————————————————————————————

其他的一些标签

  1. bind标签可以使用 OGNL 表达式创建一个变量井将其绑定到上下文中
<if test="userName != null and userName != ''">
    AND user_name like  '%'||#{userName}||'%'
</if>
           

可以修改为如下

<if test="userName != null and userName != ''">
    <bind name="userNameLike" value="'%'+userName}+'%'"/>
    AND user_name like  #{userNameLike}
</if>
           

多数据库的支持:

在mybatis-config.xml中加入如下配置,

<!--多数据库的支持-->
<databaseIdProvider type="DB_VENDOR">
    <property name="MySQL" value="mysql"/>
    <property name="Oracle" value="oracle"/>
</databaseIdProvider>
           

修改selectByUser的代码如下:(可以避免切换数据库带来的麻烦。)

<select id="selectByUser" resultType="tk.mybatis.simple.model.SysUser">
    SELECT id,
      user_name userName,
      user_password userPassword,
      user_email userEmai,
      user_info userInfo,
      head_Img headImg,
      create_time createTime
    FROM sys_user
   <where>
       <if test="userName != null and userName != ''">
          <if test="_databaseId=='mysql'">
              AND user_name like  concat('%',#{userName},'%')
          </if>
           <if test="_databaseId=='oracle'">
               AND user_name like  '%'||#{userName}||'%'
           </if>
       </if>
       <if test="userEmail != null and userEmail != ''">
           AND user_email = #{userEmail}
       </if>
   </where>
</select>
           

OGNL表达式

e1 or e2
e1 and e2
e1 == e2,e1 eq e2
e1 != e2,e1 neq e2
e1 lt e2:小于
e1 lte e2:小于等于,其他gt(大于),gte(大于等于)
e1 in e2
e1 not in e2
e1 + e2,e1 * e2,e1/e2,e1 - e2,e1%e2
!e,not e:非,求反
e.method(args)调用对象方法
e.property对象属性值
e1[ e2 ]按索引取值,List,数组和Map
@class@method(args)调用类的静态方法
@class@field调用类的静态字段值
           

定义一个工具类 tk.mybatis.util.StringUtil.java,代码如下:

/**
 * @author snow
 */
public class StringUtil {

    public static boolean isEmpty(String userName){

        return userName == null || userName.length() == ;
    }

    public static boolean isNotEmpty(String userName){

        return  !isEmpty(userName);
    }
}
           

则:

可以修改为如下代码:

<if test="@[email protected](userName)">
</if>