三、Mybatis多表操作

一、多表操作

前言

多表查询有多少种?

  • 1对1
  • 1对多(多对一)
  • 多对多

环境搭建(可忽略)

1、数据库

在这里插入图片描述

2、pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.itheima</groupId>
    <artifactId>MyBatis03</artifactId>
    <version>1.0-SNAPSHOT</version>



    <dependencies>

        <!--分页插件-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>3.7.5</version>
        </dependency>
        <dependency>
            <groupId>com.github.jsqlparser</groupId>
            <artifactId>jsqlparser</artifactId>
            <version>0.9.1</version>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
        </dependency>
        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.32</version>
            <scope>runtime</scope>
        </dependency>
        <!--单元测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>
        <!--日志-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>


    </dependencies>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
        <java.version>11</java.version>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>11.0</source>
                    <target>11.0</target>
                </configuration>
            </plugin>
        </plugins>
    </build>


</project>

3、sqlMapCongfig.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
    <!--加载jdbc配置文件-->
<properties resource="jdbc.properties"/>
    <!--自定义别名-->
    <typeAliases>
<typeAlias type="com.itheima.domain.User" alias="user" />
<typeAlias type="com.itheima.domain.Order" alias="order" />
    </typeAliases>

    <!--注册类型转换器-->
    <typeHandlers>
        <typeHandler handler="com.itheima.handler.DateTpyeHandler"/>
    </typeHandlers>
    <!--配置分页插件-->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageHelper">
            <property name="dialect" value="mysql"/>    <!--指定方言:(指定书目数据库)因为不同数据库sql命令可能不一样-->
        </plugin>
    </plugins>
<!--搭建数据源环境-->
<environments default="develoment">
    <environment id="develoment">
        <transactionManager type="JDBC"></transactionManager>
        <dataSource type="POOLED">
            <property name="driver" value="${jdbc.driver}"/>
            <property name="url" value="${jdbc.url}"/>
            <property name="username" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
        </dataSource>
    </environment>
</environments>

    <!--加载映射文件-->
    <mappers>
        <mapper resource="com/itheima/mapper/UserMapper.xml"/>
        <mapper resource="com/itheima/mapper/OrderMapper.xml"/>
    </mappers>


</configuration>

关于自定义别名:

【还有1中自定义别名的方式是:扫包】

<!--自定义别名-->
    <typeAliases>
<package name = "com.iiheima.domain"/>

【扫实体类的包,它会将包下的所有实体类都定义别名,别名该类名的首字母小写。】

4、实体类:User&Order(订单)

public class User {
    private int id;
    private String username;
    private String password;
    //忽略get、set方法和toString
    
}


public class Order {
    private int id;
    private Date orderTime;//下单时间
    private double total;//订单价格
    private User user; //当前订单属于哪个客户
	//忽略get、set方法和toString

5、UserMapper&OrderMapper:空

6、Date转毫秒值的类型转换器(省略)

代码演示多表操作

1)一对一

1个订单对应1个User
在这里插入图片描述

期望: 查询Order表,返回所有Order对象List集合,并且能够显示Order从属的User信息
问题: 单单查询Order表是不能够查询出来User的,因为Order表中没有User类型的字段,只有1个相关的uid。
在这里插入图片描述

铺垫:
先让order表和user表结合成1个表:内连接查询

SELECT * , o.id oid FROM orders o , USER u  WHERE u.id = o.id

在这里插入图片描述

解决:

手动指定:字段名与实体类属性的映射关系
(将查询结果集的字段 映射到 实体类的属性中)

①OrderMapper接口
public interface OrderMapper {
    List<Order> findAll();
}
②OrderMapper.xml

<mapper namespace="com.itheima.mapper.OrderMapper">
    <!--
    【手动指定:字段名与实体类属性的映射关系	(将查询结果集的字段映射到实体类的属性中)】
        type:你要封进的实体类
        column:数据库字段名称  (id:表示 主键   result:表示 普通字段 【都是返回查询结果的字段】)
        property:实体类属性
    -->
    <resultMap id="orderMap" type="order">   <!--order自定义别名(全限定名)-->
		//Order的简单属性
        <id column="oid" property="id"/>    <!--数据库的oid 对应着 实体类属性的id-->
        <result column="orderTime" property="orderTime"/>
        <result column="total" property="total"/>

        <result column="uid" property="user.id"/>
        <result column="username" property="user.username"/>
        <result column="password" property="user.password"/>
        <result column="birthday" property="user.birthday"/>
    </resultMap>

    <select id="findAll" resultMap="orderMap">			<!--resultMa:指定哪个结果映射的id标识-->
        SELECT * , o.id oid FROM orders o , USER u  WHERE u.id = o.uid
    </select>

</mapper>

③测试
   @Test
    public void test01() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        //获取动态代理对象
        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
        //执行SQL
        List<Order> orders = mapper.findAll();

        for (Order order : orders) {
            System.out.println(order);
        }
        
        sqlSession.close();

    }

输出:

Order{id=1, orderTime=Thu Jan 01 08:00:02 CST 1970, total=3000.0, user=User{id=1, username='lucy', password='123', birthday=Thu Jan 01 08:00:02 CST 1970}}

Order{id=2, orderTime=Thu Jan 01 08:00:02 CST 1970, total=4000.0, user=User{id=1, username='lucy', password='123', birthday=Thu Jan 01 08:00:02 CST 1970}}

Order{id=3, orderTime=Thu Jan 01 08:00:02 CST 1970, total=5000.0, user=User{id=2, username='haohao', password='123', birthday=Thu Jan 01 08:00:02 CST 1970}}
映射过程

在这里插入图片描述

映射原理

在这里插入图片描述

Mapper的第二种配置:

OrderMapper.xml:

<resultMap id="orderMap" type="order">   <!--自定义别名-->
	//Order的简单属性
    <id column="oid" property="id"/>    <!--数据库的oid 对应着 实体类属性的id-->
    <result column="orderTime" property="orderTime"/>
    <result column="total" property="total"/>
	//Order的User集合属性
    <!--
    association :翻译“匹配”
    property:表示实体类(order)的属性名称(private User user)
    javaType:表示实体类属性的类型(User)(全限定名)
    column:数据库返回结果集的字段名称
    property:实体类属性名称
    -->
    
    <association property="user" javaType="user">
        <id column="id" property="id"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
        <result column="birthday" property="birthday"/>
    </association>
</resultMap>

2)一对多

1个User对应多个订单
在这里插入图片描述
期望: 查询用户,显示用户的所有信息和有哪些订单
问题:
1)单单查询User表显示不了order表的信息,但发现order关联user的id。
2)mapper怎么手动指定;List集合属性的映射关系

解决:

铺垫:
先让order表和user表结合成1个表:内连接查询

SELECT * , o.id oid FROM orders o , USER u  WHERE u.id = o.id

在这里插入图片描述

①User添加属性
public class User {
    private int id;
    private String username;
    private String password;
    private Date birthday;
    
    //当前用户有哪些订单
    private List<Order> orderList;
②UserMapper接口
public interface UserMapper {
    List<User> findAll();
}
②UserMapper.xml
<mapper namespace="com.itheima.mapper.UserMapper">
        <resultMap id="userMap" type="user">
        		//User的简单属性
                <id column="id" property="id"/>
                <result column="username" property="username"/>
                <result column="password" property="password"/>
                <result column="birthday" property="birthday"/>
        		//User的Order集合属性
         <!--配置集合:
                  property:User中集合的属性名称(List<Order> orderList)
                  ofType:集合的类型(Order)(全限定名)
                  column:字段名称

                -->
                <collection property="orderList" ofType="order">
                        <!--封装Order数据-->
                        <id column="oid" property="id"/>
                        <result column="ordertime" property="orderTime"/>
                        <result column="total" property="total"/>
                </collection>
                
        </resultMap>
        
        <select id="findAll" resultMap="userMap">
                select * ,o.id oid from user u ,orders o where u.id=o.uid
        </select>
        
</mapper>
③测试
 @Test
    public void test02() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        //获取动态代理对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        //执行SQL
        List<User> users = mapper.findAll();
        for (User user : users) {
            System.out.println(user);
        }
        sqlSession.close();

    }

输出:

User{id=1, username='lucy', password='123', birthday=Thu Jan 01 08:00:02 CST 1970, orderList=[Order{id=1, orderTime=Thu Jan 01 08:00:02 CST 1970, total=3000.0, user=null}, Order{id=2, orderTime=Thu Jan 01 08:00:02 CST 1970, total=4000.0, user=null}]}
User{id=2, username='haohao', password='123', birthday=Thu Jan 01 08:00:02 CST 1970, orderList=[Order{id=3, orderTime=Thu Jan 01 08:00:02 CST 1970, total=5000.0, user=null}]}

3)多对多

1个用户对应多个角色,1个角色对应多个用户
在这里插入图片描述
(将3个表进行内连接查询)

0、数据库:

在这里插入图片描述

select * from sys_user u,sys_user_role ur ,sys_role r where u.id = ur.userId and r.id = ur.roleId

在这里插入图片描述

①增加role实体类
public class Role {
    private int id;
    private String roleName;
    private String roleDesc;
    //省略set/get方法
}

②增加user实体类成员变量
public class User {
    private int id;
    private String username;
    private String password;
    private Date birthday;
    private List<Order> orderList;//当前用户有哪些订单
    
    //当前用户具备哪些角色
    private List<Role> roleList;
③UserMapper接口
public interface UserMapper {
    List<User> findUserAndRoleAll();
}
④UserMapper.xml
<mapper namespace="com.itheima.mapper.UserMapper">
<resultMap id="userRoleMap" type="user">        <!--type:封进哪里的全限定名-->
                <!--User的简单属性-->
                <id column="userId" property="id"/>                <!--column:结果集字段-->
                <result column="username" property="username"/>
                <result column="password" property="password"/>
                <!--User的roleList的Role集合属性-->
                <collection property="roleList" ofType="role">  <!--ofType:集合类型(全限定名)-->
                        <id column="roleId" property="id"/>
                        <result column="roleName" property="roleName"/>
                        <result column="roleDesc" property="roleDesc"/>
                </collection>
        </resultMap>
        <select id="findUserAndRoleAll" resultMap="userRoleMap">
            select * from sys_user u ,sys_user_role ur,sys_role r where u.id = ur.userId and r.id = ur.roleId
        </select>
</mapper>
⑤测试
@Test
    public void test03() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        //获取动态代理对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        //执行SQL
        List<User> users = mapper.findUserAndRoleAll();
        for (User user : users) {
            System.out.println(user);
        }
        sqlSession.close();

    }

输出:

User{id=1, username='zhangsan', password='123', birthday=null, orderList=null, roleList=[Role{id=1, roleName='院长', roleDesc='负责全面工作'}, Role{id=2, roleName='研究员', roleDesc='课程研发工作'}]}
User{id=2, username='lisi', password='123', birthday=null, orderList=null, roleList=[Role{id=2, roleName='研究员', roleDesc='课程研发工作'}, Role{id=3, roleName='讲师', roleDesc='授课工作'}]}

4)总结

在这里插入图片描述

二、注解开发

1)概述

在这里插入图片描述

2)简单de增删改查

①Mybatis核心文件配置

删除了mapper配置文件,接口和实体类是没有映射关系的,因为没有配置值文件Mybatis不知道谁跟谁有映射关系,不使用xml配置的话,记得要加载映射关系

【这里是扫接口的包】

    <!--加载映射关系-->
    <mappers>
        <!--指定接口所在的包(扫包)-->
         //<!--<mapper resource="com/itheima/mapper/AccountMapper.xml"></mapper>-->
        <package name="com.itheima.mapper"/>
    </mappers>

②UserMapper接口:声明注解

这里跟xml文件一样的,用方法的参数来赋SQL值

public interface UserMapper {

    @Insert("insert into user values(#{id},#{username},#{password})")
    void save(User user);

    @Update("update user set username=#{username},password=#{password} where id=#{id}")
    void  update(User user);

    @Delete("delete from user where id = #{id}")
    void  delete(int id);

    @Select("select * from user where id = #{id}")
    User findById(int id);

    @Select("select * from user")
    List<User> findAll();
}

③测试

public class Demo {
    public User user = new User();
    public UserMapper mapper;

    @Before
    public void before() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        mapper = sqlSession.getMapper(UserMapper.class);
    }
    //增
    @Test
    public void testSave(){
        user.setUsername("我是谁");
        user.setPassword("123");
        mapper.save(user);
    }
    //删
    @Test
    public void testDeleteById(){
        mapper.delete(3);
    }
    //改
    @Test
    public void testUpdateById(){
        user.setId(1);
        user.setUsername("易烊");
        user.setPassword("123");
        mapper.update(user);
    }
    //查:1个
    @Test
    public void testFindAll(){
        List<User> userList = mapper.findAll();
        System.out.println(userList);
    }
    //查:所有
    @Test
    public void testFindById(){
        User user = mapper.findById(1);
        System.out.println(user);
    }

}

3)实现复杂映射开发

下面的案例都是根据在XML配置的案例上,使用注解代替xml

请看上面的 数据库样子案列需求

概述

在这里插入图片描述
在这里插入图片描述

1、一对一

需求:查询订单,返回订单的从属用户

0、实体类
public class User {
    private int id;
    private String username;
    private String password;
    //忽略get、set方法和toString
    
}
public class Order {
    private int id;
    private Date orderTime;//下单时间
    private double total;//订单价格
    private User user; //当前订单属于哪个客户
	//忽略get、set方法和toString
①OrderMapper接口
public interface OrderMapper {
    
    @Select("select * from user u,orders o where o.uid = u.id")
    
    @Results({
            //Order的简单属性
            @Result(column = "id",property = "id"),//返回结果集的字段 与 Order属性值
            @Result(column = "ordertime",property = "ordertime"),
            @Result(column = "total",property = "total"),
            //Order的User对象属性
            @Result(column = "uid",property = "user.id"),//返回结果集的字段 与 Order中User对象的属性值
            @Result(column = "username",property = "user.username"),
            @Result(column = "password",property = "user.password")
    })
    
    List<Order> findAll();
}

②测试
public class Demo2 {
    public User user = new User();
    public OrderMapper mapper;

    @Before
    public void before() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        mapper = sqlSession.getMapper(OrderMapper.class);
    }
    @Test
    public void test1(){
        List<Order> orderList = mapper.findAll();
        for (Order order : orderList) {
            System.out.println(order);
        }
    }
③输出
Order{id=1, ordertime='2018-12-12', total='3000', user=User{id=1, username='易烊', password='123'}}
Order{id=1, ordertime='2018-12-12', total='4000', user=User{id=1, username='易烊', password='123'}}
Order{id=2, ordertime='2018-12-12', total='5000', user=User{id=2, username='haohao', password='123'}}
对比一下xml:

在这里插入图片描述

2、一对一的第2种方式(常用)

第2种是什么方式呢?

上边的方式是使用内连接将2个表合成为1个表来查询
下面是通过1个表,1个表的查询
具体是 怎么样呢?

  • 先查询orders表返回查询结果集
  • 指定查询结果集中的uid(oders表中的外键,user表的主键), 根据uid查询user表

select * from useru,orders o where o.uid = u.id
↓分开
select * from orders (OrderMapper)
↓根据uid(复用)
select * from user where id = ? (UserMapper)

代码跟前面整个注解演示相关,这里只写出有改动的。

①UserMapper接口(上边已经定义<复用>)
根据id查询User:

 @Select("select * from user where id = #{id}")
    User findById(int id);
②OrderMapper接口
public interface OrderMapper {

    @Select("select * from orders")

    @Results({
            //Order的简单属性
            @Result(column = "id",property = "id"),//返回结果集的字段 与 Order属性值
            @Result(column = "ordertime",property = "ordertime"),
            @Result(column = "total",property = "total"),
            //Order的User对象属性
            @Result(
                    property = "user",  //Order实体需要封装的属性名称
                    column = "uid",     //根据orders返回查询结果集中的哪个字段进行查询
                    javaType = User.class,  //Order中user属性名称的属性类型
                    //1对1
                    one = @One(select = "com.itheima.mapper.UserMapper.findById" )   //select属性:查询哪个接口的方法 获得 Order实体需要封装的属性
            )
    })//记得,这里是{ }是数组。

    List<Order> findAll();
}
3、一对多

需求:查询用户,返回该用户有哪些订单

这里也是将2个表使用内连接合成1个表查询,分成2个表分别查询

select* from useru ,orders o where u.id = o.uid
↓分开
select * from user
↓ 根据id
select * from orders where uid = ?

①User实体类
public class User {
    private int id;
    private String username;
    private String password;
    //当前用户拥有多少订单
    private List<Order> orderList;
②OrderMapper接口
public interface OrderMapper {

    @Select("select * from orders where id = #{id}")
    List<Order> findByUid(int uid);
③UserMapper接口
public interface UserMapper {
    @Select("select * from user")
    @Results({
            //User的简单属性
            @Result(id = true,column = "id",property = "id"),	//id=true :特指这个是主键
            @Result(column = "username",property = "username"),
            @Result(column = "password",property = "password"),
            //User中Order集合属性
            @Result(
                    property = "orderList",     //User中Order集合属性名称
                    column = "id",              //User返回查询结果集中,根据哪个字段查询
                    javaType = List.class,      //User中orderList属性名称的属性类型
                    //1对多
                    many = @Many (select = "com.itheima.mapper.OrderMapper.findByUid")  //调用什么方法来查询

            )

    })
    List<User> findUserAndOrderAll();
}
④测试
public class Demo3 {
    public User user = new User();
    public UserMapper mapper;

    @Before
    public void before() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        mapper = sqlSession.getMapper(UserMapper.class);
    }

    @Test
    public void test1() {
        List<User> userList = mapper.findUserAndOrderAll();

        for (User u : userList) {
            System.out.println(u);
        }
    }
}
4、多对多

多对多:多对多都是有个中间表,这里也是将3个表的内连接,拆分成2个表来查询

根据User的id 查询 某个User具备哪些角色:
select * from user u ,sys_user_role ur , sys_role r where ur.roleId = r.id and u.id = ?
↓ 拆分
select * from user
↓ 根据id查询
select * from sys_user_role ur ,sys_role r where ur.roleId = r.id and ur.userId = ?
在这里插入图片描述

①Role实体类
public class Role {
    private int id;
    private String roleName;
    private String roleDesc;
②User实体类
public class User {
    private int id;
    private String username;
    private String password;
    //当前User具备多少个角色
    private List<Role> roleList;
③RoleMapper接口
public interface RoleMapper {
    @Select("select * from sys_user_role ur ,sys_role r where ur.roleId = r.id and ur.userId = #{uid}")
    List<Role> findByUid(int uid);
}
④UserMapper接口
public interface UserMapper {

    @Select("select * from user")
    @Results({
            //User的简单属性
            @Result(column = "id",property = "id"),
            @Result(column = "username",property = "username"),
            @Result(column = "password",property = "password"),
           
            //User中Role集合属性
            @Result(
                    property = "roleList",  //封进哪个属性
                    column = "id",          //根据哪个字段查询
                    javaType = List.class,  //封进哪个属性的属性类型
                    //多对多
                    many = @Many(select = "com.itheima.mapper.RoleMapper.findByUid")    //调用某个方法查询
            )
    })
    List<User> findUserAndRoleAll();
⑤测试(忽略)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值