JavaWeb中点赞功能的实现及完整实例
实现原理
1、功能描述:一个用户对同一文章只能点赞一次,第二次就是取消赞
2、建立一个点赞表great,字段有文章ID(aid),点赞用户ID(uid)
3、当有用户进行点赞行为时,使用aid和uid搜索点赞表。
若有该记录,则表示用户已经点过赞,本次点击是取消点赞行为,故删除great表中的该条记录,同时将该文章的点赞数减1。
若无该记录,则表示用户是要点赞,故在great表中添加该记录,同时该文章的点赞数加1。
核心代码分析
核心控制器BaseController:
@Controller
public class BaseController {
private final GreatRepository greatRepository;
private final ArticleRepository articleRepository;
//Spring团队推荐的做法是用构造器来引入依赖,而不是直接使用@Autowired引入
@Autowired
public BaseController(GreatRepository greatRepository,
ArticleRepository articleRepository) {
this.greatRepository = greatRepository;
this.articleRepository=articleRepository;
}
@RequestMapping({"/","/index"})
public String index(){
return "index";
}
//添加事务支持
@Transactional
@RequestMapping("/great")
public String great(@Param("aid") int aid, @Param("uid") int uid, Model model){
//查询是否有该用户对该文章的点赞记录
List<Great> list=greatRepository.findByAidAndUid(aid,uid);
if (list!=null && list.size()>0){
//如果找到了这条记录,则删除该记录,同时文章的点赞数减1
Great great=list.get(0);
//删除记录
greatRepository.delete(great.getId());
//文章点赞数减1,查询时使用Mysql行级锁解决并发覆盖问题
Article article=articleRepository.findByIdForUpdate(aid);
article.setGreatNum(article.getGreatNum()-1);
articleRepository.saveAndFlush(article);
}else {
//如果没有找到这条记录,则添加这条记录,同时文章点赞数加1
Great great=new Great();
great.setAid(aid);
great.setUid(uid);
//添加记录
greatRepository.saveAndFlush(great);
//文章点赞数加1,查询时使用Mysql行级锁解决并发覆盖问题
Article article=articleRepository.findByIdForUpdate(aid);
article.setGreatNum(article.getGreatNum()+1);
articleRepository.saveAndFlush(article);
}
model.addAttribute("details",articleRepository.findAll());
return "detail";
}
}
Aritcle实体的持久化仓库ArticleRepository
@Repository
public interface ArticleRepository extends JpaRepository<Article,Integer>{
@Lock(value = LockModeType.PESSIMISTIC_WRITE)
Article findByIdForUpdate(Integer id);
}
注意其中使用了@Lock注解以及 LockModeType.PESSIMISTIC_WRITE来让JPA使用数据库层的行级锁,在事务中,该行级锁能解决对同一条记录的并发修改问题。
代码中已经附有详细注解
完整实例的相关信息
为了突出重点,项目前端较为简陋,功能已经通过测试。
项目采用的框架:
1、容器框架:SpringBoot
2、持久层框架:Spring Data JPA
3、渲染框架:Thymeleaf
4、版本控制:Git
5、依赖:Maven
6、数据库:Mysql
数据库建表文件Schema.sql:
DROP TABLE IF EXISTS `article`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `article` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`num` int(11) DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `article`
--
LOCK TABLES `article` WRITE;
/*!40000 ALTER TABLE `article` DISABLE KEYS */;
INSERT INTO `article` VALUES (1,1),(2,0);
/*!40000 ALTER TABLE `article` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `great`
--
DROP TABLE IF EXISTS `great`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `great` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`aid` int(11) NOT NULL,
`uid` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `great`
--
LOCK TABLES `great` WRITE;
/*!40000 ALTER TABLE `great` DISABLE KEYS */;
INSERT INTO `great` VALUES (5,1,1);
/*!40000 ALTER TABLE `great` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
特别说明:本文章的目的只是单纯向大家说明点赞这个功能的实现思路。为了保证逻辑尽量清晰和简单,因而并没有涉及到性能优化。示例代码中的锁机制能保证并发访问下的安全性,但会对系统并发性能产生一定的影响,但在一般系统中,由于大量用户同时对同一文章集中点赞的情况并不常见,因此性能损耗扔在可以接受的范围内。
如果大家在使用过程中确实有高并发的需要,那么可以考虑使用Redis这类缓存数据库来替代mysql。Redis是高性能的内存KV数据库,且是单线程运行的,因此性能和安全性问题都能得到完美的解决。
关于JPA中如何使用行级锁,可以参考这篇文章:https://blog.csdn.net/fengyuxue11011/article/details/47039765
JavaWeb中点赞功能的实现及完整实例的更多相关文章
- JavaWeb中登陆功能
首先我们要JavaWeb登陆的基本流程:JSP页面发送请求-->Servlet-->Servlet通过调用方法从数据库中得到数据并将结果返回页面 我们先建立三个jsp页面,包括login. ...
- JavaWeb中的文件上传和下载功能的实现
导入相关支持jar包:commons-fileupload.jar,commons-io.jar 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用Servlet获取上 ...
- 全栈项目|小书架|服务器端-NodeJS+Koa2 实现点赞功能
效果图 接口分析 通过上面的效果图可以看出,点赞入口主要是在书籍的详情页面. 而书籍详情页面,有以下几个功能是和点赞有关的: 获取点赞状态 点赞 取消点赞 所以项目中理论上与点赞相关的接口就以上三个. ...
- Qt调用dll中的功能函数
声明: 事先我已经自己动手写了一个简单的dll文件(myDLL.dll),C版接口的.并且用我前两篇有关DLL文章里面的方法,从dll中导出了导入库(.lib)文件,dll中有两个函数,原型如下: ...
- 在Javaweb中使用Scala
Java 是一门比较优秀的编程语言, 其最大功劳是建立非常繁荣的JVM平台生态.不过 Java 语法比较麻烦,写过 C, Python 的人总是想使用简洁的语法,又希望利用上 Java 平台的强大,因 ...
- 在javaweb中通过servlet类和普通类读取资源文件
javaweb有两种方式读取资源文件 在Servlet中读取,可以使用servletContext,servletContext可以拿到web所有的资源文件,然后随便读,但是这种方法不常用,尽量少在S ...
- JavaScript实现评论点赞功能
通过分析评论功能的逻辑关系,学会如何使用JavaScript实现评论.回复.点赞等各种功能 1.学会JavaScript处理日期和时间. 2.掌握Dom操作中的添加/删除子节点方法. 3.使用setT ...
- JavaScript cookie操作实现点赞功能
JavaScript cookie操作实现点赞功能 参考实现原理,但是代码不够简洁,简洁代码参考:js操作cookie 实现一个点赞功能十分简单,主要问题在于不能重复点赞. 若是一个有用户的网站,可 ...
- JavaWeb中监听器+过滤器+拦截器区别、配置和实际应用
JavaWeb中监听器+过滤器+拦截器区别.配置和实际应用 1.前沿上一篇文章提到在web.xml中各个元素的执行顺序是这样的,context-param-->listener-->fil ...
随机推荐
- C语言中变量和函数的作用域和链接属性
C语言中变量和函数的作用域和链接属性 作用域 代码块作用域: 代码块指的是使用"{}"包围起来的部分. 在代码块中定义的变量,代码块之外是不能访问的. 代码块嵌套之后的变量作用域, ...
- JSP知识总结
day11 JSP入门 1 JSP概述 1.1 什么是JSP JSP(Java Server Pages)是JavaWeb服务器端的动态资源.它与html页面的作用是相同的,显示数据和获取数据. 1. ...
- CAS你知道吗?原子类AtomicInteger的ABA问题谈谈?
(1)CAS是什么? 比较并交换 举例1, CAS产生场景代码? import java.util.concurrent.atomic.AtomicInteger; public class CA ...
- Pwnable-blackjack
游戏源码 http://cboard.cprogramming.com/c-programming/114023-simple-blackjack-program.html 打开之后是一个游戏 你有5 ...
- sql 代码优化
1. where 执行顺序:右→左,筛选多的放右边:计算难度小的放右边,sql老版本(只在基于规则的优化器中有效,新版本基于代价不存在这个问题): 2. 少用子查询: 3. union快,表结构得一致 ...
- 在Python中用许多点找到两个最远点的点
我需要找到距离彼此最远的两个点. 正如屏幕截图所示,我有一个包含其他两个数组的数组.一个用于X,一个用于Y坐标.确定数据中最长线的最佳方法是什么?通过这样说,我需要选择情节中最远的两个点.希望你们能帮 ...
- 如何对jmeter设置IP欺骗
由于服务器出于安全考虑会对同一IP地址做过滤,所以如果想要达到正常的压测效果,我们需要在发请求时伪造出不同的IP地址.主要步骤分为以下3步:第一步:在负载机上绑定IP地址. 第二步:在要欺骗的http ...
- 【oracle】update
- 【2019.8.11上午 慈溪模拟赛 T3】欢迎回来(back)(设阈值+莫队)
设阈值 考虑对于询问的\(d\)设阈值进行分别处理. 对于\(d\le\sqrt{max\ d}\)的询问,我们可以\(O(n\sqrt{max\ d})\)预处理答案,\(O(1)\)输出. 对于\ ...
- PyCharm2019.3.1专业版激活
PyCharm2019.3.1专业版激活 Python的IDE非常多,但个人感觉PyCharm最好用.JetBrains 致力于为开发者打造最高效智能的开发工具,与2019.12.19带来新的版本20 ...