我的编程空间,编程开发者的网络收藏夹
学习永远不晚

springboot+websocket怎样实现并发抢红包功能

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

springboot+websocket怎样实现并发抢红包功能

这期内容当中小编将会给大家带来有关springboot+websocket怎样实现并发抢红包功能,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。

概述

抢红包功能作为几大高并发场景中典型,应该如何实现?

分析

参考微信抢红包功能,将抢红包分成一下几个步骤:

  • 发红包;主要填写红包信息,生成红包记录

  • 红包支付回调;用户发红包支付成功后,收到微信支付付款成功的回调,生成指定数量的红包。

  • 抢红包;用户并发抢红包。

  • 拆红包;记录用户抢红包记录,转账抢到的红包金额。

 效果展示

项目使用sessionId模拟用户,示例打开俩个浏览器窗口模拟两个用户。

springboot+websocket怎样实现并发抢红包功能

设计开发

表结构设计

红包记录在 redpacket 表中,用户领取红包详情记录在 redpacket_detail 表中。

CREATE DATABASE  `redpacket`;use `redpacket`;CREATE TABLE `redpacket`.`redpacket` (  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',  `packet_no` varchar(32) NOT NULL COMMENT '订单号',  `amount` decimal(5,2) NOT NULL COMMENT '红包金额最高10000.00元',  `num` int(11) NOT NULL COMMENT '红包数量',  `order_status` int(4) NOT NULL DEFAULT '0' COMMENT '订单状态:0初始、1待支付、2支付成功、3取消',  `pay_seq` varchar(32) DEFAULT NULL COMMENT '支付流水号',  `create_time` datetime NOT NULL COMMENT '创建时间',  `user_id` varchar(32) NOT NULL COMMENT '用户ID',  `update_time` datetime NOT NULL COMMENT '更新时间',  `pay_time` datetime DEFAULT NULL COMMENT '支付时间',  PRIMARY KEY (`id`)) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COMMENT='红包订单表';CREATE TABLE `redpacket`.`redpacket_detail` (  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',  `packet_id` bigint(20) NOT NULL COMMENT '红包ID',  `amount` decimal(5,2) NOT NULL COMMENT '红包金额',  `received` int(1) NOT NULL DEFAULT '0' COMMENT '是否领取0未领取、1已领取',  `create_time` datetime NOT NULL COMMENT '创建时间',  `update_time` datetime NOT NULL COMMENT '更新时间',  `user_id` varchar(32) DEFAULT NULL COMMENT '领取用户',  `packet_no` varchar(32) NOT NULL,  PRIMARY KEY (`id`)) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COMMENT='红包详情表';

发红包设计

用户需要填写红包金额、红包数量、备注信息等,生成红包记录,微信收银台下单,返回用户支付。

public RedPacket generateRedPacket(ReqSendRedPacketsVO data,String userId) {    final BigDecimal amount = data.getAmount();    //红包数量    final Integer num = data.getNum();    //初始化订单    final RedPacket redPacket = new RedPacket();    redPacket.setPacketNo(UUID.randomUUID().toString().replace("-", ""));    redPacket.setAmount(amount);    redPacket.setNum(num);    redPacket.setUserId(userId);    Date now = new Date();    redPacket.setCreateTime(now);    redPacket.setUpdateTime(now);    int i = redPacketMapper.insertSelective(redPacket);    if (i != 1) {        throw new ServiceException("生成红包出错", ExceptionType.SYS_ERR);    }    //模拟收银台下单    String paySeq = UUID.randomUUID().toString().replace("-", "");    //拿到收银台下单结果,更新订单为待支付状态    redPacket.setOrderStatus(1);//待支付    redPacket.setPaySeq(paySeq);    i = redPacketMapper.updateByPrimaryKeySelective(redPacket);    if (i != 1) {        throw new ServiceException("生成红包出错", ExceptionType.SYS_ERR);    }    return redPacket;}

springboot+websocket怎样实现并发抢红包功能

红包支付成功回调设计

用户支付成功后,系统接收到微信回调接口。

更新红包支付状态
二倍均值法生成指定数量红包,并批量入库。 红包算法参考:Java实现4种微信抢红包算法
红包总数入redis,设置红包过期时间24小时
websocket通知在线用户收到新的红包

@Transactional(rollbackFor = Exception.class)public void dealAfterOrderPayCallback(String userId,ReqOrderPayCallbackVO data) {    RedPacketExample example = new RedPacketExample();    final String packetNo = data.getPacketNo();    final String paySeq = data.getPaySeq();    final Integer payStatus = data.getPayStatus();    example.createCriteria().andPacketNoEqualTo(packetNo)            .andPaySeqEqualTo(paySeq)            .andOrderStatusEqualTo(1);//待支付状态    //更新订单支付状态    Date now = new Date();    RedPacket updateRedPacket = new RedPacket();    updateRedPacket.setOrderStatus(payStatus);    updateRedPacket.setUpdateTime(now);    updateRedPacket.setPayTime(now);    int i = redPacketMapper.updateByExampleSelective(updateRedPacket, example);    if (i != 1) {        throw new ServiceException("订单状态更新失败", ExceptionType.SYS_ERR);    }    if (payStatus == 2) {        RedPacketExample query = new RedPacketExample();        query.createCriteria().andPacketNoEqualTo(packetNo)                .andPaySeqEqualTo(paySeq)                .andOrderStatusEqualTo(2);        final RedPacket redPacket = redPacketMapper.selectByExample(query).get(0);        final List<BigDecimal> detailList = getRedPacketDetail(redPacket.getAmount(), redPacket.getNum());        final int size = detailList.size();        if (size <= 100) {            i = detailMapper.batchInsert(detailList, redPacket);            if (size != i) {                throw new ServiceException("生成红包失败", ExceptionType.SYS_ERR);            }        } else {            int times = size % 100 == 0 ? size / 100 : (size / 100 + 1);            for (int j = 0; j < times; j++) {                int fromIndex = 100 * j;                int toIndex = 100 * (j + 1) - 1;                if (toIndex > size - 1) {                    toIndex = size - 1;                }                final List<BigDecimal> subList = detailList.subList(fromIndex, toIndex);                i = detailMapper.batchInsert(subList, redPacket);                if (subList.size() != i) {                    throw new ServiceException("生成红包失败", ExceptionType.SYS_ERR);                }            }        }        final String redisKey = REDPACKET_NUM_PREFIX + redPacket.getPacketNo();        String lua = "local i = redis.call('setnx',KEYS[1],ARGV[1])\r\n" +                "if i == 1 then \r\n" +                "   local j = redis.call('expire',KEYS[1],ARGV[2])\r\n" +                "end \r\n" +                "return i";        //优化成lua脚本        final Long execute = redisTemplate.execute(new DefaultRedisScript<>(lua, Long.class), Arrays.asList(redisKey), size, 3600 * 24);        if (execute != 1L) {            throw new ServiceException("生成红包失败", ExceptionType.SYS_ERR);        }        //websocket通知在线用户收到新的红包        Websocket.sendMessageToUser(userId, JSONObject.toJSONString(redPacket));    }}private List<BigDecimal> getRedPacketDetail(BigDecimal amount, Integer num) {    List<BigDecimal> redPacketsList = new ArrayList<>(num);    //最小红包金额    final BigDecimal min = new BigDecimal("0.01");    //最少需要红包金额    final BigDecimal bigNum = new BigDecimal(num);    final BigDecimal atLastAmount = min.multiply(bigNum);    //出去最少红包金额后剩余金额    BigDecimal remain = amount.subtract(atLastAmount);    if (remain.compareTo(BigDecimal.ZERO) == 0) {        for (int i = 0; i < num; i++) {            redPacketsList.add(min);        }        return redPacketsList;    }    final Random random = new Random();    final BigDecimal hundred = new BigDecimal("100");    final BigDecimal two = new BigDecimal("2");    BigDecimal redPacket;    for (int i = 0; i < num; i++) {        if (i == num - 1) {            redPacket = remain;        } else {            //100内随机获得的整数            final int rand = random.nextInt(100);            redPacket = new BigDecimal(rand).multiply(remain.multiply(two).divide(bigNum.subtract(new BigDecimal(i)), 2, RoundingMode.CEILING)).divide(hundred, 2, RoundingMode.FLOOR);        }        if (remain.compareTo(redPacket) > 0) {            remain = remain.subtract(redPacket);        } else {            remain = BigDecimal.ZERO;        }        redPacketsList.add(min.add(redPacket));    }    return redPacketsList;}

页面加载成功后初始化websocket,监听后端新红包生成成功,动态添加红包到聊天窗口。

$(function (){    var websocket;    if('WebSocket' in window) {        console.log("此浏览器支持websocket");        websocket = new WebSocket("ws://127.0.0.1:8082/websocket/${session.id}");    } else if('MozWebSocket' in window) {        alert("此浏览器只支持MozWebSocket");    } else {        alert("此浏览器只支持SockJS");    }    websocket.onopen = function(evnt) {        console.log("链接服务器成功!")    };    websocket.onmessage = function(evnt) {        console.log(evnt.data);        var json = eval('('+evnt.data+ ')');        obj.addPacket(json.id,json.packetNo,json.userId)    };    websocket.onerror = function(evnt) {};    websocket.onclose = function(evnt) {        console.log("与服务器断开了链接!")    }});

抢红包设计

抢红包设计高并发,本地单机项目,通过原子Integer控制抢红包接口并发限制为20,

private AtomicInteger receiveCount = new AtomicInteger(0);@PostMapping("/receive")public CommonJsonResponse receiveOne(@Validated @RequestBody CommonJsonRequest<ReqReceiveRedPacketVO> vo) {    Integer num = null;    try {        //控制并发不要超过20        if (receiveCount.get() > 20) {            return new CommonJsonResponse("9999", "太快了");        }        num = receiveCount.incrementAndGet();        final String s = orderService.receiveOne(vo.getData());        return StringUtils.isEmpty(s) ? CommonJsonResponse.ok() : new CommonJsonResponse("9999", s);    } finally {        if (num != null) {            receiveCount.decrementAndGet();        }    }}

对于没有领取过该红包的用户,在红包没有过期且红包还有剩余的情况下,抢红包成功,记录成功标识入redis,设置标识过期时间为5秒。

public String receiveOne(ReqReceiveRedPacketVO data) {    final Long redPacketId = data.getPacketId();    final String redPacketNo = data.getPacketNo();    final String redisKey = REDPACKET_NUM_PREFIX + redPacketNo;    if (!redisTemplate.hasKey(redisKey)) {        return "红包已经过期";    }    final Integer num = (Integer) redisTemplate.opsForValue().get(redisKey);    if (num <= 0) {        return "红包已抢完";    }    RedPacketDetailExample example = new RedPacketDetailExample();    example.createCriteria().andPacketIdEqualTo(redPacketId)            .andReceivedEqualTo(1)            .andUserIdEqualTo(data.getUserId());    final List<RedPacketDetail> details = detailMapper.selectByExample(example);    if (!details.isEmpty()) {        return "该红包已经领取过了";    }    final String receiveKey = REDPACKET_RECEIVE_PREFIX + redPacketNo + ":" + data.getUserId();    //优化成lua脚本    String lua = "local i = redis.call('setnx',KEYS[1],ARGV[1])\r\n" +            "if i == 1 then \r\n" +            "   local j = redis.call('expire',KEYS[1],ARGV[2])\r\n" +            "end \r\n" +            "return i";    //优化成lua脚本    final Long execute = redisTemplate.execute(new DefaultRedisScript<>(lua, Long.class), Arrays.asList(receiveKey), 1, 5);    if (execute != 1L) {        return "太快了";    }    return "";}

拆红包设计

在用户抢红包成功标识未过期的状态下,且红包未过期红包未领完时,从数据库中领取一个红包,领取成功将领取记录写入redis以供查询过期时间为48小时。

@Transactional(rollbackFor = Exception.class)public String openRedPacket(ReqReceiveRedPacketVO data) {    final Long packetId = data.getPacketId();    final String packetNo = data.getPacketNo();    final String userId = data.getUserId();    final String redisKey = REDPACKET_NUM_PREFIX + packetNo;    Long num = null;    try {        final String receiveKey = REDPACKET_RECEIVE_PREFIX + packetNo + ":" + userId;        if (!redisTemplate.hasKey(receiveKey)) {            log.info("未获取到红包资格,packet:{},user:{}", packetNo, userId);            throw new ServiceException("红包飞走了", ExceptionType.SYS_ERR);        }        redisTemplate.delete(receiveKey);        if (!redisTemplate.hasKey(redisKey)) {            log.info("红包过期了,packet:{}", packetNo);            throw new ServiceException("红包飞走了", ExceptionType.SYS_ERR);        }        num = redisTemplate.opsForValue().increment(redisKey, -1);        if (num < 0L) {            log.info("红包领完了,packet:{}", packetNo);            throw new ServiceException("红包飞走了", ExceptionType.SYS_ERR);        }        final int i = detailMapper.receiveOne(packetId, packetNo, userId);        if (i != 1) {            log.info("红包真的领完了,packet:{}", packetNo);            throw new ServiceException("红包飞走了", ExceptionType.SYS_ERR);        }        RedPacketDetailExample example = new RedPacketDetailExample();        example.createCriteria().andPacketIdEqualTo(packetId)                .andReceivedEqualTo(1)                .andUserIdEqualTo(userId);        final List<RedPacketDetail> details = detailMapper.selectByExample(example);        if (details.size() != 1) {            log.info("已经领取过了,packet:{},user:{}", packetNo, userId);            throw new ServiceException("红包飞走了", ExceptionType.SYS_ERR);        }        //处理加款        log.info("抢到红包金额{},packet:{},user:{}", details.get(0).getAmount(), packetNo, userId);        final String listKey = REDPACKET_LIST_PREFIX + packetNo;        redisTemplate.opsForList().leftPush(listKey,details.get(0));        redisTemplate.expire(redisKey, 48, TimeUnit.HOURS);        return "" + details.get(0).getAmount();    } catch (Exception e) {        if (num != null) {            redisTemplate.opsForValue().increment(redisKey, 1L);        }        log.warn("打开红包异常", e);        throw new ServiceException("红包飞走了", ExceptionType.SYS_ERR);    }}

其中 detailMapper.receiveOne(packetId, packetNo, userId); sql如下,将指定红包记录下未领取的红包更新一条未当前用户已经领取,若成功更新一条则表示领取成功,否则领取失败。

update redpacket_detail dset received = 1,update_time = now(),user_id = #{userId,jdbcType=VARCHAR}where received = 0and packet_id = #{packetId,jdbcType=BIGINT}and packet_no = #{packetNo,jdbcType=VARCHAR}and user_id is nulllimit 1

获取红包领取记录设计

直接充redis中获取用户领取记录,没有则直接获取数据库并同步至redis。

public RespReceiveListVO receiveList(ReqReceiveListVO data) {    //红包记录redisKey    final String packetNo = data.getPacketNo();    final String redisKey = REDPACKET_LIST_PREFIX + packetNo;    if (!redisTemplate.hasKey(redisKey)) {        RedPacketDetailExample example = new RedPacketDetailExample();        example.createCriteria().andPacketNoEqualTo(packetNo)                .andReceivedEqualTo(1);        final List<RedPacketDetail> list = detailMapper.selectByExample(example);        redisTemplate.opsForList().leftPushAll(redisKey, list);        redisTemplate.expire(redisKey, 24, TimeUnit.HOURS);    }    List retList = redisTemplate.opsForList().range(redisKey, 0, -1);    final Object collect = retList.stream().map(item -> {        final JSONObject packetDetail = (JSONObject) item;        return ReceiveRecordVO.builder()                .amount(packetDetail.getBigDecimal("amount"))                .receiveTime(packetDetail.getDate("updateTime"))                .userId(packetDetail.getString("userId"))                .packetId(packetDetail.getLong("redpacketId"))                .packetNo(packetDetail.getString("redpacketNo"))                .build();    }).collect(Collectors.toList());    return RespReceiveListVO.builder().list((List) collect).build();}

jmeter并发测试抢红包、查红包接口

设置jmeter参数1秒中并发请求50个抢11个红包,可以看到,前面的请求都是成功的,中间并发量上来后有部分达到并发上限被拦截,后面红包抢完请求全部失败。

springboot+websocket怎样实现并发抢红包功能

springboot+websocket怎样实现并发抢红包功能

springboot+websocket怎样实现并发抢红包功能

springboot+websocket怎样实现并发抢红包功能

上述就是小编为大家分享的springboot+websocket怎样实现并发抢红包功能了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注编程网行业资讯频道。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

springboot+websocket怎样实现并发抢红包功能

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

springboot+websocket怎样实现并发抢红包功能

这期内容当中小编将会给大家带来有关springboot+websocket怎样实现并发抢红包功能,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。概述抢红包功能作为几大高并发场景中典型,应该如何实现?分析参考
2023-06-22

asp.net如何开发微信派发现金红包/H5网页抢红包功能

这篇文章将为大家详细讲解有关asp.net如何开发微信派发现金红包/H5网页抢红包功能,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一、网页版抢红包功能,1、前端先做好抢红包的页面;3、后台配置微信公众号
2023-06-14

Android微信抢红包功能的实现原理浅析

快到过农历年了,微信红包也越来越多了,出现了好多红包外挂程序,就很好奇如何实现的,于是自己研究了一番,亲自写了个微信抢红包的APP。现在就一步一步来实现它。 实现思路 微信抢红包程序开启时候,他就可以随时识别、捕获红包,服务可以实现正在功能
2022-06-06

使用JAVA怎么实现一个红包分发功能

本篇文章为大家展示了使用JAVA怎么实现一个红包分发功能,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。代码import java.util.Arrays;import java.util.Rando
2023-06-14

php代码怎么实现红包功能

PHP红包实现使用PHP语言,可以轻松实现红包功能,包括随机生成金额、分配、持久化数据和发放红包。通过生成随机金额、打乱分配、存储到数据库以及与第三方支付平台集成,PHP提供了高效且全面的红包解决方案。
php代码怎么实现红包功能
2024-04-25

php代码怎么实现红包功能

php代码实现红包功能的方法:1、通过distribute_red_bages方法实现拼手气红包;2、通过average_red_bages方法实现均分红包;3、通过rob_red_bages方法实现规定红包数。
2018-08-18

redis+mysql+quartz 一种红包发送功能的实现

概要: 这篇文章主要是对半年前开发的红包模块进行整理,把其中主要的设计思想以及具体的实现方案进行介绍,如有设计以及实现上的缺陷,或是存在漏洞,请大家批评指正! 红包功能大家都很熟悉了,那在这里就简单的对红包功能进行描述... 功能描述:红
2022-06-04

怎么用PHP+Ajax实现手机移动端发红包功能

本篇内容介绍了“怎么用PHP+Ajax实现手机移动端发红包功能”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!基本流程:当输入完红包数量和总金
2023-06-04

怎么在SpringBoot中利用WebSocket实现一个群聊功能

本篇文章为大家展示了怎么在SpringBoot中利用WebSocket实现一个群聊功能,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。消息群发创建新项目:添加依赖:
2023-06-06

php结合redis实现高并发下的抢购、秒杀功能的实例

抢购、秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个: 1 高并发对数据库产生的压力 2 竞争状态下如何解决库存的正确减少("超卖"问题) 对于第一个问题,已经很容易想到用缓存来处理抢购,避免直接操作数据库,例如使用Redis。
2022-06-04

Java与Netty怎样实现高性能高并发

本篇文章给大家分享的是有关Java与Netty怎样实现高性能高并发,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。1. 背景1.1. 惊人的性能数据最近一个圈内朋友通过私信告诉我
2023-06-04

springboot+vue组件开发怎么实现接口断言功能

本篇内容介绍了“springboot+vue组件开发怎么实现接口断言功能”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!基于 springbo
2023-06-30

使用springboot怎么样实现一个文件上传下载功能

这期内容当中小编将会给大家带来有关使用springboot怎么样实现一个文件上传下载功能,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。1.文件上传(前端页面):
2023-05-31

SpringBoot实现文件在线预览功能的过程是怎样的

SpringBoot实现文件在线预览功能的过程是怎样的,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。背景最近公司内部oa系统升级,需要增加文件在线预览服务,最常见的文件就是of
2023-06-25

SpringBoot中的利用Email发送功能怎么利用Thymeleaf实现

本篇文章为大家展示了SpringBoot中的利用Email发送功能怎么利用Thymeleaf实现,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。添加依赖(Mail starter dependenci
2023-05-31

SpringBoot+thymeleaf怎么实现读取视频列表并播放视频功能

这篇文章主要介绍了SpringBoot+thymeleaf怎么实现读取视频列表并播放视频功能的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇SpringBoot+thymeleaf怎么实现读取视频列表并播放视频功
2023-06-30

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录