从上一篇的第一个程序可以看到,我们只需要在映射器Mapper.xml中添加SQL代码和映射定义,Mybatis就会自动将查询映射到接口方法上。
根据name和pwd查询用户,SQL代码如下:
select * from user where name=? and pwd=?;
如果在Java类中属性名与数据库列名一致,直接使用#{param name}代替?即可,Mybatis能够匹配参数的名字,但不一致的情况下,可以用以下方法完成映射:
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>
注意参数名要与#{}中的名字一致
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"));
在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元素对应的属性会被标记为对象标识符,在比较对象实例中使用。
将查询结果注入到类的构造方法中,例如
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)元素处理“有一个”类型的关系。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>
运行结果
原文:https://www.cnblogs.com/jyyx20/p/14087422.html