В этом блоге в основном объясняется, как использовать тег foreach для создания динамического Sql, включая следующие три сценария:
- foreach реализует в коллекции
- foreach реализует пакетную вставку
- foreach реализует динамическое обновление
1. foreach реализует в коллекции
Предположим, есть такое требование: чтобы запросить всех подходящих пользователей в соответствии с входящим набором идентификаторов пользователей, нам нужно использовать IN в Sql, например, id в (1,1001).
Сначала добавим в интерфейс SysUserMapper следующий метод:
/**
* 根据用户id集合查询用户
*
* @param idList
* @return
*/
List<SysUser> selectByIdList(List<Long> idList);
Затем добавьте следующий код в соответствующий файл SysUserMapper.xml:
<select id="selectByIdList" resultType="com.zwwhnly.mybatisaction.model.SysUser">
SELECT id,
user_name,
user_password,
user_email,
create_time
FROM sys_user
WHERE id IN
<foreach collection="list" open="(" close=")" separator=","
item="id" index="i">
#{id}
</foreach>
</select>
Наконец, добавьте следующий тестовый метод в тестовый класс SysUserMapperTest:
@Test
public void testSelectByIdList() {
SqlSession sqlSession = getSqlSession();
try {
SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);
List<Long> idList = new ArrayList<Long>();
idList.add(1L);
idList.add(1001L);
List<SysUser> userList = sysUserMapper.selectByIdList(idList);
Assert.assertEquals(2, userList.size());
} finally {
sqlSession.close();
}
}
Запустите тестовый код, тест пройден, и выходной журнал выглядит следующим образом:
DEBUG [main] - ==> Preparing: SELECT id, user_name, user_password, user_email, create_time FROM sys_user WHERE id IN ( ? , ? )
DEBUG [main] - ==> Parameters: 1(Long), 1001(Long)
TRACE [main] - <== Columns: id, user_name, user_password, user_email, create_time
TRACE [main] - <== Row: 1, admin, 123456, admin@mybatis.tk, 2019-06-27 18:21:07.0
TRACE [main] - <== Row: 1001, test, 123456, test@mybatis.tk, 2019-06-27 18:21:07.0
DEBUG [main] - <== Total: 2
Через журнал будет обнаружено, что окончательный оператор Sql, сгенерированный содержимым в элементе foreach, равен (1,1001).
foreach содержит объяснение свойства:
- open: строка в начале всего содержимого цикла.
- close: строка в конце всего содержимого цикла.
- separator: разделитель для каждого цикла.
- item: каждое значение, взятое из итерируемого объекта.
- индекс: если параметр является коллекцией или массивом, значением является текущее значение индекса.Если параметр является типом карты, значением является ключ карты.
- коллекция: имя свойства для повторения цикла.
Некоторым может быть любопытно, почему значением коллекции является список? Как должно быть установлено это значение?
В приведенном выше примере есть только один параметр коллекции, мы устанавливаем значение атрибута коллекции в список, на самом деле его можно записать и как коллекцию Почему? Давайте посмотрим на логику обработки по умолчанию в DefaultSqlSession:
private Object wrapCollection(Object object) {
DefaultSqlSession.StrictMap map;
if (object instanceof Collection) {
map = new DefaultSqlSession.StrictMap();
map.put("collection", object);
if (object instanceof List) {
map.put("list", object);
}
return map;
} else if (object != null && object.getClass().isArray()) {
map = new DefaultSqlSession.StrictMap();
map.put("array", object);
return map;
} else {
return object;
}
}
Хотя код отлично работает со значением по умолчанию, рекомендуется использовать @Param для указания имени параметра следующим образом:
List<SysUser> selectByIdList(@Param("idList") List<Long> idList);
<foreach collection="idList" open="(" close=")" separator=","
item="id" index="i">
#{id}
</foreach>
Если параметр является параметром массива, для коллекции может быть установлено значение массива по умолчанию.После прочтения приведенного выше исходного кода это не должно быть сложно понять.
/**
* 根据用户id数组查询用户
*
* @param idArray
* @return
*/
List<SysUser> selectByIdArray(Long[] idArray);
<select id="selectByIdArray" resultType="com.zwwhnly.mybatisaction.model.SysUser">
SELECT id,
user_name,
user_password,
user_email,
create_time
FROM sys_user
WHERE id IN
<foreach collection="array" open="(" close=")" separator=","
item="id" index="i">
#{id}
</foreach>
</select>
Хотя код отлично работает со значением по умолчанию, рекомендуется использовать @Param для указания имени параметра следующим образом:
List<SysUser> selectByIdArray(@Param("idArray")Long[] idArray);
<foreach collection="idArray" open="(" close=")" separator=","
item="id" index="i">
#{id}
</foreach>
2. foreach для пакетной вставки
Допустим есть такое требование: пачками записывать в базу входящую коллекцию пользователей.
Сначала добавим в интерфейс SysUserMapper следующий метод:
/**
* 批量插入用户信息
*
* @param userList
* @return
*/
int insertList(List<SysUser> userList);
Затем добавьте следующий код в соответствующий файл SysUserMapper.xml:
<insert id="insertList" useGeneratedKeys="true" keyProperty="id">
INSERT INTO sys_user(user_name, user_password, user_email, user_info, head_img, create_time)
VALUES
<foreach collection="list" item="user" separator=",">
(#{user.userName},#{user.userPassword},#{user.userEmail},#{user.userInfo},#{user.headImg,jdbcType=BLOB},#{user.createTime,jdbcType=TIMESTAMP})
</foreach>
</insert>
Наконец, добавьте следующий тестовый метод в тестовый класс SysUserMapperTest:
@Test
public void testInsertList() {
SqlSession sqlSession = getSqlSession();
try {
SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);
List<SysUser> sysUserList = new ArrayList<SysUser>();
for (int i = 0; i < 2; i++) {
SysUser sysUser = new SysUser();
sysUser.setUserName("test" + i);
sysUser.setUserPassword("123456");
sysUser.setUserEmail("test@mybatis.tk");
sysUserList.add(sysUser);
}
int result = sysUserMapper.insertList(sysUserList);
for (SysUser sysUser : sysUserList) {
System.out.println(sysUser.getId());
}
Assert.assertEquals(2, result);
} finally {
sqlSession.close();
}
}
Запустите тестовый код, тест пройден, и выходной журнал выглядит следующим образом:
DEBUG [main] - ==> Preparing: INSERT INTO sys_user(user_name, user_password, user_email, user_info, head_img, create_time) VALUES (?,?,?,?,?,?) , (?,?,?,?,?,?)
DEBUG [main] - ==> Parameters: test0(String), 123456(String), test@mybatis.tk(String), null, null, null, test1(String), 123456(String), test@mybatis.tk(String), null, null, null
DEBUG [main] - <== Updates: 2
1035
1036
3. foreach реализует динамическое обновление
Предположим, есть такое требование: обновить информацию о пользователе согласно пришедшему параметру Map.
Сначала добавим в интерфейс SysUserMapper следующий метод:
/**
* 通过Map更新列
*
* @param map
* @return
*/
int updateByMap(Map<String, Object> map);
Затем добавьте следующий код в соответствующий файл SysUserMapper.xml:
<update id="updateByMap">
UPDATE sys_user
SET
<foreach collection="_parameter" item="val" index="key" separator=",">
${key} = #{val}
</foreach>
WHERE id = #{id}
</update>
Наконец, добавьте следующий тестовый метод в тестовый класс SysUserMapperTest:
@Test
public void testUpdateByMap() {
SqlSession sqlSession = getSqlSession();
try {
SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);
Map<String, Object> map = new HashMap<String, Object>();
map.put("id", 1L);
map.put("user_email", "test@mybatis.tk");
map.put("user_password", "12345678");
Assert.assertEquals(1, sysUserMapper.updateByMap(map));
SysUser sysUser = sysUserMapper.selectById(1L);
Assert.assertEquals("test@mybatis.tk", sysUser.getUserEmail());
Assert.assertEquals("12345678", sysUser.getUserPassword());
} finally {
sqlSession.close();
}
}
Запустите тестовый код, тест пройден, и выходной журнал выглядит следующим образом:
DEBUG [main] - ==> Preparing: UPDATE sys_user SET user_email = ? , user_password = ? , id = ? WHERE id = ?
DEBUG [main] - ==> Parameters: test@mybatis.tk(String), 12345678(String), 1(Long), 1(Long)
DEBUG [main] - <== Updates: 1
DEBUG [main] - ==> Preparing: SELECT id, user_name, user_password, user_email, create_time FROM sys_user WHERE id = ?
DEBUG [main] - ==> Parameters: 1(Long)
TRACE [main] - <== Columns: id, user_name, user_password, user_email, create_time
TRACE [main] - <== Row: 1, admin, 12345678, test@mybatis.tk, 2019-06-27 18:21:07.0
DEBUG [main] - <== Total: 1
В приведенном выше примере коллекция использует значение по умолчанию _parameter, или вы можете использовать @Param для указания имени параметра следующим образом:
int updateByMap(@Param("userMap") Map<String, Object> map);
<update id="updateByMap">
UPDATE sys_user
SET
<foreach collection="userMap" item="val" index="key" separator=",">
${key} = #{val}
</foreach>
WHERE id = #{userMap.id}
</update>
4. Исходный код и ссылка
Адрес источника:GitHub.com/Как Ухань, где/каждый шаг…, добро пожаловать на скачивание.
Лю Цзэнхуэй "MyBatis от входа до мастерства"