【javaEE】(10)——封装、主键回填、ResultMap、多表查询(一对一、一对多、多对多)(新)

本文介绍了如何在MyBatis中通过Result类优化接口返回,实现更人性化的数据封装。同时,详细讲解了主键回填功能的使用,以及ResultMap在属性名不一致情况下的映射作用。接着,文章探讨了一对一查询的两种方法,包括直接SQL查询和级联查询,并展示了如何处理一对一多表增加时的事务管理。最后,文章涵盖了多对一和多对多关系的级联查询,展示了在不同场景下的数据获取方式。
摘要由CSDN通过智能技术生成

一:数据封装(返回结果)

在之前的Mybaties中的接口中,返回值的类型不是很人性化,为了更加人性化,可以写一个返回类Result来更方便与前端的统一。

放在uilts目录下

Result类

package com.mybatis.mybatis.utils;

import java.util.HashMap;
import java.util.Map;

/**
 * 返回数据封装类
 */
public class Result extends HashMap<String, Object> {
    private static final long serialVersionUID = 1L;

    public Result() {
        put("code", 0);
        put("msg", "success");
    }

    public static Result error() {
        return error(500, "未知异常,请联系管理员");
    }

    public static Result error(String msg) {
        return error(500, msg);
    }

    public static Result error(int code, String msg) {
        Result r = new Result();
        r.put("code", code);
        r.put("msg", msg);
        return r;
    }

    public static Result ok(String msg) {
        Result r = new Result();
        r.put("msg", msg);
        return r;
    }


    public static Result ok(Object obj) {
        Result r = new Result();
        r.put("data", obj);
        return r;
    }

    public static Result ok(Map<String, Object> map) {
        Result r = new Result();
        r.putAll(map);
        return r;
    }

    public static Result ok() {
        return new Result();
    }

    public Result put(String key, Object value) {
        super.put(key, value);
        return this;
    }
}

之后将接口的返回值修改成如下即可

查询接口

public Result findAllUser(){
    return Result.ok(userService.findAllUser());
}

删除接口

public Result deleteUserById(@PathVariable int userid){
    if(userService.deleteUserById(userid) > 0){
        return Result.ok("删除成功");
    }
    return Result.error(-1,"数据库删除失败");
}

新增接口

public Result addUser(@RequestBody User user){
    if (userService.addUser(user) > 0){
        return Result.ok(user);
    }
    return Result.error(-1,"数据库增加失败");
}

更新接口

public Result updateUser(@RequestBody User  user){
    if(userService.updateUser(user) > 0){
        return Result.ok("更新成功");
    }
    return Result.error(-1,"数据库更新 失败");
}
 useGeneratedKeys="true" keyProperty="id"

二:主键回填

有时候前端在新增操作的时候需要看到新增的值是什么(比如新增的id是自增长的,新增的时候并没有指定,前端看到的就是0,所以需要返回查看),这个时候就可以用上主键回填的功能。

JavaEE   Mybatis  二    1

​ 修改前

在UserMapper.xml中修改insert部分,新增两个属性useGeneratedKeys和keyProperty

useGeneratedKeys="true"的作用是回填keyProperty指定的值

keyProperty代表的是回填的值,此处就会回填id

<insert id="addUser" parameterType="com.mybatis.mybatis.entity.User" useGeneratedKeys="true" keyProperty="id">
    insert into user (name,age) values (#{name},#{age})
</insert>
JavaEE   Mybatis  二    2

​ 修改后(会显示数据库分配的id)

三:ResultMap初见

一般情况下,实体类的属性名需要和数据库的字段名对应统一,但有时候实体类的属性名和数据库名没法保持一致时,可以采用

Result Map进行对应匹配。

JavaEE   Mybatis  二    3

​ 此处的User类的属性名和数据库中的字段名不一致

修改UserMapper.xml文件的select部分的代码如下

    <select id="findAllUser"  resultMap="userMap">
        select * from user
    </select>

    <resultMap id="userMap" type="com.mybatis.mybatis.entity.User">
<!--     id映射主键   property:实体类的字段名字   column:数据库表字段名字-->
        <id property="id" column="id" ></id>
        <result property="name1" column="name"></result>
        <result property="age" column="age"></result>
    </resultMap>
  • 将select部分的返回类型设置为userMap

  • 在resultMap中设置userMap的样式

    在resultMap中设置样式时,

    ​ < id >元素对应数据库中的字段是主键,< result>对应的是普通字段

    ​ 在元素的属性设置时,property对应的是实体类中的名字,column对应的是数据库中的名字

*修改User的实体类中属性name为name1之后,其他的方法也会受到影响(一般还是与数据库对应的为好)

JavaEE   Mybatis  二    4

!!!!!! 一对一的特点 需要在某一方保存对方的主键 !!!!!!!!

四:一对一的多表的查询

建表的注意事项:在数据库建表的时候,不要使用外键,应该在代码层维持表与表之间的关系。

案例

1:建表

创建idcard表和person表,样式如下

JavaEE   Mybatis  二    5 JavaEE   Mybatis  二    6
2:创建对应的实体类

Idcard.class

package com.mybatis.mybatis.entity;

import lombok.Data;

@Data
public class Idcard {
    private int id;
    private String code;
}

Person.class

package com.mybatis.mybatis.entity;

import lombok.Data;

@Data
public class Person {

    private int id;
    private int age;
    private String name;
    private Idcard cardid;
}

*注意:Person类中的cardid的类型是Idcard类型

3:dao层新建两个接口

IdcardMapper

package com.mybatis.mybatis.dao;

import com.mybatis.mybatis.entity.Idcard;
import org.apache.ibatis.annotations.Mapper;


@Mapper
public interface IdcardMapper {
    public Idcard findCardByid(int id);
}

PersonMapper

package com.mybatis.mybatis.dao;

import com.mybatis.mybatis.entity.Person;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper
public interface PersonMapper {
    public List<Person> findAllPerson();
    public List<Person> findAllPerson2();
}

在resources下新建IdcardMapper.xml与PersonMapper.xml

IdcardMapper.xml

<?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.mybatis.mybatis.dao.IdcardMapper">

<!--    方法1:通过sql语句查询结果得到中间表  中间表通过resultMap做映射-->
    <select id="findCardByid"  resultType="com.mybatis.mybatis.entity.Idcard">
        select * from idcard where id = #{id}
    </select>
</mapper>

PersonMapper.xml

<?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.mybatis.mybatis.dao.PersonMapper">

<!--    方法1:  一对一查询 通过sql语句查询结果得到中间表  中间表通过resultMap做映射-->
    <select id="findAllPerson"  resultMap="personMap">
        SELECT person.*,idcard.code
        from person,idcard
        where person.cardid = idcard.id
    </select>

    <resultMap id="personMap" type="com.mybatis.mybatis.entity.Person">
        <!--     id映射主键   property:实体类的字段名字   column:数据库表字段名字-->
        <id property="id" column="id" ></id>
        <result property="name" column="name"></result>
        <result property="age" column="age"></result>
        <association property="cardid" javaType="com.mybatis.mybatis.entity.Idcard">
            <id property="id" column="cardid"></id>
            <result property="code" column="code"></result>
        </association>
    </resultMap>



<!--    方法2:   级联查询-->
    <select id="findAllPerson2"  resultMap="personMap2">
        SELECT *
        from person
    </select>

    <resultMap id="personMap2" type="com.mybatis.mybatis.entity.Person">
        <!--     id映射主键   property:实体类的字段名字   column:数据库表字段名字-->
        <id property="id" column="id" ></id>
        <result property="name" column="name"></result>
        <result property="age" column="age"></result>
        <association property="cardid"
                     javaType="com.mybatis.mybatis.entity.Idcard"
                     column="cardid"
                    select="com.mybatis.mybatis.dao.IdcardMapper.findCardByid">
        </association>
    </resultMap>
</mapper>

这之中包含了两种查询方式。

其他层的代码就不附加了,重复度太高。

4:查询方式
  • 一对一查询:通过sql语句查询结果得到中间表 中间表通过resultMap做映射

    ​ 需要关注的是它用的sql语句,是直接把所有的结果都一次性查询出来了。

  • 级联查询:通过拼接,把最后的查询结果拼接到一起吗,调用到了其他部位的查询方法。

五:一对一的多表增加

一对一的多表增加,实际上就是对多个表逐个的进行增加。

当对前一个表的执行成功之后,如果对后一个表操作的事务失败了,需要进行回滚操作。

案例:

1:建表(之前有)
2:创建对应的实体类(之前也有)
3:增加代码

dao层:

​ IdcardMapper增加方法

public int addIdcard(Idcard idcard);

​ PersonMapper增加方法

public int addPerson(Person person);

mappers:

​ IdcardMapper.xml增加代码

<insert id="addIdcard"
        useGeneratedKeys="true"
        keyProperty="id"
        parameterType="com.mybatis.mybatis.entity.Idcard">
    insert into idcard (code) values (#{code})
</insert>

​ PersonMapper.xml增加代码

<insert id="addPerson" parameterType="com.mybatis.mybatis.entity.Person">
    insert into person (age,name,cardid) values (#{age},#{name},#{cardid.id})
</insert>

service层:

​ PersonService接口增加代码

public int addPerson(Person person);

​ PersonServiceImpl增加代码:

    @Transactional
//   @Transactional注解的作用是会保证所有的事务执行正确才会对数据库进行完整的修改,若其中的任一事务执行失败则会进行回滚
    public int addPerson(Person person){
        //先往idcard中增加数据
        idcardMapper.addIdcard(person.getCardid());
        //把idcard新增加的主键查询

        //再往person表中增加数据
        return personMapper.addPerson(person);
    }

这之中包含了两个对数据库的操作。

@Transactional注解的作用就是——会保证所有的事务执行正确才会对数据库进行完整的修改,若其中的任一事务执行失败则会进行回滚(回复所有原先的数据库的改动)

controller层:

​ PersonController增加代码:

@PostMapping("addPerson")
public Result addPerson(@RequestBody Person person){
    if(personService.addPerson(person) > 0){
        return Result.error("增加成功");
    }
    return Result.ok(person);
}

!!!!!! 一对多的特点:多的一方需要保存对方的主键 !!!!!!!!

六:一对多的级联查询

场景示例:

​ 用户与订单之间的关系为一对多,即一个用户可以拥有多个订单,而一个订单只属于一个用户。

1:建表

​ user表

JavaEE   mybatis   二   2

​ orders表

JavaEE   mybatis   二   1

2:实体类

​ UserOrder(和订单相关联的用户类,避免和之前的User类冲突)

package com.mybatis.mybatis.entity;

import lombok.Data;

import java.util.List;

@Data
public class UserOrder {
    private int id;
    private String name;
    private int age;
    private List<Order> orderList;
}

​ Order

package com.mybatis.mybatis.entity;

import lombok.Data;

@Data
public class Order {
    private int id;
    private String orderinfo;
    private int userid;
}
3:新的代码

dao层:

​ UserOrderMapper

package com.mybatis.mybatis.dao;

import com.mybatis.mybatis.entity.UserOrder;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;

@Mapper
public interface UserOrderMapper {
    public List<UserOrder> findAllUserOrder();
    public List<UserOrder> findAllUserOrder2();
}

​ OrderMapper

package com.mybatis.mybatis.dao;

import com.mybatis.mybatis.entity.Idcard;
import com.mybatis.mybatis.entity.Order;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;


@Mapper
public interface OrderMapper {
    public List<Order> findAllOrderById(int orderid);
}

​ 其中的findAllUserOrder2方法、OrderMapper接口都是是第二种查询方法才会用到的。

mappers:

​ UserOrderMapper.xml

<?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.mybatis.mybatis.dao.UserOrderMapper">

<!--    select 标识查询方法   id标识UserMapper接口里面方法的名字-->
<!--    resultType  表示方法的返回值的类型   如果是集合类型只需要给定集合内的对象类型-->


<!--    方法一   -->
    <select id="findAllUserOrder"  resultMap="userOrderMap">
        SELECT `user`.* ,orders.id AS ordersid,orders.orderinfo
        FROM `user`,orders
        WHERE `user`.id = orders.userid
    </select>

    <resultMap id="userOrderMap" type="com.mybatis.mybatis.entity.UserOrder">
        <!--     id映射主键   property:实体类的字段名字   column:数据库表字段名字-->
        <id property="id" column="id" ></id>
        <result property="name" column="name"></result>
        <result property="age" column="age"></result>
<!--        association的使用前提是映射到的实体类是一个对象-->
        <collection property="orderList" ofType="com.mybatis.mybatis.entity.Order">
            <id property="id" column="orderid"></id>
            <result property="orderinfo" column="orderinfo"></result>
        </collection>
    </resultMap>


<!--    方法2 级联查询    -->
<!--    第一步     查询user所得到的所有结果-->
<!--    第二步     把第一步得到的user表的id  传到orders表中-->
    <select id="findAllUserOrder2"  resultMap="userOrderMap2">
        SELECT * from user
    </select>

    <resultMap id="userOrderMap2" type="com.mybatis.mybatis.entity.UserOrder">
        <!--     id映射主键   property:实体类的字段名字   column:数据库表字段名字-->
        <id property="id" column="id" ></id>
        <result property="name" column="name"></result>
        <result property="age" column="age"></result>
        <!--        association的使用前提是映射到的实体类是一个对象-->
        <collection property="orderList"
                    select="com.mybatis.mybatis.dao.OrderMapper.findAllOrderById"
                    column="id"
                    ofType="com.mybatis.mybatis.entity.Order">
        </collection>
    </resultMap>
</mapper>

​ OrderMapper.xml

<?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.mybatis.mybatis.dao.OrderMapper">


    <select id="findAllOrderById" resultType="com.mybatis.mybatis.entity.Order">
        select * from orders where userid = #{orderid}
    </select>

</mapper>

Service层:

​ UserOrderServiceImpl

package com.mybatis.mybatis.service.impl;

import com.mybatis.mybatis.dao.UserOrderMapper;
import com.mybatis.mybatis.entity.UserOrder;
import com.mybatis.mybatis.service.UserOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserOrderServiceImpl implements UserOrderService {

    @Autowired
    UserOrderMapper userOrderMapper;

    @Override
    public List<UserOrder> findAllUserOrder() {
        return userOrderMapper.findAllUserOrder();
    }
    public List<UserOrder> findAllUserOrder2() {
        return userOrderMapper.findAllUserOrder2();
    }
}

Controller层:

​ UserOrderController

package com.mybatis.mybatis.controller;

import com.mybatis.mybatis.entity.User;
import com.mybatis.mybatis.service.UserOrderService;
import com.mybatis.mybatis.service.UserService;
import com.mybatis.mybatis.utils.Result;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;


//@RestController注解 =  @Controller  +  @ResponseBody    更加的简洁


@Api(tags = "查询用户的订单类")
@RestController
public class UserOrderController {

    @Autowired
    UserOrderService userOrderService;

    @PostMapping("findAllUserOrder")
    public Result findAllUserOrder(){
        return Result.ok(userOrderService.findAllUserOrder());
    }

    @PostMapping("findAllUserOrder2")
    public Result findAllUserOrder2(){
        return Result.ok(userOrderService.findAllUserOrder2());
    }
}

包含了两种查询方法

!!!!

多对多 两个实体 要创建三张表

其中两张表分别按照个实体创建

第三张表保存其余两张表的主键

!!!!

七:多对多的级联查询

案例

​ 多个订单对应多个产品

1:建表

​ 此处用到三张表,分别是订单表orders、产品表product、二者对应表orders_product

orders表 (在之前的文章创建过)

JavaEE   多对多的查询

product表

JavaEE   多对多的查询   2

orders_product表

JavaEE   多对多的查询   3

2:创建对应的实体类

订单类Order (之前的文章创建过,不过加了个属性)

package com.mybatis.mybatis.entity;

import lombok.Data;

import java.util.List;

@Data
public class Order {
    private int id;
    private String orderinfo;
    private int userid;

    private List<Product> productList;
}

产品类Product

package com.mybatis.mybatis.entity;

import lombok.Data;

@Data
public class Product {
    private int id;
    private String name;
    private float price;
}
3:新的代码

mappers:

​ OrderMapper.xml (之前创建过,不过此处增加了新的查询对应的代码)

<?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.mybatis.mybatis.dao.OrderMapper">


    <select id="findAllOrderById" resultType="com.mybatis.mybatis.entity.Order">
        select * from orders where userid = #{orderid}
    </select>

    <select id="findAllOrder" resultMap="orderMap">
        SELECT orders.*,product.id as productid,product.`name`,product.price
        from orders,product,orders_product
        where orders.id = orders_product.orderid
          and product.id = orders_product.productid
    </select>

    <resultMap id="orderMap" type="com.mybatis.mybatis.entity.Order">
        <id property="id" column="id"></id>
        <result property="orderinfo" column="orderinfo"></result>
        <result property="userid" column="userid"></result>
            <collection property="productList" ofType="com.mybatis.mybatis.entity.Product">
                <id property="id" column="productid"></id>
                  <result property="name" column="name"></result>
                  <result property="price" column="price"></result>
            </collection>
    </resultMap>
</mapper>

dao层:

​ OrderMapper (之前创建过,加了个方法)

public List<Product> findAllOrder();

service层、imp层、controller层重复过高,此处不予展示。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值