MyBatis:核心概念 + 环境搭建 + CRUD
一、简介本文适合 Java 开发初学者从零梳理 MyBatis 核心知识包含环境搭建、配置详解、CRUD 实战、常见避坑可直接用于学习、复习与项目开发。二、MyBatis 基础概念与环境搭建1. JDBC 痛点与 MyBatis 优势在学习 MyBatis 之前我们先回顾传统JDBC 开发的缺陷这也是 MyBatis 诞生的核心原因。JDBC 操作缺陷资源频繁创建与释放严重影响性能每次操作数据库都需要创建 Connection、Statement用完直接关闭频繁 IO 造成资源浪费。SQL 硬编码维护成本极高SQL 语句直接写在 Java 代码中修改 SQL 必须重新编译、打包、部署无法灵活配置。结果集解析繁琐手动封装冗余查询返回 ResultSet 后需要手动getXxx()取值、手动 set 到实体类代码量大且易出错。代码冗余开发效率低下连接、参数设置、结果解析大量重复代码不符合开发规范。典型 JDBC 冗余代码// 1. 加载驱动、建立连接 Class.forName(com.mysql.jdbc.Driver); Connection conn DriverManager.getConnection(url, user, pwd); // 2. 编写SQL硬编码 String sql select * from user where id ?; PreparedStatement pstmt conn.prepareStatement(sql); // 3. 设置参数 pstmt.setInt(1, id); // 4. 执行查询 ResultSet rs pstmt.executeQuery(); // 5. 手动封装结果集 User user null; if(rs.next()){ user new User(); user.setId(rs.getInt(id)); user.setUsername(rs.getString(username)); }MyBatis 优势与解决方案MyBatis 是一款优秀的持久层框架底层依然基于 JDBC但做了高度封装连接池管理避免频繁创建 / 释放连接大幅提升性能SQL 与 Java 代码解耦SQL 统一写在 XML 配置文件中修改无需编译 Java自动结果集映射自动将 ResultSet 封装为实体对象无需手动解析参数自动映射支持简单类型、实体类参数直接使用#{}占位符轻量级、学习成本低相比 HibernateMyBatis 更灵活、可控性更强。2. 项目环境配置我们以Maven 项目为例搭建标准 MyBatis 开发环境。1Maven 依赖导入在pom.xml中导入核心依赖MyBatis 核心包、MySQL 驱动、日志包、Junit 测试。dependencies !-- MyBatis核心依赖 -- dependency groupIdorg.mybatis/groupId artifactIdmybatis/artifactId version3.5.9/version /dependency !-- MySQL驱动 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version5.1.49/version /dependency !-- 日志包 -- dependency groupIdlog4j/groupId artifactIdlog4j/artifactId version1.2.17/version /dependency !-- 测试包 -- dependency groupIdjunit/groupId artifactIdjunit/artifactId version4.13.2/version scopetest/scope /dependency /dependencies2MyBatis 核心配置文件sqlMapConfig.xml在resources目录下创建核心配置文件配置数据源、事务、加载映射文件。?xml version1.0 encodingUTF-8? !DOCTYPE configuration PUBLIC -//mybatis.org//DTD Config 3.0//EN http://mybatis.org/dtd/mybatis-3-config.dtd configuration !-- 环境配置默认使用development -- environments defaultdevelopment environment iddevelopment !-- 事务管理JDBC事务 -- transactionManager typeJDBC/ !-- 数据源POOLED连接池 -- dataSource typePOOLED property namedriver valuecom.mysql.jdbc.Driver/ property nameurl valuejdbc:mysql://localhost:3306/mybatis_demo?serverTimezoneAsia/Shanghaiamp;useSSLfalseamp;characterEncodingutf8/ property nameusername valueroot/ property namepassword valueabc123/ /dataSource /environment /environments !-- 加载Mapper映射文件 -- mappers mapper resourcemapper/UserMapper.xml/ /mappers /configuration3项目标准结构src/main/java com.qcby ├── dao/ DAO接口层 ├── entity/ 实体类 src/main/resources ├── mapper/ Mapper XML映射文件 ├── sqlMapConfig.xml MyBatis核心配置三、核心配置与映射关系1. 实体类与 Mapper 映射MyBatis 实现自动封装的前提数据库表 ↔ 实体类 严格映射。1实体类编写规范类属性名 与 数据库表字段名完全一致必须提供无参构造必须生成getter/setter必须重写toString()方便测试打印。User 实体类示例public class User { private Integer id; private String username; private String sex; private Date birthday; private String address; // 无参构造 public User(){} // getter/setter // toString() }2DAO 接口与 XML 绑定规则MyBatis 采用接口代理模式开发无需编写实现类创建 DAO 接口如UserDao.javaXML 文件通过namespace绑定接口全类名XML 中 SQL 标签的id必须与 接口方法名完全一致parameterType/resultType与方法参数、返回值匹配。接口示例public interface UserDao { ListUser findAll(); User findUserById(Integer id); }XML 绑定示例!-- namespace绑定接口全限定名 -- mapper namespacecom.qcby.dao.UserDao !-- id与接口方法名一致 -- select idfindAll resultTypecom.qcby.entity.User select * from user order by id desc /select /mapper2. 参数与结果映射1参数传递parameterType用于指定 SQL 入参类型支持基本类型Integer、String实体类型com.qcby.entity.User取值语法#{属性名}安全占位符防 SQL 注入xmlselect idfindUserById parameterTypeInteger resultTypecom.qcby.entity.User select * from user where id #{id} /select2结果集封装resultType指定 SQL 返回值类型查询单条数据直接写实体类全类名查询多条数据依然写实体类MyBatis 自动封装为List实体示例查询所有用户xmlselect idfindAll resultTypecom.qcby.entity.User select * from user /select四、增删改查CRUD实战1. 查询操作Select查询是 MyBatis 最常用操作分为全量查询、精确查询、模糊查询。1全量查询 findAllselect idfindAll resultTypecom.qcby.entity.User select * from user order by id desc; /select接口方法ListUser findAll();2条件查询根据 ID 查询单条结果select idfindUserById parameterTypeInteger resultTypecom.qcby.entity.User select * from user where id #{id}; /select接口方法User findUserById(Integer id);3模糊查询根据用户名模糊匹配重点like 必须使用 concat 拼接避免 SQL 注入xmlselect idfindUserByUserName parameterTypeString resultTypecom.qcby.entity.User select * from user where username like concat(%, #{username}, %); /select接口方法ListUser findUserByUserName(String username);4字段映射异常处理常见问题查询结果部分字段为null根本原因实体类属性名 ≠ 数据库列名解决方案统一名称推荐使用resultMap手动映射2. 增删改操作Insert/Update/Delete增删改属于写操作必须注意必须手动提交事务session.commit()。1插入数据 insertinsert idinsert parameterTypecom.qcby.entity.User insert into user(username,sex,birthday,address) values(#{username},#{sex},#{birthday},#{address}); /insert接口方法int insert(User user);2修改数据 update必须传入包含 id的实体对象update idupdate parameterTypecom.qcby.entity.User update user set username#{username},sex#{sex},birthday#{birthday},address#{address} where id#{id}; /update3删除数据 deletedelete iddelete parameterTypeInteger delete from user where id#{id}; /delete4事务提交机制查询不需要提交事务增删改必须提交Test public void addUser(){ User user new User(); user.setUsername(张三); user.setSex(男); // 执行插入 userDao.insert(user); // 必须提交事务 session.commit(); }五、测试工具类通用版为了简化测试可封装 MyBatis 工具类public class MyBatisUtil { private static SqlSessionFactory sqlSessionFactory; static{ try { String resource sqlMapConfig.xml; InputStream inputStream Resources.getResourceAsStream(resource); sqlSessionFactory new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } // 获取SqlSession public static SqlSession getSession(){ return sqlSessionFactory.openSession(true); // 自动提交事务 } }