首页 > 其他 > 详细

Mybatis学习02--XML映射器(1)

时间:2020-12-04 21:39:43      阅读:36      评论:0      收藏:0      [点我收藏+]

XML映射器

从上一篇的第一个程序可以看到,我们只需要在映射器Mapper.xml中添加SQL代码和映射定义,Mybatis就会自动将查询映射到接口方法上。

参数注入

根据name和pwd查询用户,SQL代码如下:

select * from user where name=? and pwd=?;

如果在Java类中属性名与数据库列名一致,直接使用#{param name}代替?即可,Mybatis能够匹配参数的名字,但不一致的情况下,可以用以下方法完成映射:

使用@Param注解
public User selectByNamePwd(@Param("username")String name,@Param("password")String pwd);
<select id="selectByNamePwd" resultType="com.tang.User">
        select * from user
        where name=#{username} and pwd=#{password}
</select>

注意参数名要与#{}中的名字一致

使用Map
 public User selectByNamePwd2(Map<String,Object> map);
<select id="selectByNamePwd2" parameterType="map" resultType="com.tang.User">
        select * from user
        where name=#{username} and pwd=#{password}
</select>
Map<String,Object> map=new HashMap<String,Object>();
map.put("password","12345");
map.put("username","Su");
System.out.println(mapper.selectByNamePwd2(map));

注意在map中放入的key字符串与#{}中一致

字符串替换

${}和#{}的区别

‘#{}中的值作为字符串处理,会加引号;${}中的值不作处理,直接替换sql语句中的占位符。$常用于数据库对象,如表名,字段,例如:‘

‘#{}在预编译时会用?代替参数‘

${}在动态解析时直接替换字符串,会引起sql注入问题

如下面的例子,利用${}可以使用一个方法可以实现3个方法的功能,只需要定义一个接口方法 selectByColumn 而不是3个方法

selectById(int id);
selectByName(String name);
selectByPwd(String pwd);
@Select("select * from user where ${column}=#{value}")
public User selectByColumn(@Param("column")String col,@Param("value")Object val);
System.out.println(mapper.selectByColumn("id",2));      
System.out.println(mapper.selectByColumn("name","Su"));
System.out.println(mapper.selectByColumn("pwd","abcd"));

结果映射(ResultMap)

在Mapper.xml文件中,没有显式指定ResultMap的情况下,Sql语句的查询结果会简单地映射到HashMap上,HashMap的key由数据库列名决定,例如以下的查询

@Select("select * from department")
public List<Department> selectDepartment();

实体类Department:

public class Department {
    private String name;
    private int id;
    private int mid;
}

在数据库中建表如下:

技术分享图片

查询结果映射到HashMap中,会存放如下的键值对:

<"did",1> ,<"dname","HR">, <"mid", "2"> …………

mybatis根据key查找实体类User中的set(setDid,setDname,setMid)方法,由此带来的问题是,如果实体类的属性名与数据库列名不一致,那么set方法无法找到,最终的查询结果返回User对象,对象中的属性无法获得正确的值。查询结果如下:

depart name=null id=0 manager id=2
depart name=null id=0 manager id=1
depart name=null id=0 manager id=3

解决办法:使用ResultMap

<resultMap id="DepartmentMap" type="Department">
    <!--id为主键-->
    <id column="did" property="id"/>
    <!-- column 为数据库中列名,property 为实体类属性名 -->
    <result column="dname" property="name"/>
    <result column="mid" property="mid"/>
</resultMap>
    <!-- resultMap 与前面的id对应 -->
<select id="selectDepartment2" resultMap="DepartmentMap">
    select * from department
</select>

ResultMap有很多子元素

id&result

id和result都将数据库一列映射到实体类的属性或字段上,id元素对应的属性会被标记为对象标识符,在比较对象实例中使用。

constructor

将查询结果注入到类的构造方法中,例如

 public User(Integer id, String username, int age) {
     //...
  }
<constructor>
   <idArg column="id" javaType="int" name="id" />
   <arg column="age" javaType="_int" name="age" />
   <arg column="username" javaType="String" name="username" />
</constructor>

JavaType指定了参数类型,例中分别是Java.lang.Integer, int, Java.lang.String。name指定了参数名称,在构造方法中要使用@Param注解对应,如果参数顺序一致,可以省略name。

association

关联(association)元素处理“有一个”类型的关系。mybatis有两种方式加载关联:

  • 嵌套查询
  • 嵌套结果映射

接下来看一个例子,用上面的两种方法实现。

数据库建表:

技术分享图片

根据部门id查询部门及其主管信息,嵌套查询的SQL实现如下:

技术分享图片

实体类:

@Data
public class Department {
    private String name;
    private int id;
    private Employee manager;
    private List<Employee> employees;
}
@Getter
@Setter
public class Employee {
    private String name;
    private int id;
    private Department department;
    public String toString(){
        return "Employee:name="+name+" id="+id+"department"+department.getName();
    }
}

在DepartmentMapper接口中添加查询方法:

public Department selectDepartment(int did);

用mybatis实现:

<!-- 先查询部门信息,再根据mid查询主管信息 -->
<resultMap id="DepartmentManager" type="Department">
    <!-- property:在实体类中属性名 column{key=value,key=value}
    key传给sql查询的取值,value查询结果在数据库中的字段名
    javaType java类,select 嵌套查询中内层查询的名字,与下面select id对应 -->
    <id column="did" property="id"/>
    <result column="dname" property="name"/>
    <association property="manager" column="mid"
                 javaType="Employee" select="selectManager"/>
</resultMap>

<select id="selectDepartment" resultMap="DepartmentManager">
    select * from department where did=#{did}
</select>
<select id="selectManager" resultMap="Employee">
    select * from employee where id=#{id}
</select>

出现的问题

Error attempting to get column ‘ename‘ from result set.  Cause: java.sql.SQLException: Invalid value for getInt() - ‘Su‘

分析:数据库列名‘ename‘与实体属性名‘name’不匹配,而且数据库中的顺序是(id,ename,did),实体类中是(name,id,department)

用resultMap

<resultMap id="EmployeeMap" type="Employee">
        <!--constructor>
            <arg column="id" javaType="_int" name="id"/>
            <arg column="ename" javaType="String" name="name"/>
        </constructor-->
        <id column="id" property="id"/>
        <result column="ename" property="name"/>
</resultMap>
<select id="selectManager" resultMap="EmployeeMap">
    select * from employee where id=#{id}
</select>

仍然报错,添加无参构造函数,或者使用constructor并增加对应构造方法

 <resultMap id="EmployeeMap" type="Employee">
        <constructor>
            <arg column="id" javaType="_int" name="id"/>
            <arg column="ename" javaType="String" name="name"/>
        </constructor>
        <!--id column="id" property="id"/>
        <result column="ename" property="name"/-->
</resultMap>

在Employee中增加构造方法和注解:

public Employee(@Param("name") String name, @Param("id") int id){
        //System.out.println("constructor");
        this.name=name;
        this.id=id;
}

运行结果:

技术分享图片

接下来来看另一种实现方法:结果映射

连接查询的SQL语句实现如下:

技术分享图片

mybatis实现

    <select id="selectDepartment2" resultMap="DepartmentMap">
        select d.did as did,d.dname,mid,ename from department d,employee e
        where d.did=#{did} and d.mid=e.id
    </select>
    <resultMap id="DepartmentMap" type="Department">
        <result property="id" column="did"/>
        <result property="name" column="dname"/>
        <!-- 关联Department类中的成员:Employee manager -->
        <association property="manager" javaType="Employee">
            <result column="mid" property="id"/>
            <result column="ename" property="name"/>
        </association>
    </resultMap>

出现的问题:

技术分享图片

可以看到dname被当成了did进行处理,按照网上的说法,要给Java类Department添加无参构造函数和Set()方法,但我已经添加了,仍然报错,最后发现是参数顺序的问题,在Java类中是(name, id, manager),所以要改一下SQL语句,dname在前,did在后:

 select d.dname,d.did as did,mid,ename from department d,employee e
        where d.did=#{did} and d.mid=e.id

运行结果:

技术分享图片

集合的映射

上面的例子是一对一关系的映射(一个部门只有一个主管),下面来看一对多关系的映射如何处理:

SQL语句查询:查询部门1的所有员工

技术分享图片

mybatis实现:使用collection元素

<select id="selectDepartment3" resultMap="DepartmentMap2">
    select dname,d.did,e.id as eid,ename from department d,employee e
    where d.did=#{did} and d.did=e.did
</select>
<resultMap id="DepartmentMap2" type="Department">
    <result property="id" column="did"/>
    <result property="name" column="dname"/>
    <!-- ofType:集合中元素类型 -->
    <collection property="employees" ofType="Employee">
        <result column="eid" property="id"/>
        <result column="ename" property="name"/>
    </collection>
</resultMap>

运行结果

技术分享图片

Mybatis学习02--XML映射器(1)

原文:https://www.cnblogs.com/jyyx20/p/14087422.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!