一、一对一(一个User对应一个UserProfile,以从表的角度增删改查)
1.UserMapper.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.example.segmentfaulttest0.mapper.UserMapper">
<resultMap id="BaseResultMap" type="User">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="age" property="age"/>
<association property="userProfile" javaType="com.example.segmentfaulttest0.domain.UserProfile">
<id column="userprofile_id" property="id"/>
<result column="nickname" property="nickname"/>
</association>
</resultMap>
<insert id="insert" parameterType="User">
insert into user (name, age, userprofile_id) values (#{name}, #{age},#{userProfile.id})
</insert>
<select id="selectAll" resultMap="BaseResultMap">
select a.*,b.nickname from user a left join user_profile b on a.userprofile_id = b.id
</select>
<delete id="delete" parameterType="java.lang.Integer">
delete from user where id = #{id}
</delete>
<update id="update" parameterType="User">
update user set name=#{name},age=#{age},userprofile_id=#{userProfile.id} where id=#{id}
</update>
</mapper>
2.实体类User和UserProfile
package com.example.segmentfaulttest0.domain;
import lombok.Data;
/**
* @description:
* @author: 袁凯
* @time: 2023/11/23 19:36
*/
@Data
public class User {
private Integer id;
private String name;
private Integer age;
private UserProfile userProfile;
}
package com.example.segmentfaulttest0.domain;
import lombok.Data;
/**
* @description:
* @author: 袁凯
* @time: 2023/11/23 19:36
*/
@Data
public class UserProfile {
private Integer id;
private String nickname;
}
3.数据库外键设置(开启外键的update和delete级联设置)

4.UserMapper和UserController
package com.example.segmentfaulttest0.mapper;
import com.example.segmentfaulttest0.domain.User;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* @description:
* @author: 袁凯
* @time: 2023/11/23 19:31
*/
public interface UserMapper {
public Integer insert(User user);
public List<User> selectAll();
public Integer delete(Integer id);
public Integer update(User user);
}
package com.example.segmentfaulttest0.controller;
import com.example.segmentfaulttest0.domain.User;
import com.example.segmentfaulttest0.domain.UserProfile;
import com.example.segmentfaulttest0.mapper.UserMapper;
import com.example.segmentfaulttest0.message.AjaxResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @description:
* @author: 袁凯
* @time: 2023/11/23 19:31
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserMapper userMapper;
@RequestMapping("/add")
public String add(@RequestBody User user) {
userMapper.insert(user);
return "success";
}
@PostMapping("/delete")
public AjaxResult delete(@RequestParam Integer id) {
//删除从表数据对主表没有影响
userMapper.delete(id);
return AjaxResult.success("delete success");
}
@RequestMapping("/update")
public String update(@RequestBody User user) {
//更新从表数据时,更新关联字段,需进行关联检查
userMapper.update(user);
return "success";
}
@RequestMapping("/select")
public AjaxResult select() {
List<User> users = userMapper.selectAll();
return AjaxResult.success(users);
}
}
4.总结
①`外键的作用在于约束,设置外键的表(从表)会对被关联的表(主表)进行联系。当主表(UserProfile)进行更新关联字段时,从表的关联字段也会进行更新;当主表(UserProfile)进行删除时,从表中所有包含该字段的数据都会被删除。
②当从表进行插入、更新时,会对外键做关联检查,插入到从表中的数据关联字段必须是主表中可关联的数据的关联字段值`
③关于外键和association设置的问题,有时候很纠结这两个东西应该放在哪一边,如默认情况下一对一中外键和association一边,而在一对多中外键和collection则相反。后来我试着在一对一中,将外键和association不放在一起,也是可以的,说明这两个东西并没有关联性,association放在任何一边都可以,根据你的查询来定,只是通常情况下一对一中外键和association在一边;同理数据库的外键只是一种约束方便你进行更新删除(主要是删除),其次是做约束,在实际业务中并不需要设置,包括阿里巴巴规范也是禁止外键的,这个在之后的文章中说明原因
二、一对多(一个User有多个Blog,以主表的角度增删改查)
1.实体类User和Blog
package com.example.segmentfaulttest0.domain;
import lombok.Data;
import java.util.List;
/**
* @description:
* @author: 袁凯
* @time: 2023/11/23 19:36
*/
@Data
public class User {
private Integer id;
private String name;
private Integer age;
private UserProfile userProfile;
private List<Blog> blogs;
}
package com.example.segmentfaulttest0.domain;
import lombok.Data;
/**
* @description:
* @author: 袁凯
* @time: 2023/12/4 10:42
*/
@Data
public class Blog {
private Integer id;
private String name;
private Integer userId;
}
2.UserMapper.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.example.segmentfaulttest0.mapper.UserMapper">
<resultMap id="BaseResultMap" type="User">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="age" property="age"/>
<association property="userProfile" javaType="com.example.segmentfaulttest0.domain.UserProfile">
<id column="userprofile_id" property="id"/>
<result column="nickname" property="nickname"/>
</association>
<collection property="blogs" ofType="com.example.segmentfaulttest0.domain.Blog">
<id column="blog_id" jdbcType="INTEGER" property="id" />
<result column="blog_name" property="name"/>
<result column="id" property="userId"/>
</collection>
</resultMap>
<insert id="insert" parameterType="User">
insert into user (name, age) values (#{name}, #{age})
</insert>
<select id="selectAll" resultMap="BaseResultMap">
select a.*,b.nickname,c.id blog_id,c.name blog_name from user a left join user_profile b on a.userprofile_id = b.id inner join blog c on a.id = c.user_id
</select>
<delete id="delete" parameterType="java.lang.Integer">
delete from user where id = #{id}
</delete>
<update id="update" parameterType="User">
update user set name=#{name},age=#{age} where id=#{id}
</update>
</mapper>
3.UserController
package com.example.segmentfaulttest0.controller;
import com.example.segmentfaulttest0.domain.User;
import com.example.segmentfaulttest0.domain.UserProfile;
import com.example.segmentfaulttest0.mapper.UserMapper;
import com.example.segmentfaulttest0.message.AjaxResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @description:
* @author: 袁凯
* @time: 2023/11/23 19:31
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserMapper userMapper;
@RequestMapping("/add")
public String add(@RequestBody User user) {
userMapper.insert(user);
// todo,先插入User,再批量插入Blog数据
return "success";
}
@PostMapping("/delete")
public AjaxResult delete(@RequestParam Integer id) {
//删除主表数据将删除所有博客
userMapper.delete(id);
return AjaxResult.success("delete success");
}
@RequestMapping("/update")
public String update(@RequestBody User user) {
// todo,更新主表数据以及从表数据,注意这里的更新要根据实际情况来,比如从表数据也可能涉及到添加、删除,并不是一味得更新
userMapper.update(user);
return "success";
}
@RequestMapping("/select")
public AjaxResult select() {
List<User> users = userMapper.selectAll();
return AjaxResult.success(users);
}
}
4.总结
①一对多中通常设置是外键放在多的一方,Collection标签放在一的一方
②这里是以主表为视角,也就是说当User进行更新、删除的时候,从表Blog也会进行对应的操作,但这里更新只会进行外键的更新
三、多对多(多个User对应多个UserRole)
1.UserRole和Role实体类
package com.example.segmentfaulttest0.domain;
import lombok.Data;
/**
* @description:
* @author: 袁凯
* @time: 2023/12/4 15:02
*/
@Data
public class UserRole {
private Integer id;
private Integer userId;
private Integer roleId;
}
package com.example.segmentfaulttest0.domain;
import lombok.Data;
/**
* @description:
* @author: 袁凯
* @time: 2023/12/4 15:02
*/
@Data
public class Role {
private Integer id;
}
2.UserController类
package com.example.segmentfaulttest0.controller;
import com.example.segmentfaulttest0.domain.User;
import com.example.segmentfaulttest0.domain.UserProfile;
import com.example.segmentfaulttest0.mapper.UserMapper;
import com.example.segmentfaulttest0.message.AjaxResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @description:
* @author: 袁凯
* @time: 2023/11/23 19:31
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserMapper userMapper;
@RequestMapping("/add")
public String add(@RequestBody User user) {
userMapper.insert(user);
// todo,先插入User,插入UserRole,再插入Role
return "success";
}
@PostMapping("/delete")
public AjaxResult delete(@RequestParam Integer id) {
// 删除User,将会删除UserRole,但不会删除Role
userMapper.delete(id);
return AjaxResult.success("delete success");
}
@RequestMapping("/update")
public String update(@RequestBody User user) {
// 更新User,不会影响UserRole,除非更新到了id字段
// 如果需要修改User对应的Role,则需要先删除中间表,再插入中间表一条数据
userMapper.update(user);
return "success";
}
@RequestMapping("/select")
public AjaxResult select() {
// 根据Select实际情况进行Collection的设置,如需要查询某个用户的所有角色,则用户侧添加collection
List<User> users = userMapper.selectAll();
return AjaxResult.success(users);
}
}
3.总结
①在使用外键的情况下,可以看出外键唯一的作用在于当进行删除的时候可以设置级联方便进行删除,以及插入的时候进行约束
②ps:作者主要是想比较下外键和非外键设置下的区别,目前看来最大的区别在于删除的时候少做了一步关联删除以及相关的检查。所以中间部分代码我都省略了,包括部分业务上的代码,而是选择用注释贴在上面,可能对初学者不太友好,初学者可以找更完整的代码去敲一下,理解一下。
我是吃不饱的小袁,祝各位看官永远不死!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。