前言
在实际开发中,对数据库的操作通常会涉及多张表,MyBatis提供了关联映射,这些关联映射可以很好地处理表与表,对象与对象之间的的关联关系。
一对一查询
步骤:
- 先确定表的一对一关系
- 确定好实体类,添加关联对象
- 使用resultMap定义好输出参数
- 编写sql语句
- 测试
在MyBatis中,通过<association>元素来处理一对一的关联关系。<association>元素中的属性如下:
属性 | 说明 |
---|---|
property | 用于指定映射到的实体类对象的属性,与表字段一一对应 |
column | 用于指定表中对应的字段 |
javaType | 用于指定映射到实体对象的属性的类型 |
jdbcType | 用于指定数据库中对应字段的类型 |
fetchType | 用于指定关联查询时是否延迟加载。fetchType有lazy和eager两个属性值,默认为lazy延迟加载 |
select | 用于引入嵌套查询的SQL语句,该属性用于关联映射的嵌套查询 |
autoMapping | 用于指定是否自动映射 |
typeHandler | 用于指定一个类型处理器 |
<resultMap id="oneByOne" type="com.cc.User"><id column="id" property="id"/><result column="name" property="name"/><result column="gender" property="gender"/><result column="age" property="age"/><result column="address" property="address"/><result column="email" property="email"/><result column="qq" property="qq"/><association property="login" javaType="com.cc.Login"><id column="id" property="id"/><result column="username" property="username"/><result column="password" property="password"/></association></resultMap><select id="findPassword" resultMap="oneByOne">select u.*,l.* from tb_userinfo u,tb_login l where u.name=l.username;</select>
使用resultMap定义结果映射集,其中id标签用于映射数据库表中的主键字段,column为数据库的列名,property为java类的属性名。result用于映射普通字段。
association标签用于映射关联对象的信息。property为关联对象的属性名,javaType为关联对象的Java类路径
一对多查询
在MyBatis中,通过<collection>元素来处理一对多关联关系。<collection>大多与<association>元素相同,还包含一个特殊属性ofType与javaType属性相对应,它用于指定实体类对象中集合类属性所包含的元素的类型。
示例:
通过tb_userinfo表中的name值与tb_login中的username关联查询出两张表中的数据:
将userinfo表与login两张表设计成两个实体类,并将login作为属性加入到userinfo中(也可以反过来):
public class User {private String id;private String name;private String gender;private int age;private String address;private String email;private String qq;private Login login;public String getId() {return id;}public void setId(String id) {this.id = id;}public Login getLogin() {return login;}public void setLogin(Login login) {this.login = login;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getGender() {return gender;}public void setGender(String gender) {this.gender = gender;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public String getQq() {return qq;}public void setQq(String qq) {this.qq = qq;}public User(String name, String gender, int age, String address, String email, String qq) {this.name = name;this.gender = gender;this.age = age;this.address = address;this.email = email;this.qq = qq;}public User() {}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", gender='" + gender + '\'' +", age=" + age +", address='" + address + '\'' +", email='" + email + '\'' +", qq='" + qq + '\'' +", login=" + login +'}';}
}public class Login {private Integer id;private String username;private String password;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public Login(){}public Login(String password, String username) {this.password = password;this.username = username;}@Overridepublic String toString() {return "Login{" +"id=" + id +", username='" + username + '\'' +", password='" + password + '\'' +'}';}
}
<resultMap id="order" type="com.cc.User"><id column="id" property="id"/><result column="name" property="name"/><result column="gender" property="gender"/><result column="age" property="age"/><result column="address" property="address"/><result column="email" property="email"/><result column="qq" property="qq"/><collection property="login" ofType="com.cc.Login"><id column="id" property="id"/><result column="username" property="username"/><result column="password" property="password"/></collection></resultMap><select id="findPassword" resultMap="order">select u.*,l.* from tb_userinfo u,tb_login l where u.name=l.username;</select>
测试:
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);List<User> u = userMapper.findPassword();for (User user:u){System.out.println(user);}
在使用MyBatis嵌套查询进行MyBatis关联映射查询时,使用MyBatis的延迟加载在一定程度上可以降低运行消耗并提高查询效率。MyBatis默认没有开启延迟加载,需要在核心配置文件mybatis.xml中的setting元素内进行配置。
<setting name="lazyLoadingEnabled" value="true"/><setting name="aggressiveLazyLoading" value="false"/>
多对多查询
在数据库中,多对多的关联关系通常要使用一个中间表来维护。
例如,要查询每个员工的职位,根据employee的id值在emp_posi找到对应的pid,再根据pid查找position职位的名称,如下图所示:
映射思路:
将position信息映射到employee中
在position添加属性List<EP> eps
mapper配置如下:
<resultMap id="map" type="com.cc.entity.Employee"><id property="id" column="id"/><result property="name" column="name"/><result property="age" column="age"/><result property="position" column="position"/><collection property="positions" ofType="com.cc.entity.Position"><id property="id" column="id"/><result property="name" column="name"/><collection property="eps" ofType="com.cc.entity.EP"><id property="id" column="id"/><result property="eId" column="emp_id"/><result property="pId" column="posi_id"/></collection></collection></resultMap><select id="selectPosi" resultMap="map">select e.*,p.*,ep.*from employee e,position p,emp_posi epwhere e.id=ep.emp_id and ep.posi_id=p.id;</select>
查询结果如下:
发现查询出的职位错查成employee中的name值。出现该错误的原因是employee和position表使用了相同的列名name,解决方法就是给这些字段起别名: