Mybatis多表关联查询

用了MybatisPlus之后,感觉自己写sql的机会不多,但是一些多表关联还是需要自己写的。

今天复习一下mybatis中的多表关联查询

建两个简单的表:

emp员工表

dept部门表

 

 员工:部门=多:1

部门:员工=1:多

如果项目中有多对多的关系,需要引入中间表,比如rbac中的用户角色表就是多对多的关系

1.针对多对一的情况:

 即员工:部门=多:1

public class EmpDept {

    private Integer id;

    private String userName;

    private Date createDate;

    private Integer deptId;

    private Dept dept ;

    // getter 和setter方法省略 
}

方式一:对象属性名.属性

package com.tulingxueyuan.mapper;

import com.tulingxueyuan.pojo.EmpDept;

import java.util.List;

public interface EmpDeptMapper {

    List<EmpDept> selectEmpWithDept();
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tulingxueyuan.mapper.EmpDeptMapper">
    <resultMap id="BaseResultMap" type="com.tulingxueyuan.pojo.EmpDept">
        <id column="id" jdbcType="INTEGER" property="id" />
        <result column="user_name" jdbcType="VARCHAR" property="userName" />
        <result column="create_date" jdbcType="TIMESTAMP" property="createDate" />
        <result column="dept_id" jdbcType="INTEGER" property="deptId" />
        <!--方式一:对象属性名.属性-->
        <result column="d_id" property="dept.id"></result>
        <result column="d_name" property="dept.deptName"></result>
    </resultMap>

    <select id="selectEmpWithDept" resultMap="BaseResultMap">
        SELECT
            e.id,
            e.user_name,
            e.dept_id,
            d.id as d_id,
            d.dept_name as d_name
        FROM
            emp e
                INNER JOIN dept d ON e.dept_id = d.id
    </select>


</mapper>
public class SqlTest {

    SqlSessionFactory sqlSessionFactory ;

    @Before
    public void init() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

    }

    @Test
    public void test01(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        EmpDeptMapper mapper = sqlSession.getMapper(EmpDeptMapper.class);

        List<EmpDept> empDeptList = mapper.selectEmpWithDept();

        System.out.println(empDeptList.size());
        System.out.println(empDeptList);

        sqlSession.commit();
        sqlSession.close();

    }
}

方式二:association

1.使用association的第一种写法:指定javaType

  association中的property指定多对一种的一

                           javaType指定类型

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tulingxueyuan.mapper.EmpDeptMapper">
    <resultMap id="BaseResultMap" type="com.tulingxueyuan.pojo.EmpDept">
        <id column="id" jdbcType="INTEGER" property="id" />
        <result column="user_name" jdbcType="VARCHAR" property="userName" />
        <result column="create_date" jdbcType="TIMESTAMP" property="createDate" />
        <result column="dept_id" jdbcType="INTEGER" property="deptId" />
        <!--方式一:对象属性名.属性-->
<!--        <result column="d_id" property="dept.id"></result>-->
<!--        <result column="d_dept_name" property="dept.deptName"></result>-->
        <!--方式二-1:association-->
        <association property="dept" javaType="com.tulingxueyuan.pojo.Dept">
            <result column="d_id" property="id"></result>
            <result column="d_dept_name" property="deptName"></result>
        </association>
    </resultMap>

    <select id="selectEmpWithDept" resultMap="BaseResultMap">
        SELECT
            e.id,
            e.user_name,
            e.create_date,
            e.dept_id,
            d.id as d_id,
            d.dept_name as d_dept_name
        FROM
            emp e
                INNER JOIN dept d ON e.dept_id = d.id
    </select>


</mapper>

2.使用association的第二种写法:指定resultMap

   如果不想在association中再写result这种列和属性字段的映射的话,那么就用resultMap来指定一个已经写好的resultMap即可,达到重用的目的。

ps:这时候如果有命名重复的问题,比如emp中有id,dept种也有id,可以用as重命名查询出来的列,之后用columnPrefix="d_"来去掉这个前缀。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tulingxueyuan.mapper.EmpDeptMapper">
    <resultMap id="BaseResultMap" type="com.tulingxueyuan.pojo.EmpDept">
        <id column="id" jdbcType="INTEGER" property="id" />
        <result column="user_name" jdbcType="VARCHAR" property="userName" />
        <result column="create_date" jdbcType="TIMESTAMP" property="createDate" />
        <result column="dept_id" jdbcType="INTEGER" property="deptId" />
        <!--方式一:对象属性名.属性-->
<!--        <result column="d_id" property="dept.id"></result>-->
<!--        <result column="d_dept_name" property="dept.deptName"></result>-->
        <!--方式二-1:association-->
<!--        <association property="dept" javaType="com.tulingxueyuan.pojo.Dept">-->
<!--            <result column="d_id" property="id"></result>-->
<!--            <result column="d_dept_name" property="deptName"></result>-->
<!--        </association>-->
        <!--方式二-2:association-->
        <association property="dept" columnPrefix="d_"
                     resultMap="com.tulingxueyuan.mapper.DeptMapper.BaseResultMap">
        </association>
    </resultMap>

    <select id="selectEmpWithDept" resultMap="BaseResultMap">
        SELECT
            e.id,
            e.user_name,
            e.create_date,
            e.dept_id,
            d.id as d_id,
            d.dept_name as d_dept_name
        FROM
            emp e
                INNER JOIN dept d ON e.dept_id = d.id
    </select>


</mapper>
public class Dept {
    private Integer id;

    private String deptName;

    //省略getter和setter方法
}

那么使用属性名.属性的方式和使用association的两种方式有什么不同呢?

       使用association会强制的使我们的查询结果进行多对一,因为mybatis底层是将主键和查出来的对象放入一个类似hashmap的数据结构中,所以没有查emp的id会造成association失效。association是凭借id来组织多对一的结果。这是非常容易忽视的问题。

使用属性名.属性的方式就不会帮助我们多对一,我们查出来多少条数据就是多少条数据。

2.针对一对多的情况:

   其实这种情况使我们工作中应用比较多的场景。

   比如:级联查询的时候

  这里其实用到了collection,这种情况不像是association还可以用属性名.属性代替一下,这个collection只能就自己这么用,哈哈~

重点 代码:

package com.tulingxueyuan.pojo;

import java.util.List;

public class DeptEmp {

    private Integer id;

    private String deptName;

    private List<Emp> emps ;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getDeptName() {
        return deptName;
    }

    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }

    public List<Emp> getEmps() {
        return emps;
    }

    public void setEmps(List<Emp> emps) {
        this.emps = emps;
    }

    @Override
    public String toString() {
        return "DeptEmp{" +
                "id=" + id +
                ", deptName='" + deptName + '\'' +
                ", emps=" + emps +
                '}';
    }
}

  

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tulingxueyuan.mapper.DeptEmpMapper">
    <resultMap id="BaseResultMap" type="com.tulingxueyuan.pojo.DeptEmp">
        <id column="id" jdbcType="INTEGER" property="id" />
        <result column="dept_name" jdbcType="VARCHAR" property="deptName" />
        <collection property="emps" columnPrefix="e_"
                    resultMap="com.tulingxueyuan.mapper.EmpMapper.BaseResultMap"></collection>
    </resultMap>

    <select id="selectDeptWithEmp" resultMap="BaseResultMap">
        SELECT
            d.id,
            d.dept_name,
            e.id as e_id,
            e.user_name as e_user_name,
            e.create_date as e_create_date,
            e.dept_id as e_dept_id
        FROM
            dept d
                INNER JOIN emp e ON d.id = e.dept_id
    </select>


</mapper>
<mapper namespace="com.tulingxueyuan.mapper.EmpMapper">
<resultMap id="BaseResultMap" type="com.tulingxueyuan.pojo.Emp">
  <id column="id" jdbcType="INTEGER" property="id" />
  <result column="user_name" jdbcType="VARCHAR" property="userName" />
  <result column="create_date" jdbcType="TIMESTAMP" property="createDate" />
  <result column="dept_id" jdbcType="INTEGER" property="deptId" />
</resultMap>
​​​​​​​</mapper>
@Test
    public void testCollection(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        DeptEmpMapper mapper = sqlSession.getMapper(DeptEmpMapper.class);

        List<DeptEmp> deptEmpList = mapper.selectDeptWithEmp();

        System.out.println(deptEmpList.size());
        System.out.println(deptEmpList);

        sqlSession.commit();
        sqlSession.close();

    }

其实collection标签的用法和association标签的属性很多用法是相同的。

ps:

记录mapper.xml中的关于不等于的写法:

重点看注释部分

 <select id="selectProductCategoryWithChildren" resultMap="selectProductCategoryWithChildrenMap">
        SELECT
        t1.id,
        t1.`name`,
        t2.id AS son_id,
        t2.`name` AS son_name
        FROM
        pms_product_category t1
        INNER JOIN pms_product_category t2 ON t1.id = t2.parent_id
        and t1.parent_id=0
        and t2.parent_id<![CDATA[<>]]>0  <!--或者使用尖括号  但是尖括号会报错 可以使用&lt;&gt; 或者使用<![CDATA[<>]]>  还可以直接使用!= -->
        ORDER BY t1.id
    </select>

 

  • 0
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Mybatis-plus多表关联查询是指在使用Mybatis-plus框架进行数据库操作时,通过多个表之间的关联关系,实现一次性查询多个表中的数据。这种查询方式可以大大提高查询效率,减少数据库访问次数,提高系统性能。在Mybatis-plus中,可以使用注解或XML配置的方式实现多表关联查询,具体实现方式可以参考Mybatis-plus官方文档。 ### 回答2: MyBatis-Plus是基于MyBatis的增强工具,提供了很多实用的功能,其中包括了多表关联查询。在实际开发中,我们经常需要查询多个表的数据,此时就需要用到多表关联查询。下面介绍一下MyBatis-Plus多表关联查询的实现方法。 1.通过@TableName注解指定表名 在实体类上使用@TableName注解,可以指定当前实体类对应的表名,这样在进行多表关联查询时,就可以直接使用表名进行操作。示例代码如下: ``` @Data @TableName("t_user") public class User { @TableId(type = IdType.AUTO) private Long id; private String username; private String password; } ``` 2.使用Mapper中的方法进行多表关联查询 MyBatis-Plus提供了一些方法,可以进行多表关联查询。其中比较常用的方法是selectList()和selectPage()。这些方法可以通过Wrapper条件构造器指定查询条件,并且支持多表关联查询。示例代码如下: ``` public interface UserMapper extends BaseMapper<User> { @Select("select * from t_user u " + "left join t_role r on r.id = u.role_id " + "where u.id = #{id}") UserVO selectUserWithRole(Long id); @Select("select * from t_user u " + "left join t_role r on r.id = u.role_id " + "${ew.customSqlSegment}") List<UserVO> selectUserListWithRole(@Param(Constants.WRAPPER) Wrapper wrapper); } ``` 3.使用@Result注解映射查询结果 在使用Mapper中的方法进行多表关联查询时,我们可以使用@Result注解对查询结果进行映射,这样可以更方便地获取查询结果。示例代码如下: ``` public interface UserMapper extends BaseMapper<User> { @Select("select u.*, r.name as roleName from t_user u " + "left join t_role r on r.id = u.role_id " + "where u.id = #{id}") @Results({ @Result(column = "roleName", property = "roleName") }) UserVO selectUserWithRole(Long id); } ``` 总之,MyBatis-Plus多表关联查询使用起来非常方便,只需要在实体类中指定表名,使用Mapper中的方法进行查询,并使用@Result注解对查询结果进行映射即可。需要注意的是,在进行多表关联查询时,要确保关联的字段在两个表中是唯一的,并且要注意查询效率和查询结果的正确性。 ### 回答3: Mybatis-Plus是一个优秀的基于Mybatis的ORM框架,它极大地简化了开发人员的开发工作。在实际开发中,多表关联查询是常见的需求,Mybatis-Plus提供了多种方式支持多表关联查询。以下是几种常见的多表关联查询方式: 1.通过Join方式查询 使用Join语句可以在一个查询中查询多张表,从而实现多表关联查询,如下: ``` SELECT t1.*, t2.* FROM t1 INNER JOIN t2 ON t1.id = t2.t1_id ``` 如果需要使用Join方式查询,需要使用Mybatis-Plus的Wrapper类实现多表关联查询。 2.通过关联查询实现多表查询 如果需要实现包含关联实体的复杂查询,可以使用Mybatis-Plus提供的lambdaQuery方法。例如: ``` List<User> userList = userMapper.selectList(Wrappers .lambdaQuery(User.class) .eq(User::getStatus, 1) .nested(i -> i.eq(User::getName, "Tom") .or() .eq(User::getName, "Jerry")) .orderByAsc(User::getAge) .select(User::getId, User::getName, User::getAge, User::getEmail) .leftJoin(User.class, User::getId, UserRole::getUserId) .leftJoin(UserRole.class, UserRole::getRoleId, Role::getId) .select(UserRole::getRoleId, Role::getName) ) ``` 3.通过XML mapper方式查询 使用XML mapper文件可以实现多表关联查询。通过XML可以方便地实现复杂的多表查询。如下: ``` <select id="getUserRoleList" resultMap="BaseResultMap"> select ur.*, r.name as roleName from user_role ur left join role r on ur.role_id = r.id where ur.user_id = #{userId} </select> ``` 更多关于Mybatis-Plus多表关联查询,可以参考Mybatis-Plus官方文档或者相关博客文章。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值