在并发数据连接超时问题

本文探讨了在高并发环境下,如何解决优惠券券号生成时的重复问题,采用线程安全的随机数生成策略,有效避免了券号重复,并显著提升了系统性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近遇到一个高并发的问题,当初的需求优惠券券号是按照 日期 DateTime.Now.ToString("yyyyMMddHHmmss")  + 最大订单号+1 的方式去新增券号的。

由于业务里面还涉及到多张表操作,用了事务。

第一版上线:  发现 很多订单号重复,找到原因是因为 在并发量高的时候,从数据库获取最大订单号时会产生并发,最新的单号没有新增到数据库,另一个线程已经从数据库查询到最大订单号,这样两个订单号 就是相同的。

为了解决这个问题 ,于是,第二个版本产生。

第二版上线:在获取单号到 新增数据库这段代码加入了锁。

代码如下:

private static object objlock = new object();

lock (objlock)
         {   主体代码     }

这样跟踪了一天,发现不会产生重复的订单号 ,但是过了几天发现另外一个更加严重的问题:一旦并发量达到一定量的时候,这个方法就越来越慢,从最开始的10几毫秒,慢慢到几百毫秒,然后要十几秒,一百秒,然后服务就直接挂了。并且会影响到其他负载均衡到的几台服务器都挂掉。

 通过日志跟代码的分析,发现 在新增券的代码里面原先用到了事务。然后在事务里面又新增了锁。这是一个矛盾的地方,这样直接导致代码性能下降的很快。为了解决这个问题,于是再次修改代码

第三版上线:

  1:为了解决线程池超时问题,必须立刻把锁解除,于是把锁的那段代码注释。

  2:为了解决券号重复的问题,使用随机数来算,字符串+ DateTime.Now.ToString("yyyyMMddHHmmss")+随机数

注意随机数的获取方式,正常清空大家都会直接: 

Random rad = new Random();//实例化随机数产生器rad;
 int value = rad.Next(1000, 10000);//用rad生成大于等于1000,小于等于9999的随机数;

这样获取随机数,但是随机数获取机制是:

在.NET中,随机数一般是用Random来获取,但是当在多任务的并行化编程时,问题就出现了。因为Random是基于时间作为种子来生成伪随机数的,而如果程序在多核并行时,在同一时间内的多个核中取到的时间是一样的,这样一来,生成的伪随机数就有可能会有一样的。如果业务需求中需要不可重复的随机数,那么这后果将会相当严重
 所以不能直接用以上代码获取 随机数。

所以必须采取一种新的方式来获取线程安全的伪随机数。

于是用  RNGCryptoServiceProvider的加密随机生成器,再用其中的强随机序列的方法GetBytes来实现随机。

代码如下:   调用 GetRandomNumber方法 ,参数是随机数的长度,需要几位数 参数就是多少。

 public static string GetRandomNumber(int length)
        {
            string strPwd = string.Empty;
            Random rd = new Random(GetRandomSeed());
            for (int i = 0; i < length; i++)
            {
                strPwd += rd.Next(10).ToString();
            }

            return strPwd;
        }


        public static int GetRandomSeed()
        {
            byte[] bytes = new byte[4];
            System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider();
            rng.GetBytes(bytes);
            return BitConverter.ToInt32(bytes, 0);
        }
 

总结:这样修改后,后面就不会再出现重复的优惠券单号。  并且原先高峰期的要几秒,几十秒的时间 回落到 100毫秒以内。

 

### 解决高并发场景下数据连接超时的方法 #### 优化数据库配置参数 调整数据库的最大连接数、连接池大小以及等待时间等参数可以有效缓解高并发带来的压力。通过合理设置这些参数,可以在不影响性能的前提下支持更多的并发请求。 对于MySQL而言,可以通过修改`max_connections`来增加最大允许的同时连接数量;而对于PostgreSQL,则应关注`max_connections`和`shared_buffers`等关键配置项[^4]。 #### 使用分布式缓存减轻负载 引入Redis或Memcached这样的内存级数据存储服务作为前置缓存层,能够显著降低直接访问关系型数据库的压力。当面对大量读取操作时尤为明显——许多热点查询可以直接从缓存获取结果而无需每次都去查表。 此外,在写入方面也可以采取先记录到消息队列再异步处理的方式,从而实现削峰填谷的效果[^2]. #### 实施分库分表策略 随着业务量的增长,单体架构下的数据库往往会成为瓶颈所在。此时可考虑按照一定规则拆分成多个子库甚至更细粒度上的分区表格结构来进行扩展。这不仅有助于提高吞吐率还能增强系统的可用性和稳定性。 具体来说,水平切分(Sharding)是指依据特定字段值范围划分不同物理位置的数据集;垂直分割则是指根据不同功能模块分离成独立的服务单元. #### 构建合理的中间件机制 采用诸如MyBatis Plus之类的持久化框架可以帮助简化SQL语句编写并提供自动化的CRUD接口调用能力。更重要的是其内置的支持事务管理特性使得复杂业务逻辑变得易于控制而不必担心因频繁开启关闭链接造成资源浪费。 另外像HikariCP这类高性能JDBC连接池组件同样值得推荐给Java开发者们用于提升应用程序同后台交互效率. ```java // HikariCP 配置实例 HikariConfig config = new HikariConfig(); config.setMaximumPoolSize(50); // 设置最大连接数 config.setMinimumIdle(10); // 最小空闲连接数 config.setConnectionTimeout(30000L); // 连接超时时长 (毫秒) DataSource dataSource = new HikariDataSource(config); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值