mybatis-02(mapper.xml映射文件,动态sql)
一.mapper xml映射文件
MyBatis 的真正强大在于它的映射语句,也是它的魔力所在。由于它的异常强
大,映射器的 XML 文件就显得相对简单。如果拿它跟具有相同功能的 JDBC
代码进
行对比,你会立即发现省掉了将近 95% 的代码。MyBatis 就是针对 SQL
构建的,并
且比普通的方法做的更好。
SQL 映射文件有很少的几个顶级元素(按照它们应该被定义的顺序):
• cache -- 给定命名空间的缓存配置。
• cache-ref -- 其他命名空间缓存配置的引用。
• resultMap --
是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加
载对象。
• parameterMap -- 已废弃!老式风格的参数映射。内联参数是首选,这个元素可
能在将来被移除,这里不会记录。
• sql -- 可被其他语句引用的可重用语句块。
• insert -- 映射插入语句
• update -- 映射更新语句
• delete -- 映射删除语句
• select -- 映射查询语句
查询语句是 MyBatis 中最常用的元素之一(映射文件配置见代码)
**1.Select 元素标签使用
**有以下属性可供在查询时配置其对应查询属性
1输入参数分类
基本类型,字符串,java bean,map,数组(删除操作时体现),List(添加时体
现)等每种情况定义如下
基本数据类型
字符串数据类型
javabean类型
map类型
2输出类型
int类型
字符串类型
map类型
List类型
[[3.输入输出不同类型的案例测试]{.underline}]{.smallcaps}
[数据库字段:]{.smallcaps}
1)配置UserMapper.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">
<!--
1.命名空间配置 全局唯一 包名+文件名
2.配置Mapped Statement
3. statement配置
id 值声明statement编号 同一命名空间(同一文件)下不可重复
parameterType 输入参数即占位符的数据类型 类型可以是 基本数据类型,字符串,java bean ,map,list等
resultType 输出结果 类型可以是基本数据类型,字符串,java bean,map等
statement 描述 即待执行的sql
#{id} 占位符 变量名为id/value 均可 ${value} 变量名必须为value 字符串拼接形式 无法避免sql 注入
-->
<mapper namespace="com.shsxt.mapper.UserMapper">
<!-- select -->
<!-- 输入类型 -->
<!-- 基本数据类型: int -->
<select id="queryUserById" parameterType="int" resultType="user">
select id,user_name as userName,user_pwd as userPwd from user where id=#{id}
</select>
<!-- 基本数据类型: String -->
<select id="queryUserByName" parameterType="string" resultType="user">
select id,user_name as userName,user_pwd as userPwd from user where user_name=#{userName}
</select>
<!-- Java Bean -->
<select id="queryUserByUser" parameterType="user" resultType="user">
select id,user_name as userName,user_pwd as userPwd from user where user_name=#{userName}
</select>
<!-- Map -->
<select id="queryUserByMap" parameterType="map" resultType="user">
select id,user_name as userName,user_pwd as userPwd from user where user_name=#{userName}
</select>
<!-- 输出类型 -->
<!-- int -->
<select id="queryUserTotal" resultType="int">
SELECT count(*) FROM user
</select>
<!-- String -->
<select id="queryUserNameById" resultType="string">
SELECT user_name FROM user WHERE id=#{id}
</select>
<!-- Map -->
<select id="queryUserMapById" resultType="map">
SELECT * FROM user WHERE id=#{id}
</select>
<!-- List -->
<select id="queryUserList" resultType="user">
SELECT * FROM user
</select>
</mapper>
2)UserMapper接口中添加方法
*/
public interface UserMapper {
/*测试不同输入类型*/
public User queryUserById(Integer id);
public User queryUserByName(String userName);
public User queryUserByUser(User user);
public User queryUserByMap(Map map);
/*
测试不同输出结果类型
*/
public Integer queryUserTotal();
public String queryUserNameById(Integer id);
public Map queryUserMapById(Integer id);
public List<User> queryUserList();
}
3)实现类UserDaoImpl中复写方法
public class UserDaoImpl implements UserMapper {
/**
* 到整合 spring 时 直接注入即可
*/
private SqlSessionFactory build;
public UserDaoImpl(SqlSessionFactory build) {
this.build = build;
}
@Override
public User queryUserById(Integer id) {
SqlSession session = build.openSession();
/**
* 调用 selectOne 查询方法 返回单条记录 多条记录会报错!
* 参数 1:UserMapper.xml 中对应的 statement id 同时加上命名空间
* 参数 2:输入参数
*/
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = userMapper.queryUserById(id);
session.close();
return user;
}
/*
测试输入类型为String
*/
@Override
public User queryUserByName(String userName) {
SqlSession session = build.openSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = userMapper.queryUserByName(userName);
session.close();
return user;
}
/**
* 测试输入类型为javabean
* @param user
* @return
*/
@Override
public User queryUserByUser(User user) {
SqlSession session = build.openSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
User user2 = userMapper.queryUserByUser(user);
session.close();
return user2;
}
/*
测试输入类型为map
*/
@Override
public User queryUserByMap(Map map) {
SqlSession session = build.openSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = userMapper.queryUserByMap(map);
session.close();
return user;
}
/**
* 测试输出类型为int
* @return
*/
@Override
public Integer queryUserTotal() {
SqlSession session = build.openSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
Integer total = userMapper.queryUserTotal();
session.close();
return total;
}
/**
* 测试返回结果为字符串
* @param id
* @return
*/
@Override
public String queryUserNameById(Integer id) {
SqlSession session = build.openSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
String userName = userMapper.queryUserNameById(id);
session.close();
return userName;
}
/**
* 测试返回类型为map
* @param id
* @return
*/
@Override
public Map queryUserMapById(Integer id) {
SqlSession session = build.openSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
Map map = userMapper.queryUserMapById(id);
session.close();
return map;
}
/**
* 返回值为list
* @return
*/
@Override
public List<User> queryUserList() {
SqlSession session = build.openSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
List<User> list = userMapper.queryUserList();
session.close();
return list;
}
}
4)测试类中测试结果
public class UserDaoImplTest {
SqlSessionFactory build;
UserDaoImpl userDao;
@Before
public void init() throws IOException {
InputStream is= Resources.getResourceAsStream("mybatis.xml");
build = new SqlSessionFactoryBuilder().build(is);
userDao = new UserDaoImpl(build);
}
@Test
public void queryUserById() throws Exception {
User user = userDao.queryUserById(6);
System.out.println(user);
}
@Test
public void queryUserByName() throws Exception {
User user = userDao.queryUserByName("jackie02");
System.out.println(user);
}
/**
* 测试输入类型为javabean
* @throws Exception
*/
@Test
public void queryUserByUser() throws Exception {
User user2 =new User();
user2.setUserName("jackie02");
User user = userDao.queryUserByUser(user2);
System.out.println(user);
}
/**
* 测试输入类型为map
*/
@Test
public void queryUserByMap() throws Exception {
Map map =new HashMap();
map.put("userName","jackie02");
User user = userDao.queryUserByMap(map);
System.out.println(user);
}
/**
* 测试输出类型为int
*/
@Test
public void queryUserTotal() throws Exception {
Integer total =userDao.queryUserTotal();
System.out.println("total:--"+total);
}
/**
* 测试输出类型为String
*/
@Test
public void queryUserNameById() throws Exception {
String userName =userDao.queryUserNameById(6);
System.out.println("userName:--"+userName);
}
/**
* 测试输出类型为Map
*/
@Test
public void queryUserMapById() throws Exception {
Map map =userDao.queryUserMapById(6);
System.out.println("map:--"+map);
System.out.println("map:value--"+map.get("user_name"));
}
/**
* 测试输出类型为list
*/
@Test
public void queryUserList() throws Exception {
List<User> list =userDao.queryUserList();
/*遍历list*/
list.stream().forEach(System.out::println);
}
}
5)测试结果
输入类型int类型
输入类型字符串
![输入类型javabean
输入类型map结果
[[输出结果为int]{.underline}]{.smallcaps}
输出结果 为STRING
[[返回结果为map]{.underline}]{.smallcaps}
[[返回结果为list]{.underline}]{.smallcaps}
2.Insert 元素标签使用
2.1添加记录不返回主键配置
1)UserMapper.xml中配置
<insert id="addUserNoKey" parameterType="user">
sql插入语句
</insert>
2)UserMapper接口中加方法
3)UserDaoImpl中实现此方法
addUserNoKey();
(注意默认mybatis不自动提交事务)
a:手动提交:session.commit
b:自动提交openSession(true)
4)测试类UserDaoImplTest中测试方法
2.2.添加返回主键
1)UserMapper.xml中增加配置
- A利用标签方式添加:mysql与oracle不同
mysql情况
<insert id="addUserHasKey" parameterType="user">
<selectKey keyProperty="id" order="AFTER" resultType="int">
select LAST_INSERT_ID() as id
</selectKey>
insert into user(user_name,user_pwd) values(#{userName},#{userPwd})
</insert>
Oracle 情况
<selectKey resultType="int" order="BEFORE" keyProperty="id">
SELECT LOGS_SEQ.nextval AS ID FROM DUAL
</selectKey>
- B.或者使用useGeneratedKeys="true" keyProperty="id">添加
2)接口中加方法
3)UserDaoImpl中实现方法
4)UserDaoImplTest中测试方法
2.3. 批量添加记录返回影响总记录行数(属性配置)
2.4添加记录实例
1)UserMapper.xml配置文件
<!-- 添加insert操作-->
<insert id="addUserNoKey" parameterType="user">
INSERT INTO user(
user_name,user_pwd)
VALUES (
#{userName},#{userPwd})
</insert>
<!--添加返回主键1-->
<insert id="addUserHasKey" parameterType="user">
<selectKey keyProperty="id" order="AFTER" resultType="int">
SELECT LAST_INSERT_ID() as id
</selectKey>
INSERT INTO user (
user_name,
user_pwd
)
VALUES
(
#{userName},
#{userPwd}
)
</insert>
<!--添加返回主键方式2-->
<insert id="addUserHasKey2" parameterType="user" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user (
user_name,
user_pwd
)
VALUES
(
#{userName},
#{userPwd}
)
</insert>
<!-- 批量添加方法,多个对象使用list-->
<insert id="addUserBatch" parameterType="list">
INSERT INTO user (
user_name,
user_pwd
)
VALUES
<foreach collection="list" item="item" separator=",">
(
#{item.userName},
#{item.userPwd}
)
</foreach>
</insert>
</mapper>
2)UserMapper接口中添加方法
public interface UserMapper {
/*
测试添加操作(接口中加方法)
*/
public Integer addUserNoKey(User user);
public Integer addUserHasKey(User user); //添加返回主键1
public Integer addUserHasKey2(User user); //添加返回主键2
public Integer addUserBatch(List<User> list); //批量添加
3)UserDaoImpl中实现方法
public class UserDaoImpl implements UserMapper {
/**
* 到整合 spring 时 直接注入即可
*/
private SqlSessionFactory build;
public UserDaoImpl(SqlSessionFactory build) {
this.build = build;
}
/**
* insert添加记录不返回主键
* @param user
* @return
*/
@Override
public Integer addUserNoKey(User user) {
SqlSession session = build.openSession(true);//自动提交事务
UserMapper userMapper = session.getMapper(UserMapper.class);
Integer total = userMapper.addUserNoKey(user);
//第一种,手动提交事务
/* session.commit();*/
session.close();
return total;
}
/**
* 添加记录返回主键(通过标签配置)
* @param
* @return
*/
@Override
public Integer addUserHasKey(User user) {
SqlSession session = build.openSession(true);// 自动提交
UserMapper userMapper = session.getMapper(UserMapper.class);
Integer total = userMapper.addUserHasKey(user);
session.close();
return total;
}
/**
* 添加记录返回主键方式2
* @param user
* @return
*/
@Override
public Integer addUserHasKey2(User user) {
SqlSession session = build.openSession(true);// 自动提交
UserMapper userMapper = session.getMapper(UserMapper.class);
Integer total = userMapper.addUserHasKey2(user);
session.close();
return total;
}
/**
* 批量添加记录返回影响总记录行数
* @param list
* @return
*/
@Override
public Integer addUserBatch(List<User> list) {
SqlSession session = build.openSession(true);// 自动提交
UserMapper userMapper = session.getMapper(UserMapper.class);
Integer total = userMapper.addUserBatch(list);
session.close();
return total;
}
4)测试类UserDaoImplTest中测试方法
public class UserDaoImplTest {
SqlSessionFactory build;
UserDaoImpl userDao;
@Before
public void init() throws IOException {
InputStream is= Resources.getResourceAsStream("mybatis.xml");
build = new SqlSessionFactoryBuilder().build(is);
userDao = new UserDaoImpl(build);
}
/**
* 测试添加记录不返回主键
* @throws Exception
*/
@Test
public void addUserNoKey() throws Exception {
User user =new User(); //数据库添加一条记录
user.setUserName("test888");
user.setUserPwd("888888");
Integer total = userDao.addUserNoKey(user);
System.out.println(total);
}
/**
* 测试添加记录返回主键1
* @throws Exception
*/
@Test
public void addUserHasKey() throws Exception {
User user = new User();
user.setUserName("test008");
user.setUserPwd("888888");
userDao.addUserHasKey(user);
//取得ID代表返回主键成功
System.out.println("id: "+user.getId());
}
/**
* 添加记录返回主键2测试
* @throws Exception
*/
@Test
public void addUserHasKey2() throws Exception {
User user = new User();
user.setUserName("test009");
user.setUserPwd("99999");
userDao.addUserHasKey2(user);
//取得ID代表返回主键成功
System.out.println("id: "+user.getId());
}
/**
* 批量添加记录测试
* @throws Exception
*/
@Test
public void addUserBatch() throws Exception {
List<User> userList =new ArrayList<>();
for(int i=0 ;i<10;i++){ //批量添加10条记录
User user = new User();
user.setUserName("test0_"+i);
user.setUserPwd("99999");
userList.add(user);
}
userDao.addUserBatch(userList);
}
[[测试结果如下]
[[a,添加记录不返回主键配置]{.underline}]{.smallcaps}
[[b.添加记录返回主键(标签)]{.underline}]{.smallcaps}
[[c添加记录返回主键(设置属性)]{.underline}]{.smallcaps}
[[d批量添加记录]{.underline}]{.smallcaps}
3.Update 元素标签使用
3.1更新单条记录返回影响行数
3.2批量更新多条记录 属性配置
[[3.3批量更新实例]
1) UserMapper.xml配置文件
<!-- 更新操作update-->
<update id="updateUser" parameterType="user">
UPDATE user set user_name=#{userName},user_Pwd=#{userPwd} WHERE id=#{id}
</update>
<!--批量更新操作update-->
<update id="updateUserBatch">
UPDATE user set user_pwd='123456' where id in(
<foreach collection="array" item="item" separator=",">
#{item}
</foreach>
)
</update>
</mapper>
2)UserMapper接口中添加方法
public interface UserMapper {
/*
测试更新操作(接口加方法)
*/
public Integer updateUser(User user);
public Integer updateUserBatch(Integer[] ids);
3)UserDaoImpl中实现方法
public class UserDaoImpl implements UserMapper {
/**
* 到整合 spring 时 直接注入即可
*/
private SqlSessionFactory build;
public UserDaoImpl(SqlSessionFactory build) {
this.build = build;
}
/**
* 更新更新单条记录返回影响行数
* @param user
* @return
*/
@Override
public Integer updateUser(User user) {
SqlSession session = build.openSession(true);// 自动提交
UserMapper userMapper = session.getMapper(UserMapper.class);
Integer total = userMapper.updateUser(user);
session.close();
return total;
}
/**
* 批量更新记录
* @param ids
* @return
*/
@Override
public Integer updateUserBatch(Integer[] ids) {
SqlSession session = build.openSession(true);// 自动提交
UserMapper userMapper = session.getMapper(UserMapper.class);
Integer total = userMapper.updateUserBatch(ids);
session.close();
return total;
}
4)测试类UserDaoImplTest中测试方法
public class UserDaoImplTest {
SqlSessionFactory build;
UserDaoImpl userDao;
@Before
public void init() throws IOException {
InputStream is= Resources.getResourceAsStream("mybatis.xml");
build = new SqlSessionFactoryBuilder().build(is);
userDao = new UserDaoImpl(build);
}
/**
* 测试更新单条记录返回受影响行数
*/
@Test
public void updateUser() throws Exception {
User user = new User();
user.setUserName("test_100");
user.setUserPwd("888888");
user.setId(136);
userDao.updateUser(user);
}
/**
* 测试批量更新
*/
@Test
public void updateUserBatch() throws Exception {
Integer[] ids ={134,135,136};
userDao.updateUserBatch(ids);
}
[[测试结果]
[[A更新单条记录]{.underline}]{.smallcaps}
4.Delete 元素标签使用
4.1删除单条记录
4.2批量删除多条记录(属性配置)
4.3删除案例
1) UserMapper.xml配置文件
<!-- 删除操作delete-->
<delete id="delUserById" parameterType="int">
delete from user where id=#{id}
</delete>
<!-- 批量删除操作-->
<delete id="deleteUserBatch" >
delete from user where id in
<foreach collection="array" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</delete>
</mapper>
2)UserMapper接口中添加方法
public interface UserMapper {
/*
测试删除操作
*/
public Integer delUserById(Integer id);
public Integer deleteUserBatch(Integer[] ids);
3)UserDaoImpl中实现方法
public class UserDaoImpl implements UserMapper {
/**
* 到整合 spring 时 直接注入即可
*/
private SqlSessionFactory build;
public UserDaoImpl(SqlSessionFactory build) {
this.build = build;
}
/**
* 删除单条记录
*/
@Override
public Integer delUserById(Integer id) {
SqlSession session = build.openSession(true);// 自动提交
UserMapper userMapper = session.getMapper(UserMapper.class);
Integer total = userMapper.delUserById(id);
session.close();
return total;
}
/**
* 批量删除记录
*/
@Override
public Integer deleteUserBatch(Integer[] ids) {
SqlSession session = build.openSession(true);// 自动提交
UserMapper userMapper = session.getMapper(UserMapper.class);
Integer total = userMapper.deleteUserBatch(ids);
session.close();
return total;
}
4)测试类UserDaoImplTest中测试方法
public class UserDaoImplTest {
SqlSessionFactory build;
UserDaoImpl userDao;
@Before
public void init() throws IOException {
InputStream is= Resources.getResourceAsStream("mybatis.xml");
build = new SqlSessionFactoryBuilder().build(is);
userDao = new UserDaoImpl(build);
}
/**
* 删除单条记录
*/
@Test
public void delUserById() throws Exception {
userDao.delUserById(133);
}
/**
* 批量删除记录
*/
@Test
public void deleteUserBatch() throws Exception {
Integer[] ids = {134,135,136};
userDao.deleteUserBatch(ids);
}
[[测试结果]
5.sql
sql 元素用来定义一个可以复用的 SQL
语句段,供其它语句调用。比如:
先定义一个可以复用的sql
<sql id="base"> id,user_name as userName,user_pwd as userPwd </sql>
<!-- select -->
<!-- 输入类型 -->
<!-- 基本数据类型: int 用include引用-->
<select id="queryUserById" parameterType="int" resultType="user">
select <include refid="base"/> from user where id=#{id}
</select>
<!-- 基本数据类型: String -->
<select id="queryUserByName" parameterType="string" resultType="user">
select <include refid="base"/> from user where user_name=#{userName}
</select>
6.参数(Parameters)
MyBatis 的参数可以使用的基本数据类型和 Java 的复杂数据类型。
基本数据类型,string,int,date 等。
但是使用基本数据类型,只能提供一个参数,所以需要使用 Java 实
体类,或 Map 类型做参数类型。通过#{}可以直接得到其属性。
7.字符串替换
默认情况下,使用#{}格式的语法会导致 MyBatis
创建预处理语句属性并安全地设置值
(比如?) 。 这样做更安全, 更迅速, 通常也是首选做法,
不过有时你只是想直接在SQL 语句中插入一个不改变的字符串。 比如, 像 ORDER
BY, 你可以这样来使用:
ORDER BY ${columnName}
8.Result Maps
resultMap 元素是 MyBatis 中最重要最强大的元素. 简单理解它的作用就是描述
对象的属性和数据库的对应关系. 将我们从数据库中查询出来的结果自动映射成
javabean. 有了它我们不但可以单独查询一个表还可以级联查询.
resultmap的用法
<resultMap id="baseMap" type="user">
<id column="id" property="id"></id>
<result column="user_name" property="userName"></result>
<result column="user_pwd" property="userPwd"></result>
</resultMap>
<!-- Java Bean -->
<select id="queryUserByUser" parameterType="user" resultMap="baseMap">
select * from user where user_name=#{userName}
</select>
二、 mapper 接口代理方式的 crud 开发\
对于 mapper 接口方式开发,需要遵循 mybatis 开发规范,mybatis 框架可以自
动生成 mapper 接口对象。
完成账户表 crud 操作
开发规则:\
- mapper.xml 中 namespace 等于接口类全限定名\
- mapper.java 接口中的方法名必须与 mapper.xml 中 statement id 一致\
- mapper.java 输入参数类型必须与 mapper.xml 中 statement 的
parameterType 参数类型一致
4.mapper.java 中方法的返回值类型必须与 mapper.xml 中对应 statement 返回
值类型一致。
**接口名 与映射文件名称 不一致(集成环境)
映射文件与接口处于同一个包中(非集成环境)
**
三. 动态 sql 语句\
**3.1基于 xml 配置
**MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其他类似
框架的经验,你就能体会到根据不同条件拼接 SQL
语句有多么痛苦。拼接的时候要确
保不能忘了必要的空格,还要注意省掉列名列表最后的逗号。利用动态 SQL
这一特性
可以彻底摆脱这种痛苦。它借助 ognl(类似于 jsp 里面的 el
表达式)表达式来完成动
态 sql 的拼接使得非常简便。
1 if 条件判断
动态 SQL 通常要做的事情是有条件地包含 where 子句的一部分。
使用 if 标签就是加一个 test 属性作为判断, 如果有多个条件组合判断的话用
and, or连接.
1)UserMapper.xml中添加if标签,判断模糊匹配的userName是否为空
<mapper namespace="com.shsxt.mapper.UserMapper">
<!-- 模糊匹配 -->
<select id="queryUserByUserName" parameterType="user" resultType="user">
select id,user_name as userName,user_pwd as userPwd from user where 1=1
<if test="null!=userName and ''!=userName">
and user_name like concat('%',#{userName},'%')
</if>
</select>
<!-- 模糊匹配 参数类型为string-->
<select id="queryUserByUserName2" parameterType="string" resultType="user">
select id,user_name as userName,user_pwd as userPwd from user where 1=1
<if test="null!=userName and ''!=userName">
and user_name like concat('%',#{userName},'%')
</if>
</select>
2)userMappe.java中添加方法
当参数类型为string时,需要在方法中加@Param("userName"),防止查询出错
public interface UserMapper {
/*
测试if条件判断
*/
public List<User> queryUserByUserName(User user);
public List<User> queryUserByUserName2(@Param("userName") String userName);//避免if标签会造成string取不到值,添加注解
3)测试类MybatisTest测试sql 自动判断并且拼接上了
public class MyBatisTest {
UserMapper userMapper;
@Before
public void init() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(is);
SqlSession session = build.openSession();
userMapper = session.getMapper(UserMapper.class);
}
/**
* 测试if标签
*/
@Test
public void queryUserByUserName() {
User user = new User();
user.setUserName("test");
List<User> userList = userMapper.queryUserByUserName(user);
userList.stream().forEach(System.out::println);
}
@Test
public void queryUserByUserName2() {
List<User> userList = userMapper.queryUserByUserName2("test");//调用的时候直接传值就可以了
userList.stream().forEach(System.out::println);
}
[[测试结果]
2.choose, when, otherwise 选择器使用
我们不想用到所有的条件语句,而只想从中择其一二。针对这种情况,MyBatis
提供
了 choose 元素,它有点像 Java 中的 switch 语句
1)配置UserMapper.xml文件
<!-- choose when, otherwise -->
<select id="queryUserByNation" parameterType="user" resultType="user">
SELECT id,
<choose>
<when test="null!=nation and ''!=nation">
user_name as userName
</when>
<otherwise>
real_name as realName
</otherwise>
</choose>
from user
</select>
这条语句的意思就是说 如果我传进 nation 不为空就查 userName 的值, 否则是
realName 的值
2)UserMapper添加方法
public interface UserMapper {
/*
测试choose, when, otherwise 选择器使用
*/
public List<User> queryUserByNation(User user);
2)测试类MybatisTest验证
public class MyBatisTest {
UserMapper userMapper;
@Before
public void init() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(is);
SqlSession session = build.openSession();
userMapper = session.getMapper(UserMapper.class);
}
/**
* 测试choose, when, otherwise 选择器使用
*/
@Test
public void queryUserByNation() {
User user = new User();
user.setNation("china");
List<User> userList = userMapper.queryUserByNation(user);
userList.stream().forEach(System.out::println);
}
[[测试结果]
[[nation为空运行结果]{.underline}]{.smallcaps}
[[nation设定值值结果]{.underline}]{.smallcaps}
*3.trim, where, set*
***前面几个例子已经合宜地解决了一个臭名昭著的动态 SQL 问题,
然后我们再来看第一条的配置
3.1where标签
1)配置UserMapper.xml文件,利用where标签,判断userName或者userPwd是否为空进行不同的查询.
<!-- trim, where, set标签使用-->
<select id="queryUserList" parameterType="user" resultType="user">
select id,user_name as userName,user_pwd as userPwd from user
WHERE 1=1
<if test="null!=userName and ''!=userName">
and user_name like concat('%',#{userName},'%')
</if>
<if test="null!=userPwd and ''!=userPwd">
and user_pwd like concat('%',#{userPwd},'%')
</if>
</select>
<!--利用where标签判断,优化上步骤-->
<select id="queryUserList2" parameterType="user" resultType="user">
select id,user_name as userName,user_pwd as userPwd from user
<where>
<if test="null!=userName and ''!=userName">
and user_name like concat('%',#{userName},'%')
</if>
<if test="null!=userPwd and ''!=userPwd">
and user_pwd like concat('%',#{userPwd},'%')
</if>
</where>
</select>
2)UserMapper中添加查询方法
public interface UserMapper {
/**
* trim, where, set
*/
public List<User> queryUserList2(User user);
3)MybatisTest进行验证
/**
* 测试where标签.根据userName或者userPwd查询
*/
@Test
public void queryUserList2() {
User user = new User();
user.setUserName("test");
// user.setUserPwd("88");
List<User> userList = userMapper.queryUserList2(user);
// userList.stream().forEach(System.out::println);
}
[[测试结果:
userName设定值,userPwd为空时,sql只根据userName查询
userName和userPwd都设定值,两个条件一起查询
3.2trim标签
我们还是可以通过自定义 trim 元素来定制我们想要的功能。 比如, 和 where
元素等价的自定义 trim 元素.
prefixOverrides
属性会忽略通过管道分隔的文本序列(注意此例中的空格也是必要
的)。它带来的结果就是所有在 prefixOverrides
属性中指定的内容将被移除,并且插
入 prefix 属性中指定的内容。
1)配置UserMapper.xml文件,添加trim标签,自定义prefix内容,模拟where一样的效果.
<!--trim标签-->
<select id="queryUserList3" parameterType="user" resultType="user">
select id,user_name as userName,user_pwd as userPwd from user
<trim prefix="where" prefixOverrides="and">
<if test="null!=userName and ''!=userName">
and user_name like concat('%',#{userName},'%')
</if>
<if test="null!=userPwd and ''!=userPwd">
and user_pwd like concat('%',#{userPwd},'%')
</if>
</trim>
</select>
2)UserMapper中添加查询方法
/*
测试trim标签
*/
public List<User> queryUserList3(User user);
3)MybatisTest进行验证,结果同上
/**
* 测试trim标签,结果同上,模拟where效果
*/
@Test
public void queryUserList3() {
User user = new User();
user.setUserName("test");
user.setUserPwd("88");
List<User> userList = userMapper.queryUserList3(user);
// userList.stream().forEach(System.out::println);
}
3.3set标签
对于 update 语句, 我们采用<set></set>去设置值
1)配置UserMapper.xml文件,添加set标签,用来更新user_name与user_pwd.也可以用trim标签自定义实现set的效果
<!--测试set标签,可以去除多余的逗号-->
<update id="updateUser" parameterType="user">
UPDATE user
<set>
<if test="null!=userName">
user_name=#{userName},
</if>
<if test="null!=userPwd">
user_pwd=#{userPwd},
</if>
</set>
where id=#{id}
</update>
<!--还可以用trim来模拟set-->
<update id="updateUser2" parameterType="user">
UPDATE user
<trim prefix="set" suffixOverrides=",">
<if test="null!=userName">
user_name=#{userName},
</if>
<if test="null!=userPwd">
user_pwd=#{userPwd},
</if>
</trim>
where id=#{id}
</update>
</mapper>
2)UserMapper中添加查询方法
/*
测试set标签
*/
public Integer updateUser(User user);
public Integer updateUser2(User user);
3)MybatisTest进行验证
/**
* 测试set标签
*/
@Test
public void updateUser() {
User user = new User();
user.setUserName("test_132");
user.setUserPwd("test_132");
user.setId(94);
/* userMapper.updateUser(user);*/
userMapper.updateUser2(user);
}
[[测试结果
4.foreach
**动态 SQL的另外一个常用的必要操作是需要对一个集合进行遍历,通常是在构建 IN
条件语句或者是批量插入。
<select id="findUserByUserName" resultMap="RM_User" >
select
userId, userName, password
from
user
<where>
<if test="userNameList != null" >
userName in
<foreach item="item" index="index"
collection="userNameList"
open="(" separator="," close=")">
#{item}
</foreach>
</if>
</where>
</select>
编写测试方法
@Test
public void testFindUserByUserName() {
InputStream is =
MybatisSecondaryCacheTest.class.getClassLoader().getResourceAsStream("mybatis.x
ml");
SqlSessionFactory sessionFactory = new
SqlSessionFactoryBuilder().build(is);
SqlSession session = sessionFactory.openSession();
// 创建参数
Map<String, Object> params = new HashMap<>();
// 创建 string 数组然后转化成 list
String[] userName = new String[]{"Tonygogo", "hello", "哈哈哈
"};
params.put("userNameList", Arrays.asList(userName)); //string 数组转 list, key 的名称要与映射文件中的变量名要一直
List<User> users = session.selectList("findUserByUserName",
params);
System.out.println("查询结果: " + users.toString());
}
四.使用 Ognl 表达式
我们在上面的映射中, 如果用 if
去判断一个值是否为空或者是空字符串时我们是这样
做的 test="userName != null and userName !='' "这样写起来比较复杂,
为此我们采
用 Ognl 表达式@Ognl@isNotEmpty(userName)去判断。
*
Ognl工具类,主要是为了在ognl表达式访问静态方法时可以减少长长的类名称编写
* Ognl访问静态方法的表达式为: @class@method(args)
使用 ognl 表达式时我们要在根目录的包下面加上 Ognl 的一个 Java 类,
这里面会有各种各样的判断比如
为空判断@Ognl@isEmpty(userName),
不为空判断@Ognl@isNotEmpty(userName),
是否是空字符串@Ognl@isBlank(userName),
不为空字符串@Ognl@isNotBlank(userName)等等
我们常用的可能就是这四个,它只是方便我们去做一些操作,实际中也会用到
五.**注解形式动态 **sql\
**除了 xml 配置能够支持动态 sql 外,MyBatis 提供了各种注解如
@InsertProvider,@UpdateProvider,@DeleteProvider
和@SelectProvider,来帮助构
建动态 SQL 语句,然后让 MyBatis 执行这些 SQL 语句。
1)新建AccountDao接口,查询字符串sql由AccountProvider
类queryAccountByParams方法提供
public interface AccountDao {
/**
* 多条件查询账户记录
* 查询字符串sql由AccountProvider 类queryAccountByParams方法提供
* @param aname
* @param type
* @param time
* @return
*/
@SelectProvider(method="queryAccountByParams",type=AccountProvider.class)
public List<Account> queryAccountByParams(@Param("aname") String aname, @Param("type") String type, @Param("time") String time);
2)新建AccountProvider类
public class AccountProvider {
/**
* 返回多条件查询sql字符串
* @param aname
* @param type
* @param time
* @return
*/
public String queryAccountByParams(@Param("aname") final String aname,
@Param("type")final String type,
@Param("time")final String time){
String sql= new SQL(){{
SELECT("id,aname,type,remark,create_time as createTime,update_time as updateTime,user_id as userId");
FROM("account");
WHERE(" 1=1 ");
if(!StringUtils.isNullOrEmpty(aname)){
WHERE(" aname like concat('%',#{aname},'%') ");
}
if(!StringUtils.isNullOrEmpty(type)){
WHERE(" type =#{type}");
}
if(!StringUtils.isNullOrEmpty(time)){
WHERE(" create_time <=#{time}");
}
}}.toString();
return sql;
}
}
3)测试MybatisTest,测试传不同参数查询结果
/**
* 测试注解方式多条件查询账户记录
*/
@Test
public void queryAccountByParams() {
List<Account> list = accountDao.queryAccountByParams("zhang8","1",null);
list.stream().forEach(System.out::println);
}
测试结果