一:数据封装(返回结果)
在之前的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,所以需要返回查看),这个时候就可以用上主键回填的功能。
修改前
在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>
修改后(会显示数据库分配的id)
三:ResultMap初见
一般情况下,实体类的属性名需要和数据库的字段名对应统一,但有时候实体类的属性名和数据库名没法保持一致时,可以采用
Result Map进行对应匹配。
此处的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之后,其他的方法也会受到影响(一般还是与数据库对应的为好)
!!!!!! 一对一的特点 需要在某一方保存对方的主键 !!!!!!!!
四:一对一的多表的查询
建表的注意事项:在数据库建表的时候,不要使用外键,应该在代码层维持表与表之间的关系。
案例
1:建表
创建idcard表和person表,样式如下
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表
orders表
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表 (在之前的文章创建过)
product表
orders_product表
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层重复过高,此处不予展示。