MyBatis XML映射文件详解

前言

GitHub:https://github.com/yihonglei/MyBatis-Study

一 MyBatis XML配置

MyBatis真正的强大,在于其映射语句的魔力。

SQL 映射文件有很少的几个顶级元素(按照它们应该被定义的顺序):

  • cache  给定命名空间的配置缓存。
  • cache-ref  其他命名空间缓存配置的引用。
  • resultMap  是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象
  • sql 可被其他语句引用的可重用语句块。
  • insert 映射插入语句
  • update  映射更新语句
  • delete   映射删除语句
  • select   映射查询语句

在我们描述每个元素细节之前,我们先感受一些元素的使用实例,以下实例分为UserMapper.XML配置的XML版本

和Java注解版本,也可以根据实际情况两种都用,但是同名方法只能用XML或Java注解。

二 MyBatis XML配置实例

项目构建:https://blog.csdn.net/yhl_jxy/article/details/51941545

UserMapper.java接口修改为如下内容:

package com.lanhuigu.mybatis.mapper;

import com.lanhuigu.mybatis.entity.User;
import com.lanhuigu.mybatis.param.UserReq;
import org.apache.ibatis.annotations.*;

import java.util.List;
import java.util.Map;

/**
 * Mapper接口
 * @author yihonglei
 * @date 2018/11/20 19:00
 */
public interface UserMapper {

    //=======================XML版=======================
    /**
     * xml实现方式
     * @author yihonglei
     * @date 2018/11/20 19:00
     */
    User queryUserById(int id);

    /**
     * 多个参数
     */
    User queryUserByIdAndUserName(@Param("id") int id, @Param("userName") String userName);

    /**
     * Map参数封装
     */
    User queryUserByMap(Map map);

    /**
     * 对象参数封装
     */
    User queryUserByPojo(UserReq req);

    /**
     * 查询用户对象--返回多个--List
     */
    List queryUserList();

    /**
     * 查询用户对象--返回map
     */
    Map queryUserResultMap(int id);

    /**
     * 查询用户对象--返回多个--List>
     */
    List> queryUserResultListMap();

    /**
     * 插入用户对象
     */
    int insertUser(User user);

    /**
     * 更新用户对象
     */
    int updateUser(User user);

    /**
     * 删除用户对象
     */
    int deleteUser(int id);

    //=======================注解版==========================
    /**
     * Java注解实现方式--查询用户对象--返回User对象
     * @author yihonglei
     * @date 2018/11/20 19:01
     */
    @Select(" SELECT id, userName, age FROM user WHERE id = #{id} ")
    User queryUserByIdNew(@Param("id") int id);

    /**
     * 查询用户对象--返回多个--List
     */
    @Select("select id, userName, age from user ")
    List queryUserListNew();

    /**
     * 查询用户对象--返回map
     */
    @Select("select id, userName, age from user where id = #{id}")
    Map queryUserResultMapNew(@Param("id") int id);

    /**
     * 查询用户对象--返回多个--List>
     */
    @Select("select id, userName, age from user")
    List> queryUserResultListMapNew();

    /**
     * 插入用户对象
     */
    @Insert("insert into user (id, userName, age) "
            + " values(#{id}, #{userName}, #{age}) ")
    int insertUserNew(User user);

    /**
     * 更新用户对象
     */
    @Update("update user set userName=#{userName}, age=#{age} "
            + " where id=#{id} ")
    int updateUserNew(User user);

    /**
     * 删除用户对象
     */
    @Delete("delete from user where id=#{id}")
    int deleteUserNew(@Param("id") int id);

}

UserMapper.xml修改为如下内容:





    
    

    
    

    
    

    
    

    
    

    
    

    
    

    
    

    
    
  	insert into user (id,userName,age)
        values(#{id},#{userName},#{age})
    

    
    
        update user set userName=#{userName}, age=#{age}
        where id=#{id}
    

    
    
        delete from user where id=#{id}
    

MyBatisXMLConfigTest.java

package com.lanhuigu.mybatis;
import java.io.InputStream;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import com.lanhuigu.mybatis.entity.User;
import com.lanhuigu.mybatis.mapper.UserMapper;
/**
 * MyBatis XML配置测试
 * @author yihonglei
 * @date 2018/11/21 17:34
 */
public class MyBatisXMLConfigTest {
    @Test
    public void testMyBatis() {
        String resource = "mybatis-config.xml";
        SqlSessionFactory sqlSessionFactory = null;
        SqlSession session = null;
        try {
            // 读取资源文件
            InputStream is = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            session = sqlSessionFactory.openSession();
            // mapper调用
            UserMapper userMapper = session.getMapper(UserMapper.class);
            //================XML测试=================
            // 查询--select--返回User对象
            User user = userMapper.queryUserById(1);
            System.out.println("user="+user);
            System.out.println(user.getUserName());
            // 查询--select--返回多个User对象--List
			/*List list = userMapper.queryUserList();
			for(int i=0;i userMap = userMapper.queryUserResultMap(1);
			System.out.println("userMap="+userMap);
			System.out.println(userMap.get("USERNAME"));*/
            // 查询--select--返回List>
			/*List> list = userMapper.queryUserResultListMap();
			System.out.println("ListMap="+list);
			for (int i=0;i userMap = list.get(i);
				System.out.println(userMap.get("USERNAME"));
			}*/

            // 插入--insert
			/*User user = new User();
			user.setId(3);
			user.setUsername("three");
			user.setAge(25);

			int result = userMapper.insertUser(user);
			if (result > 0) {
				System.out.println("添加用户成功");
				// 事务提交
				session.commit();
			} else {
				System.out.println("添加用户失败");
				// 事务回滚
				session.rollback();
			}*/

            // 更新--update
			/*User user = new User();
			user.setId(3);
			user.setUsername("this three update");
			user.setAge(25);

			int result = userMapper.updateUser(user);
			if (result > 0) {
				System.out.println("更新成功");
				// 事务提交
				session.commit();
			} else {
				System.out.println("更新失败");
				// 事务回滚
				session.rollback();
			}*/

            //删除--delete
			/*int result = userMapper.deleteUser(3);
			if (result > 0) {
				System.out.println("删除成功");
				// 事务提交
				session.commit();
			} else {
				System.out.println("删除失败");
				// 事务回滚
				session.rollback();
			}*/

            //=================注解测试===================
            /*
             * 只需将xml测试代码copy一份,然后将方法名都加上一个New即可
             * 在UserMapper.java映射器中原本可以将xml部分注释,
             * 注解部分方法用同名,但是这样做我们就得将UserMapper.xml删掉,
             * 或者改名,否则注解不能查询出数值,着跟命名空间和class,xml加载有关系.
             * 总之class中和xml中不能出现注解和xml同时使用,对于单个方法,二者
             * 只能存在其一,否则mybatis不知道你到底想干啥,只能什么都不做了
             */
            //eg.
			/*User user = userMapper.queryUserByIdNew(1);
			System.out.println("user="+user);
			System.out.println(user.getUserName());*/
        } catch (Exception e) {
            if (session != null) {
                session.close();
            }
        }
    }
}

上面是一个MyBatis映射文件的配置实例,下面对配置文件做详细说明。

三 MyBatis 配置详细说明

1、select元素

查询语句是MyBatis中最常用的元素,作为一个持久层框架,把数据放入数据库是一个方面,

把数据取一条或多条更是重中之重。

 

    

这个语句称之为queryUserById,接受一个int或Integer的参数,

返回一个com.lanhuigu.mybatis.entity.User的对象,这个如果嫌写起来长,

可以在mybatis-config.xml中配置别名,这个地方直接用别名替代。

1.1、别名配置


	

1.2、select语句中参数id符号:

#{id}获取传入的参数。

这样MyBatis处理时底层用JDBC生产预编译语句,JDBC底层MyBatis替我们做了,

这样我们只需关注MyBatis的应用,避免写大量的JDBC代码,提高工作效率,调用时直接执行。

1.3、select元素有很多属性可供选择


    select 
    	id,
    	userName,
    	age
    from user
    
    	
    
  

将查询语句的条件由where id=#{id}修改成sql语句块替代。

这样整个xml中条件部分共同的地方都提出来,避免重复啰嗦。

当然,sql语句块除了可以用于条件部分,还可以用于其它任地方,

  
  
   	id = #{id}
  	
  
  	userName,
  	age
  
  
  

查询时,效果一样。

总结:

1)sql语句块用于提出xml共同sql

2)sql语句块可以置于xml文件中查询语句前后,位置无关系,都能调用。

4、参数(parameters)

MyBatis的参数功能是非常强大的,前面用到的sql中,如果parameterType="int"

只是进行一个简单的整数传入,但是,在插入语句中,我们传入的是类型User对象:

    
  	insert into user (id,userName,age)
        values(#{id},#{userName},#{age})
    

如果 User 类型的参数对象传递到了语句中,id、userName 和 password 属性将会被查找,然后将它们的值传入预处理语句

的参数中。这点对于向语句中传参是比较好的而且又简单,不过参数映射的功能远不止于此。

首先,像 MyBatis 的其他部分一样,参数也可以指定一个特殊的数据类型。

#{property,javaType=int,jdbcType=NUMERIC}

像 MyBatis 的剩余部分一样,javaType 通常可以从参数对象中来去确定,前提是只要对象不是一个 HashMap。

那么 javaType 应该被确定来保证使用正确类型处理器。NOTE 如果 null 被当作值来传递,对于所有可能为空的列,

JDBC Type 是需要的。你可以自己通过阅读预处理语句的 setNull() 方法的 JavaDocs 文档来研究这种情况。

为了以后定制类型处理方式,你也可以指定一个特殊的类型处理器类(或别名),比如:

#{age,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler}

尽管看起来配置变得越来越繁琐,但实际上是很少去设置它们。对于数值类型,还有一个小数保留位数的设置,

来确定小数点后保留的位数。

#{height,javaType=double,jdbcType=NUMERIC,numericScale=2}

最后,mode 属性允许你指定 IN,OUT 或 INOUT 参数。如果参数为 OUT 或 INOUT,参数对象属性的真实值将会被改变,

就像你在获取输出参数时所期望的那样。如果 mode 为 OUT(或 INOUT),而且 jdbcType 为 CURSOR

(也就是 Oracle 的 REFCURSOR),你必须指定一个 resultMap 来映射结果集到参数类型。

要注意这里的 javaType 属性是可选的,如果左边的空白是 jdbcType 的 CURSOR 类型,

它会自动地被设置为结果集。

#{department, mode=OUT, jdbcType=CURSOR, javaType=ResultSet, resultMap=departmentResultMap}

MyBatis 也支持很多高级的数据类型,比如结构体,但是当注册 out 参数时你必须告诉它语句类型名称。

比如(再次提示,在实际中要像这样不能换行):

#{middleInitial, mode=OUT, jdbcType=STRUCT, jdbcTypeName=MY_TYPE, resultMap=departmentResultMap}

尽管所有这些强大的选项很多时候你只简单指定属性名,其他的事情 MyBatis 会自己去推断,最多你需要为

可能为空的列名指定 jdbcType。

#{firstName}

#{middleInitial,jdbcType=VARCHAR}

#{lastName}

#{middleInitial,jdbcType=VARCHAR}

#{lastName}

一个完整的配置xml:


		insert into user (  
	        id ,    
	        userName ,   
	        age)
		values(
			#{id,jdbcType=INTEGER},
			#{userName,jdbcType=VARCHAR},
			#{age,jdbcType=INTEGER} 
        )

5、字符串替换

在上面中,很多地方用到#{},默认情况下,使用#{}格式的语法会导致MyBatis创建预处理语句属性并安全地设置值(比如?)。

这样做更安全,更迅速,通常也是首选做法,不过有时你只是想直接在SQL语句中插入一个不改变的字符串,

或者在条件放一个字符串。比如:

id = ${id}

以这种方式接受从用户输出的内容并提供给语句中不变的字符串是不安全的,会导致潜在的 SQL 注入攻击,

因此要么不允许用户输入这些字段,要么自行转义并检验。

你可能感兴趣的:(#,---MyBatis)