文章目录
数据库设计
建表 SQL
sql
CREATE TABLE user (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL
);
CREATE TABLE `order` (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
order_no VARCHAR(50) NOT NULL,
FOREIGN KEY (user_id) REFERENCES user(id)
);
CREATE TABLE role (
id INT PRIMARY KEY AUTO_INCREMENT,
role_name VARCHAR(50) NOT NULL
);
CREATE TABLE user_role (
user_id INT NOT NULL,
role_id INT NOT NULL,
PRIMARY KEY (user_id, role_id),
FOREIGN KEY (user_id) REFERENCES user(id),
FOREIGN KEY (role_id) REFERENCES role(id)
);
插入以下数据:
sql
INSERT INTO user (name) VALUES ('Alice'), ('Bob');
INSERT INTO `order` (user_id, order_no) VALUES (1, 'ORD001'), (1, 'ORD002'), (2, 'ORD003');
INSERT INTO role (role_name) VALUES ('Admin'), ('User');
INSERT INTO user_role (user_id, role_id) VALUES (1, 1), (1, 2), (2, 2);
MyBatis 配置
我们使用 MySQL 数据库,MyBatis 的核心配置文件如下:
sql
<?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>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test_db?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
</configuration>
定义 Java 实体类,映射数据库表:
java
@Data
public class User {
private Integer id;
private String name;
private Order order; // 一对一:用户关联一个订单
private List<Order> orders; // 一对多:用户关联多个订单
private List<Role> roles; // 多对多:用户关联多个角色
}
@Data
public class Order {
private Integer id;
private Integer userId;
private String orderNo;
}
@Data
public class Role {
private Integer id;
private String roleName;
}
MyBatis 映射文件
在 UserMapper.xml 中定义关联查询,展示一对一、一对多和多对多的实现。
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">
<!-- 一对一 -->
<resultMap id="UserWithOrderMap" type="com.example.entity.User">
<id property="id" column="user_id"/>
<result property="name" column="user_name"/>
<association property="order" javaType="com.example.entity.Order">
<id property="id" column="order_id"/>
<result property="userId" column="user_id"/>
<result property="orderNo" column="order_no"/>
</association>
</resultMap>
<select id="selectUserWithOrder" resultMap="UserWithOrderMap">
SELECT *
FROM user u
LEFT JOIN `order` o ON u.id = o.user_id
WHERE u.id = #{id}
LIMIT 1
</select>
<!-- 一对多 -->
<resultMap id="UserWithOrdersMap" type="com.example.entity.User">
<id property="id" column="user_id"/>
<result property="name" column="user_name"/>
<collection property="orders" ofType="com.example.entity.Order">
<id property="id" column="order_id"/>
<result property="userId" column="user_id"/>
<result property="orderNo" column="order_no"/>
</collection>
</resultMap>
<select id="selectUserWithOrders" resultMap="UserWithOrdersMap">
SELECT *
FROM user u
LEFT JOIN `order` o ON u.id = o.user_id
WHERE u.id = #{id}
</select>
<!-- 多对多 -->
<resultMap id="UserWithRolesMap" type="com.example.entity.User">
<id property="id" column="user_id"/>
<result property="name" column="user_name"/>
<collection property="roles" ofType="com.example.entity.Role">
<id property="id" column="role_id"/>
<result property="roleName" column="role_name"/>
</collection>
</resultMap>
<select id="selectUserWithRoles" resultMap="UserWithRolesMap">
SELECT *
FROM user u
LEFT JOIN user_role ur ON u.id = ur.user_id
LEFT JOIN role r ON ur.role_id = r.id
WHERE u.id = #{id}
</select>
</mapper>
Mapper 接口
定义对应的 Mapper 接口:
java
public interface UserMapper {
User selectUserWithOrder(Integer id); // 一对一
User selectUserWithOrders(Integer id); // 一对多
User selectUserWithRoles(Integer id); // 多对多
}
以下是测试代码,验证查询结果:
java
public class MyBatisTest {
public static void main(String[] args) throws Exception {
SqlSessionFactory factory = new SqlSessionFactoryBuilder()
.build(new FileInputStream("mybatis-config.xml"));
try (SqlSession session = factory.openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
// 测试一对一
User userWithOrder = mapper.selectUserWithOrder(1);
System.out.println(userWithOrder.getName());
// 测试一对多
User userWithOrders = mapper.selectUserWithOrders(1);
System.out.println(userWithOrders.getName());
userWithOrders.getOrders().forEach(order -> System.out.println(" - " + order.getOrderNo()));
// 测试多对多
User userWithRoles = mapper.selectUserWithRoles(1);
System.out.println(userWithRoles.getName());
userWithRoles.getRoles().forEach(role -> System.out.println(" - " + role.getRoleName()));
}
}
}
总结
一对一:通过 association 标签,查询用户及其关联的一个订单。
一对多:通过 collection 标签,查询用户及其所有订单,MyBatis 自动将多行订单数据映射到 List。
多对多:通过 collection 标签,查询用户及其所有角色,借助中间表 user_role 实现关联。