动态SQL

在mybatis3之前,需要学习和了解非常多标签,现在采用OGNL表达式语言,消除了许多其他标签
剩下
if
choose
trim
foreach
bind

if用法:

if通常用于WHERE语句中,判断参数是否使用某个查询条件,UPDATE语句中判断是否更新某个字段,INSERT语句中判断是否插入某个字段。

在WHERE语句中使用if

需求:
实现一个用户管理高级查询功能,根据输入的条件去检索用户信息。当只输入用户时,需要根据用户名进行模糊查询,当只输入邮箱时,根据邮箱进行完全匹配;当同时输入用户名和邮箱时,用这两个条件去匹配用户。


if标签有一个必填的属性 test, test的属性是一个符合OGNL要求的判断表达式,表达式的结果为TRUE或FALSE,除此之外非0都为true,0为false。

@Test
    public void testSelectByUser() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            SysUser sysUser = new SysUser();
            sysUser.setUserName("ad");
            List sysUserList = userMapper.selectByUser(sysUser);

            Assert.assertTrue(sysUserList.size()>0);

//            根据邮箱查
            sysUser.setUserEmail("[email protected]");
            sysUser.setUserName(null);
            sysUserList = userMapper.selectByUser(sysUser);


//            根据用户和邮箱查
            sysUser.setUserName("ad");
            Assert.assertTrue(sysUserList.size()==0);

        } finally {
            sqlSession.close();
        }
    }

if 用法,加一个标签
中间加 and 条件。
if中符合条件才会有and条件。

在update中使用if

需求:
只更新变化的字段。需要注意,更新的时候不能将原来有值但没发生变化的字段更新为空或者NULL。
通过IF就可以实现这种动态更新

示例:

   
        UPDATE sys_user
        SET
        
            user_name = #{userName},
        
        
            user_password = #{userPassword},
        
        
            user_email = #{userEmail},
        
        
            user_info = #{userInfo},
        
        
            head_img = #{headImg, jdbcType=BLOB},
        
        
            create_time = #{createTime, jdbcType=TIMESTAMP},
        
        id = #{id}
        WHERE id = #{id}
    

测试:

    @Test
    public void testUpdateByIdSelective() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

            SysUser sysUser = userMapper.selectById(1l);
            sysUser.setUserName("cccc");


            userMapper.updateByIdSelective(sysUser);

        } finally {
            sqlSession.rollback();
            sqlSession.close();
        }
    }
在insert中使用if

应用场景:
在数据表中插入参数是,如果参数值不为空,就传入,如果传入值为空,就使用数据库中默认的值,而不使用空值。

示例:

 
        insert INTO sys_user(
            user_name, user_password,
            
                user_email,
              user_info, head_img, create_time
        )
        VALUES (
            #{userName}, #{userPassword},
        
        #{userEmail},
        
         #{userInfo}, #{headImg, jdbcType= BLOB}, #{createTime, jdbcType= DATE}
        )
    

choose用法
可以实现if ...else...的逻辑

案例需求:
当参数id有值的时候,优先使用id查询,当id没有值的时候,便去判断用户名是否有值,如果有值就用用户名查询,如果没有值,就使SQL查询无结果。

方案:

 

测试代码:

@Test
    public void testselectByIdOrUserName() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

            SysUser sysUser = userMapper.selectById(1l);
            sysUser.setId(null);

            SysUser sysUser1 = userMapper.selectByIdOrUserName(sysUser);

            sysUser.setUserName(null);
            sysUser1 = userMapper.selectByIdOrUserName(sysUser);
        } finally {
            sqlSession.close();
        }
    }

where/set/trim用法:

where标签的用法:如果标签包含的元素中有返回值,就插入一个where,如果where后面的字符串是以and和or开头的,就将它们剔除。

where会自动剔除 and 或 or 开头的 and 和 or


set的用法:

如果标签包含元素中的返回值,就插入一个set,如果set后面中的元素是以逗号结尾的,就将这个逗号剔除。
但是如果set元素中没有内容,照样会出现SQL错误,所以,类似id = #{id}这样必然存在的赋值任然需要保留。

例子:


        UPDATE sys_user
        
            
                user_name = #{userName},
            
            
                user_password = #{userPassword},
            
            
                user_email = #{userEmail},
            
            
                user_info = #{userInfo},
            
            
                head_img = #{headImg, jdbcType=BLOB},
            
            
                create_time = #{createTime, jdbcType=TIMESTAMP},
            
            id = #{id},
        
        WHERE id = #{id}
    
trim用法:

where和set都是通过trim实现,并且底层都是通过TrimSqlNode实现的。


...


...

foreach用法

SQL语句中有时会使用IN关键字,例如 id in (1, 2, 3),可以使用$(ids)方式直接获取值,但是不能放置SQL注入,避免SQL注入就需要使用#{}的方式,这是就要配合使用foreach标签来满足需求。

foreach可以对数组、Map或实现Iterable接口的对象进行遍历

foreach实现in集合

案例需求:
根据用户ID集合查询出所有符合条件的用户

实现:

 

foreach包含以下属性:
collection:必填,值为要迭代循环的属性名。这个属性值的情况很多。
item:变量名,值为从迭代对象中取出的每一个值。
index:索引的属性名,在集合数组情况下值为当前索引值,当迭代对象是Map类型是,这个值为KEY。
open、close、separator。

foreach实现批量插入:
如果数据库支持批量插入,就可以通过foreach来实现。批量插入是SQL-92新增的特性,目前支持的数据库有DB2、SQL Server8.2及其以上版本、Mysql、Sqlite3.7.11以上、H2。
 批量插入语法如下:

INSERT INTO tablename (colum-a, [colum-b, ....])
VALUES('value-1a', ['value-1b', ...]),
('value-2a', ['value-2b', ...]),
....

例子:

    
        INSERT INTO sys_user(
            user_name, user_password, user_email, user_info, head_img, create_time
        )
        VALUES
       
           (
           #{user.userName}, #{user.userPassword}, #{user.userEmail}, #{user.userInfo}, #{user.headImg, jdbcType= BLOB},
           #{user.createTime, jdbcType= DATE}
           )
       
    

测试代码:

 @Test
    public void testInsertList() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

            List sysUserList = new ArrayList();

            for (int i = 0; i < 2; i++) {
                SysUser sysUser = new SysUser();
                sysUser.setUserName("cc");
                sysUser.setUserPassword("111111");
                sysUser.setUserEmail("[email protected]");
                sysUserList.add(sysUser);
            }

            int result = userMapper.insertList(sysUserList);

            for (SysUser s :
                    sysUserList) {
                System.out.println(s.getId());
            }

            Assert.assertEquals(2, result);
        } finally {
            //为了不影响其他测试,这里选择回滚
            sqlSession.rollback();
            sqlSession.close();
        }
    }

这里使用了useGeneratedKeys 和 keyProperty 两个属性,可以实现批量插入后返回主键。

foreach实现动态update
这个主要介绍参数是Map时,foreach怎么实现动态update。

bind标签,创建一个变量并将其绑定到上下文中。

你可能感兴趣的:(动态SQL)