2021-04-12

一、高并发的处理?

优化方案1:将库存字段number字段设为unsigned,当库存为0时,因为字段不能为负数,将会返回false

95f904f84a5a4f83f1f1f5416f51638c6c6.jpg

悲观锁思路 解决线程安全的思路很多,可以从“悲观锁”的方向开始讨论。
优化方案2:使用MySQL的事务,锁住操作的行

aaff019acdd2f7d0ad65c97f5c480770681.jpg

优化方案3:使用文件锁排它锁

flock函数用于获取文件的锁,这个锁同时只能被一个线程获取到,其它没有获取到锁的线程要么阻塞,要么获取失败。在获取到锁的时候,先查询库存,如果库存大于0,则进行下订单操作,减库存,然后释放锁。在现实应用中,很多情况下会把数据存入缓存,当缓存失效时,去数据库取数据并重新设置缓存,如果这时并发量很大,会有很多进程同时去数据库取数据,导致很多请求穿透到数据库,而使数据库奔溃,这里可用文件锁来解决。

1530676fe6b47f059d5964ec7ded759e693.jpg

优化方案4:使用队列(redis队列)

将用户的下单请求依次存入一个队列中,后台用一个单独的进程处理队列中的下单请求

优化方案5:使用Redis

redis的操作都是原子性的,可以将商品的库存存入redis中,下单之前对库存进行decr操作,如果返回的值大于等于0等可以下单,否则不能下单,这种方式效率较高。

if(redis->get(‘stock_num’) > 0){
stock_num = redis->decr(‘stock_num’)
if(stock_num >= 0){
//下订单
}else{
//库存不足
}
}else{
//库存不足
}

优化方案6:乐观锁思路

乐观锁,是相对于“悲观锁”采用更为宽松的加锁机制,大都是采用带版本号(Version)更新。实现就是,这个数据所有请求都有资格去修改,但会获得一个该数据的版本号,只有版本号符合的才能更新成功,其他的返回抢购失败。这样的话,我们就不需要考虑队列的问题,不过,它会增大CPU的计算开销。但是,综合来说,这是一个比较好的解决方案。

有很多软件和服务都“乐观锁”功能的支持,例如Redis中的watch(事务)就是其中之一。通过这个实现,我们保证了数据的安全。

二、消息队列主要用在哪些方面?应用场景

一、认识消息队列

1.1 消息对列概念

从本质上说消息对列就是一个队列结构的中间件,也就是说消息放入这个中间件之后就可以直接返回,并不需要系统立即处理,而另外会有一个程序读取这些数据,并按顺序进行逐次处理。

也就是说当你遇到一个并发特别大并且耗时特别长同时还不需要立即返回处理结果,使用消息队列可以解决这类问题。

1.2 核心结构

由一个业务系统进行入队,把消息逐次插入到消息队列中,插入成功之后直接返回成功的结果,后续会有一个消息处理系统,这个系统会把消息系统中的记录逐次进行取出并进行处理,完成一个出队的流程。

1.3 应用场景

数据冗余:比如订单系统,后续需要严格的进行数据转换和记录,消息队列可以把这些数据持久化的存储在队列中,然后有订单,后续处理程序进行获取,后续处理完之后在把这条记录进行删除来保证每一条记录都能够处理完成。

系统解耦:使用消息系统之后,入队系统和出队系统是分开的,也就说只要一天崩溃了,不会影响另外一台系统正常运转。

流量削峰:例如秒杀和抢购,我们可以配合缓存来使用消息队列,能够有效的顶住瞬间访问量,防止服务器承受不住导致崩溃。

异步通信:消息本身使用入队之后可以直接返回。

扩展性:例如订单队列,不仅可以处理订单,还可以给其他业务使用。

排序保证:有些场景需要按照产品的顺序进行处理比如单进单出从而保证数据按照一定的顺序处理,使用消息队列是可以的。

以上都是消息队列常见的使用场景,当然消息队列只是一个中间件,可以配合其他产品进行使用。

1.4 常见队列实现优缺点

队列介质

1、数据库,例如mysql(可靠性高,易实现,速度慢)

2、缓存, 例如redis (速度快,单个消息报包过大时效率低)

3、消息系统,例如rabbitMq (专业性强,可靠,学习成本高)

消息处理触发机制

1、死循环方式读取:易实现,故障时无法及时恢复;(比较适合做秒杀,比较集中,运维集中维护)

2、定时任务:压力均分,有处理上限;目前比较流行的处理触发机制。(唯一的缺点是间隔和数据需要注意,不要等上一个任务没有完成下一个任务又开始了)

3、守护进程:类似于php-fpm 和php-cg,需要shell基础

二、解藕案例:队列处理“订单系统”和“配送系统”

简单说一下程序解耦:程序解耦就是避免出现你老婆和你妈同时掉到水里先去救谁的问题(偷笑ing)

对于订单流程,我们可以设计两个系统,一个是“订单系统” 另外一个是 “配送系统”, 在网购的时候我们应该都见过,当我提交了一个订单之后,我在后台可以看到我的货物正在配送中。这个时候就要参与进来一个“配送系统”。

如果我们在做架构的时候把 “订单系统” 和 “配送系统” 设计在一起的话就会出现一些问题,首先对于订单系统来说,因为系统的压力会比较大,但是 “配送系统” 没必要为这些压力做一些即时的反应。

第二个我们也不希望在订单系统出现故障之后导致配送系统也出现故障,这个时候就会同时影响到两个系统的正常运转。所以我们希望把这两个系统进行解耦。这两系统分开之后我们可以通过一个中间的 “队列表” 进行这两个系统的沟通。

2.1 架构设计

1、首先订单系统会接收用户的订单,然后进行订单的处理。

2、然后会把这些订单信息写到队列表中,这个队列表是沟通这两个系统的关键。

3、由配送系统定时执行的一个程序来读取队列表进行处理。

4、配送系统处理之后,会把已处理的记录进行标记。

2.2 程序流程

三、流量削峰案例:Redis 的 list 类型实现秒杀

redis 基于内存,它的速度会非常快,redis 对数据库有一个非常好的补充作用因为它是可持久化的,redis会周期性的把数据写到硬盘里,所以它不用担心断电的问题,从这方面说它比另一款缓存 memcache 更有优势些,另外 redis 提供五种数据类型(字符串,双向链表,哈希,集合,有序集合)

一般情况下,做秒杀案例,抢购,瞬间高比你高发,需要排队 的案例中 redis是一个很好的选择。

3.1 redis数据类型中的 list 类型

redis 的list 是一个双向链表,可以从头部或者尾部追加数据。

* LPUSH/LPUSHX :将值插入到(/存在的)列表头部

* RPUSH/RPUSHX: 将值插入到(/存在的)列表尾部

* LPOP : 移除并获取列表的第一个元素

* RPOP: 移除并获取列表的最后一个元素

* LTRIM: 保留指定区间内的元素

* LLEN: 获取列表长度

* LSET: 通过索引设置列表元素的值

* LINDEX: 通过索引获取列表中的元素

* LRANGE: 获取列表指定范围内的元素

3.2 架构设计

一个简单结构秒杀的程序设计。

1、首先记录是哪一个用户参与了秒杀同时记录他的时间。

2、将用户的id存到redis列表中,让它排队。如果规定只有前10个用户可以参与成功,如果列表中的个数已经够了就不会让它继续追加数据。这样redis的列表长度就只会是10个

3、最后在慢慢的将redis中的数据写入到数据库中,以减少数据的压力

3.3 代码级设计

1、当用户开始秒杀时,将秒杀程序的请求写入Redis (uid, time_stamp)中。

2、假使规定只有10人可以秒杀成功,检查 Redis 已经存放数据的长度,超出上限直接丢弃说明秒杀完成。

3、最后在死循环处理存入Redis中的10条数据,然后在慢慢的取数据并存入到mysql数据库中。

在秒杀这一块对于数据库的压力特别的大,如果我们没有这样的设计,会造成mysql的写入瓶颈。我们通过Redis的一个对列list,然后把秒杀的请求放入到Redis里面, 最后通过入库程序,把数据慢慢的写入到数据库,这样的话就可以实现流量的均衡,对mysql不会造成太大的压力。

四、RabbitMQ

这里讲解一些RabbitMQ的使用,首先我们之前讲秒杀案例的时候提到了锁的机制,防止其他程序处理同一条记录,如果我们的系统架构非常的复杂,有多个程序实时的读取一个队列,或者我有多个发送程序,同时来操作一个或多个队列,甚至我还想这些程序分布在不同的机器上,这种情况下用redis队列就有些力不从心了。这种时候怎么办呢,我们就需要来引入一些更专业的消息队列系统,这些系统可以更好的来解决问题。

4.1 RabbitMQ的架构和原理

特点:完整的实现了AMQP,集群简化,持久化,跨平台

RabbitMQS使用

1、RabbitMQ安装 (rabbitmq-server, php-amqplib)

2、生产者向消息通道发送消息

3、消费者处理消息

工作队列

思想:由生产者发送给消息系统,消息系统把任务封装成消息队列之后,然后供多个消费者使用同一个队列

这不仅解决了生产者和消费者之间的解耦,还可以实现了消费者和任务的共享,减缓了服务器的压力。

五、总结

以上主要学习消息队列的概念,原理,场景。解耦案例以及削峰案例,以及了解RabbitMQ的简单使用方法。

六、问题

redis 和消息服务器 选择的最大区别是什么。

我的理解是Redis 是一个一个处理请求,redis属于单线程,它和消息服务器 IO 的实现方式不同,一个是同步一个是异步,而redis使用的是同步阻塞,而消息服务器使用的是异步非阻塞。

三、分布式是怎么做的?

1、开启Session存储数据库

在Common/Conf/config.php里添加如下几行:

1

2

3

4

5

//Session设置

‘SESSION_OPTIONS’ => array(

    'expire' => 864000,       

    'type'   => 'Db',   

),

2、假设你有AB两台云服务器A的IP地址是1.2.3.4,B的IP地址是5.6.7.8,将bbs.lingyun.net在域名解析里解析到1.2.3.4,将u.lingyun.net解析到5.6.7.8。

3、在AB两台服务器里部署同样的代码

经过以上三步实现了最简单的分布是部署,相当于A服务器主要承担论坛相关的访问,B服务器主要承担用户页面的访问。

四、sql存储优化方案

  1. 存储优化
    存储数据时,影响存储速度的主要是索引、唯一性校验、一次存储的数据条数等。

存储数据的优化,不同的存储引擎优化手段不一样,在MySQL中常用的存储引擎有,MyISAM和InnoDB,两者的区别:

1.1. 存储引擎介绍
1.1.1. MyISAM存储引擎
MyISAM存储引擎是一种非事务性的引擎,提供高速存储和检索,以及全文搜索能力,适合数据仓库等查询频繁的应用。

每一个表都被存放为三个以表名命名的物理文件。有存放表结构定义信息的.frm文件,还有存放了表的数据.MYD文件和存放索引数据的.MYI文件。

1.1.2. Innodb 存储引擎
Innodb 存储引擎是事务安全的, 因此如果需要一个事务安全的存储引擎,建议使用它。如果你的数据执行大量的INSERT或UPDATE,出于性能方面的考虑应该使用InnoDB表。

InnoDB 给 MySQL 提供了具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。InnoDB 提供了行锁(locking on row level),提供与 Oracle 类型一致的不加锁读取(non-locking read in SELECTs)。这些特性均提高了多用户并发操作的性能表现。

在InnoDB表中不需要扩大锁定(lock escalation),因为 InnoDB 的列锁定(row level locks)适宜非常小的空间。InnoDB 是 MySQL 上提供外键约束(FOREIGN KEY constraints)的表引擎。

InnoDB 的设计目标是处理大容量数据库系统,它的 CPU 利用率是其它基于磁盘的关系数据库引擎所不能比的。在技术上,InnoDB 是一套放在 MySQL 后台的完整数据库系统,InnoDB 在主内存中建立其专用的缓冲池用于高速缓冲数据和索引。

InnoDB 把数据和索引存放在表空间里,可能包含多个文件,这与MyISAM不一样。InnoDB 表的大小只受限于操作系统的文件大小,一般为 2 GB。InnoDB所有的表都保存在同一个数据文件 ibdata1 中(也可能是多个文件,或者是独立的表空间文件),相对来说比较不好备份。备份的方案可以是拷贝数据文件、备份 binlog,或者用 mysqldump。

1.2. MyISAM和Innodb的区别
InnoDB和MyISAM是许多人在使用MySQL时最常用的两个表类型,这两个表类型各有优劣,视具体应用而定。基本的差别为:MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持。MyISAM类型的表强调的是性能,其执行数度比InnoDB类型更快,但是不提供事务支持,而InnoDB提供事务支持已经外部键等高级数据库功能。

1.2.1. 具体实现的差别:
l MyISAM是非事务安全型的,而InnoDB是事务安全型的。

l MyISAM锁的粒度是表级,而InnoDB支持行级锁定。

l MyISAM支持全文类型索引,而InnoDB不支持全文索引。

l MyISAM相对简单,所以在效率上要优于InnoDB,小型应用可以考虑使用MyISAM。

l MyISAM表是保存成文件的形式,在跨平台的数据转移中使用MyISAM存储会省去不少的麻烦。

l InnoDB表比MyISAM表更安全,可以在保证数据不会丢失的情况下,切换非事务表到事务表(alter table tablename type=innodb)。

1.2.2. 应用场景
l MyISAM管理非事务表。它提供高速存储和检索,以及全文搜索能力。如果应用中需要执行大量的SELECT查询,那么MyISAM是更好的选择。

l InnoDB用于事务处理应用程序,具有众多特性,包括ACID事务支持。如果应用中需要执行大量的INSERT或UPDATE操作,则应该使用InnoDB,这样可以提高多用户并发操作的性能。

五、go和php的区别?

go语言和php是软件开发行业中的两种重要语言。Go语言与PHP之间有一些相似之处,但也存在许多差异。下面本篇文章就来给大家介绍一下go语言和php之间有哪些区别,希望对大家有所帮助。

Go也称为Golang,它基本上是一种编程语言,可用于快速机器代码编译。它由Google创建。它是一种静态类型的编译语言。它提供了并发机制,可以轻松开发多核和联网的机器级程序。它是快速,动态类型和解释语言。

PHP是服务器端脚本,也是为Web开发设计的通用编程语言;是动态类型的快速和灵活的语言。它可以与各种Web模板系统和Web开发框架结合使用。通过PHP处理的代码通常由PHP解释器实现。

go语言和php之间的区别

1、Go基本上是一种可用于快速机器代码编译的编程语言,而PHP基本上是服务器端脚本,也是用于Web开发的通用编程语言。

2、Go是一种静态类型语言。PHP是一种动态类型语言。

3、PHP使用核心PHP语言进行模板化,因此浏览器通过发送HTML代码处理PHP代码并将输出发送到浏览器,而在GO的情况下,它通常使用简单的模板系统。

4、Go的主要应用于是机器级学习及其相应的数据科学和工件分析。PHP主要应用于Web开发过程。

5、Go及其他版本有很多社区支持,并且得到Google的支持,它的社区支持比PHP增加了一点点。

六、支付宝支付流程的理解 同步异步回调

当一个支付请求被发送到支付渠道方,支付渠道会很快返回一个结果。但是这个结果,只是告诉你调用成功了,不是扣款成功,这叫同步调用。
很多新手会拿这个结果 当作支付成功了,那就会被坑死,结果就是支付成功率特别高,伴随着一堆无法解释的坏账率,测试人员尤其要注意测试数据的篡改:金额,同步返回结果,订单号等。

同步请求参数里面会有一个回调地址,这个地址是支付渠道在扣款成功后调用的,这叫异步调用。
一般同步接口仅检查参数是否正确,签名是否无误等。异步接口才告诉你扣款结果。
一般异步接口有5秒以内的延迟。调用不成功会重试。有时候是这边成功了,但支付渠道侧没收到返回,于是会继续调。
当天的支付到第二天还在 被异步调用也都是正常的。这也是开发人员需要特别注意的地方,不要当做重复支付。
测试人员也要对重复回调进行测试,应只有一次有效。这还不是最坑的,一般 支付渠道侧,只有支付成功了才通知你。
要是支付失败了,压根儿都不告诉你。
另一方面,如何老收不到异步结果呢?那就得查查了。同步结果不可靠,异步调用不可靠,那怎么确定支付结果?最终的杀招就是查单了,
反查,一般支付渠道侧都 会提供反查接口,定时获取DB中待支付的订单调用支付渠道侧的反查接口,最终把支付渠道侧扣款成功的订单完成掉。

七、阿里云OSS云存储作用(应用场景)

图片和音视频等应用的海量存储
OSS可用于图片、音视频、日志等海量文件的存储。各种终端设备、Web网站程序、移动应用可以直接向OSS写入或读取数据。OSS支持流式写入和文件写入两种方式。

场景1
网页或者移动应用的静态和动态资源分离
利用海量互联网带宽,OSS可以实现海量数据的互联网并发下载。OSS提供原生的传输加速功能,支持上传加速、下载加速,提升跨国、跨洋数据上传、下载的体验。同时,OSS也可以结合CDN产品,提供静态内容存储、分发到边缘节点的解决方案,利用CDN边缘节点缓存的数据,提升同一个文件被同一地区客户大量重复并发下载的体验。

场景2
云端数据处理
上传文件到OSS后,可以配合媒体处理服务和图片处理服务进行云端的数据处理。场景3

php日志的使用方法和配置
转自:https://www.cnblogs.com/huixingwo/articles/4469128.html

对于PHP开发者来 说,一旦某个产品投入使用,应该立即将 display_errors选项关闭,以免因为这些错误所透露的路径、数据库连接、数据表等信息而遭到黑客攻击。但是,任何一个产品在投入使用后,都难 免会有错误出现,那么如何记录一些对开发者有用的错误报告呢?我们可以在单独的文本文件中将错误报告作为日志记录。错误日志的记录,可以帮助开发人员或者 管理人员查看系统是否存在问题。 如果需要将程序中的错误报告写入错误日志中,只要在PHP的配置文件中,将配置指令log_errors开启即可。错误 报告默认就会记录到Web服务器的日志文件里,例如记录到Apache服务器的错误日志文件error.log中。当然也可以记录错误日志到指定的文件中 或发送给系统syslog,分别介绍如下:

1、使用指定的文件记录错误报告日志

使 用指定的文件记录错误报告日志使用指定的文件记录错误报告日志使用指定的文件记录错误报告日志 如果使用自己指定的文件记录错误日志,一定要确保将这个文 件存放在文档根目录之外,以减少遭到攻击的可能。并且该文件一定要让PHP脚本的执行用户(Web服务器进程所有者)具有写权限。假设在Linux操作系 统中,将/usr/local/目录下的error.log文件作为错误日志文件,并设置Web服务器进程用户具有写的权限。然后在PHP的配置文件中, 将error_log指令的值设置为这个错误日志文件的绝对路径。

八、后端日志怎么做的?

需要将php.ini中的配置指令做如下修改:

  1. error_reporting = E_ALL ;将会向PHP报告发生的每个错误

  2. display_errors = Off ;不显示满足上条 指令所定义规则的所有错误报告

  3. log_errors = On ;决定日志语句记录的位置

  4. log_errors_max_len = 1024 ;设置每个日志项的最大长度

  5. error_log = E:/php_log/php_error.log ;指定产生的 错误报告写入的日志文件位置

PHP 的配置文件按上面的方式设置完成以后,并重新启动Web服务器。这样,在执行PHP的任何脚本文件时,所产生的所有错误报告都不会在浏览器中显示,而会记 录在自己指定的错误日志/usr/local/error.log中。此外,不仅可以记录满足error_reporting所定义规则的所有错误,而且 还可以使用PHP中的error_log()函数,送出一个用户自定义的错误信息。

该函数的原型如下所示:

  1. bool error_log ( string message [, int message_type [, string destination [, string extra_headers]]] )

此 函数会送出错误信息到Web服务器的错误日志文件、某个TCP服务器或到指定文件中。该函数执行成功则返回TRUE,失败则返回FALSE。第一个参数 message 是必选项,即为要送出的错误信息。如果仅使用这一个参数,会按配置文件php.ini中所设置的位置处发送消息。第二个参数 message_type为整数值:0表示送到操作系统的日志中;1则使用PHP的Mail()函数,发送信息到某E-mail处,第四个参数 extra_headers亦会用到;2则将错误信息送到TCP 服务器中,此时第三个参数destination表示目的地IP及Port;3则将信息 存到文件destination中。

如果以登入Oracle数据库出现问题的处理为例,该函数的使用如下所示:

  1. <?php
  2. if(!Ora_Logon($username, $password)){     
    
  3.     error_log("Oracle数据库不可用!", 0);        //将错误消息写入到操作系统日志中   
    
  4. }   
    
  5. if(!($foo=allocate_new_foo()){   
    
  6.     error_log("出现大麻烦了!", 1, ". mydomain.com");   //发送到管理员邮箱中   
    
  7. }  
    
  8. error_log("搞砸了!",   2,   "localhost:5000");     //发送到本机对应5000端口的服务器中   
    
  9. error_log("搞砸了!",   3,   "/usr/local/errors.log");  //发送到指定的文件中   
    
  10. ?>

2、 错误信息记录到操作系统的日志里

错 误信息记录到操作系统的日志里错误信息记录到操作系统的日志里错误信息记录到操作系统的日志里 错误报告也可以被记录到操作系统日志里,但不同的操作系统 之间的日志管理有点区别。在Linux上错误语句将送往syslog,而在Windows上错误将发送到事件日志里。如果你不熟悉syslog,起码要知 道它是基于UNIX的日志工具,它提供了一个API来记录与系统和应用程序执行有关的消息。Windows事件日志实际上与UNIX的syslog相同, 这些日志通常可以通过事件查看器来查看。如果希望将错误报告写到操作系统的日志里,可以在配置文件中将error_log指令的值设置为syslog。

具体需要在php.ini中修改的配置指令如下所示:

  1. error_reporting = E_ALL ;将会向PHP报告发生的每个错误

  2. display_errors = Off ;不显示 满足上条指令所定义规则的所有错误报告

  3. log_errors = On ;决定日志语句记录的位置

  4. log_errors_max_len = 1024 ;设置每个日志项的最大长度

  5. error_log = syslog ;指定产生的错误报告写入操作系统的日志里

除了一般的错误输出之外,PHP还允许向系统syslog中发送定制的消息。虽然通过前面介绍的error_log()函数,也可以向syslog中发送定制的消息,但在PHP中为这个特性提供了需要一起使用的4个专用函数。

分别介绍如下:

define_syslog_variables()

在使用openlog()、syslog及closelog()三个函数之前必须先调用该函数。因为在调用该函数时,它会根据现在的系统环境为下面三个函数初使用化一些必需的常量。

openlog()

打开一个和当前系统中日志器的连接,为向系统插入日志消息做好准备。并将提供的第一个字符串参数插入到每个日志消息中,该函数还需要指定两个将在日志上下文使用的参数,可以参考官方文档使用。

syslog()

该 函数向系统日志中发送一个定制消息。需要两个必选参数,第一个参数通过指定一个常量定制消息的优先级。例如LOG_WARNING表示一般的警 告,LOG_EMERG表示严重地可以预示着系统崩溃的问题,一些其他的表示严重程度的常量可以参考官方文档使用。第二个参数则是向系统日志中发送的定制 消息,需要提供一个消息字符串,也可以是PHP引擎在运行时提供的错误字符串。

closelog()

该函数在向系统日志中发送完成定制消息以后调用,关闭由openlog()函数打开的日志连接。

如果在配置文件中,已经开启向syslog发送定制消息的指令,就可以使用前面介绍的四个函数发送一个警告消息到系统日志中,并通过系统中的syslog解析工具,查看和分析由PHP程序发送的定制消息,如下所示:

  1. define_syslog_variables();   
    
  2. openlog("PHP5", LOG_PID , LOG_USER);   
    
  3. syslog(LOG_WARNING, "警告报告向syslog中发送的演示, 警告时间:".date("Y/m/d H:i:s"));  
    
  4. closelog();   
    
  5. ?>

以Windows系统为例,通过右击"我的电脑"选择管理选项,然后到系统工具菜单中,选择事件查看器,再找到应用程序选项,就可以看到我们自己定制的警告消息了。上面这段代码将在系统的syslog文件中,生成类似下面的一条信息,是事件的一部分:

  1. PHP5[3084], 警告报告向syslog中发送的演示, 警告时间:2009/03/26 04:09:11.  

使 用指定的文件还是使用syslog记录错误日志,取决于你所在的Web服务器环境。如果你可以控制Web服务器,使用syslog是最理想的,因为你能利 用syslog的解析工具来查看和分析日志。但如果你的网站在共享服务器的虚拟主机中运行,就只有使用单独的文本文件记录错误日志了。

九、无限分类的表设计

https://www.cnblogs.com/deepSleeping/p/9938500.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值