Java高并发秒杀系统【观后总结】(一)

简介: 在慕课网上发现了一个JavaWeb项目,内容讲的是高并发秒杀,觉得挺有意思的,就进去学习了一番。

项目简介

在慕课网上发现了一个JavaWeb项目,内容讲的是高并发秒杀,觉得挺有意思的,就进去学习了一番。

记录在该项目中学到了什么玩意..

该项目源码对应的gitHub地址(由观看其视频的人编写,并非视频源代码):https://github.com/codingXiaxw/seckill

我结合其资料和观看视频的时候整理出从该项目学到了什么…

项目Dao层

日志记录工具:

<!--1.日志 java日志有:slf4j,log4j,logback,common-logging
        slf4j:是规范/接口
        日志实现:log4j,logback,common-logging
        使用:slf4j+logback
    -->

Mybatis之前没注意到的配置属性:

使用jdbc的getGeneratekeys获取自增主键值,这个属性还是挺有用的。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--配置全局属性-->
    <settings>
        <!--使用jdbc的getGeneratekeys获取自增主键值-->
        <setting name="useGeneratedKeys" value="true"/>
        <!--使用列别名替换列名  默认值为true
        select name as title(实体中的属性名是title) form table;
        开启后mybatis会自动帮我们把表中name的值赋到对应实体的title属性中
        -->
        <setting name="useColumnLabel" value="true"/>
        <!--开启驼峰命名转换Table:create_time到 Entity(createTime)-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
</configuration>

Mybatis返回的对象如果有关联字段,除了使用resultMap还有下面这种方式(虽然我还是觉得resultMap会方便一点)

<select id="queryByIdWithSeckill" resultType="SuccessKilled">
        <!--根据seckillId查询SuccessKilled对象,并携带Seckill对象-->
        <!--如何告诉mybatis把结果映射到SuccessKill属性同时映射到Seckill属性-->
        <!--可以自由控制SQL语句-->
        SELECT
            sk.seckill_id,
            sk.user_phone,
            sk.create_time,
            sk.state,
            s.seckill_id "seckill.seckill_id",
            s.name "seckill.name",
            s.number "seckill",
            s.start_time "seckill.start_time",
            s.end_time "seckill.end_time",
            s.create_time "seckill.create_time"
        FROM success_killed sk
        INNER JOIN seckill s ON sk.seckill_id=s.seckill_id
        WHERE sk.seckill_id=#{seckillId}
        AND sk.user_phone=#{userPhone}
    </select>

数据库连接池可能用到的属性:

<!--c3p0私有属性-->
        <property name="maxPoolSize" value="30"/>
        <property name="minPoolSize" value="10"/>
        <!--关闭连接后不自动commit-->
        <property name="autoCommitOnClose" value="false"/>
        <!--获取连接超时时间-->
        <property name="checkoutTimeout" value="1000"/>
        <!--当获取连接失败重试次数-->
        <property name="acquireRetryAttempts" value="2"/>

spring与Junit整合:

/**
 * Created by codingBoy on 16/11/27.
 * 配置spring和junit整合,这样junit在启动时就会加载spring容器
 */
@RunWith(SpringJUnit4ClassRunner.class)
//告诉junit spring的配置文件
@ContextConfiguration({"classpath:spring/spring-dao.xml"})
public class SeckillDaoTest {
    //注入Dao实现类依赖
    @Resource
    private SeckillDao seckillDao;
    @Test
    public void queryById() throws Exception {
        long seckillId=1000;
        Seckill seckill=seckillDao.queryById(seckillId);
        System.out.println(seckill.getName());
        System.out.println(seckill);
    }
}

Mybatis参数为一个以上时

之前在学习MyBatis的时候,如果参数超过了一个,那么是使用Map集合来进行装载的!

在这次教程中发现,可以不用Map集合(如果都是基本数据类型)!

例子:使用@Param就行了!

int reduceNumber(@Param("seckillId") long seckillId, @Param("killTime") Date killTime);

在XML文件中可以直接忽略parameterType了!

避免重复插入数据时抛出异常

如果主键重复插入数据的时候,Mybatis正常是会抛出异常的,我们又不希望它抛出异常,那么我们可以这样做:

写ignore..

微信图片_20220411225639.jpg

Service层

tdo

一个dto包作为传输层,dto和entity的区别在于:entity用于业务数据的封装,而dto用于完成web和service层的数据传递。

对于dto这个概念,在之前我是接触过一次的,但是没有好好地实践起来。这次看到了它的用法了。

我的理解是:Service与Web层数据传递数据的再包装了一个对象而已。因为很多时候Service层返回的数据如果使用的是POJO,POJO很多的属性是多余的,还有一些想要的数据又包含不了。此时,dto又可以再一次对要传输的数据进行抽象,封装想获取的数据

定义多个异常对象

之前的异常对象都是针对整个业务的,其实还是可以细分多个异常类的出来的。比如“重复秒杀”,”秒杀关闭“这些都是属于秒杀的业务。

这样做的好处就是看到抛出的异常就能够知道是具体哪部分错了。

对于视频中在Service层就catch住了很多异常,我觉得可以在Service层直接抛出,在Controller也能抛出,直接使用统一异常处理器类来管理会更加方便!

微信图片_20220411225644.jpg

提倡使用注解方式使用事务

微信图片_20220411225816.jpg

微信图片_20220411225841.jpg

我觉得就是代码更加清晰吧,使用注解的话。

在视频下面还有同学说如果在Service中调用事务方法会有些坑,我暂时还没遇到过。先存起来吧:

并发性上不去是因为当多个线程同时访问一行数据时,产生了事务,因此产生写锁,每当一个获取了事务的线程把锁释放,另一个排队线程才能拿到写锁,QPS和事务执行的时间有密切关系,事务执行时间越短,并发性越高,这也是要将费时的I/O操作移出事务的原因。

关于同类中调用事务方法的时候有个坑,同学们需要注意下AOP切不到调用事务方法。事务不会生效,解决办法有几种,可以搜一下,找一下适合自己的方案。本质问题时类内部调用时AOP不会用代理调用内部方法。

“关于同类中调用事务方法的时候有个坑”  解决方案

1、如果是基于接口动态代理 是没有问题的,直接使用接口调用

2、如果是基于class的动态代理 可以用 AopContext.currentProxy()  解决,注意剥离方法一定是public 修饰 !!

相关实践学习
通过日志服务实现云资源OSS的安全审计
本实验介绍如何通过日志服务实现云资源OSS的安全审计。
目录
相关文章
|
4月前
|
设计模式 消息中间件 传感器
Java 设计模式之观察者模式:构建松耦合的事件响应系统
观察者模式是Java中常用的行为型设计模式,用于构建松耦合的事件响应系统。当一个对象状态改变时,所有依赖它的观察者将自动收到通知并更新。该模式通过抽象耦合实现发布-订阅机制,广泛应用于GUI事件处理、消息通知、数据监控等场景,具有良好的可扩展性和维护性。
414 8
|
4月前
|
移动开发 监控 小程序
java家政平台源码,家政上门清洁系统源码,数据多端互通,可直接搭建使用
一款基于Java+SpringBoot+Vue+UniApp开发的家政上门系统,支持小程序、APP、H5、公众号多端互通。涵盖用户端、技工端与管理后台,支持多城市、服务分类、在线预约、微信支付、抢单派单、技能认证、钱包提现等功能,源码开源,可直接部署使用。
340 24
|
4月前
|
安全 前端开发 Java
使用Java编写UDP协议的简易群聊系统
通过这个基础框架,你可以进一步增加更多的功能,例如用户认证、消息格式化、更复杂的客户端界面等,来丰富你的群聊系统。
217 11
|
4月前
|
机器学习/深度学习 人工智能 自然语言处理
Java与生成式AI:构建内容生成与创意辅助系统
生成式AI正在重塑内容创作、软件开发和创意设计的方式。本文深入探讨如何在Java生态中构建支持文本、图像、代码等多种生成任务的创意辅助系统。我们将完整展示集成大型生成模型(如GPT、Stable Diffusion)、处理生成任务队列、优化生成结果以及构建企业级生成式AI应用的全流程,为Java开发者提供构建下一代创意辅助系统的完整技术方案。
283 10
|
4月前
|
人工智能 监控 Java
Java与AI智能体:构建自主决策与工具调用的智能系统
随着AI智能体技术的快速发展,构建能够自主理解任务、制定计划并执行复杂操作的智能系统已成为新的技术前沿。本文深入探讨如何在Java生态中构建具备工具调用、记忆管理和自主决策能力的AI智能体系统。我们将完整展示从智能体架构设计、工具生态系统、记忆机制到多智能体协作的全流程,为Java开发者提供构建下一代自主智能系统的完整技术方案。
661 4
|
4月前
|
机器学习/深度学习 分布式计算 Java
Java与图神经网络:构建企业级知识图谱与智能推理系统
图神经网络(GNN)作为处理非欧几里得数据的前沿技术,正成为企业知识管理和智能推理的核心引擎。本文深入探讨如何在Java生态中构建基于GNN的知识图谱系统,涵盖从图数据建模、GNN模型集成、分布式图计算到实时推理的全流程。通过具体的代码实现和架构设计,展示如何将先进的图神经网络技术融入传统Java企业应用,为构建下一代智能决策系统提供完整解决方案。
467 0
|
5月前
|
JavaScript Java 大数据
基于JavaWeb的销售管理系统设计系统
本系统基于Java、MySQL、Spring Boot与Vue.js技术,构建高效、可扩展的销售管理平台,实现客户、订单、数据可视化等全流程自动化管理,提升企业运营效率与决策能力。
|
5月前
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案
|
5月前
|
安全 Cloud Native Java
Java 模块化系统(JPMS)技术详解与实践指南
本文档全面介绍 Java 平台模块系统(JPMS)的核心概念、架构设计和实践应用。作为 Java 9 引入的最重要特性之一,JPMS 为 Java 应用程序提供了强大的模块化支持,解决了长期存在的 JAR 地狱问题,并改善了应用的安全性和可维护性。本文将深入探讨模块声明、模块路径、访问控制、服务绑定等核心机制,帮助开发者构建更加健壮和可维护的 Java 应用。
414 0
|
5月前
|
NoSQL Java 关系型数据库
超全 Java 学习路线,帮你系统掌握编程的超详细 Java 学习路线
本文为超全Java学习路线,涵盖基础语法、面向对象编程、数据结构与算法、多线程、JVM原理、主流框架(如Spring Boot)、数据库(MySQL、Redis)及项目实战等内容,助力从零基础到企业级开发高手的进阶之路。
427 1