☰
【前端转全栈java速通课】 项目实战④7-11节 操作数据库-登录-注册-修改密码-注销-mubatis-plus简化crud-
2026/10/11 7:36:09 网站建设 项目流程








JPA、MyBatis、JDBC、MyBatis-Plus 的差异与操作说明

在 Java 后端开发中,数据访问层的技术选型直接影响开发效率与维护成本。下面从 JDBC、MyBatis、MyBatis-Plus、JPA 四种方案出发,对比它们的定位、差异,并给出各自的代码示例。

1. JDBC(Java Database Connectivity)

JDBC 是 Java 访问数据库的最底层 API,所有 ORM 框架底层最终都基于 JDBC 完成数据库交互。它的特点是灵活、可控,但需要开发者手动处理连接、预编译、结果集映射和异常关闭等大量样板代码。

// 原生 JDBC 示例Stringurl="jdbc:mysql://localhost:3306/test";Stringuser="root";Stringpassword="123456";try(Connectionconn=DriverManager.getConnection(url,user,password);PreparedStatementps=conn.prepareStatement("SELECT * FROM user WHERE id = ?")){ps.setLong(1,1L);try(ResultSetrs=ps.executeQuery()){while(rs.next()){System.out.println(rs.getString("name"));}}}catch(SQLExceptione){e.printStackTrace();}

特点:性能最高、最灵活,但代码冗余、易出错,适合对 SQL 有极致控制需求的场景。

2. MyBatis

MyBatis 是半自动 ORM 框架,SQL 由开发者编写,框架负责参数映射与结果集映射。它保留了 SQL 的灵活性,同时大幅减少了 JDBC 样板代码。

// Mapper 接口publicinterfaceUserMapper{UserselectById(@Param("id")Longid);}
<!-- UserMapper.xml --><selectid="selectById"resultType="com.example.User">SELECT * FROM user WHERE id = #{id}</select>
// 调用Useruser=userMapper.selectById(1L);

特点:SQL 完全可控,适合复杂查询、多表关联、动态 SQL 场景;但需要手写 XML 或注解 SQL,开发量相对较大。

3. MyBatis-Plus

MyBatis-Plus 是 MyBatis 的增强工具,在保留 MyBatis 全部能力的基础上,提供了通用 CRUD、条件构造器、分页插件等开箱即用的能力,大幅减少重复 SQL 编写。

// 实体类@Data@TableName("user")publicclassUser{@TableId(type=IdType.AUTO)privateLongid;privateStringname;privateIntegerage;}
// Mapper 继承 BaseMapper,直接获得通用 CRUDpublicinterfaceUserMapperextendsBaseMapper<User>{}
// 使用条件构造器查询LambdaQueryWrapper<User>wrapper=newLambdaQueryWrapper<>();wrapper.eq(User::getName,"张三").gt(User::getAge,18);List<User>users=userMapper.selectList(wrapper);// 分页查询Page<User>page=userMapper.selectPage(newPage<>(1,10),wrapper);

特点:单表 CRUD 几乎零 SQL,开发效率极高;复杂 SQL 仍可手写,兼顾效率与灵活性,是目前国内最流行的 MyBatis 增强方案。

4. JPA(Java Persistence API)

JPA 是 Java 官方规范,Hibernate 是其最主流的实现。JPA 是全自动 ORM,开发者通过实体注解和接口方法命名约定即可完成数据操作,无需编写 SQL。

// 实体类@Entity@Table(name="user")publicclassUser{@Id@GeneratedValue(strategy=GenerationType.IDENTITY)privateLongid;privateStringname;privateIntegerage;}
// Repository 接口,继承 JpaRepository 获得通用 CRUDpublicinterfaceUserRepositoryextendsJpaRepository<User,Long>{// 方法命名约定自动生成查询List<User>findByNameAndAgeGreaterThan(Stringname,Integerage);}
// 调用List<User>users=userRepository.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 查询用户Stringsql="SELECT * FROM user WHERE id = ?";try(Connectionconn=DriverManager.getConnection(url,user,password);PreparedStatementps=conn.prepareStatement(sql)){ps.setLong(1,1L);try(ResultSetrs=ps.executeQuery()){if(rs.next()){Useru=newUser();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 --><selectid="selectById"resultType="com.example.User">SELECT * FROM user WHERE id = #{id}</select>
// 调用Useruser=userMapper.selectById(1L);

MyBatis-Plus

// 直接使用 BaseMapper 内置方法Useruser=userMapper.selectById(1L);

JPA

// Repository 接口publicinterfaceUserRepositoryextendsJpaRepository<User,Long>{}// 调用Useruser=userRepository.findById(1L).orElse(null);

6.2 根据用户名模糊查询用户

JDBC

// 根据用户名模糊查询Stringsql="SELECT * FROM user WHERE name LIKE ?";try(Connectionconn=DriverManager.getConnection(url,user,password);PreparedStatementps=conn.prepareStatement(sql)){ps.setString(1,"%张%");try(ResultSetrs=ps.executeQuery()){while(rs.next()){System.out.println(rs.getString("name"));}}}catch(SQLExceptione){e.printStackTrace();}

MyBatis

// Mapper 接口publicinterfaceUserMapper{List<User>selectByNameLike(@Param("name")Stringname);}
<!-- UserMapper.xml --><selectid="selectByNameLike"resultType="com.example.User">SELECT * FROM user WHERE name LIKE CONCAT('%', #{name}, '%')</select>
// 调用List<User>users=userMapper.selectByNameLike("张");

MyBatis-Plus

// 使用条件构造器模糊查询LambdaQueryWrapper<User>wrapper=newLambdaQueryWrapper<>();wrapper.like(User::getName,"张");List<User>users=userMapper.selectList(wrapper);

JPA

// Repository 接口publicinterfaceUserRepositoryextendsJpaRepository<User,Long>{List<User>findByNameContaining(Stringname);}// 调用List<User>users=userRepository.findByNameContaining("张");

6.3 根据 id、用户名、密码三个条件一起查询(用户名和密码支持模糊查询)

JDBC

// 多条件组合查询,用户名和密码模糊匹配Stringsql="SELECT * FROM user WHERE id = ? AND name LIKE ? AND password LIKE ?";try(Connectionconn=DriverManager.getConnection(url,user,password);PreparedStatementps=conn.prepareStatement(sql)){ps.setLong(1,1L);ps.setString(2,"%张%");ps.setString(3,"%123%");try(ResultSetrs=ps.executeQuery()){while(rs.next()){System.out.println(rs.getString("name"));}}}catch(SQLExceptione){e.printStackTrace();}

MyBatis

// Mapper 接口publicinterfaceUserMapper{List<User>selectByCondition(@Param("id")Longid,@Param("name")Stringname,@Param("password")Stringpassword);}
<!-- UserMapper.xml --><selectid="selectByCondition"resultType="com.example.User">SELECT * FROM user WHERE id = #{id} AND name LIKE CONCAT('%', #{name}, '%') AND password LIKE CONCAT('%', #{password}, '%')</select>
// 调用List<User>users=userMapper.selectByCondition(1L,"张","123");

MyBatis-Plus

// 使用条件构造器组合查询LambdaQueryWrapper<User>wrapper=newLambdaQueryWrapper<>();wrapper.eq(User::getId,1L).like(User::getName,"张").like(User::getPassword,"123");List<User>users=userMapper.selectList(wrapper);

JPA

// Repository 接口publicinterfaceUserRepositoryextendsJpaRepository<User,Long>{List<User>findByIdAndNameContainingAndPasswordContaining(Longid,Stringname,Stringpassword);}// 调用List<User>users=userRepository.findByIdAndNameContainingAndPasswordContaining(1L,"张","123");

小结:从上面三个查询场景可以看出,JDBC 需要手写全部 SQL 和结果集映射;MyBatis 需要手写 SQL 但映射交给框架;MyBatis-Plus 通过条件构造器几乎零 SQL;JPA 则完全靠方法命名约定自动生成查询。实际项目中可根据对 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'更新时间,创建时填写,更新时更新')ENGINE=InnoDBDEFAULTCHARSET=utf8mb4COMMENT='用户表';

7.2 实体类(MyBatis-Plus 示例)

// 实体类@Data@TableName("user")publicclassUser{@TableId(type=IdType.ASSIGN_UUID)// uid 生成主键privateStringid;privateStringusername;privateStringpassword;@TableField(fill=FieldFill.INSERT)// 创建时自动填写privateDatecreateTime;@TableField(fill=FieldFill.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 接口publicinterfaceUserMapperextendsBaseMapper<User>{}

7.3 注册代码

// 注册:用户名唯一校验 + 密码加密 + 插入用户@ServicepublicclassUserService{@AutowiredprivateUserMapperuserMapper;@AutowiredprivatePasswordEncoderpasswordEncoder;publicbooleanregister(Stringusername,Stringpassword){// 1. 校验用户名是否已存在LambdaQueryWrapper<User>wrapper=newLambdaQueryWrapper<>();wrapper.eq(User::getUsername,username);if(userMapper.selectCount(wrapper)>0){returnfalse;// 用户名已存在}// 2. 创建用户,密码加密存储Useruser=newUser();user.setUsername(username);user.setPassword(passwordEncoder.encode(password));// 3. 插入数据库(Id 由 ASSIGN_UUID 自动生成,时间字段自动填充)returnuserMapper.insert(user)>0;}}

7.4 登录代码

// 登录:根据用户名查询,校验密码publicUserlogin(Stringusername,Stringpassword){// 1. 根据用户名查询用户LambdaQueryWrapper<User>wrapper=newLambdaQueryWrapper<>();wrapper.eq(User::getUsername,username);Useruser=userMapper.selectOne(wrapper);// 2. 用户不存在或密码不匹配则登录失败if(user==null||!passwordEncoder.matches(password,user.getPassword())){returnnull;}// 3. 登录成功,返回用户信息(实际项目中可在此生成 Token)returnuser;}

说明:主键Id使用IdType.ASSIGN_UUID自动生成 uid;Username在数据库层面加了UNIQUE唯一索引,注册时再配合代码校验保证唯一;Create_time和Update_time通过MetaObjectHandler自动填充,创建时都写入当前时间,更新时只刷新Update_time。




8. 修改密码与注销账号

下面补充两个最常见的账号操作:修改密码和注销账号,均基于 MyBatis-Plus 实现。

8.1 修改密码

// 修改密码:校验原密码 + 更新为新密码publicbooleanchangePassword(StringuserId,StringoldPassword,StringnewPassword){// 1. 根据 id 查询用户Useruser=userMapper.selectById(userId);if(user==null){returnfalse;// 用户不存在}// 2. 校验原密码是否正确if(!passwordEncoder.matches(oldPassword,user.getPassword())){returnfalse;// 原密码错误}// 3. 更新为新密码(加密存储,Update_time 自动刷新)Userupdate=newUser();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)以保留历史数据。






需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询