Bootstrap

MyBatis 的多对一,一对多以及多对多的增删改查的xml映射语句

1. 多对一(Many-to-One)

表结构
  • users

    • id (INT, 主键)
    • username (VARCHAR)
    • password (VARCHAR)
    • email (VARCHAR)
    • department_id (INT, 外键)
    • created_at (TIMESTAMP)
  • departments

    • id (INT, 主键)
    • name (VARCHAR)
    • created_at (TIMESTAMP)
实体类
public class User {
    private int id;
    private String username;
    private String password;
    private String email;
    private Department department;
    private Timestamp createdAt;

    // Getters and Setters
}

public class Department {
    private int id;
    private String name;
    private Timestamp createdAt;

    // Getters and Setters
}
映射文件 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.mapper.UserMapper">

  <!-- 插入用户 -->
  <insert id="insertUser" parameterType="com.example.entity.User">
    INSERT INTO users (username, password, email, department_id, created_at) 
    VALUES (#{username}, #{password}, #{email}, #{department.id}, NOW())
  </insert>

  <!-- 更新用户信息 -->
  <update id="updateUser" parameterType="com.example.entity.User">
    UPDATE users 
    SET username = #{username}, 
        password = #{password}, 
        email = #{email}, 
        department_id = #{department.id} 
    WHERE id = #{id}
  </update>

  <!-- 删除用户 -->
  <delete id="deleteUser" parameterType="int">
    DELETE FROM users WHERE id = #{id}
  </delete>

  <!-- 根据ID查询用户及其部门 -->
  <select id="selectUserByIdWithDepartment" resultMap="UserAndDepartmentResultMap">
    SELECT u.*, d.id AS departmentId, d.name, d.created_at AS departmentCreatedAt
    FROM users u
    LEFT JOIN departments d ON u.department_id = d.id
    WHERE u.id = #{id}
  </select>
  <!-- 在 MyBatis 中,parameterType 是可选的。如果你只有一个参数传递给 SQL 语句,MyBatis 会自动推断参数类型。因此,即使不显式指定 parameterType,MyBatis 也能正确处理参数。 -->
  <!-- 查询所有用户及其部门 -->
  <select id="selectAllUsersWithDepartment" resultMap="UserAndDepartmentResultMap">
    SELECT u.*, d.id AS departmentId, d.name, d.created_at AS departmentCreatedAt
    FROM users u
    LEFT JOIN departments d ON u.department_id = d.id
  </select>

  <!-- 嵌套结果映射 -->
  <resultMap id="UserAndDepartmentResultMap" type="com.example.entity.User">
    <id property="id" column="id"/>
    <result property="username" column="username"/>
    <result property="password" column="password"/>
    <result property="email" column="email"/>
    <result property="createdAt" column="created_at"/>
    <association property="department" javaType="com.example.entity.Department">
      <id property="id" column="departmentId"/>
      <result property="name" column="name"/>
      <result property="createdAt" column="departmentCreatedAt"/>
    </association>
  </resultMap>

</mapper>

详细解释

    多对一(Many-to-One)
  • insertUser:插入用户信息。department_id 是外键,指向 departments 表的 id
  • updateUser:更新用户信息。department_id 可以更改。
  • deleteUser:删除用户。
  • selectUserByIdWithDepartment:根据用户ID查询用户及其部门。使用 LEFT JOIN 将 users 表和 departments 表连接起来。
  • selectAllUsersWithDepartment:查询所有用户及其部门。
  • resultMap:定义了 User 对象及其 department 属性的映射关系。使用 <association> 标签来映射单个对象。

2. 一对多(One-to-Many)

表结构
  • users

    • id (INT, 主键)
    • username (VARCHAR)
    • password (VARCHAR)
    • email (VARCHAR)
    • created_at (TIMESTAMP)
  • orders

    • id (INT, 主键)
    • user_id (INT, 外键)
    • product_name (VARCHAR)
    • quantity (INT)
    • price (DECIMAL)
    • created_at (TIMESTAMP)
实体类
public class User {
    private int id;
    private String username;
    private String password;
    private String email;
    private Timestamp createdAt;
    private List<Order> orders;

    // Getters and Setters
}

public class Order {
    private int id;
    private int userId;
    private String productName;
    private int quantity;
    private BigDecimal price;
    private Timestamp createdAt;

    // Getters and Setters
}
映射文件 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.mapper.UserMapper">

  <!-- 插入用户 -->
  <insert id="insertUser" parameterType="com.example.entity.User">
    INSERT INTO users (username, password, email, created_at) 
    VALUES (#{username}, #{password}, #{email}, NOW())
  </insert>

  <!-- 插入订单 -->
  <insert id="insertOrder" parameterType="com.example.entity.Order">
    INSERT INTO orders (user_id, product_name, quantity, price, created_at) 
    VALUES (#{userId}, #{productName}, #{quantity}, #{price}, NOW())
  </insert>

  <!-- 更新用户信息 -->
  <update id="updateUser" parameterType="com.example.entity.User">
    UPDATE users 
    SET username = #{username}, 
        password = #{password}, 
        email = #{email} 
    WHERE id = #{id}
  </update>

  <!-- 更新订单信息 -->
  <update id="updateOrder" parameterType="com.example.entity.Order">
    UPDATE orders 
    SET product_name = #{productName}, 
        quantity = #{quantity}, 
        price = #{price} 
    WHERE id = #{id}
  </update>

  <!-- 删除用户 -->
  <delete id="deleteUser" parameterType="int">
    DELETE FROM users WHERE id = #{id}
  </delete>

  <!-- 删除订单 -->
  <delete id="deleteOrder" parameterType="int">
    DELETE FROM orders WHERE id = #{id}
  </delete>
  <!-- 在 MyBatis 中,parameterType 是可选的。如果你只有一个参数传递给 SQL 语句,MyBatis 会自动推断参数类型。因此,即使不显式指定 parameterType,MyBatis 也能正确处理参数。 -->
  <!-- 根据ID查询用户及其订单 -->
  <select id="selectUserByIdWithOrders" resultMap="UserAndOrdersResultMap">
    SELECT u.*, o.id AS orderId, o.product_name, o.quantity, o.price, o.created_at AS orderCreatedAt
    FROM users u
    LEFT JOIN orders o ON u.id = o.user_id
    WHERE u.id = #{id}
  </select>

  <!-- 查询所有用户及其订单 -->
  <select id="selectAllUsersWithOrders" resultMap="UserAndOrdersResultMap">
    SELECT u.*, o.id AS orderId, o.product_name, o.quantity, o.price, o.created_at AS orderCreatedAt
    FROM users u
    LEFT JOIN orders o ON u.id = o.user_id
  </select>

  <!-- 嵌套结果映射 -->
  <resultMap id="UserAndOrdersResultMap" type="com.example.entity.User">
    <id property="id" column="id"/>
    <result property="username" column="username"/>
    <result property="password" column="password"/>
    <result property="email" column="email"/>
    <result property="createdAt" column="created_at"/>
    <collection property="orders" ofType="com.example.entity.Order">
      <id property="id" column="orderId"/>
      <result property="userId" column="id"/>
      <result property="productName" column="product_name"/>
      <result property="quantity" column="quantity"/>
      <result property="price" column="price"/>
      <result property="createdAt" column="orderCreatedAt"/>
    </collection>
  </resultMap>

</mapper>

详细解释

    一对多(One-to-Many)
  • insertUser:插入用户信息。
  • insertOrder:插入订单信息。user_id 是外键,指向 users 表的 id
  • updateUser:更新用户信息。
  • updateOrder:更新订单信息。
  • deleteUser:删除用户。
  • deleteOrder:删除订单。
  • selectUserByIdWithOrders:根据用户ID查询用户及其订单。使用 LEFT JOIN 将 users 表和 orders 表连接起来。
  • selectAllUsersWithOrders:查询所有用户及其订单。
  • resultMap:定义了 User 对象及其 orders 列表的映射关系。使用 <collection> 标签来映射集合属性。

3. 多对多(Many-to-Many)

表结构
  • users

    • id (INT, 主键)
    • username (VARCHAR)
    • password (VARCHAR)
    • email (VARCHAR)
    • created_at (TIMESTAMP)
  • roles

    • id (INT, 主键)
    • name (VARCHAR)
    • created_at (TIMESTAMP)
  • user_roles

    • user_id (INT, 外键)
    • role_id (INT, 外键)
实体类
public class User {
    private int id;
    private String username;
    private String password;
    private String email;
    private Timestamp createdAt;
    private List<Role> roles;

    // Getters and Setters
}

public class Role {
    private int id;
    private String name;
    private Timestamp createdAt;

    // Getters and Setters
}
映射文件 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.mapper.UserMapper">

  <!-- 插入用户 -->
  <insert id="insertUser" parameterType="com.example.entity.User">
    INSERT INTO users (username, password, email, created_at) 
    VALUES (#{username}, #{password}, #{email}, NOW())
  </insert>

  <!-- 插入角色 -->
  <insert id="insertRole" parameterType="com.example.entity.Role">
    INSERT INTO roles (name, created_at) 
    VALUES (#{name}, NOW())
  </insert>

  <!-- 插入用户角色关系 -->
  <insert id="insertUserRole" parameterType="map">
    INSERT INTO user_roles (user_id, role_id) 
    VALUES (#{userId}, #{roleId})
  </insert>

  <!-- 更新用户信息 -->
  <update id="updateUser" parameterType="com.example.entity.User">
    UPDATE users 
    SET username = #{username}, 
        password = #{password}, 
        email = #{email} 
    WHERE id = #{id}
  </update>

  <!-- 更新角色信息 -->
  <update id="updateRole" parameterType="com.example.entity.Role">
    UPDATE roles 
    SET name = #{name} 
    WHERE id = #{id}
  </update>

  <!-- 删除用户 -->
  <delete id="deleteUser" parameterType="int">
    DELETE FROM users WHERE id = #{id}
  </delete>

  <!-- 删除角色 -->
  <delete id="deleteRole" parameterType="int">
    DELETE FROM roles WHERE id = #{id}
  </delete>

  <!-- 删除用户角色关系 -->
  <delete id="deleteUserRole" parameterType="map">
    DELETE FROM user_roles 
    WHERE user_id = #{userId} 
      AND role_id = #{roleId}
  </delete>
  <!-- 在 MyBatis 中,parameterType 是可选的。如果你只有一个参数传递给 SQL 语句,MyBatis 会自动推断参数类型。因此,即使不显式指定 parameterType,MyBatis 也能正确处理参数。 -->
  <!-- 根据ID查询用户及其角色 -->
  <select id="selectUserByIdWithRoles" resultMap="UserAndRolesResultMap">
    SELECT u.*, r.id AS roleId, r.name, r.created_at AS roleCreatedAt
    FROM users u
    LEFT JOIN user_roles ur ON u.id = ur.user_id
    LEFT JOIN roles r ON ur.role_id = r.id
    WHERE u.id = #{id}
  </select>

  <!-- 查询所有用户及其角色 -->
  <select id="selectAllUsersWithRoles" resultMap="UserAndRolesResultMap">
    SELECT u.*, r.id AS roleId, r.name, r.created_at AS roleCreatedAt
    FROM users u
    LEFT JOIN user_roles ur ON u.id = ur.user_id
    LEFT JOIN roles r ON ur.role_id = r.id
  </select>

  <!-- 嵌套结果映射 -->
  <resultMap id="UserAndRolesResultMap" type="com.example.entity.User">
    <id property="id" column="id"/>
    <result property="username" column="username"/>
    <result property="password" column="password"/>
    <result property="email" column="email"/>
    <result property="createdAt" column="created_at"/>
    <collection property="roles" ofType="com.example.entity.Role">
      <id property="id" column="roleId"/>
      <result property="name" column="name"/>
      <result property="createdAt" column="roleCreatedAt"/>
    </collection>
  </resultMap>

</mapper>

详细解释

    多对多(Many-to-Many)
  • insertUser:插入用户信息。
  • insertRole:插入角色信息。
  • insertUserRole:插入用户角色关系。user_id 和 role_id 分别是外键,指向 users 表和 roles 表的 id
  • updateUser:更新用户信息。
  • updateRole:更新角色信息。
  • deleteUser:删除用户。
  • deleteRole:删除角色。
  • deleteUserRole:删除用户角色关系。
  • selectUserByIdWithRoles:根据用户ID查询用户及其角色。使用 LEFT JOIN 将 users 表、user_roles 表和 roles 表连接起来。
  • selectAllUsersWithRoles:查询所有用户及其角色。
  • resultMap:定义了 User 对象及其 roles 列表的映射关系。使用 <collection> 标签来映射集合属性。

配置文件

要使上述映射文件生效,你需要在 MyBatis 的配置文件(如 mybatis-config.xml)中引用它:

<configuration>
  <mappers>
    <mapper resource="mappers/UserMapper.xml"/>
  </mappers>
</configuration>

接口定义

UserMapper.java 接口中定义相应的方法:

package com.example.mapper;

import com.example.entity.User;
import com.example.entity.Role;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;
import java.util.Map;

@Mapper
public interface UserMapper {

  void insertUser(User user);
  void insertRole(Role role);
  void insertUserRole(@Param("userId") int userId, @Param("roleId") int roleId);

  void updateUser(User user);
  void updateRole(Role role);

  void deleteUser(int id);
  void deleteRole(int id);
  void deleteUserRole(@Param("userId") int userId, @Param("roleId") int roleId);

  User selectUserByIdWithDepartment(int id);
  List<User> selectAllUsersWithDepartment();

  User selectUserByIdWithOrders(int id);
  List<User> selectAllUsersWithOrders();

  User selectUserByIdWithRoles(int id);
  List<User> selectAllUsersWithRoles();
}

示例调用

在你的服务层或控制器中,可以通过 UserMapper 接口调用这些方法:

@Autowired
private UserMapper userMapper;

public void createUserAndRole() {
  User user = new User();
  user.setUsername("john_doe");
  user.setPassword("secret");
  user.setEmail("[email protected]");
  userMapper.insertUser(user);

  Role role = new Role();
  role.setName("Admin");
  userMapper.insertRole(role);

  userMapper.insertUserRole(user.getId(), role.getId());
}

public List<User> getUsersWithRoles() {
  return userMapper.selectAllUsersWithRoles();
}

注意事项:

         在 MyBatis 中,resultMapresultType 是两种不同的方式,用于将数据库查询结果映射到 Java 对象。

          resultType 是一个简单的属性,用于指定查询结果应该映射到的 Java 对象类型。MyBatis 会自动将查询结果的每一列映射到 Java 对象的属性上,前提是列名和属性名一致(或者通过别名匹配)。

           resultMap 是一个更强大的映射工具,用于定义如何将数据库查询结果映射到 Java 对象。它允许你定义复杂的映射逻辑,包括嵌套对象、集合、自定义映射规则等。

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;