# Mybaits框架 **Repository Path**: hrbu2023/mybaits-framework ## Basic Information - **Project Name**: Mybaits框架 - **Description**: Mybaits框架 学习 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-03-03 - **Last Updated**: 2026-03-06 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Mybatis框架 - SSH Spring(IOC DI ) Struts1.x(MVC) Hibernate(持久层框架JDBC) - SSH Spring(IOC DI ) Struts2.x (MVC) Hibernate(持久层框架JDBC) - SSI Spring(IOC DI ) Struts2.x(MVC) Ibatis(持久层框架JDBC) - SSM Spring(IOC DI ) Struts2.x (MVC) MyBatis(持久层框架JDBC) - Ibatis SSI - 3.x MyBatis org.apache.ibatis.xxxxxx - SSM Spring(IOC DI ) SpringMVC MyBatis(持久层框架JDBC) - SpringBoot+ SpringBoot + MyBatis(持久层框架JDBC) [01.MyBatis框架 (yuque.com)](https://www.yuque.com/jshand/hrbu-edu/rxzta7740gs19pp2) - JDBC - 加载驱动 com.mysql.cj.jdbc.Driver - 创建链接 Connection - url 、 user、 password - 创建Statement - 执行SQL - 绑定SQL变量 - select * from user where username= ? and password = ? - stmt.setInt stmt.setString - 查询- Resultset - Map - 单条 User对象 - 多条 `List` - rs.GetString rs.getInt 解析结果 - 更新 int - 释放资源 # MyBatis入门项目 - 准备数据库 - 准备项目 - 添加依赖 - pom.xml - junit - mysql - mybaits - 编写代码 - 编写主配置文件 - 环境信息(URL、用户名、密码) - 编写sql文件 - 使用配置文件 - SQLSessionFactory - SQlSession - 执行SQL语句 resources: Maven管理的项目要求 Java目录中只能存放.java文件,非Java文件放到 resources目录 ![image-20260303144347811](assets/image-20260303144347811.png) ## 核心配置文件 src/main/resources/SqlMapConfig.xml ```xml ``` ## 编辑SQL语句的文件(Mapper) - src/main/resources/mapper/User.xml ```xml ``` ## 使用Java代码访问数据库 ```java package com.neuedu.crud; 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.Test; import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.Map; public class HelloMybaitsTest { @Test public void test() { try { //加载配置文件 InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml"); //创建SQLSEssionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); //创建SQLSession SqlSession session = sqlSessionFactory.openSession(); //使用 SQLSession 执行SQL语句 // session.selectList("语句的ID") List list = session.selectList("test.selectList"); //事务的提交、回滚 list.forEach(System.out::println); //关闭资源 session.close(); } catch (IOException e) { throw new RuntimeException(e); } } } ``` # SQLSession对象 ![image-20260304085311477](assets/image-20260304085311477.png) # 结果类型映射PO 核心配置[MyBatis 3 | 配置 – mybatis](https://mybatis.org/mybatis-3/zh_CN/configuration.html#settings) ## SQL 语句 resultType: 写成 User ```xml ``` ## User ```java package com.neuedu.crud.po; public class User { private Integer userId; private String username; private String password; public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "userId=" + userId + ", username='" + username + '\'' + ", password='" + password + '\'' + '}'; } } ``` ## 执行sql语句 ```java @Test public void testWithPo() { SqlSessionFactory sqlSessionFactory = null; SqlSession session = null; try { //加载配置文件 InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml"); //创建 重量级的 SQLSEssionFactory 全局唯一 sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); //创建SQLSession 现成不安全的 session = sqlSessionFactory.openSession(); //使用 SQLSession 执行SQL语句 // session.selectList("语句的ID") List list = session.selectList("test.selectListWithUser"); //事务的提交、回滚 for (User user : list) { System.out.println(user); } } catch (IOException e) { throw new RuntimeException(e); }finally { //关闭资源 session.close(); } } ``` ## 配置驼峰自动转换 在SQLMapConfig.xml中添加配置 `settings` ```xml ``` # 执行各种SQL - 插入单条 - 根据主键更新 - 根据主键删除 - 查询集合 - 查询单条 - 查询总条数 ## 搭建Mybatis工程 - 创建一个项目 - 添加一个核心配置文件 - 编写SQL语句 - 编写PO对象 - 执行各种SQL语句 ## 完整的User.java ```java package com.neuedu.crud.po; import java.util.Date; /** * 持久层数据对象 PO ( Domain ) */ public class User { private Integer userId; private String username; private String password; private Date expire; private Date lastLogin; private String realName; private Date createTime; public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Date getExpire() { return expire; } public void setExpire(Date expire) { this.expire = expire; } public Date getLastLogin() { return lastLogin; } public void setLastLogin(Date lastLogin) { this.lastLogin = lastLogin; } public String getRealName() { return realName; } public void setRealName(String realName) { this.realName = realName; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } @Override public String toString() { return "User{" + "userId=" + userId + ", username='" + username + '\'' + ", password='" + password + '\'' + ", expire=" + expire + ", lastLogin=" + lastLogin + ", realName='" + realName + '\'' + ", createTime=" + createTime + '}'; } } ``` ## 插入单条 ### 1. SQL语句的编写(User.xml) ```xml INSERT INTO `his`.`user` ( `username`, `password`, `expire`, `last_login`, `real_name` ) VALUES ( #{username}, #{password}, #{expire}, #{lastLogin}, #{realName} ) ``` ### 2. 单元测试的代码 ```java /** * 插入数据 */ @Test public void testInsert() { SqlSessionFactory factory = null; SqlSession session = null; try { InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); factory = new SqlSessionFactoryBuilder().build(is); //不自动提交 boolean autoCommit = false; session = factory.openSession(autoCommit); //执行SQL语句 User user = new User(); user.setUsername("zhangsan"); user.setPassword("123456"); user.setExpire(new Date()); user.setLastLogin(new Date()); user.setRealName("张三"); int count = session.insert("User.insert",user); System.out.println(count); //提交事务 session.commit(); } catch (IOException e) { //回滚实物 session.rollback(); throw new RuntimeException(e); } finally { if (session != null) { session.close(); } } } ``` ## 根据主键更新 ### 1. SQL语句的编写(User.xml) ```xml UPDATE `user` SET `username` = #{username}, `password` = #{password}, `expire` = #{expire}, `last_login` = #{lastLogin}, `real_name` = #{realName} WHERE `user_id` = #{userId} ``` ### 2. 单元测试的代码 ```java /** * 更新数据 */ @Test public void testUpdateById() { SqlSessionFactory factory = null; SqlSession session = null; try { InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); factory = new SqlSessionFactoryBuilder().build(is); //不自动提交 boolean autoCommit = false; session = factory.openSession(autoCommit); //执行SQL语句 User user = new User(); user.setUserId(4); user.setUsername("zhangfei"); user.setPassword("9875654321"); user.setExpire(new Date()); user.setLastLogin(new Date()); user.setRealName("张飞"); // insert 方法中 第一个参数表示的语句的ID, 通常由 namespace + id int count = session.update("User.updateById", user); System.out.println(count); //提交事务 session.commit(); } catch (IOException e) { //回滚实物 session.rollback(); throw new RuntimeException(e); } finally { if (session != null) { session.close(); } } } ``` ## 根据主键删除 ### 1. SQL语句的编写(User.xml) ```xml delete from user WHERE `user_id` = #{userId} ``` ### 2. 单元测试的代码 ```java /** * 更新数据 */ @Test public void testDeleteById() { SqlSessionFactory factory = null; SqlSession session = null; try { InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); factory = new SqlSessionFactoryBuilder().build(is); //不自动提交 boolean autoCommit = false; session = factory.openSession(autoCommit); //执行SQL语句 // insert 方法中 第一个参数表示的语句的ID, 通常由 namespace + id int id = 3; int count = session.delete("User.deleteById", id); System.out.println(count); //提交事务 session.commit(); } catch (IOException e) { //回滚实物 session.rollback(); throw new RuntimeException(e); } finally { if (session != null) { session.close(); } } } ``` ## 查询集合 ### 1. SQL语句的编写(User.xml) ```xml ``` ### 2. 单元测试的代码 ```java /** * 查询集合 */ @Test public void testSelectList() { SqlSessionFactory factory = null; SqlSession session = null; try { InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); factory = new SqlSessionFactoryBuilder().build(is); session = factory.openSession(); //执行SQL语句 List list = session.selectList("User.selectList"); for (User user : list) { System.out.println(user); } } catch (IOException e) { throw new RuntimeException(e); } finally { if (session != null) { session.close(); } } } ``` ## 查询单条 ### 1. SQL语句的编写(User.xml) ```xml ``` ### 2. 单元测试的代码 ```java /** * 查询单条 */ @Test public void testSelectById() { SqlSessionFactory factory = null; SqlSession session = null; try { InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); factory = new SqlSessionFactoryBuilder().build(is); session = factory.openSession(); //执行SQL语句 int userId = 4; User user = session.selectOne("User.selectById", userId); System.out.println(user); } catch (IOException e) { throw new RuntimeException(e); } finally { if (session != null) { session.close(); } } } ``` ## 查询总条数 ### 1. SQL语句的编写(User.xml) ```xml ``` ### 2. 单元测试的代码 ```java /** * 查询总条数 count max min avg sum 适合分组函数使用 */ @Test public void testCount() { SqlSessionFactory factory = null; SqlSession session = null; try { InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); factory = new SqlSessionFactoryBuilder().build(is); session = factory.openSession(); //执行SQL语句 int count = session.selectOne("User.count"); System.out.println("总条数: "+ count); } catch (IOException e) { throw new RuntimeException(e); } finally { if (session != null) { session.close(); } } } ``` # 接口对象 - SqlSessionFactory 重量级的对象,线程安全, 尽量全局唯一, - SqlSession 现成不安全, 每个现成需要独立创建 利用单利模式创建一个全局唯一的SQLSessionFactory对象 ```java package com.neuedu.crud.util; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.InputStream; /** * 提供相关的 MyBatis操作 */ public class MybatisUtils { private static SqlSessionFactory sqlSessionFactory = null; /** * 创建全局唯一的 SQLSessionFactory * @return */ public synchronized static SqlSessionFactory getSqlSessionFactory() throws IOException { if (sqlSessionFactory == null) { try { InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); } catch (IOException e) { throw e; } } return sqlSessionFactory; } } ``` ## 使用全局唯一对象 ```java package com.neuedu.crud; import com.neuedu.crud.po.User; import com.neuedu.crud.util.MybatisUtils; 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.Test; import java.io.IOException; import java.io.InputStream; import java.util.Date; import java.util.List; public class CRUDWithUtilsTest { /** * 查询集合 */ @Test public void testSelectList() { SqlSessionFactory factory = null; SqlSession session = null; try { factory = MybatisUtils.getSqlSessionFactory(); session = factory.openSession(); //执行SQL语句 List list = session.selectList("User.selectList"); for (User user : list) { System.out.println(user); } } catch (IOException e) { throw new RuntimeException(e); } finally { if (session != null) { session.close(); } } } /** * 查询单条 */ @Test public void testSelectById() { SqlSessionFactory factory = null; SqlSession session = null; try { factory = MybatisUtils.getSqlSessionFactory(); session = factory.openSession(); //执行SQL语句 int userId = 4; User user = session.selectOne("User.selectById", userId); System.out.println(user); } catch (IOException e) { throw new RuntimeException(e); } finally { if (session != null) { session.close(); } } } /** * 查询总条数 count max min avg sum 适合分组函数使用 */ @Test public void testCount() { SqlSessionFactory factory = null; SqlSession session = null; try { factory = MybatisUtils.getSqlSessionFactory(); session = factory.openSession(); //执行SQL语句 int count = session.selectOne("User.count"); System.out.println("总条数: " + count); } catch (IOException e) { throw new RuntimeException(e); } finally { if (session != null) { session.close(); } } } /** * 插入数据 */ @Test public void testInsert() { SqlSessionFactory factory = null; SqlSession session = null; try { factory = MybatisUtils.getSqlSessionFactory(); //不自动提交 boolean autoCommit = false; session = factory.openSession(autoCommit); //执行SQL语句 User user = new User(); user.setUsername("zhangsan"); user.setPassword("123456"); user.setExpire(new Date()); user.setLastLogin(new Date()); user.setRealName("张三"); // insert 方法中 第一个参数表示的语句的ID, 通常由 namespace + id int count = session.insert("User.insert", user); System.out.println(count); //提交事务 session.commit(); } catch (IOException e) { //回滚实物 session.rollback(); throw new RuntimeException(e); } finally { if (session != null) { session.close(); } } } /** * 更新数据 */ @Test public void testUpdateById() { SqlSessionFactory factory = null; SqlSession session = null; try { factory = MybatisUtils.getSqlSessionFactory(); //不自动提交 boolean autoCommit = false; session = factory.openSession(autoCommit); //执行SQL语句 User user = new User(); user.setUserId(4); user.setUsername("zhangfei"); user.setPassword("9875654321"); user.setExpire(new Date()); user.setLastLogin(new Date()); user.setRealName("张飞"); // insert 方法中 第一个参数表示的语句的ID, 通常由 namespace + id int count = session.update("User.updateById", user); System.out.println(count); //提交事务 session.commit(); } catch (IOException e) { //回滚实物 session.rollback(); throw new RuntimeException(e); } finally { if (session != null) { session.close(); } } } /** * 更新数据 */ @Test public void testDeleteById() { SqlSessionFactory factory = null; SqlSession session = null; try { factory = MybatisUtils.getSqlSessionFactory(); //不自动提交 boolean autoCommit = false; session = factory.openSession(autoCommit); //执行SQL语句 // insert 方法中 第一个参数表示的语句的ID, 通常由 namespace + id int id = 3; int count = session.delete("User.deleteById", id); System.out.println(count); //提交事务 session.commit(); } catch (IOException e) { //回滚实物 session.rollback(); throw new RuntimeException(e); } finally { if (session != null) { session.close(); } } } } ``` # Dao封装 ## UserDao ```java package com.neuedu.crud.dao; import com.neuedu.crud.po.User; import com.neuedu.crud.util.MybatisUtils; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.List; public class UserDao { /** * 查询集合 * @return */ public List selectList(){ SqlSessionFactory factory = null; SqlSession session = null; List list = new ArrayList(); try { factory = MybatisUtils.getSqlSessionFactory(); session = factory.openSession(); //执行SQL语句 list = session.selectList("User.selectList"); } catch (IOException e) { throw new RuntimeException(e); } finally { if (session != null) { session.close(); } } return list; } /** * 根据主键查询 查询单条结果 * @param id * @return */ public User getUserById(int id) { SqlSessionFactory factory = null; SqlSession session = null; User user = null; try { factory = MybatisUtils.getSqlSessionFactory(); session = factory.openSession(); //执行SQL语句 user = session.selectOne("User.selectById", id); } catch (IOException e) { throw new RuntimeException(e); } finally { if (session != null) { session.close(); } } return user; } /** * 查询总条数 * @return */ public int count(){ SqlSessionFactory factory = null; SqlSession session = null; int count = 0; try { factory = MybatisUtils.getSqlSessionFactory(); session = factory.openSession(); //执行SQL语句 count = session.selectOne("User.count"); } catch (IOException e) { throw new RuntimeException(e); } finally { if (session != null) { session.close(); } } return count; } /** * 插入数据 * @param user 插入数据 * @return */ public int insert(User user){ SqlSessionFactory factory = null; SqlSession session = null; int count = 0; try { factory = MybatisUtils.getSqlSessionFactory(); //不自动提交 boolean autoCommit = false; session = factory.openSession(autoCommit); count = session.insert("User.insert", user); //提交事务 session.commit(); } catch (IOException e) { //回滚实物 session.rollback(); throw new RuntimeException(e); } finally { if (session != null) { session.close(); } } return count; } /** * 根据主键根据数据 * @param user * @return */ public int update(User user){ SqlSessionFactory factory = null; SqlSession session = null; int count = 0; try { factory = MybatisUtils.getSqlSessionFactory(); //不自动提交 boolean autoCommit = false; session = factory.openSession(autoCommit); //执行SQL语句 count = session.update("User.updateById", user); //提交事务 session.commit(); } catch (IOException e) { //回滚实物 session.rollback(); throw new RuntimeException(e); } finally { if (session != null) { session.close(); } } return count; } /** * 根据主键删除数据 * @param id * @return */ public int deleteById(int id ){ SqlSessionFactory factory = null; SqlSession session = null; int count = 0; try { factory = MybatisUtils.getSqlSessionFactory(); //不自动提交 boolean autoCommit = false; session = factory.openSession(autoCommit); //执行SQL语句 count = session.delete("User.deleteById", id); //提交事务 session.commit(); } catch (IOException e) { //回滚实物 session.rollback(); throw new RuntimeException(e); } finally { if (session != null) { session.close(); } } return count; } } ``` ## 单元测试 ```java package com.neuedu.crud.dao; import com.neuedu.crud.po.User; import org.junit.Test; import java.util.Date; import java.util.List; import static org.junit.Assert.*; public class UserDaoTest { UserDao userDao = new UserDao(); @Test public void selectList() { List users = userDao.selectList(); for (User user : users) { System.out.println(user); } } @Test public void getUserById() { int id = 1; User user = userDao.getUserById(id); System.out.println("user = " + user); } @Test public void count() { int count = userDao.count(); System.out.println("count = " + count); } @Test public void insert() { //1 默认从页面输入的信息 User user = new User(); user.setUsername("likui"); user.setPassword("456789"); user.setExpire(new Date()); user.setLastLogin(new Date()); user.setRealName("李逵"); int insertCount = userDao.insert(user); System.out.println("insertCount = " + insertCount); } @Test public void update() { int id = 1; User user = userDao.getUserById(id); System.out.println("user = " + user); user.setRealName("超级管理员"); int updateCount = userDao.update(user); System.out.println("updateCount = " + updateCount); } @Test public void deleteById() { int id = 6; int deleteCount = userDao.deleteById(id); System.out.println("deleteCount = " + deleteCount); } } ``` # Mapper接口映射 在封装DAO的时候发现出现大量重复的代码,抽象出来,编写接口,剩下的大量的重复代码,由代理对象对象 ```java package com.neuedu.crud.dao; import com.neuedu.crud.po.User; import com.neuedu.crud.util.MybatisUtils; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import java.io.IOException; import java.util.ArrayList; import java.util.List; public interface UserMapper { /** * 查询集合 * * @return */ public List selectList(); /** * 根据主键查询 查询单条结果 * * @param id * @return */ public User selectById(int id); /** * 查询总条数 * * @return */ public int count(); /** * 插入数据 * * @param user 插入数据 * @return */ public int insert(User user); /** * 根据主键根据数据 * * @param user * @return */ public int updateById(User user); /** * 根据主键删除数据 * * @param id * @return */ public int deleteById(int id); } ``` 编写接口 然后由 MyBatis帮我们生成 UserDao的实现类 - 接口的方法名称 与xml中的 Statement ID 保持一致 - Xml中的namespace需要跟接口的全限定名保持一致 - 参数和返回值 - 方法的参数类型 就是 SQL语句中的参数类型 - 查询SQL中返回的类型是单行的结果类型 ## 使用Mapper实现自动代理 - 核心配置SQlMapConfig.xml - SQL语句 UserMapper.xml - User实体类 - 全局的工具类(MyBatisUtils) - 编写接口 - UserMapper - 通过SQLSession获取UserMapper的代理对象 - 调用UserMapper代理对象中的方法 执行CRUD ### UserMapper.xml ```xml INSERT INTO `his`.`user` (`username`, `password`, `expire`, `last_login`, `real_name`) VALUES (#{username}, #{password}, #{expire}, #{lastLogin}, #{realName}) UPDATE `user` SET `username` = #{username}, `password` = #{password}, `expire` = #{expire}, `last_login` = #{lastLogin}, `real_name` = #{realName} WHERE `user_id` = #{userId} delete from user WHERE `user_id` = #{userId} ``` ### User.java ```java package com.neuedu.po; import java.util.Date; /** * 持久层数据对象 PO ( Domain ) */ public class User { private Integer userId; private String username; private String password; private Date expire; private Date lastLogin; private String realName; private Date createTime; public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Date getExpire() { return expire; } public void setExpire(Date expire) { this.expire = expire; } public Date getLastLogin() { return lastLogin; } public void setLastLogin(Date lastLogin) { this.lastLogin = lastLogin; } public String getRealName() { return realName; } public void setRealName(String realName) { this.realName = realName; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } @Override public String toString() { return "User{" + "userId=" + userId + ", username='" + username + '\'' + ", password='" + password + '\'' + ", expire=" + expire + ", lastLogin=" + lastLogin + ", realName='" + realName + '\'' + ", createTime=" + createTime + '}'; } } ``` ### UserMapper.java ```java package com.neuedu.mapper; import com.neuedu.po.User; import java.util.List; public interface UserMapper { /** * 查询集合 * * @return */ public List selectList(); /** * 根据主键查询 查询单条结果 * * @param id * @return */ public User selectById(int id); /** * 查询总条数 * * @return */ public int count() ; /** * 插入数据 * * @param user 插入数据 * @return */ public int insert(User user); /** * 根据主键根据数据 * * @param user * @return */ public int updateById(User user); /** * 根据主键删除数据 * * @param id * @return */ public int deleteById(int id) ; } ``` ### 单元测试 ```java /** * 查询集合 * * @return */ public List selectList() { SqlSessionFactory factory = null; SqlSession session = null; List list = new ArrayList(); try { factory = MybatisUtils.getSqlSessionFactory(); session = factory.openSession(); //执行SQL语句 list = session.selectList("User.selectList"); } catch (IOException e) { throw new RuntimeException(e); } finally { if (session != null) { session.close(); } } return list; } ``` ## 练习 Mapper 当Dao 使用Mapper的方式 练习一下 role、dept表的操作 - XXXMapper.xml - XXXMapper.java - XXX.java实体类 - 测试代码 ### role #### Role.java ```java package com.neuedu.po; import java.util.Date; public class Role { private Integer roleId; private String roleName; private Date createTime; public Integer getRoleId() { return roleId; } public void setRoleId(Integer roleId) { this.roleId = roleId; } public String getRoleName() { return roleName; } public void setRoleName(String roleName) { this.roleName = roleName; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } @Override public String toString() { return "Role{" + "roleId=" + roleId + ", roleName='" + roleName + '\'' + ", createTime=" + createTime + '}'; } } ``` #### RoleMapper.java ```java package com.neuedu.mapper; import com.neuedu.po.Role; import com.neuedu.po.User; import java.util.List; public interface RoleMapper { /** * 查询集合 * * @return */ public List selectList(); /** * 根据主键查询 查询单条结果 * * @param id * @return */ public Role selectById(int id); /** * 查询总条数 * * @return */ public int count(); /** * 插入数据 * * @param po 插入数据 * @return */ public int insert(Role po); /** * 根据主键根据数据 * * @param po * @return */ public int updateById(Role po); /** * 根据主键删除数据 * * @param id * @return */ public int deleteById(int id); } ``` #### RoleMapper.xml ```xml INSERT INTO `his`.`role` (`role_name`) VALUES (#{roleName}) UPDATE `role` SET `role_name` = #{roleName} WHERE `role_id` = #{roleId} delete from role WHERE `role_id` = #{roleId} ``` #### 报错 ``` D:\app\Java\jdk-17\bin\java.exe -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:D:\app\IntelliJ IDEA 2024.3.5\lib\idea_rt.jar=50493" -javaagent:C:\Users\Administrator\AppData\Local\JetBrains\IntelliJIdea2024.3\captureAgent\debugger-agent.jar -Dkotlinx.coroutines.debug.enable.creation.stack.trace=false -Ddebugger.agent.enable.coroutines=true -Dkotlinx.coroutines.debug.enable.flows.stack.trace=true -Dkotlinx.coroutines.debug.enable.mutable.state.flows.stack.trace=true -Dfile.encoding=UTF-8 -classpath "D:\app\IntelliJ IDEA 2024.3.5\lib\idea_rt.jar;D:\app\IntelliJ IDEA 2024.3.5\plugins\junit\lib\junit5-rt.jar;D:\app\IntelliJ IDEA 2024.3.5\plugins\junit\lib\junit-rt.jar;D:\课程\workspace\mybatis-mvn\mybatis-03-dao\target\test-classes;D:\课程\workspace\mybatis-mvn\mybatis-03-dao\target\classes;D:\app\apache-maven-3.9.12\repository\junit\junit\4.13\junit-4.13.jar;D:\app\apache-maven-3.9.12\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;D:\app\apache-maven-3.9.12\repository\com\mysql\mysql-connector-j\8.2.0\mysql-connector-j-8.2.0.jar;D:\app\apache-maven-3.9.12\repository\com\google\protobuf\protobuf-java\3.21.9\protobuf-java-3.21.9.jar;D:\app\apache-maven-3.9.12\repository\org\mybatis\mybatis\3.5.19\mybatis-3.5.19.jar" com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 com.neuedu.mapper.RoleMapperTest,insert org.apache.ibatis.binding.BindingException: Type interface com.neuedu.mapper.RoleMapper is not known to the MapperRegistry. at org.apache.ibatis.binding.MapperRegistry.getMapper(MapperRegistry.java:47) at org.apache.ibatis.session.Configuration.getMapper(Configuration.java:947) at org.apache.ibatis.session.defaults.DefaultSqlSession.getMapper(DefaultSqlSession.java:291) at com.neuedu.mapper.RoleMapperTest.setup(RoleMapperTest.java:34) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56) at org.junit.internal.runners.statements.RunBefores.invokeMethod(RunBefores.java:33) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24) at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63) at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329) at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293) at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) at org.junit.runners.ParentRunner.run(ParentRunner.java:413) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69) at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232) at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55) Process finished with exit code -1 ``` 在Sqlmapconfig.xml中注册RoleMapper.xml ![image-20260304143633940](assets/image-20260304143633940.png) - 测试代码 ```java package com.neuedu.mapper; import com.neuedu.po.Role; import com.neuedu.po.User; import com.neuedu.util.MybatisUtils; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.junit.Before; import org.junit.Test; import java.io.IOException; import java.util.List; import static org.junit.Assert.*; public class RoleMapperTest { private RoleMapper roleMapper; private SqlSession session = null; /** * 每个@Test方法执行之前有限执行 @Before方法 * @throws IOException */ @Before public void setup() throws IOException { SqlSessionFactory factory = null; try { factory = MybatisUtils.getSqlSessionFactory(); session = factory.openSession(false); //获取UserMapper的代理对象 roleMapper = session.getMapper(RoleMapper.class); } catch (IOException e) { throw new RuntimeException(e); } } @Test public void selectList() { List roles = roleMapper.selectList(); roles.forEach(System.out::println); } @Test public void selectById() { } @Test public void count() { } @Test public void insert() { Role role = new Role(); role.setRoleName("管理员"); try { int count = roleMapper.insert(role); System.out.println("count = " + count); session.commit(); }catch (Exception e) { session.rollback(); } finally { session.close(); } } @Test public void updateById() { } @Test public void deleteById() { } } ``` ## 基于包扫描的方式注册Mapper 需要遵循 前述 Mapper的相关规则 - 接口的方法名称 与xml中的 Statement ID 保持一致 - Xml中的namespace需要跟接口的全限定名保持一致 - 参数和返回值 - 方法的参数类型 就是 SQL语句中的参数类型 - 查询SQL中返回的类型是单行的结果类型 - Xml文件的路径与接口的路径保持一致(编译完成应该在同一个目录) ![image-20260304145819906](assets/image-20260304145819906.png) # 类型别名 - ` ` - `` - 别名为类名或者类名首字母小写 类名User 别名就是 user 、User - 或者使用 注解 @Alias("user1") ![image-20260304153145317](assets/image-20260304153145317.png) ## 内置的别名 [MyBatis 3 | 配置 – mybatis](https://mybatis.org/mybatis-3/zh_CN/configuration.html#typeAliases) 下面是一些为常见的 Java 类型内建的类型别名。它们都是不区分大小写的,注意,为了应对原始类型的命名重复,采取了特殊的命名风格。 | 别名 | 映射的类型 | |---------------------------|--------------| | _byte | byte | | _char (since 3.5.10) | char | | _character (since 3.5.10) | char | | _long | long | | _short | short | | _int | int | | _integer | int | | _double | double | | _float | float | | _boolean | boolean | | string | String | | byte | Byte | | char (since 3.5.10) | Character | | character (since 3.5.10) | Character | | long | Long | | short | Short | | int | Integer | | integer | Integer | | double | Double | | float | Float | | boolean | Boolean | | date | Date | | decimal | BigDecimal | | bigdecimal | BigDecimal | | biginteger | BigInteger | | object | Object | | date[] | Date[] | | decimal[] | BigDecimal[] | | bigdecimal[] | BigDecimal[] | | biginteger[] | BigInteger[] | | object[] | Object[] | | map | Map | | hashmap | HashMap | | list | List | | arraylist | ArrayList | | collection | Collection | | iterator | Iterator | # 属性配置文件 ```xml ``` ## jdbc.properties ```properties driver=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/his?characterEncoding=utf-8 username=root password=root ``` # 配置显示SQL语句 在settings中配置 ![image-20260304161533724](assets/image-20260304161533724.png) # #和$的区别 - `#` 相当于是使用了 PreparedStatement 预编译的 SQL - `$` 相当于字符串拼接 ![image-20260304161804932](assets/image-20260304161804932.png) ## 插入后获取主键 - MySQL SELECT LAST_INSERT_ID() 方法 # 参数和返回值 ## 参数(绑定变量) 使用parameterType定义 参数类型 - 基础类型 int short byte long float double char boolean 、String - 使用的时候 #{ 参数} 参数名称可以随意定义 - 复杂类型 - **实体类** User(username、password、lastLogin) Role - 使用的时候 #{ key} key 是 类中的属性 - Map : Map{ key=value, k1=v1 , k2 = v2 } - 使用的时候 #{ key} key 是 Map 中的key - 集合后者数组, foreach : array list ## 返回结果 使用resultType, 适用于查询SQL (update、insert、delete 这些SQL返回的是固定 整形: 影响行数) - 查询集合 : `List ` : resultType: com.neuedu.po.User - 查询单条数据 `User` : resultType: com.neuedu.po.User - 查询单行 单列(分组函数 max、min、avg、sum、count, ‘ String’) : : resultType: 【int String 等 】 ## ResultMap 使用menu表进行演示 先完整普通的CRUD - PO Menu.java - MenuMapper.xml - MenuMapper.java - 单元测试 # MyabtisX 插件 安装插件 ![image-20260305133616594](assets/image-20260305133616594.png) 作用: 从数据库 中 生成 Java代码 - Mapper.xml. - 实体类 - Mapper.java ## 在IDEA中创建数据库 ![image-20260305133836552](assets/image-20260305133836552.png) ![image-20260305133923053](assets/image-20260305133923053.png) ![image-20260305134108639](assets/image-20260305134108639.png) ## 使用MybatisX生成代码 - 基础包名:**com.neuedu.mybatis** - com.neuedu.mybatis.po - com.neuedu.mybatis.mapper - com.neuedu.mybatis.services - com.neuedu.mybatis.controller - com.neuedu.mybatis.xxxxxxxx ![image-20260305134437686](assets/image-20260305134437686.png) ![image-20260305134543040](assets/image-20260305134543040.png) ![image-20260305134722888](assets/image-20260305134722888.png) ![image-20260305134956425](assets/image-20260305134956425.png) ![image-20260305135543004](assets/image-20260305135543004.png) ![image-20260305135551614](assets/image-20260305135551614.png) ## 测试 ```java package com.neuedu.mybatis.mapper; import com.neuedu.mybatis.po.User; import com.neuedu.mybatis.util.MybatisUtils; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.junit.Before; import org.junit.Test; import java.io.IOException; import static org.junit.Assert.*; public class UserMapperTest { private UserMapper userMapper; private SqlSession session = null; /** * 每个@Test方法执行之前有限执行 @Before方法 * * @throws IOException */ @Before public void setup() throws IOException { SqlSessionFactory factory = null; try { factory = MybatisUtils.getSqlSessionFactory(); session = factory.openSession(false); userMapper = session.getMapper(UserMapper.class); } catch (IOException e) { throw new RuntimeException(e); } } @Test public void deleteByPrimaryKey() { } @Test public void insert() { } @Test public void insertSelective() { } @Test public void selectByPrimaryKey() { Long id = 1L; User user = userMapper.selectByPrimaryKey(id); System.out.println("user = " + user); } @Test public void updateByPrimaryKeySelective() { } @Test public void updateByPrimaryKey() { } } ``` # 使用Lombok简化开发 - 安装插件 ![image-20260305142541350](assets/image-20260305142541350.png) ## 使用lomkok 开启插件生效 ![image-20260305142736499](assets/image-20260305142736499.png) ## 在项目中使用 添加依赖 ```xml org.projectlombok lombok 1.18.42 compile ``` ![image-20260305143051106](assets/image-20260305143051106.png) ## 使用注解 ```java package com.neuedu.mybatis.po; import lombok.*; /** * Data @Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode. */ //@Getter //@Setter //@ToString //@EqualsAndHashCode @AllArgsConstructor @NoArgsConstructor @Data public class Person { private Integer id; private String name; // public Person() { // } // // public Person(Integer id, String name) { // this.id = id; // this.name = name; // } // public Integer getId() { // return id; // } // // public void setId(Integer id) { // this.id = id; // } // // public String getName() { // return name; // } // // public void setName(String name) { // this.name = name; // } public static void main(String[] args) { Person person1 = new Person(); person1.setId(1); person1.setName("jshand"); System.out.println("person1.getName() = " + person1.getName()); System.out.println("person1 = " + person1); Person person2 = new Person(); person2.setId(1); person2.setName("jshand"); System.out.println("person1.equals(person2) = " + person1.equals(person2)); Person person3 = new Person(1,"asdfsaf"); } } ``` ## 生成带有 lombok注解的 MyBatis代码 ![image-20260305143805403](assets/image-20260305143805403.png) # 多表之间的关系 ## 准备数据 ```sql /* SQLyog Ultimate v12.08 (64 bit) MySQL - 8.0.30 : Database - assica ********************************************************************* */ /*!40101 SET NAMES utf8 */; /*!40101 SET SQL_MODE=''*/; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; CREATE DATABASE /*!32312 IF NOT EXISTS*/`assica` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */; USE `assica`; /*Table structure for table `classes` */ DROP TABLE IF EXISTS `classes`; CREATE TABLE `classes` ( `id` int NOT NULL AUTO_INCREMENT COMMENT '主键', `class_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '班级名称', `grade` int NOT NULL COMMENT '年级', `teacher_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '班主任', `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; /*Data for the table `classes` */ insert into `classes`(`id`,`class_name`,`grade`,`teacher_name`,`create_time`) values (1,'Java1班',3,'张金山','2026-03-06 09:12:07'),(2,'java2班',3,'柳成林','2026-03-06 09:12:24'),(3,'java3班',3,'杨旭梦','2026-03-06 09:12:25'); /*Table structure for table `courses` */ DROP TABLE IF EXISTS `courses`; CREATE TABLE `courses` ( `id` int NOT NULL AUTO_INCREMENT COMMENT '主键', `course_code` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '课程编码', `course_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '课程名称', `teacher_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '授课教师', PRIMARY KEY (`id`), UNIQUE KEY `course_code` (`course_code`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; /*Data for the table `courses` */ insert into `courses`(`id`,`course_code`,`course_name`,`teacher_name`) values (1,'930001','计算机基础','张飞'),(2,'930002','软件开发框架技术','赵云'),(3,'930003','移动应用开发技术','蓝玉'); /*Table structure for table `id_cards` */ DROP TABLE IF EXISTS `id_cards`; CREATE TABLE `id_cards` ( `id` int NOT NULL AUTO_INCREMENT COMMENT '主键', `card_number` varchar(18) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '身份证号码', `real_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '真实姓名', `address` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '家庭住址', `user_id` int DEFAULT NULL COMMENT '用户ID', `create_time` date DEFAULT NULL COMMENT '创建时间', PRIMARY KEY (`id`), UNIQUE KEY `card_number` (`card_number`), UNIQUE KEY `user_id` (`user_id`), CONSTRAINT `id_cards_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; /*Data for the table `id_cards` */ insert into `id_cards`(`id`,`card_number`,`real_name`,`address`,`user_id`,`create_time`) values (1,'232301198801012525','张三','黑龙江',1,'2026-03-06'),(2,'232301198801012522','李四','河南',2,'2026-03-05'); /*Table structure for table `student_courses` */ DROP TABLE IF EXISTS `student_courses`; CREATE TABLE `student_courses` ( `id` int NOT NULL AUTO_INCREMENT COMMENT '主键', `student_id` int NOT NULL COMMENT '学生ID', `course_id` int NOT NULL COMMENT '课程ID', PRIMARY KEY (`id`), UNIQUE KEY `unique_enrollment` (`student_id`,`course_id`), KEY `course_id` (`course_id`), CONSTRAINT `student_courses_ibfk_1` FOREIGN KEY (`student_id`) REFERENCES `students` (`id`) ON DELETE CASCADE, CONSTRAINT `student_courses_ibfk_2` FOREIGN KEY (`course_id`) REFERENCES `courses` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; /*Data for the table `student_courses` */ insert into `student_courses`(`id`,`student_id`,`course_id`) values (1,1,1),(2,1,2),(3,1,3),(4,2,1),(5,3,1),(6,3,3); /*Table structure for table `students` */ DROP TABLE IF EXISTS `students`; CREATE TABLE `students` ( `id` int NOT NULL AUTO_INCREMENT COMMENT '主键', `student_no` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '学号', `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '姓名', `gender` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '性别', `birth_date` date DEFAULT NULL COMMENT '出生日期', `class_id` int DEFAULT NULL COMMENT '班级ID', PRIMARY KEY (`id`), UNIQUE KEY `student_no` (`student_no`), KEY `class_id` (`class_id`), CONSTRAINT `students_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `classes` (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; /*Data for the table `students` */ insert into `students`(`id`,`student_no`,`name`,`gender`,`birth_date`,`class_id`) values (1,'00001','赵云','男','2019-01-01',1),(2,'00002','关云长','男','2019-01-01',1),(3,'00003','诸葛亮','男','2019-01-01',1),(4,'00004','马超','男','2019-01-01',1),(5,'00005','司马懿','男','2019-01-01',1),(6,'00006','孙悟空','男','2019-01-01',2),(7,'00007','红孩儿','男','2019-01-01',2),(8,'00008','老龙王','男','2019-01-01',2),(9,'00009','贾宝玉','男','2019-01-01',3),(10,'00010','刘姥姥','男','2019-01-01',3); /*Table structure for table `users` */ DROP TABLE IF EXISTS `users`; CREATE TABLE `users` ( `id` int NOT NULL AUTO_INCREMENT COMMENT '用户主键', `username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名', `email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '邮箱', `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`id`), UNIQUE KEY `email` (`email`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; /*Data for the table `users` */ insert into `users`(`id`,`username`,`email`,`create_time`) values (1,'admin','admin@neuedu.com','2026-03-06 09:08:10'),(2,'zhangsan','zhangsan@neuedu.com','2026-03-06 09:08:24'); /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; ``` ## 一对一的关系 ![image-20260306092447157](assets/image-20260306092447157.png) 用户表 和 身份信息 1:1 ## 一对多 ![image-20260306092618324](assets/image-20260306092618324.png) 一个班级包含多个学生 班级和学生 1:m ## 多对多关系(Many-to-Many) ![image-20260306092829625](assets/image-20260306092829625.png) 一般会查分成两个一对多 ## 完成单表CRUD的实现 使用MyBatisX生成 PO Mapper.java Mapper.xml ### 创建新项目(带依赖、SQLMapConfig.xml) ![image-20260306094115787](assets/image-20260306094115787.png) ### 使用MyBatisX生成代码 ![image-20260306094336592](assets/image-20260306094336592.png) ![image-20260306094403873](assets/image-20260306094403873.png) ![image-20260306094427905](assets/image-20260306094427905.png) ## 一对一(一个SQL完成查询) ### 修改实体类 Users : 主表实体类 添加一个 属性 private IdCards idCards; IdCards:从表的实体类 ```java package com.neuedu.mybatis.po; import java.io.Serializable; import java.util.Date; import lombok.Data; /** * @TableName users */ @Data public class Users implements Serializable { /** * 用户主键 */ private Integer id; /** * 用户名 */ private String username; /** * 邮箱 */ private String email; /** * 创建时间 */ private Date createTime; /** * 身份信息 */ private IdCards idCards; private static final long serialVersionUID = 1L; } ``` ### 修改查询 使用 association进行关联 映射的是 从表的字段属性映射关系 - property: 从表数据 映射后 放到主表 实体中的哪个属性 - javaType: property属性Java中的类型 ```xml ``` ![image-20260306133457199](assets/image-20260306133457199.png) ### 单元测试 ```java package com.neuedu.mybatis.mapper; import com.neuedu.mybatis.po.Classes; import com.neuedu.mybatis.po.Users; import com.neuedu.mybatis.util.MybatisUtils; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.junit.Before; import org.junit.Test; import java.io.IOException; import java.util.List; public class UsersMapperTest { private UsersMapper usersMapper; private SqlSession session = null; /** * 每个@Test方法执行之前有限执行 @Before方法 * * @throws IOException */ @Before public void setup() throws IOException { SqlSessionFactory factory = null; try { factory = MybatisUtils.getSqlSessionFactory(); session = factory.openSession(false); usersMapper = session.getMapper(UsersMapper.class); } catch (IOException e) { throw new RuntimeException(e); } } @Test public void selectByList() { List users = usersMapper.selectByList(); for (Users user : users) { System.out.println("user = " + user); } } } ``` ![image-20260306105855189](assets/image-20260306105855189.png) ## 一对多(一个SQL完成) - 在班级中添加学生信息 ![image-20260306111741812](assets/image-20260306111741812.png) ![image-20260306133701822](assets/image-20260306133701822.png) ### 编写SQL语句 多条数据使用 collection 标签进行映射, - property="students" 表示将数据映射到主表实体类中的 students 属性 - ofType="com.neuedu.mybatis.po.Students": 表示 单条数据 的类型 property ```xml ``` ![image-20260306112347789](assets/image-20260306112347789.png) ### 单元测试 ```java package com.neuedu.mybatis.mapper; import com.neuedu.mybatis.po.Classes; import com.neuedu.mybatis.util.MybatisUtils; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.junit.Before; import org.junit.Test; import java.io.IOException; import java.util.List; public class ClassesMapperTest { private ClassesMapper classesMapper; private SqlSession session = null; /** * 每个@Test方法执行之前有限执行 @Before方法 * * @throws IOException */ @Before public void setup() throws IOException { SqlSessionFactory factory = null; try { factory = MybatisUtils.getSqlSessionFactory(); session = factory.openSession(false); classesMapper = session.getMapper(ClassesMapper.class); } catch (IOException e) { throw new RuntimeException(e); } } @Test public void selectByPrimaryKey() { long id = 1; Classes classes = classesMapper.selectByPrimaryKey(id); System.out.println("classes = " + classes); } @Test public void selectList() { List list = classesMapper.selectList(); for (Classes classes : list) { System.out.println("班级: "+classes.getClassName() + ": 人数: "+ classes.getStudents().size()); } } } ``` ## 分成多个SQl实现关联查询 可以在懒加载中实现 ### 一对一 通过多个SQL实现 - property="idCards" 从表数据在主表实体类中的**属性名称** - javaType="com.neuedu.mybatis.po.IdCards" 从表数据在主表实体类中的属性 **Java类型** - select="selectIdCards" : 查询从表数据的SQL语句 - column="id" : 从表查询时关联的**主表字段** 作为条件存在 ```xml ``` ### 一对多 - property="students" 表示将数据映射到主表实体类中的 students 属性 - ofType="com.neuedu.mybatis.po.Students": 表示 单条数据 的类型 property - select="selectStudentsByClassId" 查询从表数据的SQL语句 - column="id" 从表查询时关联的**主表字段** 作为条件存在 ```xml ```