• 关于

    判断时间段

    的搜索结果

问题

请问ios 怎么判断一个时间是否在另一个时间段内

怎样判断一个时间是否在另一个时间段内,比如:判断12点是否在七点到九点之间?...
爵霸 2019-12-01 20:22:53 820 浏览量 回答数 1

回答

你设想一下每个房间都有一个时间对象,这个时间对象是时间段,那么你要解决的就是这个时间对象如何插入时间段、如何删除时间段以及如何计算有效时间段。时间段的计算,开始时间是否包含在已定时间段内,结束时间是否在已定时间段内,新时间段是否包含任何已定时间段的开始时间或截至时间。通过以上判断可以得出是否可以预定。如果你一定要用你的数组来表达的话那么建议你预定日期用一个数组表示,并且用字符串记录下来,然后查找字符串进行比对即可。不然比较月份、
a123456678 2019-12-02 01:59:00 0 浏览量 回答数 0

问题

java 如何判断当前日期与用户登录日期是否相同

当前用户登录日期为2015-08-03 17:10,假如该用户(会员)有效日期为,7天。到了 2015-08-10 17:10 ,这段时间该用户就自动注销,或者删除。(注销和删除这部分不用处理,主要是如何判断时间)前端是用EXTJS写的。 ...
蛮大人123 2019-12-01 20:20:55 1370 浏览量 回答数 1

回答

地域管理接口 API 描述 OnsRegionList 使用 OnsRegionList 获取消息队列 RocketMQ 版(目前开放服务的地域(Region)信息列表。 实例管理接口 API 描述 OnsInstanceBaseInfo 使用 OnsInstanceBaseInfo 查询实例基本信息和收发消息的接入点。 OnsInstanceCreate 使用 OnsInstanceCreate 创建实例。 OnsInstanceDelete 使用 OnsInstanceDelete 删除实例。 OnsInstanceInServiceList 使用 OnsInstanceInServiceList 查询当前用户账号下某地域所有实例的信息。 OnsInstanceUpdate 使用 OnsInstanceUpdate 更新实例名称和描述。 Topic 管理接口 API 描述 OnsTopicCreate 使用 OnsTopicCreate 创建 Topic。 OnsTopicDelete 使用 OnsTopicDelete 删除您账号下指定的 Topic。 OnsTopicList 使用 OnsTopicList 查询账号下所有 Topic 的信息列表。 OnsTopicStatus 使用 OnsTopicStatus 查询当前 Topic 下的消息总量以及 Topic 的最后更新时间。 OnsTopicUpdate 使用 OnsTopicUpdate 配置 Topic 的读写模式。 OnsTopicSubDetail 一般使用 OnsTopicSubDetail 查看有哪些在线订阅组订阅了这个 Topic。 Group 管理接口 API 描述 OnsGroupCreate 使用 OnsGroupCreate 创建客户端 Group ID。 OnsGroupDelete 使用 OnsGroupDelete 删除之前使用 OnsGroupCreate 接口创建的 Group。 OnsGroupList 使用 OnsGroupList 展示您的 Group ID 资源的列表,并不用于具体的信息查询。 OnsGroupSubDetail 使用 OnsGroupSubDetail 查看 Group 订阅了哪些 Topic,如果 Group ID 对应的消费者实例不在线则查不到数据。 OnsGroupConsumerUpdate 使用 OnsGroupConsumerUpdate 配置指定 Group ID 对应的消费集群的消息读取权限。 消费管理接口 API 描述 OnsConsumerAccumulate 使用 OnsConsumerAccumulate 查询指定 Group ID 的消息消费堆积情况,包括当前消息堆积数量和消费延迟时间等。 OnsConsumerStatus 使用 OnsConsumerStatus 查询指定 Group ID 的详细状态数据,包含订阅关系检查、消费 TPS 统计、负载均衡状态、消费端连接等。 OnsConsumerGetConnection 使用 OnsConsumerGetConnection 查询指定 Group ID 下当前客户端的连接情况。 OnsConsumerResetOffset 使用 OnsConsumerResetOffset 重置指定的 Group ID 的消费位点到指定时间戳。 OnsConsumerTimeSpan 使用 OnsConsumerTimeSpan 查询当前 Group ID 订阅的 Topic 的最新消息时间戳以及消费的最新时间。 消息查询接口 API 描述 OnsMessageTrace 使用 OnsMessageTrace 根据 Message ID 来判断目标消息是否曾被消费过。 OnsMessageGetByMsgId 使用 OnsMessageGetByMsgId 通过传入 Message ID 查询指定消息的信息以及判断该指定的消息是否曾被消费过。查询到的信息包括发送时间、存储服务器和消息的 Key 和 Tag 等属性。 OnsMessageGetByKey 使用 OnsMessageGetByKey 通过传入 Topic 名称和 Message Key 进行模糊查询,得到符合条件的消息的信息列表。 OnsMessagePageQueryByTopic 使用 OnsMessagePageQueryByTopic 通过传入 Topic 名称和时间段,分页查询指定时间段内该 Topic 内存在的所有消息。 发布订阅统计接口 API 描述 OnsTrendTopicInputTps 使用 OnsTrendTopicInputTps 查询一段时间内指定的 Topic 的消息写入报表数据。 OnsTrendGroupOutputTps 使用 OnsTrendGroupOutputTps 查询指定的 Group ID 在一段时间内消费消息的统计信息。 消息轨迹接口 API 描述 OnsTraceGetResult 使用 OnsTraceGetResult 通过传入轨迹查询任务的 ID 获取之前的轨迹查询结果。 OnsTraceQueryByMsgId 使用 OnsTraceQueryByMsgId 通过传入 Topic 名称和 Message ID 创建轨迹查询任务,得到该查询任务的 ID。 OnsTraceQueryByMsgKey 使用 OnsTraceQueryByMsgKey 通过传入 Topic 名称和 Message Key 创建轨迹查询任务,得到该查询任务的 ID。 死信队列接口 API 描述 OnsDLQMessageGetById 使用 OnsDLQMessageGetById 通过传入 Message ID 查询指定的死信消息。查询到的信息包括死信消息的存储时间、消息体、Key 和 Tag 等属性。 OnsDLQMessagePageQueryByGroupId 使用 OnsDLQMessagePageQueryByGroupId 通过传入 Group ID 和时间段,分页查询指定时间段内该 Group ID 内存在的所有死信消息。 OnsDLQMessageResendById 使用 OnsDLQMessageResendById 通过传入 Message ID 重发指定的死信消息,使该消息能够被 Consumer 再次消费。
保持可爱mmm 2020-03-28 20:49:38 0 浏览量 回答数 0

回答

你好,建议稍稍等待,开机需要一小段时间。如果无法启动,建议贴上报错,以便判断。 如有帮助,还望采纳,谢谢。
星屋易购 2019-12-02 00:29:39 0 浏览量 回答数 0

问题

根据编译时终端的显示判断编译是否卡住的问题

需求如下: 编译时会卡住,所以需要当终端上显示的编译信息在一段时间不更新后重新编译开始时认为编译信息写到标准输出时对应的编译线程的标准输出文件的修改时间会改变,所以想通过shell脚本取得编译的进程pid,然后将当前时间与文件/proc/p...
a123456678 2019-12-01 20:04:54 967 浏览量 回答数 1

回答

首先可以确认该时间段内是否属于服务升级时间段内 ( 可以看官网公告 ) 这 是 MQ 服务升级过程中 , 会出现短暂的网络闪断 , 但是我们的 mq 服务是集 群部署的 , 一台网络的闪断是不会影响消息的。在自己的应用服务器上执行 telnet brokerip port,确认服务端的端口是否 通畅。执行 ping brokerip , 查看网络是否延迟。同时检查网络监控指标,观察在问 题时间点流量是否有下降的情况。如果 ping 或者 telnet 不通,需要检查下 服务器的防火墙,网络设置等。检查应用的网络带宽情况,是否打满。可执行 jstack -l 进程号 > 文件名 .dump 来分析堆栈信息,判断当时应用系 统有没有 Full GC 现象 (Full GC 会造成一定的网络延迟 )。确认下使用的 sdk,如果是较低的 javasdk 版本,建议升级 sdk 版本到 1.8.4。这个版本里容灾策略较之前版本优化了许多内容。 同时建议客户端做一下补偿机制 ,可以 try…catch 一下异常,做下消息的重试。
Lee_tianbai 2021-01-01 15:11:50 0 浏览量 回答数 0

回答

推荐阀值 50-100之间 ------------------------- 设置http监控即可  如果ping 值比较异常 就要根据发送的时间段 查看服务器带宽是否够用了 ------------------------- 可以截图  云监控设置  和  报警提示  方便我们帮你判断
小艺 2019-12-02 02:00:55 0 浏览量 回答数 0

问题

多线程下对一个串多次调用strok后strlen报段错误

while(1) { char buf[800] ={0}; ret=fgets(buf, sizeof(buf) -1, fp); if(!ret){ ...lseek to head of file ...
a123456678 2019-12-01 19:46:17 991 浏览量 回答数 1

回答

什么是时间轮呢?其实我们可以简单的将其看做是一个多维数组。在很多框架中都使用了时间轮来做一些定时的任务,用来替代我们的Timer,比如我之前讲过的有关本地缓存Caffeine一篇文章,在Caffeine中是一个二层时间轮,也就是二维数组,其一维的数据表示较大的时间维度比如,秒,分,时,天等,其二维的数据表示该时间维度较小的时间维度,比如秒内的某个区间段。当定位到一个TimeWhile[i][j]之后,其数据结构其实是一个链表,记录着我们的Node。在Caffeine利用时间轮记录我们在某个时间过期的数据,然后去处理。 由于时间轮是一个数组的结构,那么其插入复杂度是O(1)。我们解决了效率之后,但是我们的内存依旧不是无限的,我们时间轮如何使用呢?答案当然就是磁盘,在去哪儿开源的QMQ中已经实现了时间轮+磁盘存储,这里为了方便描述我将其转化为RocketMQ中的结构来进行讲解,实现图如下: Step 1: 生产者投递延时消息到CommitLog,这个时候使用了偷换Topic的那招,来达到后面的效果。 Step 2: 后台有一个Reput的任务定时拉取,延时Topic相关的Message。 Step 3: 判断这个Message是否在当前时间轮范围中,如果不在则来到Step4,如果在的话就直接将消息投递进入时间轮。 Step 4: 找到当前消息所属的scheduleLog,然后写入进去,去哪儿默认划分是一个小时为一段,这里可以根据业务自行调整。 Step 5:时间轮会定时预加载下个时间段的scheduleLog到内存。 Step 6: 到点的消息会还原topic再次投递到CommitLog,如果投递成功这里会记录dispatchLog。记录的原因是因为时间轮是内存的,你不知道已经执行到哪个位置了,如果执行到最后最后1s钟的时候挂了,这段时间轮之前的所有数据又得重新加载,这里是用来过滤已经投递过的消息。 时间轮+磁盘存储我个人觉得比上面的RocksDB要更加正统一点,不依赖其他的中间件就可以完成,可用性自然也就更高,当然阿里云的RocketMQ具体怎么实现的这个两种方案都有可能。
kun坤 2020-04-23 20:05:19 0 浏览量 回答数 0

问题

最近发现打开网页速度变慢了!不知道该升级cpu还是内存或是带宽

如题,该如何判断呢!!明显这段时间速度比较慢,,,我的一个wordpress首页图片用的是oss的,打开速度似乎不受什么影响,&...
bcaiwa 2019-12-01 21:58:49 5961 浏览量 回答数 4

问题

物联网设备连接云平台之后如何离线

1.我的设备已经接入了物联网平台,但是运行一段时间之后会自动离线,所以想问一下离线的判断机制是怎么样的,设备多长时间不发数据,或者是设备多长时间不连接服务器判断离线。 2.关于计...
famlee 2019-12-01 19:09:26 757 浏览量 回答数 1

回答

在冒泡排序,插入排序,选择排序,快速排序中,在最最坏情况下,快速排序的时间复杂为O(n2) ,插入排序O(n2),选择排序O(n2),冒泡排序O(n2)。所以ABCD时间复杂度是一样的。 知识拓展: 在快速排序算法中,最为关键的就是选取一个基值,将数组分为大于基值以及小于基值两部分,并返回基值所以在位置以利用于递归划分。 对数组a,设需要划分的其中一段为a[p]~a[r],我们期待的结果是得到一个q,其中p<=q<=r,使得a[p]~a[q-1]<=a[q]<=a[q+1]~a[r],这个时候原先的一段数组被分成了三部分。 首先,设基值为这段数组的最后一个元素a[r],我们希望最后得到的结果是a[r]现在对应的值在算法结束后可以排在比他大和小的两部分的中间爱。 然后令i=p-1; j=p,当发现有a[j]>x时,j继续前进,不需要任何移动。当发现a[j]<=x时,我们需要将这个元素放到小于基值的一边,于是将i自加1,并交换此时a[i],与a[j]的元素,然后j自加1。这个时候i指向的是比基值小的那段数据的最后一个元素,j指向的是第一个还没有判断的剩余元素。 上面一步不断循环直到j指向了r,此时只剩下r没有和基值判断了,而a[r]本来就是基值,而除了a[r]以外,a[p]~a[i]是小于基值的部分,a[i+1]~a[r-1]是大于基值的部分,所以此时只需交换a[i+1]和a[r]即可。 由于对数组a从头到尾扫描一次就可以得到结果,因此这一部分算法复杂度为o(n)
青衫无名 2019-12-02 01:17:21 0 浏览量 回答数 0

回答

一、 Cassandra数据失效机制 现在使用Cassandra的地方很多,由于Cassandra的写的性能很好,所以有一部分使用Cassandra做为类似于日志功能来使用,所 以一个需求就提出来了,那就是希望Cassandra能提供一个自动失效功能,希望Cassandra能保留一定天数后,能自动删除数据。 这种需求的确很常见,但是遗憾的是Cassandra目前仍然不能满足这个需求,虽然Cassandra已经提供了实现这个功能的基础,下面详细看一下Cassandra是怎么删除数据的:在我写的另一篇文章中也介绍了Cassandra删除数据的规则《Cassandra分布式数据库详解》系列文档。 Cassandra判断数据是否有效有三个地方,分别是下面代码片段: 第一段代码 long maxChange = column.mostRecentLiveChangeAt(); return (!column.isMarkedForDelete() || column.getLocalDeletionTime() > gcBefore || maxChange > column.getMarkedForDeleteAt()) // (1) && (!container.isMarkedForDelete() || maxChange > container.getMarkedForDeleteAt()); //(2) 这段代码判断这个列是否应该被关联,关联有两个条件 (1) 列没有被删除或者删除的时间在有效期以内或者删除的时间在最后修改数据的数据之前 (2) 列所在的容器没有被删除或者列的修改时间在容器删除时间之后 第二段代码 for (byte[] cname : cf.getColumnNames()) { IColumn c = cf.getColumnsMap().get(cname); long minTimestamp = Math.max(c.getMarkedForDeleteAt(), cf.getMarkedForDeleteAt()); for (IColumn subColumn : c.getSubColumns()) { if (subColumn.timestamp() <= minTimestamp || (subColumn.isMarkedForDelete() && subColumn.getLocalDeletionTime()<= gcBefore)){ ((SuperColumn)c).remove(subColumn.name()); }} if (c.getSubColumns().isEmpty() && c.getLocalDeletionTime() <=gcBefore){ cf.remove(c.name()); }} 或 for (byte[] cname : cf.getColumnNames()) {IColumn c = cf.getColumnsMap().get(cname); if ((c.isMarkedForDelete() && c.getLocalDeletionTime() <= gcBefore)|| c.timestamp() <= cf.getMarkedForDeleteAt()){ cf.remove(cname); }} if (cf.getColumnCount() == 0 && cf.getLocalDeletionTime() <=gcBefore){ return null; } 第二段代码是判断数据是否应该被删除,也有两个或条件 (1) 列已经被删除了并且数据已经过了时效期 (2) 数据的修改时间在容器删除时间之前 当所有列都删除并且容器已失效,这个key就会被删除,key的删除是在SSTable合并的时候完成的 第三段代码是在客户端中 for (IColumn column : columns) { if (column.isMarkedForDelete()) { continue; } Column thrift_column = new Column(column.name(), column.value(), column.timestamp()); thriftColumns.add(createColumnOrSuperColumn_Column(thrift_column)); } 这段代码清楚的说明只要列被删除,客户端将取不到数据 关于gcBefore是在配置文件中设置的864000,很多人以为这个时间就是数据的失效时间,以为在这个时间段内数据可以被使用,从上面的三段代码来看,Cassandra在设计数据失效机制,在实际应用中几乎没有利用价值,也就是数据失效对使用者来说没有任何好处 二、 改造Cassandra实现真正的自动失效功能 从上分析Cassandra判断数据是否失效主要根据三个标识 (1) Column是否被删除标识:isMarkedForDelete (2)Column的getLocalDeletionTime(),这个时间就是个失效时间GCGraceSeconds比较,判断该Column是否已经失效,这个和前面的条件是并集 (3)Column和所在ColumnFamily的删除时间markedForDeleteAt比较如果小于这个时间,改Column就会被删除 所以我们要实现自动失效数据,不用通过调用remove接口,就能实现。也就是当数据在写到数据库之前,就标识这个数据在GCGraceSeconds时间内有效,一旦超过这个时间,数据被被自动删除,而且是物理删除。 需要改造的地方如下: A.改造org.apache.cassandra.thrift. ColumnPath类,增加一个 public boolean is_delete; 属性,当我们在调用insert接口是标识这个Column数据是自动失效的。如下所示: ColumnPath col = new ColumnPath(columnFamily,superColumn,column.getBytes(“UTF-8″),true); client.insert(keyspace,key,col,value.getBytes(),System.currentTimeMillis(), ConsistencyLevel.ONE); B.改造org.apache.cassandra.thrift. Column类 也增加同样增加is_delete属性,当我们调用batch_insert或batch_mutate接口是同样可以设置Column时支持自动失效的。 A和B是客户端接口需要修改的地方,下面是服务器端要修改的地方: C.org.apache.cassandra.db.filter. QueryPath类 也增加同样增加is_delete属性,用来保存客户端传过来的is_delete值。并增加一个结构体: public QueryPath(String columnFamilyName, byte[] superColumnName, byte[] columnName,boolean is_delete) { this.columnFamilyName = columnFamilyName; this.superColumnName = superColumnName; this.columnName = columnName; this.is_delete = is_delete; } 在insert、batch_insert和batch_mutate三个接口创建QueryPath对象的地方改成上面这个结构体创建对象 D. org.apache.cassandra.db. ColumnFamily类 修改addColumn方法,将false改为path.is_delete public void addColumn(QueryPath path, byte[] value, long timestamp) { addColumn(path, value, timestamp, path.is_delete); //addColumn(path, value, timestamp, false); } E. org.apache.cassandra.db. Column类 修改getLocalDeletionTime方法,直接去timestamp时间 public int getLocalDeletionTime() { assert isMarkedForDelete; //return ByteBuffer.wrap(value).getInt(); return (int)(timestamp/1000); } 同时修改comparePriority方法,改变Column替换规则 public long comparePriority(Column o) { if(o.timestamp == -1){ return -1; } if(this.timestamp == -1){ return 1; } if(isMarkedForDelete) { // tombstone always wins ties. return timestamp < o.timestamp ? -1 : 1; } return timestamp – o.timestamp; } F. org.apache.cassandra.db. RowMutation类 修改delete方法 public void delete(QueryPath path, long timestamp) { assert path.columnFamilyName != null; String cfName = path.columnFamilyName; int localDeleteTime = (int) (System.currentTimeMillis() / 1000); ColumnFamily columnFamily = modifications_.get(cfName); if (columnFamily == null) columnFamily = ColumnFamily.create(table_, cfName); if (path.superColumnName == null && path.columnName == null) { columnFamily.delete(localDeleteTime, timestamp); } else if (path.columnName == null) { SuperColumn sc = new SuperColumn(path.superColumnName, DatabaseDescriptor.getSubComparator(table_, cfName)); sc.markForDeleteAt(localDeleteTime, timestamp); columnFamily.addColumn(sc); } else { ByteBuffer bytes = ByteBuffer.allocate(4); bytes.putInt(localDeleteTime); long deleteTime = -1; //columnFamily.addColumn(path, bytes.array(), timestamp, true); columnFamily.addColumn(path, bytes.array(), deleteTime, true); } modifications_.put(cfName, columnFamily); } 调用删除接口时将删除时间设为-1,这个和前面的修改的comparePriority方法相适应。 G. 修改CassandraServer类的thriftifyColumns和thriftifySubColumns 却掉isMarkedForDelete检查 public List thriftifyColumns(Collection columns, boolean reverseOrder) { ArrayList thriftColumns = new ArrayList (columns.size()); for (IColumn column : columns) { /*if (column.isMarkedForDelete()) { continue; }*/ Column thrift_column = new Column(column.name(), column.value(), column.timestamp()); thriftColumns.add(createColumnOrSuperColumn_Column(thrift_column)); } // we have to do the reversing here, since internally we pass results around in ColumnFamily // objects, which always sort their columns in the “natural” order // TODO this is inconvenient for direct users of StorageProxy if (reverseOrder) Collections.reverse(thriftColumns); return thriftColumns; } 数据有效时间可以通过GCGraceSeconds配置项来设置,这样超过gcBefore时间,客户端就会取不到数据,并且Cassandra 在执行SSTable合并的时候会执行物理删除,如果想立即删除数据可以调用remove接口,数据将会立即被删除,但是在有效时间内被删除的数据客户端仍然能够取到数据。这样就真正实现了数据自动失效和删除的功能。 原文链接:https://blog.csdn.net/rockecsn/article/details/84221161
苍霞学子 2021-04-02 22:04:26 0 浏览量 回答数 0

回答

应该使用的是计划任务吧。1.利用主机系统功能实现:具体来说就是Linux主机利用crontab实现(CPanel面板上是写时钟守护作业,其它的应该都是叫Cron吧),Windows好像是叫计划任务2.将定时任务的代码写在一个文件里头然后在首页以图片的形式包含这个文件,并设定这张图片大小为1px。这样当别人访问首页的时候就会执行这段代码。例如:cron文件代码如下: if (现在的时间是8:00) 输出 “早上好” <img src="cron文件" width="1px" height="1px"> 将这段代码加入到首页后只要有人访问首页就会执行一次判断,而且因为是一张大小为1px的无效图片,所以不影响网页的载入速度。两种方法的区别就是,一个是系统自动访问代码页面,而另外一种则是用户访问代码页面,系统访问能做到定时执行,而用户访问除非您的访问量特别的大,否则很难做到定时执行,只能做到自动执行。但是第一种方法对主机要求高,Linux需要安装有Crontab,而第二种方法对主机没有具体的要求。
落地花开啦 2019-12-02 02:42:07 0 浏览量 回答数 0

问题

请问下OSS日志文件到多大时,会生成新日志文件

       比如在12点这个时间段内 有 logccp022014-01-16-12-00-00-0001 但是如果这个文件过大,就会有 logccp022014-01-16-12-00-00-0002 文件产生࿰...
臣仔 2019-12-01 21:38:29 5473 浏览量 回答数 3

问题

RDS故障分析,请阿里云给予解释

1. 事件经过描述2016年5月27日7时许,研发人员接到前方反映两家用户的系统运行有问题——用户正常登录后,画面操作没反映。初步怀疑是应用系统故障,但后来发现主数据库实例有报警,并且...
长天秋水 2019-12-01 21:35:57 8807 浏览量 回答数 3

问题

Redis应该如何存储带时间戳的分类实时数据?

一个物联网项目,最初选用了Linux + Twisted + MySQL + Python来构建。看重的是Twisted的扩展性。但是MySQL成为性能瓶颈。系统架构是:大量设备每隔0.5秒以TCP长连接方式连接Twisted Socket...
蛮大人123 2019-12-01 19:52:11 3317 浏览量 回答数 1

回答

一、乐观锁 乐观锁不是数据库自带的,需要我们自己去实现。乐观锁是指操作数据库时(更新操作),想法很乐观,认为这次的操作不会导致冲突,在操作数据时,并不进行任何其他的特殊处理(也就是不加锁),而在进行更新后,再去判断是否有冲突了。 通常实现是这样的:在表中的数据进行操作时(更新),先给数据表加一个版本(version)字段,每操作一次,将那条记录的版本号加1。也就是先查询出那条记录,获取出version字段,如果要对那条记录进行操作(更新),则先判断此刻version的值是否与刚刚查询出来时的version的值相等,如果相等,则说明这段期间,没有其他程序对其进行操作,则可以执行更新,将version字段的值加1;如果更新时发现此刻的version值与刚刚获取出来的version的值不相等,则说明这段期间已经有其他程序对其进行操作了,则不进行更新操作。比如下面的sql 语句就使用了乐观锁思想。 update t1 set status=2, version=version+1 where id=#{id} and version=#{version}; 悲观锁 悲观锁就是在操作数据时,认为此操作会出现数据冲突,所以在进行每次操作时都要通过获取锁才能进行对相同数据的操作,这点跟java中的synchronized很相似,所以悲观锁需要耗费较多的时间。另外与乐观锁相对应的,悲观锁是由数据库自己实现了的,要用的时候,我们直接调用数据库的相关语句就可以了。 具体的悲观锁实现,可以了解一下 InnoDB 的行锁之类的知识。
carpediem123 2020-08-05 12:19:10 0 浏览量 回答数 0

问题

IOT判断离线的时长是多少?是否能修改呢?经常发现在心跳时间内就发现IOT 发布消息失败,再等一段时间才知道离线。

常见问题 设备相关...
iot小能手 2019-12-01 19:23:10 722 浏览量 回答数 1

问题

android 怎么判断已连接上指定的wifi网络?注意是验证 注意是验证 注意是验证!!!

mWifiAdmin.addNetWork(mWifiAdmin.CreateWifiInfo(getSSID, "", 1)使用这个方法去连接wifi返回true后表示wifi连接成功,但是还需要好像wifi连接真正稳定下来还需要一段时间...
爵霸 2019-12-01 20:04:11 1315 浏览量 回答数 1

回答

“短链接优化功能”可以优化业务短链接,短链接是指业务侧发起一个链接,指向了一个或者几个SQL后马上断开链接,当下一次再次执行时再次发起,这个看起来没有什么问题,但是当业务并发很高时,意味着每一次请求可能都会经历建立连接-查询-断开连接的过程,高并发情况下会耗费非常大的资源,售后遇到很多客户因为链接建立以及断开频繁(有时每秒5000次),造成CPU打满或者RDShang住。这里的优化主要是当业务断开连接后,数据库代理会判断之前的连接是否为空闲(idle)连接,如果是空闲连接,代理会将代理与数据库之间的连接保留在连接池内一段时间(仅释放客户端与代理之间的连接)。在保留连接的这段时间内如果该客户端发起新连接,代理会直接从连接池里使用保留的连接,从而减少与数据库建立连接的开销。
爱吃鱼的程序员 2020-12-29 10:37:53 0 浏览量 回答数 0

回答

Player 在播放音频文件时,它不会知道现在读的是那一个单词,所以你得准备一个时间数组,放在一个plist 文件里面,在播放前读到一个 NSArray 里面,时间数组记录着每个单词在音频文件中的起始时间和结束时间。用这个数组再结合 Player 的 currentTime 属性,你就能判断当前正在读那个单词或者是在两个单词之间的空白阶段,再将那个单词所在的 label 高亮/变色 处理,注意:每个单词都要作为单独的 label 画在屏幕上。同样,你点击一个单词(label),就从时间数组中读出那个单词的起始时间和结束时间,将 Player 的 currentTime 设置为起始时间,Player 便开始读那个单词,然后在 currentTime 到结束时间后 pause 掉 Player ,这样便完成点击读某个单词。
a123456678 2019-12-02 03:12:27 0 浏览量 回答数 0

问题

Swarm 集群&nbsp;&nbsp;监控&nbsp;&nbsp;弹性伸缩不起作用怎么办

如果您创建的容器弹性伸缩或节点弹性伸缩不起作用,您可以按照以下内容来进行问题排查。 查看监控指标,确认监控指标有数据并达到阈值一段时间。 查看容器弹性伸缩的监控指标单击左侧导航栏中的服务。选择服务所在的集...
青蛙跳 2019-12-01 21:36:20 698 浏览量 回答数 0

问题

wireshark从入门到精通(协议排错安全篇)8

通过前面的TCP介绍我们对以后的排错以及网站编写和优化处理有了基础了解,接下来我们讨论一下TCP重传 当我们的数据有的因为网络等原因没有发送过去时通过重传进行重新发送。 我们的重传计时器维护着一个重传超时RTO,当TCP发...
我的中国 2019-12-01 21:15:30 2758 浏览量 回答数 0

问题

大量IP直接访问,如何预防

最近发现一个问题 1)网站通过百度统计和ECS日志发现,来自四川,重庆等第大量的IP直接访问 2)直接IP访问都是使用WIN7系统,和IE8, 3ÿ...
useit_知识库 2019-12-01 20:56:54 4638 浏览量 回答数 2

回答

HashMap HashMap 底层是基于 数组 + 链表 组成的,不过在 jdk1.7 和 1.8 中具体实现稍有 不同 其实1.7一个很明显需要优化的地方就是: 当 Hash 冲突严重时,在桶上形成的链表会变的越来越长,这样在查询时的效 率就会越来越低;时间复杂度为 O(N)。 因此 1.8 中重点优化了这个查询效率。 1.8 HashMap 结构图 JDK 1.8 对 HashMap 进行了修改: 最大的不同就是利用了红黑树,其由数组+链表+红黑树组成。 JDK 1.7 中,查找元素时,根据 hash 值能够快速定位到数组的具体下标, 但之后需要顺着链表依次比较才能查找到需要的元素,时间复杂度取决于链 表的长度,为 O(N)。 为了降低这部分的开销,在 JDK 1.8 中,当链表中的元素超过 8 个以后,会 将链表转换为红黑树,在这些位置进行查找的时候可以降低时间复杂度为 O(logN)。 JDK 1.8 使用 Node(1.7 为 Entry) 作为链表的数据结点,仍然包含 key, value,hash 和 next 四个属性。 红黑树的情况使用的是 TreeNode。 根据数组元素中,第一个结点数据类型是 Node 还是 TreeNode 可以判断该位 置下是链表还是红黑树。 核心成员变量于 1.7 类似,增加了核心变量,如下表。 属性说明TREEIFY_THRESHOLD用于判断是否需要将链表转换为红黑树的阈值,默认 为 8。 put步骤: 判断当前桶是否为空,空的就需要初始化(resize 中会判断是否进行初始 化)。 根据当前 key 的 hashcode 定位到具体的桶中并判断是否为空,为空表明没有 Hash 冲突就直接在当前位置创建一个新桶即可。 如果当前桶有值( Hash 冲突),那么就要比较当前桶中的 key、key 的 hashcode 与写入的 key 是否相等,相等就赋值给 e,在第 8 步的时候会统一进 行赋值及返回。 如果当前桶为红黑树,那就要按照红黑树的方式写入数据。 如果是个链表,就需要将当前的 key、value 封装成一个新节点写入到当前桶的 后面(形成链表)。 接着判断当前链表的大小是否大于预设的阈值,大于时就要转换为红黑树。 如果在遍历过程中找到 key 相同时直接退出遍历。 如果 e != null 就相当于存在相同的 key,那就需要将值覆盖。 后判断是否需要进行扩容. get 方法看起来就要简单许多了。 首先将 key hash 之后取得所定位的桶。 如果桶为空则直接返回 null 。 否则判断桶的第一个位置(有可能是链表、红黑树)的 key 是否为查询的 key,是 就直接返回 value。 如果第一个不匹配,则判断它的下一个是红黑树还是链表。 红黑树就按照树的查找方式返回值。 不然就按照链表的方式遍历匹配返回值。 从这两个核心方法(get/put)可以看出 1.8 中对大链表做了优化,修改为红黑树之 后查询效率直接提高到了 O(logn)。 但是 HashMap 原有的问题也都存在,比如在并发场景下使用时容易出现死循环。 但是为什么呢?简单分析下。 看过上文的还记得在 HashMap 扩容的时候会调用 resize() 方法,就是这里的并 发操作容易在一个桶上形成环形链表;这样当获取一个不存在的 key 时,计算出的 index 正好是环形链表的下标就会出现死循环。 如下图: HashTable HashTable 容器使用 synchronized来保证线程安全,但在线程竞争激烈的情况下 HashTable 的效 率非常低下。 当一个线程访问 HashTable 的同步方法时,其他线程访问 HashTable 的同步方 法可能会进入阻塞或轮询状态。 HashTable 容器在竞争激烈的并发环境下表现出效率低下的原因,是因为所有 访问它的线程都必须竞争同一把锁,假如容器里有多把锁,每一把锁用于锁容 器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就 不会存在锁竞争,从而可以有效的提高并发访问效率,这就是 ConcurrentHashMap(JDK 1.7) 使用的 锁分段技术。 ConcurrentHashMap 将数据分成一段一段的存储,然后给每一段数据配一把 锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他 线程访问。 有些方法需要跨段,比如 size() 和 containsValue(),它们可能需要锁定整个表 而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所 有段的锁。 按顺序 很重要,否则极有可能出现死锁,在 ConcurrentHashMap 内部,段数 组是 final 的,并且其成员变量实际也是 final 的,但是,仅仅是将数组声明为 final 的并不保证数组成员也是 final 的,需要实现上的保证。这可以确保不会 出现死锁,因为获得锁的顺序是固定的。 HashTable 的迭代器是强一致性的,而 ConcurrentHashMap 是弱一致的。 ConcurrentHashMap 的 get,clear,iterator 方法都是弱一致性的。 初识ConcurrentHashMap Concurrent翻译过来是并发的意思,字面理解它的作用是处理并发情况的 HashMap。 通过前面的学习,我们知道多线程并发下 HashMap 是不安全的(如死循环),更普遍 的是多线程并发下,由于堆内存对于各个线程是共享的,而 HashMap 的 put 方法 不是原子操作,假设Thread1先 put 值,然后 sleep 2秒(也可以是系统时间片切换失 去执行权),在这2秒内值被Thread2改了,Thread1“醒来”再 get 的时候发现已经不 是原来的值了,这就容易出问题。 那么如何避免这种多线程出错的情况呢? 常规思路就是给 HashMap 的 put 方法加锁(synchronized),保证同一个时刻只允 许一个线程拥有对 hashmap 有写的操作权限即可。然而假如线程1中操作耗时,其 他需要操作该 hashmap 的线程就需要在门口排队半天,严重影响用户体验, HashTable 就是这样子做的。 举个生活中的例子,很多银行除了存取钱,还支持存取贵重物品,贵重物品都放在 保险箱里,把 HashMap 和 HashTable 比作银行,结构: 把线程比作人,对应的情况如下: 多线程下用 HashMap 不确定性太高,有破产的风险,不能选;用 HashTable 不会 破产,但是用户体验不太好,那么怎样才能做到多人存取既不影响他人存值,又不 用排队呢? 有人提议搞个「银行者联盟」,多开几个像HashTable 这种「带锁」的银行就好 了,有多少人办理业务,就开多少个银行,一对一服务,这个区都是大老板,开银 行的成本都是小钱,于是「银行者联盟」成立了。 接下来的情况是这样的:比如用户A和用户B一起去银行存各自的项链,这个「银行 者联盟」操作后,然后对用户A说,1号银行现在没人你可以去那存,不用排队,然 后用户A就去1号银行存项链,1号银行把用户A接进门,马上拉闸,然后把用户A的 项链放在第x行第x个保险箱,等用户A办妥离开后,再开闸;对于用户B同理。此时 不管用户A和用户B在各自银行里面待多久都不会影响到彼此,不用担心自己的项链 被人偷换了。这就是ConcurrentHashMap的设计思路,用一个图来理解 从上图可以看出,此时锁的是对应的单个银行,而不是整个「银行者联盟」。分析 下这种设计的特点: 多个银行组成的「银行者联盟」 当有人来办理业务时,「银行者联盟」需要确定这个人去哪个银行 当此人去到指定银行办理业务后,该银行上锁,其他人不能同时执行修改操作,直 到此人离开后解锁. ConcurrentHashMap源码解析 ConcurrentHashMap 同样也分为 1.7 、1.8 版,两者在实现上略有不同。 先来看看 1.7 的实现,下面是结构图: 如图所示,是由 Segment 数组、HashEntry 组成,和 HashMap 一样,仍然是数组 加链表。主要是通过分段锁实现的。 关于分段锁 段Segment继承了重入锁ReentrantLock,有了锁的功能,每个锁控制的是一段, 当每个Segment越来越大时,锁的粒度就变得有些大了。 分段锁的优势在于保证在操作不同段 map 的时候可以并发执行,操作同段 map 的时候,进行锁的竞争和等待。这相对于直接对整个map同步 synchronized是有优势的。 缺点在于分成很多段时会比较浪费内存空间(不连续,碎片化); 操作map时竞争 同一个分段锁的概率非常小时,分段锁反而会造成更新等操作的长时间等待; 当 某个段很大时,分段锁的性能会下降。 1.7 已经解决了并发问题,并且能支持 N 个 Segment 这么多次数的并发,但依然存 在 HashMap 在 1.7 版本中的问题。 那就是查询遍历链表效率太低。 因此 1.8 做了一些数据结构上的调整。 首先来看下底层的组成结构: 其实和 1.8 HashMap 结构类似,当链表节点数超过指定阈值的话,也是会转换成红 黑树的,大体结构也是一样的。 那么 JDK 1.8 ConcurrentHashMap 到底是如何实现线程安全的? 答案:其中抛弃了原有的Segment 分段锁,而采用了 CAS + synchronized 来保证 并发安全性。(cas:比较并替换) **① 基本组成 ** 抛弃了 JDK 1.7 中原有的 Segment 分段锁,而采用了 CAS + synchronized 来 保证并发安全性。 将JDK 1.7 中存放数据的 HashEntry 改为 Node,但作用是相同的。、 我们来看看 ConcurrentHashMap 的几个重要属性. 重要组成元素 Node:链表中的元素为 Node 对象。他是链表上的一个节点,内部存储了 key、 value 值,以及他的下一 个节点的引用。这样一系列的 Node 就串成一串,组成一 个链表。 ForwardingNode:当进行扩容时,要把链表迁移到新的哈希表,在做这个操作 时,会在把数组中的头节点替换为 ForwardingNode 对象。ForwardingNode 中不 保存 key 和 value,只保存了扩容后哈希表 (nextTable)的引用。此时查找相应 node 时,需要去 nextTable 中查找。 TreeBin:当链表转为红黑树后,数组中保存的引用为 TreeBin,TreeBin 内部不保 存 key/value,他保存了 TreeNode 的 list 以及红黑树 root。 TreeNode:红黑树的节点。 **② put 方法过程 ** 存储结构定义了容器的 “形状”,那容器内的东西按照什么规则来放呢?换句话讲, 某个 key 是按 照什么逻辑放入容器的对应位置呢? 我们假设要存入的 key 为对象 x,这个过程如下 : 1、通过对象 x 的 hashCode () 方法获取其 hashCode; 2、将 hashCode 映射到数组的某个位置上; 3、把该元素存储到该位置的链表中。 put 方法用来把一个键值对存储到 map 中。代码如下: 实际调用的是 putVal 方 法,第三个参数传入 false,控制 key 存在时覆盖原来的值。 请先看完代码注释,有个大致的了解,然后我们更加详细的学习一下: 判断存储的 key、value 是否为空,若为空,则抛出异常,否则,进入步骤 2。 计算 key 的 hash 值,随后进入自旋,该自旋可以确保成功插入数据,若 table 表为空或者长度为 0,则初始化 table 表,否则,进入步骤 3。 根据 key 的 hash 值取出 table 表中的结点元素,若取出的结点为空(该桶为 空),则使用 CAS 将 key、value、hash 值生成的结点放入桶中。否则,进入 步骤 4。 若该结点的的 hash 值为 MOVED(-1),则对该桶中的结点进行转移,否则, 进入步骤 5。 5 . 对桶中的第一个结点(即 table 表中的结点)进行加锁,对该桶进行遍历,桶中 的结点的 hash 值与 key 值与给定的 hash 值和 key 值相等,则根据标识选择是 否进行更新操作(用给定的 value 值替换该结点的 value 值),若遍历完桶仍 没有找到 hash 值与 key 值和指定的 hash 值与 key 值相等的结点,则直接新生 一个结点并赋值为之前后一个结点的下一个结点。进入步骤 6。 若 binCount 值达到红黑树转化的阈值,则将桶中的结构转化为红黑树存储, 后,增加 binCount 的值。 如果桶中的第一个元素的 hash 值大于 0,说明是链表结构,则对链表插入或者 更新。 如果桶中的第一个元素是 TreeBin,说明是红黑树结构,则按照红黑树的方式进 行插入或者更新。 在锁的保护下,插入或者更新完毕后,如果是链表结构,需要判断链表中元素 的数量是否超过 8(默认),一旦超过,就需要考虑进行数组扩容,或者是链表 转红黑树。 扩容 什么时候会扩容? 使用put()添加元素时会调用addCount(),内部检查sizeCtl看是否需要扩容。 tryPresize()被调用,此方法被调用有两个调用点: 链表转红黑树(put()时检查)时如果table容量小于64(MIN_TREEIFY_CAPACITY),则会 触发扩容。 调用putAll()之类一次性加入大量元素,会触发扩容。 addCount() addCount()与tryPresize()实现很相似,我们先以addCount()分析下扩容逻辑: **1.链表转红黑树 ** 首先我们要理解为什么 Map 需要扩容,这是因为我们采用哈希表存储数据,当固定 大小的哈希表存 储数据越来越多时,链表长度会越来越长,这会造成 put 和 get 的 性能下降。此时我们希望哈希表中多一些桶位,预防链表继续堆积的更长。 ConcurrentHashMap 有链表转红黑树的操作,以提高查找的速度,红黑树时间复 杂度为 O (logn),而链表是 O (n/2),因此只在 O (logn)<O (n/2) 时才会进行转换, 也就是以 8 作为分界点。 接下来我们分析 treeifyBin 方法代码,这个代码中会选择是把此时保存数据所在的 链表转为红黑树,还是对整个哈希表扩容。 treeifyBin 不一定就会进行红黑树转换,也可能是仅仅做数组扩容。 构造完TreeBin这个空节点之后,就开始构造红黑树,首先是第一个节点,左右 子节点设置为空,作为红黑树的root节点,设置为黑色,父节点为空。 然后在每次添加完一个节点之后,都会调用balanceInsertion方法来维持这是一 个红黑树的属性和平衡性。红黑树所有操作的复杂度都是O(logn),所以当元素量比 较大的时候,效率也很高。 **数组扩容 ** 我们大致了解了 ConcurrentHashMap 的存储结构,那么我们思考一个问题,当数 组中保存的链表越来越多,那么再存储进来的元素大概率会插入到现有的链表中, 而不是使用数组中剩下的空位。 这样会造成数组中保存的链表越来越长,由此导致 哈希表查找速度下降,从 O (1) 慢慢趋近于链表 的时间复杂度 O (n/2),这显然违背 了哈希表的初衷。 所以 ConcurrentHashMap 会做一个操作, 称为扩容。也就是把数组长度变大,增 加更多的空位出来,终目的就是预防链表过长,这样查找的时间复杂度才会趋向于 O (1)。扩容的操作并不会在数组没有空位时才进行,因为在桶位快满时, 新保存元 素更大的概率会命中已经使用的位置,那么可能后几个桶位很难被使用,而链表却 越来 越长了。ConcurrentHashMap 会在更合适的时机进行扩容,通常是在数组中 75% 的位置被使用 时。 其实以上内容和 HashMap 类似,ConcurrentHashMap 此外提供了线程安全的保 证,它主要是通 过 CAS 和 Synchronized 关键字来实现,我们在源码分析中再详细 来看。 我们做一下总结: 1、ConcurrentHashMap 采用数组 + 链表 + 红黑树的存储结构; 2、存入的 Key 值通过自己的 hashCode 映射到数组的相应位置; 3、ConcurrentHashMap 为保障查询效率,在特定的时候会对数据增加长度,这个 操作叫做扩容; 4、当链表长度增加到 8 时,可能会触发链表转为红黑树(数组长度如果小于 64, 优先扩容,具体 看后面源码分析)。 接下来,我们的源码分析就从 ConcurrentHashMap 的构成、保存元素、哈希算 法、扩容、查找数 据这几个方面来进行 扩容后数组容量为原来的 2 倍。 **数据迁移( 扩容时的线程安全) ** ConcurrentHashMap 的扩容时机和 HashMap 相同,都是在 put 方法的后一步 检查是否需要扩容,如果需要则进行扩容,但两者扩容的过程完全不同, ConcurrentHashMap 扩容的方法叫做 transfer,从 put 方法的 addCount 方法进 去,就能找到 transfer 方法,transfer 方法的主要思路是: 首先需要把老数组的值全部拷贝到扩容之后的新数组上,先从数组的队尾开始 拷贝; 拷贝数组的槽点时,先把原数组槽点锁住,保证原数组槽点不能操作,成功拷 贝到新数组时,把 原数组槽点赋值为转移节点; 这时如果有新数据正好需要 put 到此槽点时,发现槽点为转移节点,就会一直 等待,所以在扩容完成之前,该槽点对应的数据是不会发生变化的; 从数组的尾部拷贝到头部,每拷贝成功一次,就把原数组中的节点设置成转移 节点; 直到所有数组数据都拷贝到新数组时,直接把新数组整个赋值给数组容器,拷 贝完成 putTreeVal()与此方法遍历方式类似不再介绍。  ④ get 方法过程 ConcurrentHashMap 读的话,就比较简单,先获取数组的下标,然后通过判断数 组下标的 key 是 否和我们的 key 相等,相等的话直接返回,如果下标的槽点是链表 或红黑树的话,分别调用相应的 查找数据的方法,整体思路和 HashMap 很像,源 码如下: 计算 hash 值。 根据 hash 值找到数组对应位置: (n – 1) & h。 根据该位置处结点性质进行相应查找。 如果该位置为 null,那么直接返回 null。 如果该位置处的结点刚好就是需要的,返回该结点的值即可。 如果该位置结点的 hash 值小于 0,说明正在扩容,或者是红黑树。 如果以上 3 条都不满足,那就是链表,进行遍历比对即可。 ** 初始化数组 ** 数组初始化时,首先通过自旋来保证一定可以初始化成功,然后通过 CAS 设置 SIZECTL 变量的值,来保证同一时刻只能有一个线程对数组进行初始化,CAS 成功 之后,还会再次判断当前数组是否已经初始化完成,如果已经初始化完成,就不会 再次初始化,通过自旋 + CAS + 双重 check 等 手段保证了数组初始化时的线程安 全,源码如下: 里面有个关键的值 sizeCtl,这个值有多个含义。 1、-1 代表有线程正在创建 table; 2、-N 代表有 N-1 个线程正在复制 table; 3、在 table 被初始化前,代表 根据构造函数传入的值计算出的应被初始化的大小; 4、在 table 被初始化后,则被 设置为 table 大小 的 75%,代表 table 的容量(数组容量)。 initTable 中使用到 1 和 4,2 和 3 在其它方法中会有使用。下面我们可以先看下 ConcurrentHashMap 的构造方法,里面会使用上面的 3 最后来回顾总结下HashMap和ConcurrentHashMap对比 ConcurrentHashMap 和 HashMap 两者的相同之处: 1.数组、链表结构几乎相同,所以底层对数据结构的操作思路是相同的(只是思路 相同,底层实现 不同); 2.都实现了 Map 接口,继承了 AbstractMap 抽象类,所以大多数的方法也都是相 同的, HashMap 有的方法,ConcurrentHashMap 几乎都有,所以当我们需要从 HashMap 切换到 ConcurrentHashMap 时,无需关心两者之间的兼容问题 不同点: 1.红黑树结构略有不同,HashMap 的红黑树中的节点叫做 TreeNode,TreeNode 不仅仅有属 性,还维护着红黑树的结构,比如说查找,新增等等; ConcurrentHashMap 中红黑树被拆分成 两块,TreeNode 仅仅维护的属性和查找 功能,新增了 TreeBin,来维护红黑树结构,并负责根 节点的加锁和解锁; 2.新增 ForwardingNode (转移)节点,扩容的时候会使用到,通过使用该节点, 来保证扩容时的线程安全。
剑曼红尘 2020-03-25 11:21:44 0 浏览量 回答数 0

问题

如何用发展的眼光看待seo

    如今,人们的日常生活越来越离不开网络,网络的发展已经成为像电视、报纸一样重要的媒体。精明的商家自然不忽略这样重要的的媒体,想通过各种办法,在网络上展示自己的产品,...
纸鸳鸯 2019-12-01 22:01:22 7256 浏览量 回答数 0

回答

楼主您好, 按这里的介绍说明,主要是以是否使用超过“全日带宽的30%”来判断的,如超过30%,则使用按“带宽”的计费方式,反之是使用“流量”。 两种计费方式,可能不会主要体现在速度差别上(理论上,按流量计算上限是10Gbps,而按带宽则有100Gbps)。 您可以先估算用户大概是在什么时间段下载文件,大概有多少用户下载的,得出单日的带宽大概会消耗多少,再选择“按流量”或“按带宽”的计费方式喔。 这两种计费方式是可以切换的,即在下一个计费周期可切换到另一种计费方式。 资料出处: http://help.aliyun.com/document_detail/cdn/billing/price.html?spm=5176.product8314936_cdn.4.51.DjO4SF
dongshan8 2019-12-02 01:01:47 0 浏览量 回答数 0

回答

<#ifuserModel.modifyTime?exists>  //TODO </#if>回复 @jet_zhang:厉害了我的哥,测试成功回复 @Mpengpeng:你现在页面能使用${},说明你已经配了html拦截器,你可以直接这样试试value="<#ifuserModel.modifyTime??>${(userModel.modifyTime)?string('yyyy-MM-ddHH:mm:ss')}</#if>"html页面怎么弄?回复 @Mpengpeng:freemarker是ftl页面html页面支持这种写法吗??问号前加个惊叹号!加上后也不行,还是会报错加上后也不行,报错如下:freemarker.template.TemplateException:Expectedmethod.(userModel.modifyTime)!?stringevaluatedinsteadtofreemarker.template.SimpleScalaronline55,column73inuser/userInfo.html. 页面:<inputtype="text"disabled="disabled"value="${(userModel.modifyTime)!?string('yyyy-MM-ddHH:mm:ss')}"/> 先用if判断一下吧<#if userModel??&& userModel.modifyTime??></#if>你可以先判断时间是否存在,存在的话执行你原来的这段代码即可 ${(userModel.modifyTime?string('yyyy-MM-ddHH:mm:ss'))!}一样的是undefined,说是找不到modifyTime,但是后台有这个属性,传的是个null值?exists試試
爱吃鱼的程序员 2020-06-08 20:20:06 0 浏览量 回答数 0

云产品推荐

上海奇点人才服务相关的云产品 小程序定制 上海微企信息技术相关的云产品 国内短信套餐包 ECS云服务器安全配置相关的云产品 开发者问答 阿里云建站 自然场景识别相关的云产品 万网 小程序开发制作 视频内容分析 视频集锦 代理记账服务 阿里云AIoT