MyBatis学习——MyBatis映射文件

MyBatis学习——MyBatis映射文件_第1张图片

1、增删改查操作

    在mybatis的增删改查操作也有对应于原始JDBC的SQL语句的标签来执行增删改查操作。



    INSERT INTO tbl_employee(last_name, email, gender) VALUES (#{lastName}, #{email}, #{gender})


    UPDATE tbl_employee SET last_name = #{lastName}, email = #{email}, gender = #{gender} WHERE id = #{id}


    DELETE FROM tbl_employee WHERE id = #{id}

注意:
mybatis允许增删改直接定义以下类型返回值,  Integer、Long、Boolean 基本类或包装类均可
 数据需要手动提交
      SqlSession sqlSession = sqlSessionFactory.openSession(); =》手动提交
      SqlSession sqlSession = sqlSessionFactory.openSession(true); =》自动提交

2、获取自增主键的方法

    在使用mybatis的过程中,当执行插入操作时,若主键为自增类型,需要我们进行进一步的设置。

    获取自增主键:

    MySQL支持自增主键。自增主键的获取,mybatis也是利用statement.getGeneratedKeys()来获取主键值。userGeneratedKeys属性用以说明是否使用自增主键获取策略;keyProperty属性用于指定对应的主键属性,也就是mybatis获取到主键属性后(执行插入操作后会返回插入记录的主键值),将这个值封装给JavaBean的哪个属性。 

       在Oracle数据库条件下,与MySQL数据库有所不同。Oracle数据库不支持主键自增,而是使用序列来模拟自增,所以需要在插入之前或插入时取出此时的序列号来作为当前的主键值。在xml文件中,之前与之后体现在BEFORE和AFTER两个属性属性上。BEFORE运行顺序:向运行selectKey查询id的SQL语句,查询id值封装给JavaBean的id属性,再运行插入SQL。AFTER运行顺序:先运行插入的SQL(从序列中取出新值作为id),再运行selectKey查询id的SQL,返回的为当前的id值。




    INSERT INTO tbl_employee(last_name, email, gender) VALUES (#{lastName}, #{email}, #{gender})




    /*order="BEFORE":当前SQL在插入SQL之前运行*/
    
        /*编写查询主键的sql语句*/
        SELECT EMPLOYEE_SEQ.nextval FROM dual
        /*AFTER: SELECT EMPLOYEE_SEQ.currval FROM dual*/
    
    INSERT INTO tbl_employee(EMPLOYEE_ID, LAST_NAME, EMAIL) VALUES (#{id}, #{lastName}, #{email})
    /*AFTER: INSERT INTO tbl_employee(EMPLOYEE_ID, LAST_NAME, EMAIL) VALUES (employees_seq.nextval, #{lastName}, #{email})*/

3、mybatis映射文件参数处理(单个参数&多个参数&命名参数)

单个参数:(mybatis不会做处理,即{}中写任何东西都可以)

        #{参数名};取出参数值

    

多个参数:
        操作:
                方法:Employee getEmpByIdAndLastName(Integer id, String lastName);
                取值:#{id},#{lastName}
        异常:
                org.apache.ibatis.exceptions.PersistenceException:
                ### Error querying database.  Cause: org.apache.ibatis.binding.BindingException: Parameter 'id' not found. Available parameters are [arg1, arg0, param1, param2]

                ### Cause: org.apache.ibatis.binding.BindingException: Parameter 'id' not found. Available parameters are [arg1, arg0, param1, param2]

        多个参数会被封装成一个map
                key:param1,param2...paramN,或者参数的索引
                value:传入的参数值

                #{}就是从map中获取指定的key的值;eg:#{param1}。但是若核心配置文件中开启了驼峰命名规则,其实体类属性名称与数据库表中字段名称符合驼峰命名规则,也可以进行封装。

    

命名参数:明确指定封装参数时map的key。
        多个参数会被封装成一个map
                key:使用@Param注解指定的值
                #{指定的key}取出对应的参数

                eg:Employee getEmpByIdAndLastName(@Param("id") Integer id, @Param("lastName") String lastName);

    Employee getEmpByIdAndLastName(@Param("id") Integer id, @Param("lastName") String lastName);
    

        对于类对象来说,若所执行的方法的多个参数正好是业务逻辑的数据模型,就直接可以传递 POJO即可。如果多个参数值不是业务逻辑的数据模型,没有对应的POJO,并且不经常使用,为了方便起见,可以封装为一个Map,传入Map。

POJO:
        如果多个参数正好是业务逻辑的数据模型,就可以直接传入POJO即可。

                #{属性名};可以直接取出POJO的属性名

Map
    如果多个参数不是业务逻辑的数据模型,没有对应的POJO,不经常使用。为了方便,我们可以传入Map

        #{key};取出map中对应的值

    Employee getEmpByMap(Map map);
    
    public void test03() throws IOException {
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        SqlSession sqlSession = sqlSessionFactory.openSession();

        try {
            EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
            Map map = new HashMap<>();
            map.put("id", 1);
            map.put("lastName", "tom");
            map.put("tableName", "tbl_employee");
            Employee employee = employeeMapper.getEmpByMap(map);
            System.out.println(employee);

            sqlSession.commit();
        } finally {
            sqlSession.close();
        }
    }
=========================== 思考=================================
public Employee getEmp(@Param("id") Integer id, String lastName);
        取值:id => #{id/param1} lastName => #{param2}
public Employee getEmp(Integer id, Employee employee);
        取值:id => #{param1} lastName => #{param2.lastName}


## 特别注意:如果是Collection(List、Set)类型或者是数组,也会特殊处理。也是把传入的list或者数组封装在map中。
    key:Collection(collection),如果是List还可以使用这个key(list)
        数组(array)
public Employee getEmpById(List ids);
    取值: 第一个id的值 => #{list[0]}

总结:参数多时会封装map,为了不混乱,可以使用@Param来指定封装时使用的key,#{key}就可以取出map的值。

============================结合源码=============================

1、ParamNameResolver类是用来解析参数并封装为Map类型。

     public ParamNameResolver(Configuration config, Method method) {
         Class[] paramTypes = method.getParameterTypes();
         Annotation[][] paramAnnotations = method.getParameterAnnotations();
         SortedMap map = new TreeMap(); // 使用TreeMap保证参数的有序性
         int paramCount = paramAnnotations.length;

         for(int paramIndex = 0; paramIndex < paramCount; ++paramIndex) {
             if (!isSpecialParameter(paramTypes[paramIndex])) {
                 String name = null;
                 Annotation[] var9 = paramAnnotations[paramIndex];
                 int var10 = var9.length;

                 for(int var11 = 0; var11 < var10; ++var11) {
                     Annotation annotation = var9[var11];
                     // 1、获取每个标了param注解的参数的@param的值:id,lastName。赋值给name;
                     if (annotation instanceof Param) {
                         this.hasParamAnnotation = true;
                         name = ((Param)annotation).value();
                         break;
                     }
                 }

                 if (name == null) {
                     if (config.isUseActualParamName()) {
                         name = this.getActualParamName(method, paramIndex);
                     }

                     if (name == null) {
                         name = String.valueOf(map.size());
                     }
                 }
                /*
                 2、每次解析一个参数给map中保存信息:{key:参数索引, value:name的值}
                     name的值:标注了param注解,注解的值
                     没有标注:
                        1、全局配置:userActualParamName(jdk1.8):name=参数名
                        2、name = map.size(),相当于当前元素的索引
                */
                 map.put(paramIndex, name);
             }
         }
         this.names = Collections.unmodifiableSortedMap(map);
     }    
public Object getNamedParams(Object[] args) {
        int paramCount = this.names.size();

        if (args != null && paramCount != 0) {
            // 如果没有param注解 && paramCount只有一个参数,直接args[0]。单个参数直接返回
            if (!this.hasParamAnnotation && paramCount == 1) {
                return args[(Integer)this.names.firstKey()];

            // 多个参数或者没有Param注解
            } else {
                Map param = new ParamMap();
                int i = 0;

                // 遍历names集合:{0=id, 1=lastName, 2=2}
                for(Iterator var5 = this.names.entrySet().iterator(); var5.hasNext(); ++i) {
                    Entry entry = (Entry)var5.next();

                    // names集合的value作为key;names集合的key又作为取值args[0]:args[1]。。。
                    // eg: {id=args[0]:1, lastName=args[1]:tom, 2=args[2]:2}
                    param.put(entry.getValue(), args[(Integer)entry.getKey()]);

                    // 额外的将每一个参数也保存到map中,使用新的key:param1,param2
                    // 有Param注解可以#{指定的key},或者#{param1}
                    String genericParamName = "param" + String.valueOf(i + 1);
                    if (!this.names.containsValue(genericParamName)) {
                        param.put(genericParamName, args[(Integer)entry.getKey()]);
                    }
                }

                return param;
            }
        } else {
            // 若参数为空,则直接返回
            return null;
        }
    }

上述两段代码简单分析了mybatis如何处理参数的过程,下一次将进一步学习关于mybatis的参数处理问题。如有错误,请联系博主,多多指教。


你可能感兴趣的:(mybatis)