6-15笔记
- 实现登录查询(根据用户名密码查询用户)。
- 实现发布新闻(插入
news表,同时更新用户news_count),使用事务保证一致性。
二、核心知识点(简要)
- 事务:一组操作要么全部成功,要么全部失败。
setAutoCommit(false):关闭自动提交,开启事务。commit()和rollback():提交或回滚事务。ResultSet:查询结果集,使用next()遍历。
三、操作步骤
1. 创建news表
-
打开SQLyog,选中weitout数据库,点+号,新建查询
-
在新的询问中输入如下内容:
CREATE TABLE `news` (-- 创建名为 news 的表 `id` INT PRIMARY KEY AUTO_INCREMENT,-- 【主键】定义 id 字段,类型为整数,设为主键并开启自增 `user_id` INT NOT NULL,--记录这条新闻是由哪个用户发布的,关联 user 表的 id `title` VARCHAR(200) NOT NULL, -- 【标题】 `content` TEXT, -- 【正文】定义 content 字段,文本类型 `publish_time` DATETIME DEFAULT CURRENT_TIMESTAMP,--【发布时间】定义 publish_time 字段,日期时间类型 `view_count` INT DEFAULT 0,-- 【浏览量】默认为 0,后续可通过 UPDATE 语句累加 FOREIGN KEY (`user_id`) REFERENCES `user`(`id`)-- 【外键约束】建立 user_id 与 user 表 id 之间的关联,确保发布的 user_id 必须在 user 表中真实存在 ); -
然后选中全部内容,点击运行
-
点开weitoutiao数据库中的表,可以看到新增了一张名为news的表,再点击表数据,点击刷新,新的表就显示出来,表示news数据表已成功创)
2. 创建News实体类(包含id, userId, title, content, publishTime, viewCount)
-
打开IDEA,继续在上个工程上修改,右键entity,新建java类,News类
-
News类中编写代码如下:
package com.weitoutiao.entity;// 【包声明】表明该类属于 entity(实体)层 import java.time.LocalDateTime;// 【导入包】引入 Java 8 的时间处理类,对应数据库中的 DATETIME 类型 public class News {// News 实体类,对应数据库中的 news 表 private Integer id; // 【主键】对应表中的 id 字段 private Integer userId;// 【外键】对应表中的 user_id 字段,表示发布该新闻的用户ID private String title;// 存储新闻的简短标题 private String content; // 存储新闻的详细内容 private LocalDateTime publishTime; //使用 LocalDateTime精确匹配数据库的DATETIME格式 private Integer viewCount;// 统计该新闻被查看的次数 }
3. 在UserDAO中添加login方法
-
login方法如下:
public User login(String username, String password) { String sql = "SELECT id, username, role, news_count FROM user WHERE username=? AND password=?"; // 定义 SQL 查询语句:从 user 表中查找匹配的用户名和密码,并只查询需要的字段(id, username, role, news_count) try (Connection conn = DBUtil.getConnection();// 调用工具类获取数据库连接对象 PreparedStatement ps = conn.prepareStatement(sql)) {// 预编译 SQL 语句,生成 PreparedStatement 对象 ps.setString(1, username); // 设置 SQL 语句中第一个问号 (?) 的值为传入的 username 参数 ps.setString(2, password); ResultSet rs = ps.executeQuery();// 执行 SQL 查询语句,并将结果存储在 ResultSet 结果集对象中 if (rs.next()) {// 判断结果集中是否有数据(即是否找到了匹配的用户) User user = new User();// 如果找到用户,实例化一个新的 User 对象用于封装数据 user.setId(rs.getInt("id"));// 从结果集中获取 "id" 字段的值,并设置到 user 对象的 id 属性中 user.setUsername(rs.getString("username")); user.setRole(rs.getString("role")); user.setNewsCount(rs.getInt("news_count")); return user;// 将封装好数据的 user 对象返回给调用者,表示登录成功 } } catch (SQLException e) {// 捕获在执行数据库操作过程中可能发生的 SQL 异常 e.printStackTrace();// 在控制台打印异常的堆栈信息,方便开发者调试和排查错误 } return null; //如果没有找到匹配的用户(if 条件不成立)or发生了异常,则返回null,表示登录失败 } -
在
UserDao类中,login方法添加的位置如下: -
ResultSet会爆红,鼠标悬停之上,选择导入类 -
user的set方法还会爆红,这是因为User类的选择器没有配置,再返回到User实体类中添加
-
在User实体类中的空白位置右键,选择生成,再选择
Getter和Setter,生成set和get方法 -
可以全选中,一次全部生成
-
最后生成的方法如下所示:
-
再看
UserDao类中的set已经不红了。
4. 创建NewsDAO实现发布新闻(事务)
-
右键
dao包名,新建NewsDAO类 -
NewsDAO类中的代码如下:package com.weitoutiao.dao;// 【包声明】表明该类属于 dao(数据访问)层 import com.weitoutiao.util.DBUtil;// 【导入工具类】引入自定义的数据库连接工具 import java.sql.Connection;// 【导入类】数据库连接接口 import java.sql.PreparedStatement;// 【导入类】预编译 SQL 语句接口 import java.sql.SQLException;// 【导入异常】SQL 异常处理类 public class NewsDAO {//新闻数据访问对象 //发布新闻的方法 public boolean publish(int userId, String title, String content) { //【定义 SQL】向 news 表中插入一条新记录,使用 ? 占位符防注入 String insertSql = "INSERT INTO news (user_id, title, content) VALUES (?, ?, ?)"; // 【定义 SQL】根据用户 id,将该用户的发帖总数 (news_count) 累加 1 String updateSql = "UPDATE user SET news_count = news_count + 1 WHERE id = ?"; Connection conn = null; PreparedStatement psInsert = null; PreparedStatement psUpdate = null; try { conn = DBUtil.getConnection();// 【获取连接】通过工具类获取一个活跃的数据库连接 conn.setAutoCommit(false); // 开启事务,关闭自动提交功能!这是保证数据一致性的关键一步 psInsert = conn.prepareStatement(insertSql);// 【准备插入语句】预编译第一条 SQL(插入新闻) psInsert.setInt(1, userId);// 【设置参数】依次为占位符赋值:用户ID、标题、内容 psInsert.setString(2, title); psInsert.setString(3, content); psInsert.executeUpdate();// 【执行插入】将新闻写入数据库(此时尚未真正落盘) psUpdate = conn.prepareStatement(updateSql);// 【准备更新语句】预编译第二条 SQL(增加用户发帖数) psUpdate.setInt(1, userId);// 【设置参数】指定要更新的用户 ID psUpdate.executeUpdate();// 【执行更新】增加发帖计数(同样尚未真正落盘) conn.commit(); // 提交事务,两步操作都成功后,统一提交!让所有修改真正生效 return true; // 【返回结果】全部顺利执行,返回 true 表示发布成功 } catch (SQLException e) {// 【捕获异常】如果上述任何一步发生错误(如插入成功但更新失败),进入此块 // 【回滚事务】检查连接是否存在,保证“插入新闻”和“更新用户发帖数”一致 if (conn != null) { try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } } e.printStackTrace(); return false; } finally { try { if (psInsert != null) psInsert.close(); } catch (SQLException e) {} try { if (psUpdate != null) psUpdate.close(); } catch (SQLException e) {} try { if (conn != null) conn.close(); } catch (SQLException e) {} } } }
5. 修改Main测试登录和发布新闻
-
具体内容如下:
package com.weitoutiao;// 【包声明】这是项目的根包,通常用于存放程序的启动类 Main import com.weitoutiao.dao.UserDAO;// 【导入 DAO 类】引入用户数据访问对象 import com.weitoutiao.dao.NewsDAO;// 【导入 DAO 类】引入新闻数据访问对象 import com.weitoutiao.entity.User;// 【导入实体类】引入 User 实体类,用于接收登录返回的数据 public class Main { public static void main(String[] args) { UserDAO userDAO = new UserDAO(); User user = userDAO.login("testuser", "123456");// 【调用登录方法】传入硬编码的用户名和密码进行验证 if (user != null) { System.out.println("登录成功,用户ID:" + user.getId()); NewsDAO newsDAO = new NewsDAO(); boolean published = newsDAO.publish(user.getId(), "我的第一条新闻", "内容"); System.out.println(published ? "发布成功" : "发布失败"); } else { System.out.println("登录失败"); } } }
6.运行测试
- 创建SpringBoot 3.1.5项目,配置数据库连接和MyBatis-Plus。
- 编写
HelloController验证项目启动。
二、核心知识点(简要)
- SpringBoot:自动配置,简化Spring应用开发。
- application.yml:配置文件,使用YAML格式。
- @RestController:标记控制器,返回JSON。
- MyBatis-Plus:增强MyBatis,简化数据库操作。
三、操作步骤
1. 创建项目
-
文件➡️新建➡️项目
-
配置如下:
配置完成后,点
下一步。 -
先选一下SpringBoot的版本,用3.5.15,依赖选这3个:Spring Web、MySQL Driver、Lombok。
-
选完之后,右侧会显示
已添加的依赖,最后点击创建
2. 添加MyBatis-Plus依赖(在pom.xml中):
-
添加的内容:
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-spring-boot3-starter</artifactId> <version>3.5.5</version> </dependency><!--告别繁琐的 Connection、PreparedStatement--> -
在
pom.xml中添加的位置如下,添加完之后点一下maven的刷新按钮,下载依赖,就不会红了。
3. 配置application.yml:
-
在
src/main/resources文件夹中,找到application.properties文件,重命名为application.yml -
其中内容改为:
#--JDBC:DBUtil # ======================== 服务器配置 ======================== server: port: 8080 # 【端口号】指定当前 Web 应用启动时监听的端口为 8080 # ======================== Spring 基础配置 ======================== spring: application: name: WeiTouTiao-SpringBoot # 【应用名称】为当前项目命名,方便在日志或注册中心中识别 datasource: # 【数据库连接 URL】指定 MySQL 数据库的地址、库名及连接参数 url: jdbc:mysql://localhost:3306/weitoutiao? #本机 3306 端口下的 weitoutiao 数据库 useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8 username: root # 【数据库账号】登录 MySQL 的用户名 password: root # 【数据库密码】登录 MySQL 的密码 driver-class-name: com.mysql.cj.jdbc.Driver # MyBatis-Plus 框架配置 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl map-underscore-to-camel-case: true global-config: db-config: id-type: auto # 【逻辑删除字段】指定表中用于标记“是否被删除”的字段名为 deleted logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0
4.编写HelloController:
-
右键
com.weitoutiao包名,新建controller.HelloController类 -
HelloController类中的代码如下:
// 【包声明】表明该类属于 controller(控制)层,专门负责处理前端请求 package com.weitoutiao.controller; import org.springframework.web.bind.annotation.GetMapping;// 【导入注解】引入 GET 请求映射注解 import org.springframework.web.bind.annotation.RestController;// 【导入注解】引入 REST 控制器注解 // 【REST 控制器注解】这是一个组合注解(相当于 @Controller + @ResponseBody) // 作用1:告诉 Spring 这是一个处理 Web 请求的控制器类,并将其注册到容器中 // 作用2:将该类中所有方法的返回值直接作为 HTTP 响应体(通常是 JSON 或纯文本)返回给前端 @RestController public class HelloController { @GetMapping("/hello")// 【GET 请求映射】限定该方法只处理 GET 类型的 HTTP 请求 public String hello() { // 当浏览器或前端访问 http://localhost:8080/hello 时,就会触发这个方法 return "微头条后端启动成功!";// 【返回响应】将字符串直接写入 HTTP 响应体中 } }
5.运行测试
-
找到主程序,点击运行
-
可以看到主程序的返回值,说明程序运行成功。
核心知识点
LambdaQueryWrapper:类型安全的查询条件构造器。
*分页插件**:自动拦截SQL添加LIMIT,并查询总记录数。
Page:分页参数对象。
三、操作步骤
-
创建分页配置类:
右键
com.weitoutiao,创建config.MyBatisPlusConfig类类中代码如下:
package com.weitoutiao.config; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MyBatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 创建分页插件并指定数据库类型(根据实际使用的数据库选择) PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor(DbType.MYSQL); // 可选:超出最大页码时是否处理(false表示返回空数据,true表示返回最后一页) paginationInterceptor.setOverflow(false); // 将分页插件添加到拦截器容器[reference:0] interceptor.addInnerInterceptor(paginationInterceptor); return interceptor; } } -
创建Service(使用MyBatis-Plus的IService):
右键
com.weitoutiao,创建service.NewsService类NewsService中的代码如下:package com.weitoutiao.service; import com.baomidou.mybatisplus.extension.service.IService; import com.weitoutiao.entity.News; public interface NewsService extends IService<News> { }右键
service,创建impl.NewsServiceImpl的实现类NewsServiceImpl中的代码如下:package com.weitoutiao.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.weitoutiao.entity.News; import com.weitoutiao.mapper.NewsMapper; import com.weitoutiao.service.NewsService; import org.springframework.stereotype.Service; @Service public class NewsServiceImpl extends ServiceImpl<NewsMapper, News> implements NewsService { } -
测试分页
打开
test文件夹中的testSelect文件,在代码最后添加如下测试代码:@SpringBootTest class NewsServiceTest { @Autowired private NewsService newsService; @Test void testPage() { Page<News> page = new Page<>(1, 5);// 第1步:准备分页参数(我要第1页,每页5条) LambdaQueryWrapper<News> wrapper = new LambdaQueryWrapper<>();// 创建条件构造器(一个装条件的盒子) wrapper.orderByDesc(News::getPublishTime);//放条件:按发布时间排序 Page<News> result = newsService.page(page, wrapper);// 调用 Service 的分页方法,把分页参数和条件盒子一起传进去 System.out.println("总记录数:" + result.getTotal()); System.out.println("当前页数据:" + result.getRecords()); } }红色错误的代码,可以鼠标悬停到错误位置上,选择导入类即可解决
点击
testPage旁边的运行按钮,进行测试会报如下错误:
因为 MyBatis-Plus 开启了逻辑删除功能,但
news表中没有deleted字段。 -
所以需要打开
SQLyog, 在查询中执行如下语句ALTER TABLE `news` ADD COLUMN `deleted` TINYINT DEFAULT 0 COMMENT '逻辑删除(0未删除,1已删除)';在
SQLyog中,先选中该条语句,再点击执行点刷新,表中就会多一列
deleted -
回到IDEA中,再执行
testPage的测试,还会报如下错误需要在
SQLyog中再执行如下语句:ALTER TABLE `news` ADD COLUMN `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'; -
回到IDEA中,再执行
testPage的测试,程序log已成功打印
浙公网安备 33010602011771号