资讯详情 【前端转全栈java速通课】 项目实战④7-11节 操作数据库-登录-注册-修改密码-注销-mubatis-plus简化crud-
📅 2026/10/11 7:36:14
JPA、MyBatis、JDBC、MyBatis-Plus 的差异与操作说明在 Java 后端开发中数据访问层的技术选型直接影响开发效率与维护成本。下面从 JDBC、MyBatis、MyBatis-Plus、JPA 四种方案出发对比它们的定位、差异并给出各自的代码示例。1. JDBCJava Database ConnectivityJDBC 是 Java 访问数据库的最底层 API所有 ORM 框架底层最终都基于 JDBC 完成数据库交互。它的特点是灵活、可控但需要开发者手动处理连接、预编译、结果集映射和异常关闭等大量样板代码。// 原生 JDBC 示例Stringurljdbc:mysql://localhost:3306/test;Stringuserroot;Stringpassword123456;try(ConnectionconnDriverManager.getConnection(url,user,password);PreparedStatementpsconn.prepareStatement(SELECT * FROM user WHERE id ?)){ps.setLong(1,1L);try(ResultSetrsps.executeQuery()){while(rs.next()){System.out.println(rs.getString(name));}}}catch(SQLExceptione){e.printStackTrace();}特点性能最高、最灵活但代码冗余、易出错适合对 SQL 有极致控制需求的场景。2. MyBatisMyBatis 是半自动 ORM 框架SQL 由开发者编写框架负责参数映射与结果集映射。它保留了 SQL 的灵活性同时大幅减少了 JDBC 样板代码。// Mapper 接口publicinterfaceUserMapper{UserselectById(Param(id)Longid);}!-- UserMapper.xml --selectidselectByIdresultTypecom.example.UserSELECT * FROM user WHERE id #{id}/select// 调用UseruseruserMapper.selectById(1L);特点SQL 完全可控适合复杂查询、多表关联、动态 SQL 场景但需要手写 XML 或注解 SQL开发量相对较大。3. MyBatis-PlusMyBatis-Plus 是 MyBatis 的增强工具在保留 MyBatis 全部能力的基础上提供了通用 CRUD、条件构造器、分页插件等开箱即用的能力大幅减少重复 SQL 编写。// 实体类DataTableName(user)publicclassUser{TableId(typeIdType.AUTO)privateLongid;privateStringname;privateIntegerage;}// Mapper 继承 BaseMapper直接获得通用 CRUDpublicinterfaceUserMapperextendsBaseMapperUser{}// 使用条件构造器查询LambdaQueryWrapperUserwrappernewLambdaQueryWrapper();wrapper.eq(User::getName,张三).gt(User::getAge,18);ListUserusersuserMapper.selectList(wrapper);// 分页查询PageUserpageuserMapper.selectPage(newPage(1,10),wrapper);特点单表 CRUD 几乎零 SQL开发效率极高复杂 SQL 仍可手写兼顾效率与灵活性是目前国内最流行的 MyBatis 增强方案。4. JPAJava Persistence APIJPA 是 Java 官方规范Hibernate 是其最主流的实现。JPA 是全自动 ORM开发者通过实体注解和接口方法命名约定即可完成数据操作无需编写 SQL。// 实体类EntityTable(nameuser)publicclassUser{IdGeneratedValue(strategyGenerationType.IDENTITY)privateLongid;privateStringname;privateIntegerage;}// Repository 接口继承 JpaRepository 获得通用 CRUDpublicinterfaceUserRepositoryextendsJpaRepositoryUser,Long{// 方法命名约定自动生成查询ListUserfindByNameAndAgeGreaterThan(Stringname,Integerage);}// 调用ListUserusersuserRepository.findByNameAndAgeGreaterThan(张三,18);特点全自动映射开发效率高跨数据库移植性好但复杂 SQL 和动态查询控制力较弱性能调优相对困难学习曲线较陡。5. 四种方案对比总结维度JDBCMyBatisMyBatis-PlusJPA自动化程度无半自动半自动增强全自动SQL 控制力完全控制完全控制完全控制较弱开发效率低中高高学习成本低中中较高复杂查询手写 SQL手写 SQL手写 SQL 条件构造器较难典型场景底层框架/极致性能复杂业务 SQL快速 CRUD 复杂 SQL标准规范/快速开发选型建议追求极致 SQL 控制选 JDBC复杂查询多选 MyBatis国内快速开发首选 MyBatis-Plus追求规范统一、跨库移植选 JPA。6. 常见查询操作示例下面补充几种最常见的用户查询场景分别用 JDBC、MyBatis、MyBatis-Plus、JPA 四种方式实现方便对比它们的写法差异。6.1 根据 id 查询用户JDBC// 根据 id 查询用户StringsqlSELECT * FROM user WHERE id ?;try(ConnectionconnDriverManager.getConnection(url,user,password);PreparedStatementpsconn.prepareStatement(sql)){ps.setLong(1,1L);try(ResultSetrsps.executeQuery()){if(rs.next()){UserunewUser();u.setId(rs.getLong(id));u.setName(rs.getString(name));u.setAge(rs.getInt(age));System.out.println(u);}}}catch(SQLExceptione){e.printStackTrace();}MyBatis// Mapper 接口publicinterfaceUserMapper{UserselectById(Param(id)Longid);}!-- UserMapper.xml --selectidselectByIdresultTypecom.example.UserSELECT * FROM user WHERE id #{id}/select// 调用UseruseruserMapper.selectById(1L);MyBatis-Plus// 直接使用 BaseMapper 内置方法UseruseruserMapper.selectById(1L);JPA// Repository 接口publicinterfaceUserRepositoryextendsJpaRepositoryUser,Long{}// 调用UseruseruserRepository.findById(1L).orElse(null);6.2 根据用户名模糊查询用户JDBC// 根据用户名模糊查询StringsqlSELECT * FROM user WHERE name LIKE ?;try(ConnectionconnDriverManager.getConnection(url,user,password);PreparedStatementpsconn.prepareStatement(sql)){ps.setString(1,%张%);try(ResultSetrsps.executeQuery()){while(rs.next()){System.out.println(rs.getString(name));}}}catch(SQLExceptione){e.printStackTrace();}MyBatis// Mapper 接口publicinterfaceUserMapper{ListUserselectByNameLike(Param(name)Stringname);}!-- UserMapper.xml --selectidselectByNameLikeresultTypecom.example.UserSELECT * FROM user WHERE name LIKE CONCAT(%, #{name}, %)/select// 调用ListUserusersuserMapper.selectByNameLike(张);MyBatis-Plus// 使用条件构造器模糊查询LambdaQueryWrapperUserwrappernewLambdaQueryWrapper();wrapper.like(User::getName,张);ListUserusersuserMapper.selectList(wrapper);JPA// Repository 接口publicinterfaceUserRepositoryextendsJpaRepositoryUser,Long{ListUserfindByNameContaining(Stringname);}// 调用ListUserusersuserRepository.findByNameContaining(张);6.3 根据 id、用户名、密码三个条件一起查询用户名和密码支持模糊查询JDBC// 多条件组合查询用户名和密码模糊匹配StringsqlSELECT * FROM user WHERE id ? AND name LIKE ? AND password LIKE ?;try(ConnectionconnDriverManager.getConnection(url,user,password);PreparedStatementpsconn.prepareStatement(sql)){ps.setLong(1,1L);ps.setString(2,%张%);ps.setString(3,%123%);try(ResultSetrsps.executeQuery()){while(rs.next()){System.out.println(rs.getString(name));}}}catch(SQLExceptione){e.printStackTrace();}MyBatis// Mapper 接口publicinterfaceUserMapper{ListUserselectByCondition(Param(id)Longid,Param(name)Stringname,Param(password)Stringpassword);}!-- UserMapper.xml --selectidselectByConditionresultTypecom.example.UserSELECT * FROM user WHERE id #{id} AND name LIKE CONCAT(%, #{name}, %) AND password LIKE CONCAT(%, #{password}, %)/select// 调用ListUserusersuserMapper.selectByCondition(1L,张,123);MyBatis-Plus// 使用条件构造器组合查询LambdaQueryWrapperUserwrappernewLambdaQueryWrapper();wrapper.eq(User::getId,1L).like(User::getName,张).like(User::getPassword,123);ListUserusersuserMapper.selectList(wrapper);JPA// Repository 接口publicinterfaceUserRepositoryextendsJpaRepositoryUser,Long{ListUserfindByIdAndNameContainingAndPasswordContaining(Longid,Stringname,Stringpassword);}// 调用ListUserusersuserRepository.findByIdAndNameContainingAndPasswordContaining(1L,张,123);小结从上面三个查询场景可以看出JDBC 需要手写全部 SQL 和结果集映射MyBatis 需要手写 SQL 但映射交给框架MyBatis-Plus 通过条件构造器几乎零 SQLJPA 则完全靠方法命名约定自动生成查询。实际项目中可根据对 SQL 控制力的需求灵活选型。7. 用户表设计与登录注册实现下面实现一个最简单的用户表包含Id、Username、Password、Create_time、Update_time五个字段并给出登录与注册的完整代码。7.1 表结构设计字段类型说明Id字符串主键uid 生成主键使用 UUID 生成Username字符串Unique 唯一索引用户名唯一Password字符串密码Create_timeDate 类型创建时自动填写Update_timeDate 类型创建时自动填写更新时更新-- 建表语句CREATETABLEuser(IdVARCHAR(32)PRIMARYKEYCOMMENT主键uid 生成,UsernameVARCHAR(50)NOTNULLUNIQUECOMMENT用户名唯一索引,PasswordVARCHAR(100)NOTNULLCOMMENT密码,Create_timeDATETIMENOTNULLCOMMENT创建时间自动填写,Update_timeDATETIMENOTNULLCOMMENT更新时间创建时填写更新时更新)ENGINEInnoDBDEFAULTCHARSETutf8mb4COMMENT用户表;7.2 实体类MyBatis-Plus 示例// 实体类DataTableName(user)publicclassUser{TableId(typeIdType.ASSIGN_UUID)// uid 生成主键privateStringid;privateStringusername;privateStringpassword;TableField(fillFieldFill.INSERT)// 创建时自动填写privateDatecreateTime;TableField(fillFieldFill.INSERT_UPDATE)// 创建时填写更新时更新privateDateupdateTime;}// 自动填充处理器ComponentpublicclassMyMetaObjectHandlerimplementsMetaObjectHandler{OverridepublicvoidinsertFill(MetaObjectmetaObject){this.strictInsertFill(metaObject,createTime,Date.class,newDate());this.strictInsertFill(metaObject,updateTime,Date.class,newDate());}OverridepublicvoidupdateFill(MetaObjectmetaObject){this.strictUpdateFill(metaObject,updateTime,Date.class,newDate());}}// Mapper 接口publicinterfaceUserMapperextendsBaseMapperUser{}7.3 注册代码// 注册用户名唯一校验 密码加密 插入用户ServicepublicclassUserService{AutowiredprivateUserMapperuserMapper;AutowiredprivatePasswordEncoderpasswordEncoder;publicbooleanregister(Stringusername,Stringpassword){// 1. 校验用户名是否已存在LambdaQueryWrapperUserwrappernewLambdaQueryWrapper();wrapper.eq(User::getUsername,username);if(userMapper.selectCount(wrapper)0){returnfalse;// 用户名已存在}// 2. 创建用户密码加密存储UserusernewUser();user.setUsername(username);user.setPassword(passwordEncoder.encode(password));// 3. 插入数据库Id 由 ASSIGN_UUID 自动生成时间字段自动填充returnuserMapper.insert(user)0;}}7.4 登录代码// 登录根据用户名查询校验密码publicUserlogin(Stringusername,Stringpassword){// 1. 根据用户名查询用户LambdaQueryWrapperUserwrappernewLambdaQueryWrapper();wrapper.eq(User::getUsername,username);UseruseruserMapper.selectOne(wrapper);// 2. 用户不存在或密码不匹配则登录失败if(usernull||!passwordEncoder.matches(password,user.getPassword())){returnnull;}// 3. 登录成功返回用户信息实际项目中可在此生成 Tokenreturnuser;}说明主键Id使用IdType.ASSIGN_UUID自动生成 uidUsername在数据库层面加了UNIQUE唯一索引注册时再配合代码校验保证唯一Create_time和Update_time通过MetaObjectHandler自动填充创建时都写入当前时间更新时只刷新Update_time。8. 修改密码与注销账号下面补充两个最常见的账号操作修改密码和注销账号均基于 MyBatis-Plus 实现。8.1 修改密码// 修改密码校验原密码 更新为新密码publicbooleanchangePassword(StringuserId,StringoldPassword,StringnewPassword){// 1. 根据 id 查询用户UseruseruserMapper.selectById(userId);if(usernull){returnfalse;// 用户不存在}// 2. 校验原密码是否正确if(!passwordEncoder.matches(oldPassword,user.getPassword())){returnfalse;// 原密码错误}// 3. 更新为新密码加密存储Update_time 自动刷新UserupdatenewUser();update.setId(userId);update.setPassword(passwordEncoder.encode(newPassword));returnuserMapper.updateById(update)0;}8.2 注销账号// 注销账号根据 id 删除用户publicbooleandeleteUser(StringuserId){// 直接调用 BaseMapper 内置删除方法returnuserMapper.deleteById(userId)0;}说明修改密码时先校验原密码避免被他人恶意篡改新密码同样使用PasswordEncoder加密后存储Update_time由MetaObjectHandler自动刷新。注销账号直接按主键Id删除即可实际项目中可改为逻辑删除TableLogic以保留历史数据。