mybatis-标签,接口,动态sql--G07

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 元素标签使用
**有以下属性可供在查询时配置其对应查询属性

image.png

image.png

1输入参数分类
基本类型,字符串,java bean,map,数组(删除操作时体现),List(添加时体
现)等每种情况定义如下

基本数据类型

字符串数据类型

javabean类型

map类型

2输出类型

int类型

字符串类型

map类型

List类型

[[3.输入输出不同类型的案例测试]{.underline}]{.smallcaps}

image.png

[数据库字段:]{.smallcaps}

image.png

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类型

image.png

输入类型字符串

![
image.png

输入类型javabean


image.png

输入类型map结果

image.png

[[输出结果为int]{.underline}]{.smallcaps}

![
image.png

输出结果 为STRING


image.png

[[返回结果为map]{.underline}]{.smallcaps}

image.png

[[返回结果为list]{.underline}]{.smallcaps}

image.png

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}

image.png

[[b.添加记录返回主键(标签)]{.underline}]{.smallcaps}

image.png

[[c添加记录返回主键(设置属性)]{.underline}]{.smallcaps}

image.png

[[d批量添加记录]{.underline}]{.smallcaps}

image.png

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}

image.png

[[b批量更新]

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);

    }


[[测试结果]

image.png

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 操作

开发规则:\

  1. mapper.xml 中 namespace 等于接口类全限定名\
  2. mapper.java 接口中的方法名必须与 mapper.xml 中 statement id 一致\
  3. 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连接.

image.png

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}


image.png

[[nation设定值值结果]{.underline}]{.smallcaps}

image.png

*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查询

image.png

userName和userPwd都设定值,两个条件一起查询

image.png

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);

}


[[测试结果

image.png

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 语句。

image.png

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);

}


测试结果

image.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • 1. Mybatis的介绍 MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由ap...
    itzhouq的笔记阅读 650评论 0 5
  • 之前在面试工作的时候,我当时用的是hibernate,但是现在互联网项目并发量大,一般都会选择使用Mybatis,...
    唐伟耀阅读 548评论 1 0
  • 1. 开发规范 Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架...
    _凌浩雨阅读 1,471评论 0 3
  • 每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能共享使用,它是线程不安全的 配置文...
    蕊er阅读 464评论 0 0
  • 今天带俩孩子在床上玩,我给女儿拿了两根巧合克力棒,她最爱吃了。 为了防止零食吃多,她又不吃饭,我总是不会给她多吃。...
    人生留白_81e6阅读 421评论 2 15