数据准备
数据库表
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '用户id',
`username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`birthday` datetime NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
INSERT INTO `user` VALUES (1, 'xrkhy', '0000', NULL);
INSERT INTO `user` VALUES (2, 'gtxy', '0000', NULL);
INSERT INTO `user` VALUES (3, 'mll', '0000', NULL);
INSERT INTO `user` VALUES (4, 'fbpc', '0000', NULL);
INSERT INTO `user` VALUES (7, 'hsh', '123', NULL);
DROP TABLE IF EXISTS `orders`;
CREATE TABLE `orders` (
`id` int NOT NULL AUTO_INCREMENT,
`ordertime` datetime NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
`total` int NULL DEFAULT NULL,
`uid` int NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
INSERT INTO `orders` VALUES (1, '2025-07-30 19:44:07', 3000, 1);
INSERT INTO `orders` VALUES (2, '2025-07-25 19:44:34', 5800, 1);
INSERT INTO `orders` VALUES (3, '2025-07-10 19:44:51', 323, 2);
INSERT INTO `orders` VALUES (4, '2025-07-13 19:45:04', 2345, 1);
INSERT INTO `orders` VALUES (5, '2025-07-15 19:45:36', 100, 2);
INSERT INTO `orders` VALUES (6, '2025-07-26 19:45:50', 2009, 3);
DROP TABLE IF EXISTS `userrole`;
CREATE TABLE `userrole` (
`userId` int NOT NULL,
`roleId` int NOT NULL,
PRIMARY KEY (`userId`, `roleId`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
INSERT INTO `userrole` VALUES (1, 1);
INSERT INTO `userrole` VALUES (1, 2);
INSERT INTO `userrole` VALUES (2, 2);
INSERT INTO `userrole` VALUES (2, 3);
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
`id` int NOT NULL AUTO_INCREMENT,
`roleName` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`roleDesc` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
INSERT INTO `role` VALUES (1, '院长', '负责全面工作');
INSERT INTO `role` VALUES (2, '研究员', '课程研发工作');
INSERT INTO `role` VALUES (3, '讲师', '授课工作');
INSERT INTO `role` VALUES (4, '助教', '协助解决学生问题');
INSERT INTO `role` VALUES (5, '班主任', '负责学生生活');
INSERT INTO `role` VALUES (6, '就业指导', '负责学生就业工作');
pom.xml
<dependencies>
<!--JDBC-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.13</version>
</dependency>
<!--Spring 6默认不再绑定Log4j 1.x,建议使用Log4j 2.x(性能更强、安全性更高)。-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.23.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId>
<version>2.23.1</version>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.38</version>
<scope>provided</scope>
</dependency>
</dependencies>
resources
JDBC.properties
# 数据库驱动
jdbc.driver=com.mysql.cj.jdbc.Driver
# 数据库地址
jdbc.url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false
# 用户名
jdbc.username=root
# 密码
jdbc.password=root
sqlMapConfig.xml
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 加载外部配置文件 -->
<properties resource="JDBC.properties"></properties>
<settings>
<!-- value="STDOUT_LOGGING" 配置打印SQL语句 -->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<typeAliases>
<!-- 单个创建别名 -->
<!-- 需手动指定别名,通过type属性设置类的全限定名,alias属性设置自定义别名-->
<typeAlias type="com.hsh.pojo.User" alias="User"></typeAlias>
<!-- 批量创建别名 -->
<!-- 自动扫描包路径下所有类,默认以类名(不区分大小写)作为别名 -->
<package name="com.hsh.pojo"/>
</typeAliases>
<!-- default: 指定默认环境的名称 -->
<environments default="development">
<!-- id="development": 指定当前环境的名称 -->
<environment id="development">
<!-- type="JDBC": 指定事务管理类型是JDBC -->
<transactionManager type="JDBC"/>
<!-- type="POOLED": 指定当前数据源类型是连接池 -->
<dataSource type="POOLED">
<!-- 数据源配置的基本参数 -->
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- 加载上面的UserMapper映射文件 -->
<mapper resource="com/hsh/mapper/UserMapper.xml"/>
<mapper resource="com/hsh/mapper/OrderMapper.xml"/>
</mappers>
</configuration>
com/hsh/mapper/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.hsh.mapper.UserMapper">
</mapper>
com/hsh/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.hsh.mapper.OrderMapper">
</mapper>
pojo层
User
package com.hsh.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
private String username;
private String password;
private Date birthday;
private List<Order> orderList;
private List<Role> roleList;
}
Order
package com.hsh.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order {
private Integer id;
private Date orderTime;
private Integer total;
private User user;
}
Role
package com.hsh.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Role {
private Integer id;
private String roleName;
private String roleDesc;
}
Mapper层
UserMapper
package com.hsh.mapper;
import com.hsh.pojo.User;
import java.util.List;
public interface UserMapper {
void save(User user);
void update(User user);
void delete(Integer id);
User findById(Integer id);
List<User> findAll();
}
OrderMapper
public interface OrderMapper {
}
Test
OrderMapperTest
public class OrderMapperTest {
}
UserMapperTest
public class UserMapperTest {
package mapper;
import com.hsh.mapper.UserMapper;
import com.hsh.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import java.util.List;
/**
* @author xrkhy
* @date 2025/7/31 20:07
* @description
*/
public class UserMappeTest {
private UserMapper userMapper;
@Before
public void setUp() throws Exception {
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
userMapper = sqlSession.getMapper(UserMapper.class);
}
@Test
public void save() throws Exception {
User user = new User();
user.setUsername("hsh");
user.setPassword("123456");
userMapper.save(user);
}
@Test
public void update() throws Exception {
User user = new User();
user.setId(7);
user.setUsername("hsh");
user.setPassword("123456");
userMapper.update(user);
}
@Test
public void delete() throws Exception {
userMapper.delete(7);
}
@Test
public void findById() throws Exception {
User user = userMapper.findById(1);
System.out.println(user);
}
@Test
public void findAll() throws Exception {
List<User> users = userMapper.findAll();
users.forEach(System.out::println);
}
}
目录如下
MyBatis的常用注解
这几年来注解开发越来越流行,Mybatis也可以使用注解开发方式,这样我们就可以减少编写Mapper映射文件了。我们先围绕一些基本的CRUD来学习,再学习复杂映射多表操作。
@Insert:实现新增
@Update:实现更新
@Delete:实现删除
@Select:实现查询
@Result:实现结果集封装
@Results:可以与@Result 一起使用,封装多个结果集
@One:实现一对一结果集封装
@Many:实现一对多结果集封装
MyBatis的简单增删改查
修改sqlMapConfig.xml
修改MyBatis的核心配置文件,我们使用了注解替代的映射文件,所以我们只需要加载使用了注解的Mapper接口即可。
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 省略....... -->
<mappers>
<!-- 加载上面的UserMapper映射文件 这个注释掉,-->
<!-- <mapper resource="com/hsh/mapper/UserMapper.xml"/>-->
<!-- <mapper resource="com/hsh/mapper/OrderMapper.xml"/>-->
<!--扫描使用注解的类 开启注解 -->
<!-- <mapper class="com.hsh.mapper.UserMapper"></mapper>-->
<!--扫描使用注解的类所在的包 或者使用下面这个开启注解 -->
<package name="com.hsh.mapper"></package>
</mappers>
</configuration>
注释掉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.hsh.mapper.UserMapper">
<!--全注释-->
</mapper>
编写UserMapper
package com.hsh.mapper;
import com.hsh.pojo.User;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.util.List;
public interface UserMapper {
@Insert("insert into user values(null,#{username},#{password},#{birthday})")
void save(User user);
@Update("update user set username = #{username},password = #{password},birthday = #{birthday} where id = #{id}")
void update(User user);
@Delete("delete from user where id = #{id}")
void delete(Integer id);
@Select("select * from user where id = #{id}")
User findById(Integer id);
@Select("select * from user")
List<User> findAll();
}
依次运行测试类
package mapper;
import com.hsh.mapper.UserMapper;
import com.hsh.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import java.util.List;
/**
* @author xrkhy
* @date 2025/7/31 20:07
* @description
*/
public class UserMappeTest {
private UserMapper userMapper;
@Before
public void setUp() throws Exception {
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
userMapper = sqlSession.getMapper(UserMapper.class);
}
@Test
public void save() throws Exception {
User user = new User();
user.setUsername("hsh");
user.setPassword("123456");
userMapper.save(user);
}
@Test
public void update() throws Exception {
User user = new User();
user.setId(7);
user.setUsername("hsh");
user.setPassword("123456");
userMapper.update(user);
}
@Test
public void delete() throws Exception {
userMapper.delete(7);
}
@Test
public void findById() throws Exception {
User user = userMapper.findById(1);
System.out.println(user);
}
@Test
public void findAll() throws Exception {
List<User> users = userMapper.findAll();
users.forEach(System.out::println);
}
}
结果都能正常运行
MyBatis的注解实现复杂映射开发
实现复杂关系映射之前我们可以在映射文件中通过配置来实现,使用注解开发后,我们可以使用@Results注解,@Result注解,@One注解,@Many注解组合完成复杂关系的配置
注解 | 说明 |
---|---|
@Results | 代替的是标签<resultMap> 该注解中可以使用单个@Result注解,也可以使用@Result集 合。使用格式:@Results({@Result(),@Result()}) 或@Results(@Result()) |
@Resut | 代替了<id> 标签和<result> 标签 @Result中属性介绍: column:数据库的列名 property:需要装配的属性名 one:需要使用的@One注解(@Result(one=@One)())) many:需要使用的@Many注解(@Result(many=@many)())) |
注解 | 说明 |
---|---|
@ One ( 一 对 一 ) | 代替了<assocation> 标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。 @One注解属性介绍: select:指定用来多表查询的sqlmapper 使用格式:@Result(column=“”,property=“”,one=@One(select=“”)) |
@Many(多对 一 ) | 代替了<collection> 标签,是是多表查询的关键,在注解中用来指定子查询返回对象集合。 使用格式:@Result(property=“”,column=“”,many=@Many(select=“”)) |
1 一对一查询
1. 一对一查询的模型
用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户
一对一查询的需求:查询一个订单,与此同时查询出该订单所属的用户
2. 一对一查询的语句
对应的sql语句:
select * from orders;
select * from user where id=查询出订单的uid;
查询的结果如下:
3. 创建Order和User实体
4. 创建OrderMapper接口
public interface OrderMapper {
List<Order> findAll();
}
5. 使用注解配置Mapper
package com.hsh.mapper;
import com.hsh.pojo.Order;
import org.apache.ibatis.annotations.One;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface OrderMapper {
@Select("select * from `order`")
@Results({
@Result(id = true, property = "id", column = "id"),
@Result(property = "orderTime", column = "ordertime"),
@Result(property = "total", column = "total"),
@Result(property = "user",column = "uid",
javaType = com.hsh.pojo.User.class,
one = @One(select = "com.hsh.mapper.UserMapper.findById"))
})
List<Order> findAll();
}
package com.hsh.mapper;
import com.hsh.pojo.User;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.util.List;
public interface UserMapper {
@Insert("insert into user values(null,#{username},#{password},#{birthday})")
void save(User user);
@Update("update user set username = #{username},password = #{password},birthday = #{birthday} where id = #{id}")
void update(User user);
@Delete("delete from user where id = #{id}")
void delete(Integer id);
@Select("select * from user where id = #{id}")
User findById(Integer id);
@Select("select * from user")
List<User> findAll();
}
6. 测试结果
@Test
public void testSelectOrderAndUser() {
List<Order> all = orderMapper.findAll();
for(Order order : all){
System.out.println(order);
}
}
2 一对多查询
1. 一对多查询的模型
用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户
一对多查询的需求:查询一个用户,与此同时查询出该用户具有的订单
2. 一对多查询的语句
对应的sql语句:
select * from user;
select * from orders where uid=查询出用户的id;
查询的结果如下:
3. 修改User实体
4. 创建UserMapper接口
List<User> findAllUserAndOrder();
5. 使用注解配置Mapper
6. 测试结果
List<User> all = userMapper.findAllUserAndOrder();
for(User user : all){
System.out.println(user.getUsername());
List<Order> orderList = user.getOrderList();
for(Order order : orderList){
System.out.println(order);
}
System.out.println("-----------------------------");
}
3 多对多查询
1. 多对多查询的模型
用户表和角色表的关系为,一个用户有多个角色,一个角色被多个用户使用
多对多查询的需求:查询用户同时查询出该用户的所有角色
2. 多对多查询的语句
对应的sql语句:
select * from user;
select * from role r,user_role ur where r.id=ur.role_id and ur.user_id=用户的id
查询的结果如下:
3. 创建Role实体,修改User实体
4. 添加UserMapper接口方法
List<User> findAllUserAndRole();
5. 使用注解配置Mapper
6. 测试结果
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> all = mapper.findAllUserAndRole();
for(User user : all){
System.out.println(user.getUsername());
List<Role> roleList = user.getRoleList();
for(Role role : roleList){
System.out.println(role);
}
System.out.println("----------------------------------");
}