Mybatis2

 

Mybatis2

本章目标:

  1. myBatis类型别名处理

  2. myBatis参数处理

  3. myBatis结果集类型

  4. myBatis结果集列名和属性名称对应方式处理

  5. 附录

本章内容

一、类型别名(typeAliases)处理

类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如,在配置文件中加入以下配置:

自己配置类型别名

配置方式一:

<typeAliases>
    <typeAlias type="com.entity.Dept" alias="dept"/>
</typeAliases>

配置方式二:直接配置包名:底层会为包中的每一个类自动起别名(类的短名(movie|Movie))

<typeAliases>    
    <package name="com.entity"/>
</typeAliases>

已有的类型别名

别名 类型

_bytebyte
_longlong
_shortshort
_intint
_integerint
_doubledouble
_floatfloat
_booleanboolean
stringString
byteByte
longLong
shortShort
intInteger
integerInteger
doubleDouble
floatFloat
booleanBoolean
dateDate
decimalBigDecimal
bigdecimalBigDecimal
objectObject
mapMap
hashmapHashMap
listList
arraylistArrayList
collectionCollection
iteratorIterator
二、MyBatis参数处理:
  1. 单个参数,参数非实体类类型(简单数据类型—八种基本数据类型及对应的封装类、Date,String)

    接口方法

    public void deleteStudentById(Integer studentId);

    映射文件

    <delete id="deleteStudentById" parameterType="integer">
        delete from student where student_id=#{student_id}
    </delete>
    <delete id="deleteStudentById" parameterType="int">
        delete from student where student_id=#{student_id}
    </delete>

    单个参数:parameterType可以不写,管理比较松散,如果写了,只要类型匹配就可以了(映射期接口中方法的参数类型和映射文件中的parameterType的属性值应该匹配,parameterType和参数类型一致或者能够方法参数类型的父类类型),名称无所谓,如果参数为int,配置为short,则会出现异常,参数名称没有要求

    ### Error updating database. Cause: org.apache.ibatis.type.TypeException: Could not set parameters for mapping: ParameterMapping{property='student_id', mode=IN, javaType=class java.lang.Short, jdbcType=null, numericScale=null, resultMapId='null', jdbcTypeName='null', expression='null'}. Cause: org.apache.ibatis.type.TypeException: Error setting non null for parameter #1 with JdbcType null . Try setting a different JdbcType for this parameter or a different configuration property. Cause: java.lang.ClassCastException:

  2. 多个参数,且非实体类类型

    接口中的方法

    public void saveStudent1(String studentName,String studentSex);

    映射文件第一种方式

    <insert id="saveStudent1" >
        insert into student(student_id,student_name,student_sex)values(20,#{arg0},#{arg1})
    </insert>

    映射文件第二种方式

    <insert id="saveStudent1" >    
        insert into student(student_id,student_name,student_sex)    values(21,#{param1},#{param2})    
    </insert>

    以上两种方式的问题:参数名称补明确,不能望文生义,于是有第三种方式,借助于Param注解

    映射文件第三种方式(重点掌握)

    接口方法:

    public void saveStudent1(@Param("sname")String studentName,@Param("ssex")String studentSex);

    映射文件:

    <insert id="saveStudent1" >             
        insert into student(student_id,student_name,student_sex)values(22,#{sname},#{ssex})    
    </insert>
  3. 实体类类型参数

    接口方法

    public void saveStudent(Student s);

    映射文件

    <insert id="saveStudent" parameterType="Student">             
    insert into student(student_id,student_name,student_sex,student_grade,student_profession,student_age)           values(#{student_id},#{student_name},#{student_sex},#{student_grade},#{student_profession},#{student_age})</insert>

    注意:#{实体类对象属性名称} 参数名 称要和pojo属性名称一致,原理:先找getter,再根据属性进行匹配

  4. 带多个参数并且有的为实体类类型

    映射器接口:

    public List<Student> selectStudent2(@Param("s")Student s,@Param("sname")String sname);

    映射文件 :

    <select id="selectStudent2" resultType="student">    
        select * from student where student_id=#{s.student_id} and student_name=#{sname}
    </select>
  5. map参数

    接口

    public List selectEmpByEnameAndEmpno1(Map params);

    映射文件:依靠map集合的键进行值的引用

    <select id="selectEmpByEnameAndEmpno1" parameterType="map" resultType="emp"> 
    	SELECT * FROM emp WHERE ename LIKE CONCAT('%',#{key1},'%') AND empno=#{key2}
    </select>

    测试

    public void test5(){    
    	SqlSession sqlSession= MyBatisUtil.crateSqlSession();    
        EmpMapper empMapper=sqlSession.getMapper(EmpMapper.class);     
        Map<String,Object> param=new HashMap<>();    
        param.put("key1","A");    param.put("key2",(short)7900);    
        List<Emp> emps=empMapper.selectEmpByEnameAndEmpno1(param);    
        logger.info(emps);    
        MyBatisUtil.closeSqlSession(sqlSession);
    }
  6. 精确指定参数类型,解决类型的对应问题

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

    不指定会按照默认的处理方式进行处理,但是一些特殊的数据类型如Date类型可能不符合我们的要求,那就需要精确指定(uitl.Date能表示 年月日 年月日时分秒,如果不指定,默认会取年月日时分秒)

    #{property,javaType=int,jdbcType=NUMERIC}<insert id="saveMovie"  parameterType="Movie">    
    <!-- #{实体类对象的属性名称}:自动获取对应的属性值,默认调用#号后的属性对应的getter获取属性值,如果getter找不到,会直接找同名的属性 -->    
    insert into movies(movie_code,movie_name,movie_time,movie_date,movie_price,movie_com,movie_type)values(${movie_code},#{movie_name,javaType=string,jdbcType=VARCHAR},#{movie_time,javaType=int,jdbcType=INTEGER},#{movie_date,javaType=date,jdbcType=DATE},#{movie_price,javaType=float,jdbcType=FLOAT},#{movie_com,javaType=int,jdbcType=INTEGER},#{movie_type,javaType=int,jdbcType=INTEGER})  
    </insert>
  7. $和#的区别(面试爱问)

    $:引用的值会直接替换sql语句中的部分,编译的时候值已经替换了,常见于设置表名列名等信息

    #:会在sql中先处理为?,进行预编译,编译之后,然后再进行值的替换

  8. 总结

    如果参数多于4个以上,建议不要单独写,这种情况在特殊业务情况下必须使用实体对象和map比较通用

三、myBatis结果集结果集返回类型的处理
  1. 返回单个对象(单个实体类对象)

    接口方法

    public Student getStudentById(Integer studentId);

    映射文件

    <select id="getStudentById" parameterType="integer" resultType="Student">          
    	select * from student where student_id=#{ids}     
    </select>
  2. 返回集合(封装的依然为实体类对象)

    接口方法

    public List<Student>getAll();

    映射文件集合中封装的实体类类型

    <select id="getAll" resultType="Student"> select * from student </select>

  3. 返回Map,返回的是一行记录,将一行记录封装到map中 ,键为结果集的列名,值就是结果集对应列的值

    实例1:(建议用实体类对象返回,了解)

    接口方法

    public Map<String, Object> getStudentReturnMap(Integer studentId);

    映射文件

    <select id="getStudentReturnMap" resultType="map">    
    select * from student where student_id=#{ids}
    </select>

    测试方法:

    session=sqlSessionFactory.openSession();
    StudentMapper mapper=session.getMapper(StudentMapper.class);
    Map<String,Object> map=mapper.getStudentReturnMap(id);
    System.out.println(map);
    session.commit();
    session.close();

    实例二:返回多个聚合函数的结果(多见)

    接口方法

    public Map<String, Object> getCountAndAge();

    映射文件

    map中封装的数据:

    结果集的列名-(键)———对应列的值(值)

    <select id="getCountAndAge" resultType="map">
    select count(student_id) as studentCount,max(student_age) as studentAge from student
    </select>

    测试

    SqlSession session=sqlSessionFactory.openSession();
    StudentMapper mapper=session.getMapper(StudentMapper.class);
    Map<String,Object> map=mapper.getCountAndAge();
    System.out.println(map);
    session.commit();
    session.close();
  4. 返回多条记录List

    返回分组聚合的结果(多见,重点掌握)

    image-20220602153406395

    接口方法

    接口方法:    /*接收分组统计之后的结果     *      * 
    {studentCount=10, studentAge=25}
    {studentCount=25, student_grade=1, studentAge=26}
    {studentCount=2, student_grade=2, studentAge=25}
    {studentCount=2, student_grade=3, studentAge=25}
    {studentCount=1, student_grade=4, studentAge=27} 
    会将每一行数据先封装为一个map,以结果集的列名作为键,对应列的值作为值, 然后将map封装到List中     
    *      
    * */
    public List<Map<String, Object>> getCountAndAgeByGrade();

    映射文件

    <select id="getCountAndAgeByGrade" resultType="map">    
    select student_grade,count(student_id) as studentCount,max(student_age) as studentAge from student group by student_grade
    </select>

    测试

    SqlSession sqlSession=DBTools.getSqlSession();
    //会根据命名空间+id去找对应的标记,执行标记中sql语句,根据配置的结果集类型进行封装
    //根据sqlSession。getMapper传入的接口类型,得到一个接口对应的实现类型对象
    //调用接口中的方法(会自动执行映射文件中对应的sql)
    StudentMapper mapper=sqlSession.getMapper(StudentMapper.class);
    //获得一条记录,返回值为map
    List<Map<String,Object>> l=mapper.getCountAndAgeByGrade();
    for(Map<String, Object> map:l){    
    	System.out.println(map);
    }
四、结果集的列名和实体类属性名称对应方式的处理

默认按照属性名称和结果集列名一致的原则进行封装,如果不一致,会有以下处理方式

  1. 如上虽然数据库已经查到了数据,但是由于数据库字段的名称和实体对象的属性名称不一致,这样resultType属性就不能实现自动的设置,遇到这样问题,有如下三种解决方案

  • 使用AS关键字来解决

    <select id="findAllPerson"resultType="person">     
    SELECT person_id AS personId,person_name AS personName,person_age personAge FROM person
    </select>
  • 如果你的项目中采用驼峰命名法,那么可以在mybatis-cofig.xml文件中进行设置person_id==>personId(要求:项目中的pojo需要符合驼峰命名法的规则)

    结果的列名为下划线风格,实体类的属性名称为驼峰风格,才有必要这样使用

    <settings>    
        <setting name="mapUnderscoreToCamelCase" value="true"></setting>
    </settings>

    注意:如上设置一定实体类的属性要符合驼峰命名法才行,否则不能起到效果

  • 采用resultMap方式来解决(推荐使用)

    image-20220602164317765

    可以解决如下问题:

    1)列名和属性名称对应的问题

    2)数据类型对应的问题(如何对应,查看笔记第四部分附录)

    3)关联映射

    配置resultMap(自定义结果集的映射方式)

    <mapper namespace="com.dao.GradeMapper">
        <resultMap type="grade" id="gradeResult">        
            <id property="gradeId" column="grade_id" javaType="integer" jdbcType="INTEGER"/>    
            <result property="gradeName" column="grade_name" javaType="string" jdbcType="VARCHAR"/></resultMap>
        <select id="getAll"  resultMap="gradeResult">     
            select * from grade     
        </select>    
    </mapper>

    这两者之间的唯一不同是,id 元素对应的属性会被标记为对象的标识符,在比较对象实例时使用。 这样可以提高整体的性能,尤其是进行缓存和嵌套结果映射(也就是连接映射)的时候。

    注意:select标记的resultMap属性和resultType属性的区别

    resultType:属性值是一个具体的类型,用的是列名和属性名称一致原则自动封装

    resultMap:属性值是映射文件中resultMap标记的id属性的属性值,想采用自定义的映射规则去进行封装

五、附录

数据库数据类型和JAVA类型的对应关系

两个元素都有一些属性:

属性描述
property映射到列结果的字段或属性。如果 JavaBean 有这个名字的属性(property),会先使用该属性。否则 MyBatis 将会寻找给定名称的字段(field)。 无论是哪一种情形,你都可以使用常见的点式分隔形式进行复杂属性导航。 比如,你可以这样映射一些简单的东西:“username”,或者映射到一些复杂的东西上:“address.street.number”。
column数据库中的列名,或者是列的别名。一般情况下,这和传递给 resultSet.getString(columnName) 方法的参数一样。
javaType一个 Java 类的全限定名,或一个类型别名(关于内置的类型别名,可以参考上面的表格)。 如果你映射到一个 JavaBean,MyBatis 通常可以推断类型。然而,如果你映射到的是 HashMap,那么你应该明确地指定 javaType 来保证行为与期望的相一致。
jdbcTypeJDBC 类型,所支持的 JDBC 类型参见这个表格之后的“支持的 JDBC 类型”。 只需要在可能执行插入、更新和删除的且允许空值的列上指定 JDBC 类型。这是 JDBC 的要求而非 MyBatis 的要求。如果你直接面向 JDBC 编程,你需要对可以为空值的列指定这个类型。

支持的 JDBC 类型

为了以后可能的使用场景,MyBatis 通过内置的 jdbcType 枚举类型支持下面的 JDBC 类型。

BITFLOATCHARTIMESTAMPOTHERUNDEFINED
TINYINTREALVARCHARBINARYBLOBNVARCHAR
SMALLINTDOUBLELONGVARCHARVARBINARYCLOBNCHAR
INTEGERNUMERICDATELONGVARBINARYBOOLEANNCLOB
BIGINTDECIMALTIMENULLCURSORARRAY
  • 28
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值