2021年1月30日星期六

深入理解JavaScript作用域和作用域链

JavaScript中有一个被称为作用域(Scope)的特性。虽然对于许多新手开发者来说,作用域的概念并不是很容易理解,本文我会尽我所能用最简单的方式来解释作用域和作用域链,希望大家有所收获!

目录
  • 前言
  • 作用域(Scope)
    • 1.什么是作用域
    • 2.全局作用域和函数作用域
    • 3.块级作用域
  • 作用域链
    • 1.什么是自由变量
    • 2.什么是作用域链
    • 3.关于自由变量的取值
  • 作用域与执行上下文
    • 解释阶段:
    • 执行阶段:
  • 后记

前言

JavaScript中有一个被称为作用域(Scope)的特性。虽然对于许多新手开发者来说,作用域的概念并不是很容易理解,本文我会尽我所能用最简单的方式来解释作用域和作用域链,希望大家有所收获!

作用域(Scope)

1.什么是作用域

作用域是在运行时代码中的某些特定部分中变量,函数和对象的可访问性。换句话说,作用域决定了代码区块中变量和其他资源的可见性。可能这两句话并不好理解,我们先来看个例子:

function outFun2() { var inVariable = "内层变量2";}outFun2();//要先执行这个函数,否则根本不知道里面是啥console.log(inVariable); // Uncaught ReferenceError: inVariable is not defined

从上面的例子可以体会到作用域的概念,变量inVariable在全局作用域没有声明,所以在全局作用域下取值会报错。我们可以这样理解:作用域就是一个独立的地盘,让变量不会外泄、暴露出去。也就是说作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突。

ES6 之前 JavaScript 没有块级作用域,只有全局作用域和函数作用域。ES6的到来,为我们提供了'块级作用域',可通过新增命令let和const来体现。

2.全局作用域和函数作用域

在代码中任何地方都能访问到的对象拥有全局作用域,一般来说以下几种情形拥有全局作用域:

  • 最外层函数 和在最外层函数外面定义的变量拥有全局作用域
var outVariable = "我是最外层变量"; //最外层变量function outFun() { //最外层函数 var inVariable = "内层变量"; function innerFun() { //内层函数  console.log(inVariable); } innerFun();}console.log(outVariable); //我是最外层变量outFun(); //内层变量console.log(inVariable); //inVariable is not definedinnerFun(); //innerFun is not defined
  • 所有末定义直接赋值的变量自动声明为拥有全局作用域
function outFun2() { variable = "未定义直接赋值的变量"; var inVariable2 = "内层变量2";}outFun2();//要先执行这个函数,否则根本不知道里面是啥console.log(variable); //未定义直接赋值的变量console.log(inVariable2); //inVariable2 is not defined
  • 所有window对象的属性拥有全局作用域

一般情况下,window对象的内置属性都拥有全局作用域,例如window.name、window.location、window.top等等。

全局作用域有个弊端:如果我们写了很多行 JS 代码,变量定义都没有用函数包括,那么它们就全部都在全局作用域中。这样就会 污染全局命名空间, 容易引起命名冲突。

// 张三写的代码中var data = {a: 100}// 李四写的代码中var data = {x: true}

这就是为何 jQuery、Zepto 等库的源码,所有的代码都会放在(function(){....})()中。因为放在里面的所有变量,都不会被外泄和暴露,不会污染到外面,不会对其他的库或者 JS 脚本造成影响。这是函数作用域的一个体现。

函数作用域,是指声明在函数内部的变量,和全局作用域相反,局部作用域一般只在固定的代码片段内可访问到,最常见的例如函数内部。

function doSomething(){ var blogName="浪里行舟"; function innerSay(){  alert(blogName); } innerSay();}alert(blogName); //脚本错误innerSay(); //脚本错误

作用域是分层的,内层作用域可以访问外层作用域的变量,反之则不行。我们看个例子,用泡泡来比喻作用域可能好理解一点:

最后输出的结果为 2, 4, 12

  • 泡泡1是全局作用域,有标识符foo;
  • 泡泡2是作用域foo,有标识符a,bar,b;
  • 泡泡3是作用域bar,仅有标识符c。

值得注意的是:块语句(大括号"{}"中间的语句),如 if 和 switch 条件语句或 for 和 while 循环语句,不像函数,它们不会创建一个新的作用域。在块语句中定义的变量将保留在它们已经存在的作用域中。

if (true) { // 'if' 条件语句块不会创建一个新的作用域 var name = 'Hammad'; // name 依然在全局作用域中}console.log(name); // logs 'Hammad'

JS 的初学者经常需要花点时间才能习惯变量提升,而如果不理解这种特有行为,就可能导致
bug 。正因为如此, ES6 引入了块级作用域,让变量的生命周期更加可控。

3.块级作用域

块级作用域可通过新增命令let和const声明,所声明的变量在指定块的作用域外无法被访问。块级作用域在如下情况被创建:

  1. 在一个函数内部
  2. 在一个代码块(由一对花括号包裹)内部

let 声明的语法与 var 的语法一致。你基本上可以用 let 来代替 var 进行变量声明,但会将变量的作用域限制在当前代码块中。块级作用域有以下几个特点:

  • 声明变量不会提升到代码块顶部

let/const 声明并不会被提升到当前代码块的顶部,因此你需要手动将 let/const 声明放置到顶部,以便让变量在整个代码块内部可用。

function getValue(condition) {if (condition) {let value = "blue";return value;} else {// value 在此处不可用return null;}// value 在此处不可用}
  • 禁止重复声明

如果一个标识符已经在代码块内部被定义,那么在此代码块内使用同一个标识符进行 let 声明就会导致抛出错误。例如:

var count = 30;let count = 40; // Uncaught SyntaxError: Identifier 'count' has already been declared

在本例中, count 变量被声明了两次:一次使用 var ,另一次使用 let 。因为 let 不能在同一作用域内重复声明一个已有标识符,此处的 let 声明就会抛出错误。但如果在嵌套的作用域内使用 let 声明一个同名的新变量,则不会抛出错误。

var count = 30;// 不会抛出错误if (condition) {let count = 40;// 其他代码}
  • 循环中的绑定块作用域的妙用

开发者可能最希望实现for循环的块级作用域了,因为可以把声明的计数器变量限制在循环内,例如:

for (let i = 0; i < 10; i++) { // ...}console.log(i);// ReferenceError: i is not defined

上面代码中,计数器i只在for循环体内有效,在循环体外引用就会报错。

var a = [];for (var i = 0; i < 10; i++) { a[i] = function () { console.log(i); };}a[6](); // 10

上面代码中,变量i是var命令声明的,在全局范围内都有效,所以全局只有一个变量i。每一次循环,变量i的值都会发生改变,而循环内被赋给数组a的函数内部的console.log(i),里面的i指向的就是全局的i。也就是说,所有数组a的成员里面的i,指向的都是同一个i,导致运行时输出的是最后一轮的i的值,也就是 10。

如果使用let,声明的变量仅在块级作用域内有效,最后输出的是 6。

var a = [];for (let i = 0; i < 10; i++) { a[i] = function () { console.log(i); };}a[6](); // 6

上面代码中,变量i是let声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量,所以最后输出的是6。你可能会问,如果每一轮循环的变量i都是重新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值?这是因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。

另外,for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。

for (let i = 0; i < 3; i++) { let i = 'abc'; console.log(i);}// abc// abc// abc

上面代码正确运行,输出了 3 次abc。这表明函数内部的变量i与循环变量i不在同一个作用域,有各自单独的作用域。

作用域链

1.什么是自由变量

首先认识一下什么叫做 自由变量 。如下代码中,console.log(a)要得到a变量,但是在当前的作用域中没有定义a(可对比一下b)。当前作用域没有定义的变量,这成为 自由变量 。自由变量的值如何得到 —— 向父级作用域寻找(注意:这种说法并不严谨,下文会重点解释)。

var a = 100function fn() { var b = 200 console.log(a) // 这里的a在这里就是一个自由变量 console.log(b)}fn()

2.什么是作用域链

如果父级也没呢?再一层一层向上寻找,直到找到全局作用域还是没找到,就宣布放弃。这种一层一层的关系,就是 作用域链 。

var a = 100function F1() { var b = 200 function F2() {  var c = 300  console.log(a) // 自由变量,顺作用域链向父作用域找  console.log(b) // 自由变量,顺作用域链向父作用域找  console.log(c) // 本作用域的变量 } F2()}F1()

3.关于自由变量的取值

关于自由变量的值,上文提到要到父作用域中取,其实有时候这种解释会产生歧义。

var x = 10function fn() { console.log(x)}function show(f) { var x = 20 (function() { f() //10,而不是20 })()}show(fn)

在fn函数中,取自由变量x的值时,要到哪个作用域中取?——要到创建fn函数的那个作用域中取,无论fn函数将在哪里调用

所以,不要在用以上说法了。相比而言,用这句话描述会更加贴切:要到创建这个函数的那个域"。
作用域中取值,这里强调的是"创建",而不是"调用"
,切记切记——其实这就是所谓的"静态作用域"

var a = 10function fn() { var b = 20 function bar() { console.log(a + b) //30 } return bar}var x = fn(), b = 200x() //bar()

fn()返回的是bar函数,赋值给x。执行x(),即执行bar函数代码。取b的值时,直接在fn作用域取出。取a的值时,试图在fn作用域取,但是取不到,只能转向创建fn的那个作用域中去查找,结果找到了,所以最后的结果是30

作用域与执行上下文

许多开发人员经常混淆作用域和执行上下文的概念,误认为它们是相同的概念,但事实并非如此。

我们知道JavaScript属于解释型语言,JavaScript的执行分为:解释和执行两个阶段,这两个阶段所做的事并不一样:

解释阶段:

  • 词法分析
  • 语法分析
  • 作用域规则确定

执行阶段:

  • 创建执行上下文
  • 执行函数代码
  • 垃圾回收

JavaScript解释阶段便会确定作用域规则,因此作用域在函数定义时就已经确定了,而不是在函数调用时确定,但是执行上下文是函数执行之前创建的。执行上下文最明显的就是this的指向是执行时确定的。而作用域访问的变量是编写代码的结构确定的。

作用域和执行上下文之间最大的区别是:
执行上下文在运行时确定,随时可能改变;作用域在定义时就确定,并且不会改变

一个作用域下可能包含若干个上下文环境。有可能从来没有过上下文环境(函数从来就没有被调用过);有可能有过,现在函数被调用完毕后,上下文环境被销毁了;有可能同时存在一个或多个(闭包)。同一个作用域下,不同的调用会产生不同的执行上下文环境,继而产生不同的变量的值

后记

如需前端指导、前端资料、Java指导和 Java 资料的请联系本人,感谢您的支持。

WECHAT:xzsj07
备注:请注明来源。

作者:浪里行舟
链接:深入理解JavaScript作用域和作用域链
来源:github
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。









原文转载:http://www.shaoqun.com/a/521183.html

跨境电商:https://www.ikjzd.com/

四海商舟:https://www.ikjzd.com/w/1516

logo免费制作:https://www.ikjzd.com/w/1998


JavaScript中有一个被称为作用域(Scope)的特性。虽然对于许多新手开发者来说,作用域的概念并不是很容易理解,本文我会尽我所能用最简单的方式来解释作用域和作用域链,希望大家有所收获!目录前言作用域(Scope)1.什么是作用域2.全局作用域和函数作用域3.块级作用域作用域链1.什么是自由变量2.什么是作用域链3.关于自由变量的取值作用域与执行上下文解释阶段:执行阶段:后记前言JavaSc
hemingway:hemingway
笨鸟海淘:笨鸟海淘
近期美国企业对华出口产品发起337调查申请汇总:近期美国企业对华出口产品发起337调查申请汇总
好消息!2018双11菲律宾Lazada线上订单达5000多万份!:好消息!2018双11菲律宾Lazada线上订单达5000多万份!
注意!中国邮政发往美国部分产品价格已上调!:注意!中国邮政发往美国部分产品价格已上调!

2021年1月29日星期五

脱发严重怎么回事

核心提示:现如今每个人肩膀上的担子都比较重,压力也在不断加大,从而导致人们的精神状态一直不是很好,不仅对健康有些影响,也容易让人出现脱发的现象。本身因为工作与生活就已经非常烦燥,再加上每天不断脱发,更是让人苦闷不已。脱发严重怎么回事呢?

现如今每个人肩膀上的担子都比较重,压力也在不断加大,从而导致人们的精神状态一直不是很好,不仅对健康有些影响,也容易让人出现脱发的现象。本身因为工作与生活就已经非常烦燥,再加上每天不断脱发,更是让人苦闷不已。脱发严重怎么回事呢?

脱发严重怎么回事

脱发问题似乎是很多人都会遇到的事情,这里所说的脱发是指每天掉发量已经超过标准线,正常生理代谢的脱发量大概每天是在几十到一百根左右,如果超过这个量则被判定为脱发。脱发已经属于一种疾病,需要引起重视,最好通过一些方法进行控制,避免真的到了秃顶的地步,到那个时候若再想控制就真的非常难。


长期熬夜,长期处于精神压力大的状态就容易发生脱发,不管因为什么原因经常熬夜,会使内分泌失调,长期内分泌紊乱无法保持正常生理代谢,头发生长周期也会被打乱,久而久之就会有脱发。要知道人体正常新陈代谢的稳定性需要保持足够睡眠时间才能维系,如果长期熬夜或是睡眠不足,新陈代谢势必会被打乱,造成内分泌失调这种问题。精神压力大也是这个原理,长期压抑自己的情况,内分泌会紊乱,使身体血液循环变差,当头皮血液运行不畅,毛细血管收缩,引起头皮血液循环障碍,导致脱发。

有不少女性在经历生产后三四个月会有严重脱发现象,这是每个产妇都会经历的过程,不要过于惊讶,主要是因为在孕期雌激素偏高,在胎儿出生后,雌激素含量会突然下降,头皮来不及反应,无法快速适应,从而造成脱发,不过多数是在产后六到一年内即可自然恢复,停止脱发。若超过一年还在继续脱发,最好还是到皮肤科接受检查,找到根本诱因并进行调理。

脱发严重怎么回事?诱因有很多,上述内容中主要说明我们生活中常见的一些情况,也有极个人别脱发人群确实与疾病有关系,比如发生某些癌变,在接受化疗放疗时确实会使头发大幅度脱落,这种特殊情况就需要特殊对待,多听医生的建议即可。


原文转载:http://health.shaoqun.com/a/148939.html

跨境电商:https://www.ikjzd.com/

xinong:https://www.ikjzd.com/w/1368

crowd:https://www.ikjzd.com/w/880


核心提示:现如今每个人肩膀上的担子都比较重,压力也在不断加大,从而导致人们的精神状态一直不是很好,不仅对健康有些影响,也容易让人出现脱发的现象。本身因为工作与生活就已经非常烦燥,再加上每天不断脱发,更是让人苦闷不已。脱发严重怎么回事呢? 现如今每个人肩膀上的担子都比较重,压力也在不断加大,从而导致人们的精神状态一直不是很好,不仅对健康有些影响,也容易让人出现脱发的现象。本身因为工作与生活就已经非常
百思买:百思买
卖家网:卖家网
欺诈近700万!4名印度人利用退换货"玩转"亚马逊!:欺诈近700万!4名印度人利用退换货"玩转"亚马逊!
Facebook重要更新:Shops电商准入要求更新:Facebook重要更新:Shops电商准入要求更新
黑科技复出!天天秒杀、关键词上首页都有新姿势了?:黑科技复出!天天秒杀、关键词上首页都有新姿势了?

白带血丝怎么回事儿

核心提示:白带健康对每个女性都至关重要,它可是女性确认自己妇科健康的重要依据,如果白带有异常必须引起警惕,极有可能是妇科健康出现隐患的警告信息,有必要第一时间到医院接受白带常规检查,那白带血丝怎么回事儿?

白带健康对每个女性都至关重要,它可是女性确认自己妇科健康的重要依据,如果白带有异常必须引起警惕,极有可能是妇科健康出现隐患的警告信息,有必要第一时间到医院接受白带常规检查,那白带血丝怎么回事儿?

白带血丝怎么回事儿


白带中有血丝这种症状在临床的发生率确实比较高,很多女性因为遇到这种现象,会感觉到害怕,以为自己患上了哪种恶劣的妇科病,常常被吓到六神无主。白带有血丝出现后不要紧张,如果真的是重大妇科疾病,也不止只有这一种症状,身体还会伴有其它不适感,比如腹痛、月经不调、白带分泌量或伴有其它异样,若只是单纯白带中有血丝,也不能排除可能是生理性因素。

所谓生理性因素白带有血丝,就是指女性在排卵期或者是月经刚刚结束那几天。确实有部分女性在排卵期会有阴道出血,只不过出血量真的很少,甚至是肉眼看不到的量,而且持续时间大概只有两三天的样子,在此期间并不会有任何其它综合性症状,所以不用过于担心。经期快要结束那几天经血量会越来越少,慢慢再完全干净,其实在少量那几天有可能会有一部分经血滞留在阴道内没有排出,所以隔几天突然随白带一起流出,血色发暗,同样属于生理性。当然若正好在排卵期,或正好在经期结束那几天,阴道确实有出血,出血量却很大,最好还是要引起注意,要有自我辨别、判断的能力。

关于白带血丝怎么回事儿?以上内容中主要说明生活中常见的两种情况,属于生理性 。当然也有些女性白带有血丝确实与疾病有关系,妇科疾病有很多症状表现都是如此,比如阴道炎、宫颈炎、宫颈糜烂、功血等,这些妇科疾病若发现晚治疗晚,确实会有白带血丝这种症状表现。一旦经过检查后被确诊是病理性因素,必须第一时间接受治疗,避免病情恶化。


原文转载:http://health.shaoqun.com/a/148936.html

跨境电商:https://www.ikjzd.com/

tiki:https://www.ikjzd.com/w/2053

www.made-in-china.com:https://www.ikjzd.com/w/2777


核心提示:白带健康对每个女性都至关重要,它可是女性确认自己妇科健康的重要依据,如果白带有异常必须引起警惕,极有可能是妇科健康出现隐患的警告信息,有必要第一时间到医院接受白带常规检查,那白带血丝怎么回事儿? 白带健康对每个女性都至关重要,它可是女性确认自己妇科健康的重要依据,如果白带有异常必须引起警惕,极有可能是妇科健康出现隐患的警告信息,有必要第一时间到医院接受白带常规检查,那白带血丝怎么回事儿?
贝贝官网:贝贝官网
折扣网站:折扣网站
从全球消费报告看跨境营销:社交媒体的有效推广:从全球消费报告看跨境营销:社交媒体的有效推广
出海中东:中国-沙特物流全链路了解一下!:出海中东:中国-沙特物流全链路了解一下!
13款最佳跨境电商关键词深度挖掘工具,提高您的网站自然流量:13款最佳跨境电商关键词深度挖掘工具,提高您的网站自然流量

青汁减肥喝法

核心提示:想要通过喝青汁的方式得到减肥的效果,首先要掌握正确的时间段,不要在早晨空腹的时候喝,最好是早饭的时候随餐饮用,这样可以减少吃早饭的量,还能增加人的饱腹感,而且随餐饮用青汁,可以促进肠胃蠕动,也可以预防食物中的脂肪被肠胃吸收。

在减肥期间如果能喝一些对于润肠通便有帮助的饮品,也能使减肥达到事半功倍的效果,青汁就是一种非常好的减肥饮品。可是有些朋友喝了一段时间青汁之后,并没有觉得有多么管用,所以担心是自己喝的方法不对,那么今天就来带大家了解青汁减肥喝法有哪些?

想要通过喝青汁的方式得到减肥的效果,首先要掌握正确的时间段,不要在早晨空腹的时候喝,最好是早饭的时候随餐饮用,这样可以减少吃早饭的量,还能增加人的饱腹感,而且随餐饮用青汁,可以促进肠胃蠕动,也可以预防食物中的脂肪被肠胃吸收。


正确的喝青汁,每天只能喝2~3杯,千万不要喝的太多,因为青汁属性寒凉,喝的太多容易导致腹泻,也不要喝的太少,如果喝青汁太少,就会导致减肥效果不好,在喝青汁的时候不要吃肉食,中午的时候可以喝青汁也可以不喝,如果中午饭吃的蔬菜和水果比较多,就可以不用喝青汁,如果午饭中吃的肉食比较多,就一定要喝一杯青汁,这样能够将肠胃中的油脂排出去。

减肥期间喝青汁只是一种辅助的方式,而喝青汁并不能起到主要的减肥功效,想要减肥效果好,一定要在日常生活中多做运动,因为运动能够消耗大量的皮下脂肪,皮下脂肪得到燃烧之后,减肥才会有明显的效果,每天至少要做30~40分钟有氧运动,或者做20~30分钟的无氧结合有氧运动。

看了上面的介绍,相信大家都明白了,青汁减肥喝法要怎么做才正确?希望所有的朋友都能正确地使用减肥茶饮,在喝减肥茶饮的过程中,饮食要控制好,如果饮食不加以节制,单纯的想依靠青汁来控制热量摄入是不会有太好效果的,只有将饮食控制加强运动和喝青汁,这三种方式相互结合,减肥的效果才能达到令人满意的程度。


原文转载:http://lady.shaoqun.com/a/265102.html

跨境电商:https://www.ikjzd.com/

tracker:https://www.ikjzd.com/w/2720

dmm.adult:https://www.ikjzd.com/w/2026


核心提示:想要通过喝青汁的方式得到减肥的效果,首先要掌握正确的时间段,不要在早晨空腹的时候喝,最好是早饭的时候随餐饮用,这样可以减少吃早饭的量,还能增加人的饱腹感,而且随餐饮用青汁,可以促进肠胃蠕动,也可以预防食物中的脂肪被肠胃吸收。 在减肥期间如果能喝一些对于润肠通便有帮助的饮品,也能使减肥达到事半功倍的效果,青汁就是一种非常好的减肥饮品。可是有些朋友喝了一段时间青汁之后,并没有觉得有多么管用,
海维:海维
跨境通:跨境通
【基础必修课】listing优化该这样做:【基础必修课】listing优化该这样做
想拿下客户?先做好定位再说!:想拿下客户?先做好定位再说!
分享购物信息就有奖励 亚马逊推出购物小组计划:分享购物信息就有奖励 亚马逊推出购物小组计划

JavaFx ObservableList的使用详解

原文地址:JavaFx ObservableList的使用详解 | Stars-One的杂货小窝

最近在研究MVVM模式,发现可以将之前写的FxRecyclerView控件改造一下,便是开始尝试,尝试过程中发现了不少坑,但是网上资料不是太全面,这里便写一篇笔记记录一下,以供后来者的学习

注:由于本人使用的是TornadoFx来编写JavaFx项目,所以本文代码是使用Kotlin进行编写,需要有Kotlin基础,阅读前请须知,以免浪费你宝贵的时间

介绍

在MVVM模式火的今天,没想到之前JavaFx已经早有实现,估计现在市面这些都是玩别人剩下的了

这次也是想到了之前的FxRecyclerView控件可以拿MVVM改造一番

网上的资料并不多,仅有少有的一两篇,无奈之下,只得自己啃着官方文档,自己摸索,终于是把基本的使用摸清了

ObservableList,正如其名,可观察的List,它与List一样,也是个接口(Java的基础知识了..)

官方简短介绍:
A list that allows listeners to track changes when they occur.

大意为当数据改变时,ObservableList可以监听到这些改变,本质上是提供了一个监听器接口ListChangeListener.Change来进行相关的监听,

怎么监听呢?只需要设置监听器即可

val observableList = observableListOf(0,1,2,3)observableList.onChange { change ->  while (change.next()) {   when {   change.wasPermutated() -> println("permutated (${change.from} ,${change.to})")   change.wasReplaced() -> println("replace (${change.from} ,${change.to})")   else -> {    when {     change.wasAdded() -> println("add (${change.from} ,${change.to})")     change.wasRemoved() -> println("remove (${change.from} ,${change.to})")     change.wasUpdated() -> println("update (${change.from} ,${change.to})")    }   }  }  }}

官方的使用中,必须要求我们在监听之前调用next方法,其返回false表示当前已经是最后一次改变

wasPermutated()这种方法都是返回的boolean值,当数据发生对应符合的变化,各自对应的方法会返回true

change.fromchange.to两个属性在后面提及,这里稍微留意一下

三种监听类型

从上面的代码中,我们可以看到有几个分支条件,每个分支就是数据发生了某种改变,基本的有三种情况:

  1. List排列顺序改变
  2. List中的数据发生改变(数据更新)
  3. List的数据添加及删除(数据新增或删除)

PS:官方文档说明中,监听的顺序依次为wasPermutated、add/remove、update

下面对这几种情况进行说明

1.排列更新监听

顺序排列更新,对应的change.wasPermutated(),其返回值为boolean值,当ObservableList的顺序发生变化(即进行了排序操作),此方法就会返回为true

fun main() { val observableList = observableListOf(0,1,2,3) println(observableList) observableList.onChange { change ->  while (change.next()) {   when {    change.wasPermutated() -> println("permutated (${change.from} ,${change.to})")        change.wasReplaced() -> println("replace (${change.from} ,${change.to})")    else -> {     when {      change.wasAdded() -> println("add (${change.from} ,${change.to})")      change.wasRemoved() -> println("remove (${change.from} ,${change.to})")      change.wasUpdated() -> println("update (${change.from} ,${change.to})")     }    }   }  } } observableList.sortBy { it } println(observableList) observableList.sortByDescending { it } println(observableList)}

对应的输出结果为:

[0, 1, 2, 3] //源数组permutated (0 ,4) //回调监听器中的方法[0, 1, 2, 3] //升序排列permutated (0 ,4) [3, 2, 1, 0] //降序排列

2.数据更新监听(replace)

这里大家可能会有点疑惑,最上面的代码不是有个wasUpdated()方法吗,这里怎么标的是replace?

我自己研究的时候,也是很奇怪...官方的那个wasUpdated()方法没有找到对应的回调方式,照理说我更新了数组中的一个数据,这个wasUpdated()应该返回的是true,但是实际测试的时候根本没有,反而是wasReplaced()返回了true

//上面省略相关代码...//JavaFx对应是set(index,element)方法observableList[1] = 12 //下标为1的对象更新为12println(observableList)

输出结果:

[0, 1, 2, 3]replace (1 ,2)[0, 12, 2, 3]

3.数据添加与删除监听(add remove)

数据添加和删除就和上面同理了,当我们调用add()(包括addAll())和remove()方法,对应的wasAdd()wasRemove()方法就会返回true

另外,ObservableList提供了两个List供我们拿到添加的数据和移除的数据

  • change.addedSubList 新增的数据列表
  • change.removed 被移除的数据列表

补充:from与to

这里大家可能就注意到了change对象的fromto这两个属性的区别了

本质上,ObservableList里面定义的fromto这两个代表开始下标和结束下标,在数据发生改变的时候,记录了是哪几条数据发生了改变,之后提供给我们,我们在ObservableList.change监听器方法中就可以使用这两个变量来进行相关的逻辑操作

以下是官方对from的说明:

If wasAdded is true, the interval contains all the values that were added. If wasPermutated is true, the interval marks the values that were permutated. If wasRemoved is true and wasAdded is false, getFrom() and getTo() should return the same number - the place where the removed elements were positioned in the list.

注意重点:如果是数据移除操作,返回的from和to数值是相同的

ObservableList方法说明

  • addAll()
  • remove(from,to) 移除[from,to)之间的元素,from是包含,to是不包含的,注意与remove监听事件返回的from和to都是相同的
  • move(oldIndex,newIndex) 将下标为oldIndex移动至newIndex下标处

补充:移动监听(move)

之前没有找到更新的方法,发现了ObservableList有move的方法,没想到这个在ObservableList中其实是先做remove操作,之后再做add操作

//代码与上面的一致,已省略//将下标1的数据移动到下标3的位置observableList.moveAt(1,3)println(observableList)

输出结果:

[0, 1, 2, 3]remove (1 ,1)add (3 ,4)[0, 2, 3, 1]

参考

  • JavaFX - 如何处理ObservableList的更改操作_W3Cschool代码实例
  • ListChangeListener.Change (JavaFX 8)
  • ObservableList (JavaFX 8)








原文转载:http://www.shaoqun.com/a/521112.html

跨境电商:https://www.ikjzd.com/

数魔跨境:https://www.ikjzd.com/w/1425.html

乐宝:https://www.ikjzd.com/w/2200


原文地址:JavaFxObservableList的使用详解|Stars-One的杂货小窝最近在研究MVVM模式,发现可以将之前写的FxRecyclerView控件改造一下,便是开始尝试,尝试过程中发现了不少坑,但是网上资料不是太全面,这里便写一篇笔记记录一下,以供后来者的学习注:由于本人使用的是TornadoFx来编写JavaFx项目,所以本文代码是使用Kotlin进行编写,需要有Kotlin基
sca:sca
谷歌趋势:谷歌趋势
FBA卖家注意啦!这7种情况下卖家可向亚马逊索赔!:FBA卖家注意啦!这7种情况下卖家可向亚马逊索赔!
2020年亚马逊店铺如何避免封号?疫情间亚马逊店铺想避免封号需要注意的地方有哪些?:2020年亚马逊店铺如何避免封号?疫情间亚马逊店铺想避免封号需要注意的地方有哪些?
普通产品和独特产品,怎么做亚马逊广告?:普通产品和独特产品,怎么做亚马逊广告?

面条属于粗粮吗?

核心提示:随着饮食种类的不断更新换代,有越来越多的健康饮食爱好者会回归食物的本质,经常以粗粮为食,归求食物最简单的加工过程,主要为了自身的身体健康及营养摄取。而平时的碳水化合物中,想要保证低碳水高营养,也会选择粗粮。那么,面条属于粗粮吗?

随着饮食种类的不断更新换代,有越来越多的健康饮食爱好者会回归食物的本质,经常以粗粮为食,归求食物最简单的加工过程,主要为了自身的身体健康及营养摄取。而平时的碳水化合物中,想要保证低碳水高营养,也会选择粗粮。那么,面条属于粗粮吗?

面条是大众比较受欢迎的主食种类,经常会出现在饭桌上。无论是一碗简单的泡面,还是经过长时间熬煮的浓汤面、臊子面,都可以当作正餐来食用。下面我们就来介绍一下面条属于粗粮吗,对此不太了解的朋友可以通过下文来学习一下。

1面条属于粗粮吗?

面条是否属于粗粮我们要从面条的加工成份上来分析。市面上大多数的手擀面、挂面、方便面都是由小麦制作而成。这时的面条属于细粮。但如果采用大麦、荞麦、玉米等原材料来压制的面条,就属于粗粮分属了。所以单纯从面条外观上判断属于粗粮还是细粮是无法确定的,需要看面条的制作材料。


2减肥可以吃面条么?


如果是小麦制作的面条,属于细粮范畴,会具有高碳水的营养,在减肥期间应当注意食用的量,因为这类面条升糖较快,易饱也易饿,可能会在食用之后二小时消化完毕。但如果是粗粮材料制作的面条,具有较高的纤维成份,易饱腹,升糖速度慢,消化也慢,是适合在减肥期间食用的。并且荞麦面、玉米面条都具有较好的口感,无论怎么吃,都要比细粮更有嚼劲,是广大健身人士经常选择的主食。但减肥期间如果特别想吃泡面,也并不是不可以。我们可以选择在早餐时煮一碗泡面,在煮面之后可以过一遍凉水,将多余的油脂冲掉,而且不要食用泡面当中的任何调料,这样可以大大减少热量的摄入。用清汤再将过水的泡面烧开,放入少量的食盐及蔬菜,也是相当美味的。


原文转载:http://lady.shaoqun.com/a/265086.html

跨境电商:https://www.ikjzd.com/

hemingway:https://www.ikjzd.com/w/2344

环球华网:https://www.ikjzd.com/w/1063


核心提示:随着饮食种类的不断更新换代,有越来越多的健康饮食爱好者会回归食物的本质,经常以粗粮为食,归求食物最简单的加工过程,主要为了自身的身体健康及营养摄取。而平时的碳水化合物中,想要保证低碳水高营养,也会选择粗粮。那么,面条属于粗粮吗? 随着饮食种类的不断更新换代,有越来越多的健康饮食爱好者会回归食物的本质,经常以粗粮为食,归求食物最简单的加工过程,主要为了自身的身体健康及营养摄取。而平时的碳水
汇通天下物流:汇通天下物流
rakuten:rakuten
虾皮最新DTS讲解,台湾出货有5天啦!:虾皮最新DTS讲解,台湾出货有5天啦!
跨境电商新手卖家须掌握的产品数据分析工具和方法:跨境电商新手卖家须掌握的产品数据分析工具和方法
亚马逊品牌备案!日本商标的注册流程,费用和流程详解:亚马逊品牌备案!日本商标的注册流程,费用和流程详解

晨勃每天都有的吗?

核心提示:男性每天早上4:00-7:00左右生殖器官会有晨勃,几乎所有男生都会经历这个过程,如果从进入青春期开始一直未有晨勃这种表现,很有可能是自己生殖器官健康存在隐患,需要检查并治疗。难道晨勃每天都有吗?

男性每天早上4:00-7:00左右生殖器官会有晨勃,几乎所有男生都会经历这个过程,如果从进入青春期开始一直未有晨勃这种表现,很有可能是自己生殖器官健康存在隐患,需要检查并治疗。难道晨勃每天都有吗?

晨勃每天都有吗

所谓晨勃是指男性阴茎在毫无意识、不受任何刺激、不受思想控制、不受任动作刺激的情况下自然勃起。多数人认为男性阴茎只有在某种受某种特定刺激后才会自然勃起,很明显这是一种误解,自从男生进入青春期开始就会时常发生无意识地自然勃起情况。


并不是每天都会有晨勃,但间隔时间并不会很长,相比之下经常性出现晨勃反而会更健康一些,当然也不是每天一定会发现明显晨勃,有可能是在夜间无意间,完全不知情的情况下已经发生晨勃。晨勃是男性生理正常症状表现,并不是每天都能感受到,但是值得注意的是,如果长期或长时间内没有晨勃,则可能真的是性功能出现异常或是存在性功能障碍,避免影响未来生活。

拥有正常性能力这是每个男性都希望的事情,如果自己性功能有异常,可能已无心再其它任何事情,而体现男性性功能是否正常的标准依据就包括晨勃。晨勃每天都有吗?正常情况下正处于青春期的青年男式确实每天早上会有晨勃,当进入中老年阶段,身体机能在不断下降,甚至可能患有泌尿系统类疾病,这种情况下就不一定每天早上都会有晨勃。

总之,晨勃是年轻男性的生理特征之一,只要身体完全健康的情况下,几乎每天都会有晨勃,偶尔因为身体过于疲惫,或是其它因素可能会暂时无晨勃,但间隔时间不会太久,只是偶尔发生的事情都不用过于紧张。短时间没有晨勃并不代表身体健康存在隐患,每天有晨勃也不代表性功能健康没有问题,一切要根据临床检查后综合判断。


原文转载:http://health.shaoqun.com/a/148929.html

跨境电商:https://www.ikjzd.com/

菜鸟网:https://www.ikjzd.com/w/1547

sgshop:https://www.ikjzd.com/w/1982


核心提示:男性每天早上4:00-7:00左右生殖器官会有晨勃,几乎所有男生都会经历这个过程,如果从进入青春期开始一直未有晨勃这种表现,很有可能是自己生殖器官健康存在隐患,需要检查并治疗。难道晨勃每天都有吗? 男性每天早上4:00-7:00左右生殖器官会有晨勃,几乎所有男生都会经历这个过程,如果从进入青春期开始一直未有晨勃这种表现,很有可能是自己生殖器官健康存在隐患,需要检查并治疗。难道晨勃每天都有
ensogo:ensogo
c88是什么:c88是什么
拉美国家海关这些特殊规定,你了解多少?:拉美国家海关这些特殊规定,你了解多少?
m2epro:m2epro
卖家账号被黑损失超30万美金!看资深卖家如何成功应对和预防:卖家账号被黑损失超30万美金!看资深卖家如何成功应对和预防

汇率波动影响外贸企业,阿里国际站“锁汇保”帮商家稳住利润

2020年,中国外贸逆势翻盘,从下半年开始,出口数据稳步增长。很多外贸企业订单接到手软,货品供不应求。但是年终盘点时,不少企业却发现利润遭遇"缩水"。背后很重要的一个原因,是人民币在过去的一年大幅升值。

 

"疫情对汇率的影响很大,下半年中国经济回暖,美元对人民币汇率从6.9直接掉到6.4左右。打个比方,若去年公司下半年出口额为400万美元;结汇后,汇率的波动可以导致营收上直接差出200万元。"苏州贝特瑞周小姐表示,实际营收差异虽然比这个数字小,但是足够让外贸商家唏嘘一番。

 

外贸企业从接到订单签订合同开始,一般有2个半月左右的时间进行原材料采购、设计、加工、最后到运输验收。

 

在这个过程中,只有签订合约时,商家拿到的定金不受汇率影响。而汇率下跌,最直接的反馈就是商家到手的尾款少了。加上疫情影响导致的交货期拉长,利润被二次压缩。

 

对此,商务部国际贸易经济合作研究院国际市场研究所副所长白明表示,汇率波动对外贸企业的影响是难以避免的汇率剧烈波动的情况下建议企业在可承受范围内锁定汇率

 

阿里巴巴国际站的锁汇保,便是一款帮助外贸商家减少汇率波动影响的产品。该产品通过锁定未来某一时间段的结汇汇率,减少人民币升值带来的损失。

 

"过往只是为了规避风险,去年直接帮公司保住了利润。"无锡赛诺星公司的运营Amy表示,公司使用阿里国际站的锁汇保产品,去年80%的订单都进行了锁汇。不仅如此,相较于线下跑银行,线上锁汇效率提升了90%以上。

 

阿里国际站支付结算业务相关负责人建议,商家可考虑从两方面规避风险:一、提前与买家商定用人民币结算;二,使用锁汇保这样的产品,规避汇率风险。





原文转载:http://www.shaoqun.com/a/521110.html

跨境电商:https://www.ikjzd.com/

prime:https://www.ikjzd.com/w/129

浩方:https://www.ikjzd.com/w/1046


2020年,中国外贸逆势翻盘,从下半年开始,出口数据稳步增长。很多外贸企业订单接到手软,货品供不应求。但是年终盘点时,不少企业却发现利润遭遇"缩水"。背后很重要的一个原因,是人民币在过去的一年大幅升值。"疫情对汇率的影响很大,下半年中国经济回暖,美元对人民币汇率从6.9直接掉到6.4左右。打个比方,若去年公司下半年出口额为400万美元;结汇后,汇率的波动可以导致营收上直接差出200万元。"苏州贝特
活动树:活动树
kili:kili
跨境物流经历最难旺季:海陆空线路"全灭":跨境物流经历最难旺季:海陆空线路"全灭"
春节期间,亚马逊卖家该如何打理店铺?:春节期间,亚马逊卖家该如何打理店铺?
国家出手:美国联邦快递已被立案调查!:国家出手:美国联邦快递已被立案调查!

亚马逊刷单又出事,众多卖家收到警告信!!!

即使在亚马逊明令禁止刷单行为之下,仍然还是有很多卖家"顶风作案",而亚马逊打击刷单的脚步也从未停歇!近来,有卖家反馈,收到了亚马逊发来的一封"警告信"。

图片

邮件中表示:卖家涉嫌通过提供补偿换取买家评论,因此需要采取相应措施以避免销售账户被停用。

图片


美国再现"神秘包裹"

此前,美媒曝光的种子刷单事件受到了广泛的关注,大批种子包裹从中国境内流向西方国家,中国跨境卖家也因此遭到平台警告。但如今,类似事件在美国仍不断发生。

近日,外媒报道,大多数人网购只需担心他们的货是否延迟或丢失,但现在有些人却要面临这这样的问题:收到一些没有购买过的奇怪的东西,比如理发器、面霜和太阳镜。

图片

对此,联邦贸易委员会(FTC)发出警告,提醒人们这些包裹可能是来自亚马逊、eBay等平台卖家的"刷单"骗局。

据大多数美国消费者表示,他们隔三差五就能收到一些不知名的包裹,包裹里通常是一些廉价的小商品,例如iPad保护套、床垫套、鱼玩具等。

刷单骗局大约在五年前开始在中国的电子商务网站兴起。去年夏天,当全美50个州都对神秘的、未经请求的种子包裹发出警告时,这些问题再次出现在新闻头条上。

但不仅仅是种子。毫不知情的收信人还在家门口发现了一些箱子,里面装着从狗屎铲到电源线到肥皂机等各种物品。

加州千橡树市的Jen Blinn(詹·布林)表示,自6月以来,她收到了很多随机的包裹,最近一次是一个公文包、一个背包、一个直发器和一个咖啡杯加热器。"每两周我就会收到一个包裹,里面都是我从未订购过的东西。"布林将这个问题反馈给了亚马逊。

图片

亚马逊前政策执行调查员克里斯·麦凯布(Chris McCabe)表示"事实上,你收到了一个你没有订购的包裹,这对你来说通常是无害的,但这对那些在决定购买时依赖评论的人造成了伤害。"根据美国西北大学研究报告显示,网购消费者购买有5条评论的产品的可能性比购买零评论的产品的可能性高270%。此外,由于还有许多收到类似包裹的消费者没有进行举报,因此,很难知道卖家具体的刷单数量及虚假评论的占比。

FTC在发出的邮件警告中提醒消费者:"如果您在没有购买的情况下收到了商品,很可能是由于刷单人员使用您的信息创建了一个账户,或者利用与您的地址绑定的其他名字创建了新的账户来发布虚假评论。建议大家提高警惕,及时查看您的网购平台账户。有任何异常情况,请立即向平台报告,并考虑更改平台账户密码"。

 图片

相关平台作出回应

亚马逊发言人表示一直以来都在严控卖家刷单行为,平台也有制定相关政策,违反政策的卖家将面临扣留付款、暂停或取消销售权限,严重者还将追究法律责任。

亚马逊前政策执行调查员McCabe指出,一些虚假评论可能是由Facebook群组推动的,亚马逊和Facebook应该合作打击这些群组。

对此,亚马逊发言人表示,为防止虚假评论泛滥,平台每周都会审查超1000万条评论,并将审核细节提供给社交媒体公司,这样他们就可以阻止这些不良卖家滥用他们的平台。

Facebook发言人也表示,当平台被告知某些群组涉嫌刷单交易时,它会立即对其展开审查,如果证实该群组违反了平台政策,则会将其删除。



文章来源:https://www.ikjzd.com/home/141588

跨境电商:https://www.ikjzd.com/

心怡科技:https://www.ikjzd.com/w/1327

002315焦点科技:https://www.ikjzd.com/w/1831

华翰物流:https://www.ikjzd.com/w/1799

亚马逊刷单又出事,众多卖家收到警告信!!!

即使在亚马逊明令禁止刷单行为之下,仍然还是有很多卖家"顶风作案",而亚马逊打击刷单的脚步也从未停歇!近来,有卖家反馈,收到了亚马逊发来的一封"警告信"。邮件中表示:卖家涉嫌通过提供补偿换取买家评论,因此需要采取相应措施以避免销售账户被停用。美国再现"神秘包裹"此前,美媒曝光的种子刷单事件受到了广泛的关注,大批种子包裹从中国境内流向西方国家,中国跨境卖家也因此遭到平台警告。但如今,类似事件在美国仍不

Facebook广告如何选择正确的兴趣词

Facebook的兴趣词并非天生完美得...
在这个有关Facebook兴趣定位的权威指南的上一章中,您了解到Facebook给兴趣词增加了大量的人数。
结果是这些受众中的许多人并不真正感兴趣...
在本章中,您将学习什么才是您想要的兴趣词,以及如何选择合适的兴趣词。

Facebook广告如何选择正确的兴趣词

这个"没有其他人的"标准是挑选最佳Facebook兴趣词的标准

如果你正在为你的Facebook广告活动选择兴趣,你应该瞄准明确定义和隔离你的目标受众的兴趣。

您可以使用"但没有其他人"标准来做到这一点

我将用一个例子来解释这个标准。

假设您有一家高尔夫商店,并向热心的业余高尔夫选手出售不同类型的产品。因此,您希望通过Facebook广告吸引的受众是经常打高尔夫球的人。您能做的最糟糕的事情恰恰是Facebook建议您做的...

针对广泛关注的"高尔夫"的受众。


虽然听起来很傻,但实际上这不是您应该选择的兴趣。
至少不是从一开始。
当您的Facebook广告系列逐渐成熟并且您收集了很多转化数据后,您就可以逐渐关注更广泛的兴趣,因为Facebook可以在庞大的"高尔夫"受众群体中找到最有可能转化的细分受众群。
我们将在本指南的最后一章中讨论如何扩展基于兴趣的受众定位。
您绝对不应该针对诸如"高尔夫"之类的广泛兴趣从一开始就付诸于广告系列。
第一个问题,大多数广告商选择这些广泛的受众,因为他们不懂,仅仅是Facebook向他们推荐了。

第二个问题是,他们虽然获得了大量的观众,但是其中许多人对这个主题甚至不感兴趣。考虑一下...真正的高尔夫爱好者对"高尔夫"的兴趣有多清晰?
一点也不。
Facebook认为有很多人对高尔夫感兴趣。根据他们的页面喜欢量,网站访问次数,对朋友关于高尔夫的帖子的评论等。但这并不意味着他们实际上对高尔夫感兴趣,并且很可能会购买您的产品。Facebook喜欢尽可能扩大这些受众的规模,因为这可以增加Facebook他们自己的收入。
但是,这些引起广泛关注的观众中,有很大比例的人是偶然地进入那里的。您不想向他们展示您的广告,您想向真正喜欢高尔夫的人展示广告。
再举一个例子...
您可能想要定位" Tiger Woods",这是当今最著名的高尔夫选手。
这可能是一个好主意吧!


在Facebook的眼里,有很多人对Tiger Woods感兴趣,也许根本就不是高尔夫球手。老虎在媒体上引起了很多与高尔夫无关的事情(例如,欺骗妻子)。
他还是咨询公司埃森哲的代表。
与Tiger Woods互动的所有这些人是否都满足了狂热的高尔夫选手和您的高尔夫商店的理想受众的需求?可能不会。选择正确的Facebook兴趣意味着您必须考虑兴趣词,并评估拥有该兴趣是否就是完美受众的定义特征。
还是其他人也有这种兴趣,但是不是你的受众!
换句话说,它是否明确定义和隔离了您的理想受众?您的高尔夫商店最感兴趣的是" Bubba Watson"。


如果您不喜欢高尔夫,您可能甚至从未听说过他的名字。但是,如果您对高尔夫充满热情,那么您肯定会知道他的名字。
他的名字实际上是Gerry Lester" Bubba" Watson Jr.,所以这是多次高尔夫大师锦标赛冠军的昵称。
这是一个极好的目标,因为您的目标高尔夫爱好者可能会"只有其他人"有此兴趣。那是"但没有其他人"标准背后的好选择。它定义了您的完美受众,并隔离了其他所有人。在进行Facebook兴趣定位研究时,明确定义受众并隔离其他所有人的想法是在定位目标受众的同时限制浪费广告预算的关键所在。

原文出自微信公众号:托帕信息,微信号:audtools,转载请注明出处。

来源:活活的杂谈

文章来源:https://www.ikjzd.com/home/141623

跨境电商:https://www.ikjzd.com/

丰趣海淘:https://www.ikjzd.com/w/1716

upc:https://www.ikjzd.com/w/111

卖家网:https://www.ikjzd.com/w/1569

Facebook广告如何选择正确的兴趣词

Facebook认为有很多人对高尔夫感兴趣。在Facebook的眼里,有很多人对Tiger Woods感兴趣,也许根本就不是高尔夫球手。在进行Facebook兴趣定位研究时,明确定义受众并隔离其他所有人的想法是在定位目标受众的同时限制浪费广告预算的关键所在。

这5种药多吃一口,你的肾多伤一分!别以身试验了

核心提示:近年来,肾脏疾病逐年增加的趋势越来越明显,有很大一部分与药物使用不当有关。一些常见的解热镇痛药和中草药等五类药物对肾脏的伤害很大。

近年来,肾脏疾病逐年增加的趋势越来越明显,有很大一部分与药物使用不当有关。一些常见的解热镇痛药和中草药等五类药物对肾脏的伤害很大。

肾脏作为人体新陈代谢赖以生存的基础器官,对我们有着非常重要的意义。但值得深思的是,近年来,肾脏疾病逐年增加的趋势非常明显,特别是用药不当导致的肾病也越来越多。哪些药物最伤肾呢?下面就介绍五类可能会危害肾脏健康的药物。

一、抗生素

抗生素是一种很常见的药物,日常生活中一旦出现感冒发烧或者拉肚子,都可能会用到抗生素,很多人把抗生素列入家庭常备的药物之一,却对抗生素的一些毒副作用了解甚少。

俗话说是药三分毒,抗生素也是一样。目前较常见的抗生素类药物有庆大霉素、卡那霉素、链霉素、氯霉素、新霉素、四环素等,它们都是具有肾毒性的抗生素,尤其是新霉素的毒性最强,长期服用这类药物,肾损害的发生率会明显上升。

二、利尿药

例如氢氯噻嗪、呋塞米等利尿剂都具有潜在的肾毒性,导致尿液减少甚至无尿,有可能诱发急性间质性肾炎和急性肾小管坏死等肾脏疾病。尤其是肾功能不全患者,长期利尿药会降低肾小球滤过率,不过停药后可以逐渐恢复。特别是利尿剂与其他有害肾脏的药物一起使用时,最伤肾。

三、部分中草药

研究发现,应用中药引起的尿毒症患者越来越多。一直以来,人们普遍认为西药的毒副作用比中药大,认为中药是天然植物,无毒副作用的,所以长期大量地服用中药的现象非常普遍,其实这是很危险的。

在上世纪90年代初,应用中草药减肥较为流行,深受年轻爱美人士的追捧,却没想到有人发生进行肾功能衰竭,导致尿毒症。国外学者最先提出中草药肾病这个概念,从此引起人们对中药肾毒性的注意。

部分中药会引起严重的、甚至不可逆的肾脏损害,像雷公藤、关木通、马兜铃、厚朴、秋水仙等都可引起肾脏损害。

四、解热镇痛药

常见的解热镇痛药物有阿司匹林、对乙酰氨基酚、非那西丁、消炎痛、保泰松、去痛片、炎痛喜康和布洛芬等,这些药物长期使用可导致肾脏慢性中毒,最终可导致肾功能衰竭。

五、镇静催眠药


催眠类药物例如苯巴比妥、安眠酮、水合氯醛等,现代人由于工作、生活压力越来越重,好多人出现失眠多梦等问题,就会滥用一些助睡眠的药物,虽然是解决了睡眠问题,但其带来的副作用不可估量,切不可长期服用。

可以利用运动、旅游等方式来减压,减少此类药品对肾脏的危害。

通常来说,用量过大、长期用药是出现肾脏损害最主要的原因。因此,在服用上述五类药物时,一定要谨遵医嘱,合理使用。


原文转载:http://health.shaoqun.com/a/148922.html

跨境电商:https://www.ikjzd.com/

粉丝通:https://www.ikjzd.com/w/743

贝贝母婴网:https://www.ikjzd.com/w/1321


核心提示:近年来,肾脏疾病逐年增加的趋势越来越明显,有很大一部分与药物使用不当有关。一些常见的解热镇痛药和中草药等五类药物对肾脏的伤害很大。 近年来,肾脏疾病逐年增加的趋势越来越明显,有很大一部分与药物使用不当有关。一些常见的解热镇痛药和中草药等五类药物对肾脏的伤害很大。肾脏作为人体新陈代谢赖以生存的基础器官,对我们有着非常重要的意义。但值得深思的是,近年来,肾脏疾病逐年增加的趋势非常明显,特别是
米兰网:米兰网
rfq:rfq
独立站如何做Google广告引流?Google广告有那些类型与优势呢?:独立站如何做Google广告引流?Google广告有那些类型与优势呢?
给新手亚马逊卖家做站外引流的一些建议 :给新手亚马逊卖家做站外引流的一些建议
关于亚马逊评论的重要准则:关于亚马逊评论的重要准则

jackson学习之四:WRAP_ROOT_VALUE(root对象)

欢迎访问我的GitHub

https://github.com/zq2599/blog_demos

内容:所有原创文章分类汇总及配套源码,涉及Java、Docker、Kubernetes、DevOPS等;

系列文章汇总

  • jackson学习之一:基本信息
  • jackson学习之二:jackson-core
  • jackson学习之三:常用API操作
  • jackson学习之四:WRAP_ROOT_VALUE(root对象)
  • jackson学习之五:JsonInclude注解
  • jackson学习之六:常用类注解
  • jackson学习之七:常用Field注解
  • jackson学习之八:常用方法注解
  • jackson学习之九:springboot整合(配置文件)
  • jackson学习之十(终篇):springboot整合(配置类)

本篇概览

本文是《jackson学习》系列的第四篇,前面学习了常用API,可以执行最基本的序列化和反序列化操作,接下来要学习的就是jackson强大的注解能力,本篇要学的是root对象特性,主要内容如下:

  1. 关于root对象
  2. 测试用的POJO类
  3. 序列化实战
  4. 反序列化实战

关于root对象(WRAP_ROOT_VALUE)

  1. 对于只有id和name两个字段的POJO实例来说,正常的序列化结果如下:
{ "id" : 1, "name" : "book"}
  1. jackson在序列化时,可以在上述json外面再包裹一层,官方叫做WRAP_ROOT_VALUE,本文中叫做root对象,如下所示,整个json的只有一个键值对,key是aaabbbccc,value内部才是POJO实例的id和name字段的值:
{ "aaabbbccc" : { "id" : 2, "name" : "food" }}

提前小结

root对象特性提前做个小结,这样如果您时间有限,仅看这一节即可:

  • 先看序列化场景:
  1. 执行下面代码,jackson在序列化时会增加root对象:
mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
  1. root对象的key,默认是实例的类名,如果实例有JsonRootName注解,就是该注解的value值;
  2. root对象的value如下所示,相当于不支持root对象时的序列化结果:
{ "id" : 1, "name" : "book"}
  • 再看反序列化场景:
  1. 执行下面代码,jackson在反序列化时会先解析root对象:
mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
  1. root对象的key,默认是实例的类名,如果实例有JsonRootName注解,就是该注解的value值;
  2. root对象的value如下所示,相当于不支持root对象时用来反序列化的json字符串:
{ "id" : 1, "name" : "book"}

准备两个POJO类

用对比的方式可以更清楚了解JsonRootName的作用,接下来的学习咱们准备两个POJO类,一个没有JsonRootName注解,另一个有JsonRootName注解:

  1. 名为Order1.java的,没有JsonRootName注解:
public class Order1 { private int id; private String name;	// 省去get、set、toString方法	...}
  1. 名为Order2.java的,有JsonRootName注解,value值为aaabbbccc:
import com.faster
  • 可见Order1和Order2的代码是一致的,唯一的不同是Order2带有注解JsonRootName;

序列化

  1. 需要设置WRAP_ROOT_VALUE属性,jackson才会支持root对象,JsonRootName注解才会发挥作用,设置代码如下:
mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
  1. 写一段代码,在不开启WRAP_ROOT_VALUE属性的时候执行序列化,再开启WRAP_ROOT_VALUE属性执行序列化,对比试试:
public static void main(String[] args) throws Exception {  // 实例化Order1和Order2  Order1 order1 = new Order1();  order1. setId(1);  order1.setName("book");  Order2 order2 = new Order2();  order2. setId(2);  order2.setName("food");  // 没有开启WRAP_ROOT_VALUE的时候  logger.info("没有开启WRAP_ROOT_VALUE\n");  ObjectMapper mapper1 = new ObjectMapper();  // 美化输出  mapper1.enable(SerializationFeature.INDENT_OUTPUT);  logger.info("没有JsonRootName注解类,序列化结果:\n\n{}\n\n", mapper1.writeValueAsString(order1));  logger.info("有JsonRootName注解的类,序列化结果:\n\n{}\n\n\n\n", mapper1.writeValueAsString(order2));  // 开启了WRAP_ROOT_VALUE的时候  logger.info("开启了WRAP_ROOT_VALUE\n");  ObjectMapper mapper2 = new ObjectMapper();  // 美化输出  mapper2.enable(SerializationFeature.INDENT_OUTPUT);  // 序列化的时候支持JsonRootName注解  mapper2.enable(SerializationFeature.WRAP_ROOT_VALUE);  logger.info("没有JsonRootName注解类,序列化结果:\n\n{}\n\n", mapper2.writeValueAsString(order1));  logger.info("有JsonRootName注解的类,序列化结果:\n\n{}", mapper2.writeValueAsString(order2)); }
  1. 执行结果如下,JsonRootName在序列化时的作用一目了然:指定了root对象的key:

在这里插入图片描述

反序列化(默认设置)

  1. 在没有做任何设置的时候,下面这个字符串用来反序列化成Order2对象,会成功吗?
{ "id" : 2, "name" : "food"}
  1. 试了下是可以的:

在这里插入图片描述
3. 那下面这个字符串能反序列化成Order2对象吗?

{ "aaabbbccc" : { "id" : 2, "name" : "food" }}
  1. 代码和结果如下图所示,反序列化时jackson并不认识aaabbbccc这个key,因为jackson此时并不支持root对象:

在这里插入图片描述

  • 小结:默认情况下,反序列化时json字符串不能有root对象;

反序列化(开启UNWRAP_ROOT_VALUE属性)

  1. 如果开启了UNWRAP_ROOT_VALUE属性,用于反序列化的json字符串就必须要有root对象了,开启UNWRAP_ROOT_VALUE属性的代码如下:
mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
  1. 代码和结果如下图,可见带有root对象的json字符串,可以反序列化成功,root对象的key就是JsonRootName注解的value属性:

在这里插入图片描述
3. 值得注意的是,上述json字符串中,root对象的key为aaabbbccc,这和Order2的JsonRootName注解的value值是一致的,如果不一致就会反序列化失败,如下图:

在这里插入图片描述

  • 至此,jackson的WRAP_ROOT_VALUE特性就学习完成了,在web开发时这是个很常用的功能,用于在最外面包裹一层,以便整体上添加额外的内容,希望能给您带来参考;

你不孤单,欣宸原创一路相伴

  1. Java系列
  2. Spring系列
  3. Docker系列
  4. kubernetes系列
  5. 数据库+中间件系列
  6. DevOps系列

欢迎关注公众号:程序员欣宸

微信搜索「程序员欣宸」,我是欣宸,期待与您一同畅游Java世界...
https://github.com/zq2599/blog_demos









原文转载:http://www.shaoqun.com/a/520058.html

跨境电商:https://www.ikjzd.com/

易麦:https://www.ikjzd.com/w/2048

蜜芽宝贝官网:https://www.ikjzd.com/w/1320


欢迎访问我的GitHubhttps://github.com/zq2599/blog_demos内容:所有原创文章分类汇总及配套源码,涉及Java、Docker、Kubernetes、DevOPS等;系列文章汇总jackson学习之一:基本信息jackson学习之二:jackson-corejackson学习之三:常用API操作jackson学习之四:WRAP_ROOT_VALUE(root对象)
tineye:tineye
跨境通:跨境通
如何让零数据的单页面快速有关键词排名和流量?:如何让零数据的单页面快速有关键词排名和流量?
新手做shopee,打死都不能碰的10大禁区!:新手做shopee,打死都不能碰的10大禁区!
口述:老婆与上司在车里缠绵酿成车祸:口述:老婆与上司在车里缠绵酿成车祸

英超一夜刹车!3场平局,2场爆冷,热刺、利物浦、曼城都笑了_比赛日

原标题:英超一夜刹车!3场平局,2场爆冷,热刺、利物浦、曼城都笑了

英超第20轮第二比赛日结束了5场比赛,之前一个比赛日结束的四场比赛基本上没有冷门,结果还算可以接受,都分出了胜负,其中西汉姆客场3-2战胜水晶宫,利兹联客场2-1纽卡,阿森纳客场3-1南安普顿,曼城客场5-0西布朗,但是第二比赛日风云突变,5场比赛有3场打平,2场爆冷,而且这些比赛都直接影响到争冠和保级的排位,一夜间几个强队全部刹车,而保级队却看到保级希望。

这五场比赛分别是切尔西0-0狼队,伯恩利3-2阿斯顿维拉,布莱顿0-0富勒姆,曼联1-2谢菲尔德联,埃弗顿1-1莱切斯特城,这9场比赛过后,目前只有一场最重量级的比赛没有打,就是热刺主场对阵利物浦,看到这样的结果相信曼城、热刺、利物浦都笑了,曼城笑是因为争冠对手都没有取胜,自己可以进一步拉开积分,而利物浦和热刺笑是因为曼联、莱切斯特城没有拉开和他们的积分,这场比赛赢球他们都有机会进入前四。

曼联主场1-2输给谢菲尔德联的比赛确实是目前为止最大的冷门,因为谢菲尔德联本赛季只赢过一次球,而且一直垫底,只拿到5分,早早预订一个降级名额,而曼联联赛已经13场不败,最近3轮都坐在积分榜第一的位置,索尔斯克亚看到球队的表现也直接面对新闻媒体说出了球队冬窗不引援的豪言壮语,声称很满意队员的表现,下半程要多给范德贝克机会,但是这场一输大家又开始拿博格巴出气,看来这个冠军不好拿。

保级球队伯恩利逆转维拉也算是一大冷门,本赛季的维拉不是保级的实力,他们只是可能刚刚复出,可能球队还没有恢复到最佳,但结果看上去就是爆冷,切尔西这场比赛也让球迷大跌眼镜,换帅之后球队还是无法取胜,还是处于低迷状态,一球未进,要知道狼队目前的状态也不好,球队射手希门尼斯还没有回来,目前的组合并没有让球队有扭转颓势的趋势。返回搜狐,查看更多

责任编辑:

原文转载:http://sport.shaoqun.com/a/388606.html

跨境电商:https://www.ikjzd.com/

trademanager:https://www.ikjzd.com/w/730

史泰博办公用品:https://www.ikjzd.com/w/2112


原标题:英超一夜刹车!3场平局,2场爆冷,热刺、利物浦、曼城都笑了英超第20轮第二比赛日结束了5场比赛,之前一个比赛日结束的四场比赛基本上没有冷门,结果还算可以接受,都分出了胜负,其中西汉姆客场3-2战胜水晶宫,利兹联客场2-1纽卡,阿森纳客场3-1南安普顿,曼城客场5-0西布朗,但是第二比赛日风云突变,5场比赛有3场打平,2场爆冷,而且这些比赛都直接影响到争冠和保级的排位,一夜间几个强队全部刹车
bap:bap
c88:c88
在北美站爆卖的家居和厨房类目产品究竟要做什么认证?:在北美站爆卖的家居和厨房类目产品究竟要做什么认证?
重大好消息!意大利2020年免征口罩等防疫用品的增值税:重大好消息!意大利2020年免征口罩等防疫用品的增值税
越南之后,Shopee菲律宾站点SLS Standard Express渠道运费也下调!:越南之后,Shopee菲律宾站点SLS Standard Express渠道运费也下调!

2021年1月28日星期四

InnoDB中不同SQL语句设置的锁

锁定读(locking read)、更新(UPDATE)或删除(DELETE)通常会在SQL语句处理过程中扫描的每个索引记录上设置记录锁。语句中是否存在排除行的WHERE条件并不重要。InnoDB不记得确切的WHERE条件,而只知道哪个索引范围被扫描。这些锁通常是next-key锁,它还会阻止在记录之前插入"间隙"。然而,间隙锁(gap lock)可以被显式禁用,这会导致不使用next-key锁。

如果在检索中使用了二级索引,并且要设置的索引记录锁是排它的,则InnoDB也会检索相应的聚集索引记录并在它们上设置锁。

执行SQL语句时,如果没有找到可用的索引,MySQL必须扫描整个表来处理该语句,这样的话表的每一行都会被锁定,从而阻塞其他用户对表的所有插入。因此,创建良好的索引非常重要,这样可以避免扫描许多不必要的行。

InnoDB设置特定类型的锁,如下所示:

  • SELECT ... FROM 是一致读,读取数据库快照,除非将事务隔离级别设置为SERIALIZABLE,否则不设置锁。对于SERIALIZABLE级别,检索会在遇到的索引记录上设置共享的next-key锁。但是,对于使用唯一索引来搜索唯一行的语句,只需要一个索引记录锁。

  • 对于 SELECT ... FOR UPDATE 或者 SELECT ... LOCK IN SHARE MODE ,对扫描的行加锁,并对不符合结果集中包含条件的行(例如,如果它们不满足WHERE子句中给出的条件)释放锁。

  • SELECT ... LOCK IN SHARE MODE 在所有遇到的索引记录上设置共享的next-key锁。但是,对于使用唯一索引来搜索唯一行的语句,只需要一个索引记录锁。

  • SELECT ... FOR UPDATE 在搜索遇到的每个记录上设置排它的next-key锁。但是,对于使用唯一索引来搜索唯一行的语句,仅需要索引记录锁定。

  • UPDATE ... WHERE ... 在搜索遇到的每个记录上设置排它的next-key锁。但是,对于使用唯一索引来搜索唯一行的语句,仅需要索引记录锁定。

  • DELETE FROM ... WHERE ... 在搜索遇到的每个记录上设置排它的next-key锁。但是,对于使用唯一索引来搜索唯一行的语句,仅需要索引记录锁定。

  • INSERT 在插入的行上设置排他锁。该锁是索引记录锁,不是next-key锁(即没有间隙锁),并且不会阻止其他会话插入到插入行之前的间隙中。

举个例子,假设有一张表t1,结构如下:

CREATE TABLE t1 (i INT, PRIMARY KEY (i)) ENGINE = InnoDB;

再假设,有三个会话操作顺序如下:

Session 1:

START TRANSACTION;INSERT INTO t1 VALUES(1);

Session 2:

START TRANSACTION;INSERT INTO t1 VALUES(1);

Session 3:

START TRANSACTION;INSERT INTO t1 VALUES(1);

Session 1:

ROLLBACK;

首先Session1获得i=1这一行的排它锁,接下来Session2和Session3由于主键重复只能请求获取该行的共享锁,由于行上已经有排它锁,因此Session2和Session3请求的共享锁不能被立即授予。再接着,Session1回滚,行上的排它锁被释放,于是Session2和Session3在该行上都持有共享锁,此时,死锁发生了,由于对方持有的共享锁,任何一方都不能获得该行的排它锁。

下面这组操作也是类似:

Session 1:

START TRANSACTION;DELETE FROM t1 WHERE i = 1;

Session 2:

START TRANSACTION;INSERT INTO t1 VALUES(1);

Session 3:

START TRANSACTION;INSERT INTO t1 VALUES(1);

Session 1:

COMMIT;

和前面的情况类似,Session1提交以后,Session2和Session3请求该行上的共享锁被立即授予,此时它们再请求获取排它锁时就出现死锁了,因为共享锁被另一个事务持有。

补充: 聚集索引与辅助索引

clustered index (译:聚集索引、聚簇索引)

secondary index (译:二级索引、辅助索引)

每个InnoDB表都有一个特殊的索引,称为聚集索引,用于存储行数据。通常,聚集索引与主键是同义词。为了从查询、插入和其他数据库操作中获得最佳性能,必须了解InnoDB如何使用聚集索引来优化每个表的最常见的查找和DML操作。

Typically, the clustered index is synonymous with the primary key.

通常,"clustered index" 和 "primary key" 是一个意思。

  • 当你在表上定义一个PRIMARY KEY时,InnoDB将它用作聚集索引。为创建的每个表定义一个主键。如果没有逻辑唯一的非空列或列集,请添加一个新的自动递增(auto-increment)列,其值将自动填充。

  • 如果你没有为你的表定义一个PRIMARY KEY,则MySQL会在所有键列都不为NULL的情况下找到第一个唯一索引,并且InnoDB使用它作为聚集索引。

  • 如果表没有主键或合适的唯一索引,InnoDB会在包含行ID值的合成列上内部生成一个名为GEN_CLUST_INDEX的隐藏聚集索引

通过聚集索引访问行非常快,因为索引搜索直接指向包含所有行数据的页。如果表很大,聚集索引体系结构通常节省磁盘I/O操作。

除了聚集索引之外的所有索引都称为二级索引。在InnoDB中,二级索引中的每条记录都包含该行的主键列,以及为二级索引指定的列。InnoDB使用此主键值在聚集索引中搜索行。

如果主键很长,则辅助索引将使用更多空间,因此具有主键较短是比较有利的。

With the exception of spatial indexes, InnoDB indexes are B-tree data structures. Index records are stored in the leaf pages of their B-tree or R-tree data structure. The default size of an index page is 16KB. Supported sizes are 64KB, 32KB, 16KB (default), 8KB, and 4KB.

 

 









原文转载:http://www.shaoqun.com/a/520054.html

跨境电商:https://www.ikjzd.com/

好卖家:https://www.ikjzd.com/w/776

eori:https://www.ikjzd.com/w/499


锁定读(lockingread)、更新(UPDATE)或删除(DELETE)通常会在SQL语句处理过程中扫描的每个索引记录上设置记录锁。语句中是否存在排除行的WHERE条件并不重要。InnoDB不记得确切的WHERE条件,而只知道哪个索引范围被扫描。这些锁通常是next-key锁,它还会阻止在记录之前插入"间隙"。然而,间隙锁(gaplock)可以被显式禁用,这会导致不使用next-key锁。如果
贝贝网:贝贝网
黄劲:黄劲
Prime Day给旺季带来的一点思考:谁赢了?:Prime Day给旺季带来的一点思考:谁赢了?
Azimo:Azimo
Lazada什么产品好做?选品推荐:Lazada什么产品好做?选品推荐

亚马逊直送政策更新,游戏驿站(GameStop)空头巨亏超300亿人民币,有散户盈利超1亿元

游戏驿站(GameStop)空头巨亏超300亿人民币,有散户盈利超1亿元

 

根据S3 Partners的数据,今年迄今为止,游戏驿站(GameStop)的空头亏损超过50亿美元(约300多亿人民币)。与此同时,在美国社交平台上,散户们却在狂欢,网络上充斥了大量的散户持仓截图,盈利从几万到千万美元不等,甚至有网友表示,已盈利了1700万美金(折合人民币1.1亿元),于1月26日至少翻了一倍。

 

亚马逊直送政策更新

 

亚马逊公告表示,如果卖家通过第三方配送订单(即"直送"),则必须遵守所有亚马逊政策。任何违反直送政策的行为都可能会损害买家对卖家的信任。因此,任何违反直送政策的行为都可能会对卖家的账户状况以及以后使用卖家自行配送网络 (MFN) 配送订单商品的能力产生负面影响。

 

亚马逊沙特站点正式引入Prime会员

 

亚马逊宣布在沙特阿拉伯地区推出Prime会员,沙特阿拉伯Prime会员将享受免费快速送货等多种服务。Prime会员还可以享受从亚马逊美国和阿联酋提供的产品免费国际送货服务,以及享受娱乐活动。用户每月仅需支付16沙特里亚尔,同时,用户可以注册30天免费试用版来试用Prime会员并享受所有优惠。

 

Shopee调整禁止运输禁运商品和空包政策

 

虾皮(Shopee)平台对禁止运输禁运商品和空包政策做如下调整:

 

卖家运输违禁商品:

一经发现有卖家寄运A类禁运商品,每个订单将计3分惩罚计分;

一经发现有卖家寄运B类禁运商品,每5个订单将计1分惩罚计分;

 

卖家运输空包裹或与订单不符的商品:

 

卖家产生的运输空包裹或者运输订单不符的包裹的次数和情节季度累计,下个季度清零重新计算;

若卖家可以提供证据证明未违反上述规则,请务必在客户经理通知的保存期内提出异议。

超过保存期后,包裹将被做销毁处理;

卖家店铺在接受以上惩罚的同时将接受调查运输空包裹或与订单不符的商品原因,如若发现刷单等欺诈或滥用行为,将受到相应处罚;

卖家若违反运输违禁政策,被海关查处的一切费用由卖家自行承担。

 

1688平台修订网站品牌准入标准

 

阿里巴巴中国站发布关于《阿里巴巴中国网站品牌准入标准》的修订公告,新修改后的规则将于2021年2月3日正式生效施行。公告显示,1688平台家用电器行业新增LG、东芝(Toshiba)、海尔(Haier)、海信(Hisense)、雅马哈(Yamaha)、3M、澳柯玛(Aucma)、格兰仕(Galanz)、格力(Gree)、美的(Midea)、美菱(MeiLing)、博朗(Braun)、飞科(Flyco)、华帝(Vatti)等品牌。

 




原文转载:http://www.shaoqun.com/a/520043.html

跨境电商:https://www.ikjzd.com/

友家快递:https://www.ikjzd.com/w/1341

汇通天下物流:https://www.ikjzd.com/w/2055


游戏驿站(GameStop)空头巨亏超300亿人民币,有散户盈利超1亿元根据S3Partners的数据,今年迄今为止,游戏驿站(GameStop)的空头亏损超过50亿美元(约300多亿人民币)。与此同时,在美国社交平台上,散户们却在狂欢,网络上充斥了大量的散户持仓截图,盈利从几万到千万美元不等,甚至有网友表示,已盈利了1700万美金(折合人民币1.1亿元),于1月26日至少翻了一倍。亚马逊直送政策
慧聪商务网:慧聪商务网
赛兔:赛兔
春节物流都放假了,如何让亚马逊店铺春节"不打烊"?:春节物流都放假了,如何让亚马逊店铺春节"不打烊"?
权威解读:亚马逊标题新规要点详解!:权威解读:亚马逊标题新规要点详解!
亚马逊日本站指南:亚马逊日本站指南

API服务接口签名代码与设计,如果你的接口不走SSL的话?

在看下面文章之前,我们先问几个问题

  • rest 服务为什么需要签名?
  • 签名的几种方式?
  • 我认为的比较方便的快捷的签名方式(如果有大神持不同意见,可以交流!)?
  • 怎么实现验签过程 ?
  • 开放式open api sign怎么设计 (openkey 和 openid 的设计) ?
  • 在一个服务中,有些接口不需要签名,接口怎么滤过签名 ?

我认为好的签名设计,应该要解决以上问题。

 

  一: Rest 服务为什么需要签名?

    在介绍签名之前,我们先对服务进行分一分,我们的服务从内网以及外网角度分为:内网服务以及开放型外网服务两大类

  1.     内网服务,我们认为它是可靠安全,受局域网的防火墙保护,内网型的服务,我们不开放出INTERNET 访问。
  2.     暴露在外网型的服务,我们认为是它本质是提供到INTERNET 网络允许访问的服务。我们认为它是不可靠的,不安全的。

外网型的服务,我们通常面临两个问题:收到恶意请求和数据安全(如果你不是通过SSL走的话) 的问题。

在恶意请求方面,又涉及到恶意高频请求以及数据拦截窜篡改请求。

数据安全方面涉及到,网络传输的数据如果被拦截,涉及到客户隐私数据被窃取等相关问题。

因此,为了解决上述问题,伟大的 服务 "签名" 就诞生了。 你可以这么认为:签名 就是 请求当前业务接口的 前提钥匙。通过软实施实现。

 

签名如何解决上述问题:

  1. 恶意请求: 我们知道,签名在设计上面具有防篡改性质,如果这一点没有实现,那么就会失去签名的意义。被拦截的请求,修改请求报文后,再次发送,将会被服务端 验签 过程中 检测到,直接打回--我们通常说是验签失败
  2. 客户隐私:客户隐私数据的保护,加签后的接口,只能请求当前的相同请求报文的请求,而不能尝试请求被篡改后报文的请求。如果数据被拦截,也只能是当前此条数据客户隐私被泄露。因此,如果要绝对的保护客户隐私的话,还有对报文数据进行加密。这样,我们就可以做到数据安全级别较高的接口。下面的文章将对具体实现过程展开。
  3. 高频请求的保护,如果签名产生的uuid 加上 时间戳,就可以解决高频请求的容错限流等问题.

 

因此签名尤其变为重要。

我上面的标题,如果你的接口不走SSL的话,你的外网接口就需要走上述这些事情,为了你接口安全而考虑。

 

二:签名的几种方式

   签名的几种方式:我们通常见到的有 SHA 加密签名,MD5 签名。我个人比较推崇的是 MD5 加签签名。

原因:简单,易懂,跨语言平台型强,通用性强。尤其是.NET 与 JAVA 跨语言的的接口签名对接时。因为JAVA 的 SHA  版本有很多中,而更甚的是,有些 SHA 在某些银行还被改过,形成自己私有的版本。如果:

你要对接他们的 他们的接口,你必须使用JAVA 语言.   然而 MD5 的算法比较统一。只要 确认 对方的最简单的 字符串 123 MD5  值跟 你 这边的 MD5 值一样。就可以保证 底层算法 的一致 性,就 可以采用上述的加签方式。

 

 

MD5 加签原理:

我们假设有这么一个统一入参结构的请求报文

请求对象协议结构

类型

说明

object

object

说明:请求的业务参数(包装对象),各接口不同的参数

二:包装对象中实体中特殊业务字段中的具体格式要求:

① 如果业务对象参数是时间类型的, 将时间参数转成时间戳(当前时间与'1970-01-01'精确到毫秒,类型Long)

② 业务中的浮点型使用字符串定义传送(避免不同跨语言造成序列化形成的浮点位数不一致性)

time

long

当前时间的时间戳:datekong(当前时间与'1970-01-01'相对值,精确到毫秒)

sign

string

sign=MD5(openkey+ time+ JsonConvert.SerializeObject(object))

备注:OpenKey: 分配给调用方的key值,此值无需暴露在网络中传输。

 

 

在我们构建传送报文的时候,我们看到有一个字段: sign 是 由 服务方分配给客户端一个 秘钥字符串 再加上 报文中 ( time 时间戳+ objcet 业务参序列化)相加后的字符串 后 MD5值。 

我们这里 sign 的形成有两个关键点:

第一: sign  值形成的算法,我这边算法暂时是 :sign= MD5(openkey+ time+ JsonConvert.SerializeObject(object))

第二: sign 分配给客户端的秘钥值—openkey

 

如下加签请求伪代码:

 1 namespace T.API 2 { 3  4  5  /// <summary> 6  /// 请求的报文对象 7  /// </summary> 8  public class SendObject 9  { 10   /// <summary> 11   /// 发送实体对象 12   /// </summary> 13   public object @object { get; set; } 14  15   /// <summary> 16   /// 签名 17   /// </summary> 18  19   public string sign { get; set; } 20   /// <summary> 21   /// 当前请求的时间戳 22   /// </summary> 23   public long? time { get; set; } 24  25   /// <summary> 26   /// 用户id 27   /// </summary> 28   public int userId { get; set; } 29  } 30  31  /// <summary> 32  /// 接收到的报文对象 33  /// </summary> 34  public class ReciveObject 35  { 36   /// <summary> 37   /// 发送实体对象 38   /// </summary> 39   public object @object { get; set; } 40  41   /// <summary> 42   /// 服务请求响应值 code 为 1:请求成功 ,请求无异常  43   /// 当code 为 "1" 的情况下,下面的RevRep 对象中的 message 字段 90% 的场景为空, 44   /// 如果有必要赋值视双方业务场景而定; 45   /// code为 0:我方程序异常/业务性质失败/接口参数校验失败, 46   /// 当 code 为 "0"的情况下,下面message字段包装了异常/失败信息。 47   /// </summary> 48  49   public int code { get; set; } 50    51  52   /// <summary> 53   /// 请求响应的错误消息/或者其他业务场景响应提示信息 54   /// </summary> 55   public int message { get; set; } 56  } 57  58  59  /// <summary> 60  /// 上面 Req 对象中的object 封装字段具体实体定义 61  /// </summary> 62  public class ObjectEntity 63  { 64  65   public string orderNum { get; set; } 66  67   /// <summary> 68   /// 如果参数是浮点型,在实体中定义成字符串类型. 69   /// </summary> 70   public string orderMoney { get; set; } 71  72   /// <summary> 73   /// 如果参数是时间类型的,在实体中定义成long 时间戳类型 74   /// </summary> 75   public long? orderTime { get; set; } 76  } 77  78  79  80  81  /// <summary> 82  /// 请求示例代码 83  /// </summary> 84  public class RequestDemo 85  { 86  87   /// <summary> 88   /// 请求示例,调用方请求 89   /// </summary> 90  91   public static void Request() 92   { 93  94    //服务端分配给调用方:openkey 95    string openKey = "455853655-7dff-5585545-a1c3-7778887"; // 96  97    //定义发送对象 98    SendObject sendobject = new SendObject(); 99    //定义请求时间戳100    long? reqtime= DateTime.Now.ToSafeDateTime().ToSafeDataLong();// 赋值101    sendobject.time = reqtime;102    try103    {104     //定义以及赋值业务实体105     ObjectEntity objectEntity = new ObjectEntity();106     objectEntity.orderNum = "20200506071001";107     objectEntity.orderTime = DateTime.Now.ToSafeDateTime().ToSafeDataLong();108     objectEntity.orderMoney = "526.00";109 110     //将定义好的业务实体塞入SendObject的object字段中.111     sendobject.@object = objectEntity;112 113     //加签并且赋值签名114     sendobject.sign = sign(reqtime, openkey,JsonConvert.SerializeObject(sendobject.@object));115 116 117     RestRequest rq = new RestRequest(Method.POST);118    119     rq.Method = Method.POST; //请求设置为POST120     121     rq.AddHeader(" Content-Type", "application/json;charset=utf-8"); //头部塞入Content-Type122     rq.AddParameter("application/json", JsonConvert.SerializeObject(sendobject), ParameterType.RequestBody);123 124 125     RestClient restclient = new RestClient { BaseUrl = new Uri("") }; //调用地址126     TaskCompletionSource<IRestResponse> tcs = new TaskCompletionSource<IRestResponse>();127     restclient.ExecuteAsync(rq, r =>128     {129      tcs.SetResult(r);130     });131     IRestResponse respones = tcs.Task.Result; // 请求返回的数据132 133     //如果请求状态正常134     if ((int)respones.StatusCode == 200)135     {136      ReciveObject recive = JsonConvert.DeserializeObject<ReciveObject>(respones.Content);137      if (recive.code == 1)138      {139       //处理业务140      }141      else142      {143       //处理业务144      }145 146 147 148     }149     else150     {151      throw new Exception("调用异常通讯状态:${respones.StatusCode}");152     153     }154    155 156 157 158 159 160    }161    catch (Exception ex)162    {163    164    }165   166   }167 168 169   /// <summary>170   /// Md5 方法171   /// </summary>172   public static string MD5(string md5orgincontent)173   {174 175    string md5result = string.Empty;176    if (string.IsNullOrEmpty(md5result)) return md5result;177    StringBuilder sb = new StringBuilder();178 179    MD5 md5 = new MD5CryptoServiceProvider();180    byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(md5orgincontent));181    md5.Clear();182    for (int i = 0; i < s.Length; i++)183    {184     sb.Append(s[i].ToString("x2"));185    }186    md5result=sb.ToString();187   return md5result;188 189 190   }191  192   193   /// <summary>194   /// 加签195   /// </summary>196   /// <param name="time">时间戳</param>197   /// <param name="openkey">服务端分配给调用方:openkey</param>198   /// <param name="szobject">参与加签的object的json序列化字符串</param>199   /// <returns></returns>200   public static string sign(long? time, string openkey, string szobject)201   {202 203   204    string signresult = string.Empty;205    var signcontent = openkey+time.ToSafeString()+szobject;206    signresult = MD5(signcontent);207    return signresult;208 209   }210 211 212 213 214  }215 216 }

View Code

 

服务端验签原理:

服务端通过  服务端定义接口拦截器或者全局过拦截器。 接口接收到的报文是上述表格的报文结构后,做如下事情

  1: 同样:接拦截器中,做同样的事情: 秘钥字符串 再加上 报文传送过来的 ( time 时间戳+ objcet 业务参序列化)相加后的字符串 MD5值 ,我将此值 为 service_sign

2:将服务端的  service_sign 值跟 报文中的 sign 进行比对,如果发现不匹配(假设在双方算法一直,openkey 一致的情况下):报文被篡改,签名验证不通过

我在这里贴出服务端验签 C# 代码:其他语言可以参考:

  • 服务端先定义一个接收报文的对象:
     1 [JsonObject(MemberSerialization.OptIn)] 2  public class ResultRequset : BaseRequestEntity 3  { 4   [JsonProperty] 5   public object @object { get; set; } 6   public virtual string openKey{ get; set; } 7  /// <summary> 8   /// 服务端加签:此值将于传送过来的 sign 值最终进行比对/// </summary> 9   public override string checkedSign10   {11    get12    {13     var orgin =this.time.ToString() + openKey+ JsonConvert.SerializeObject(@object);14     return EntitySign.To32Md5(orgin);15    }16   }17 18  /// <summary>19   /// 签名验证20   /// </summary>21   /// <returns></returns>22   public Result CheckedSign()23   {24    Result r = new Result();25    if (this.sign == checkedSign)26    {27     r.code = 1;28     return r;29    }30    else31    {32     r.code = 0;33     r.message = "延签失败!";34    }35    return r;36   }

    View Code
  • 然后构建一个拦截器,拦截器的工作如下所示 NETFramework 代码,其他语言可以参考:
     1 public class OpenSignAttribute : ActionFilterAttribute 2  { 3   public Type RequestType { get; set; } 4  5   public override void OnActionExecuting(HttpActionContext actionContext) 6   { 7    HttpContent content = actionContext.Request.Content; 8    var gloablkey = string.Empty;  9    ResultRequset resultRequset = new ResultRequset();10  foreach (KeyValuePair<string, object> obj in actionContext.ActionArguments)11     {12 13      resultRequset = (ResultRequset)obj.Value; //第一步:获取报文数据,强制转换到 上面定义的 ResultRequset 报文接收对象14     }15 Result re = resultRequset.CheckedSign(); //第二步: 服务端进行加签并且验签16     if (re.code == 1)17     {18      base.OnActionExecuting(actionContext);19     }20     else21     {22      actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.BadRequest, re);23     }24    }25   }

    View Code

     

  • 我们看一下接口定义- 给 接口 打上  OpenSign  标签,并且使用  ResultRequset 来接收对方过来的报文数据。
    1 [HttpPost]2 3 [OpenSign]4 public ResultRequset test([FromBody]ResultRequset obj)5  {6 7 }

    View Code

     

上述我们基本上形成了 MD5 加签和验签的逻辑过程。那么上述的这这个过程还是有个缺陷,就是文章一开头要解决的一个问题,开放式open api sign怎么设计 (openkey 和 openid 的设计) ?

也就是说:上述的 demo 的openkey 在是死的,如果我们想 服务端分配给每个调用方的openkey 都不一样,怎么办?

其实原理很简单:我们在增加一个 openid 概念:openid 是服务端分配给对调用方的唯一标识,openkey 是我们分配调用方参与加签的 钥匙。

怎么做呢:

 1:调用方: openid 一定要让对方 放入 HTTP HEADER  里面 传送到服务端。openkey  是参与加密,不需要传送。

2:服务端:在接收到 调用方 传送过来的 openid后,通过查库或者其他方式 查出 openid 对应的 openkey, 然后将查到的openkey 参与服务端验签算法。

上述原理,也就是我们通常看到的ALI,腾讯,或者其他第三方提供出来的 API  为什么需要分配一个OPENID,OPENKEY 的原因,或许有些厂商不是这种叫法。但是原理都是这样。

 

在贴出改造代码之前,我们还需要解决一个问题:就是 服务端在"接收到 调用方 传送过来的 openid后,通过查库或者其他方式 查出 openid 对应的 openkey, 然后将查到的openkey 参与服务端验签算法" 这里的蓝色字体标注的具体怎么查,这对

openid,openkey 配置对 怎么配置在服务端(有可能存库,有可能放在配置文件中)可能每个服务端都不太一样,我们把这层也抽象出来。让接口标签指定。

我们代码再次改造,如下所示:

  • 我们先定义一个查找方式的接口:
    1 public interface ISingSecret2  {3   string OpenId(Microsoft.AspNetCore.Http.HttpRequest request =null);4   5   string OpenKey(string OpenId);6  }

    View Code
  • 服务端接收对象改造:
     1 [JsonObject(MemberSerialization.OptIn)] 2  public class ResultRequset 3  { 4   [JsonProperty] 5   public object @object { get; set; } 6  7  8   /// <summary> 9   /// 可以覆盖此KEY的方式10   /// </summary>11   public virtual string openKey{ get; set; }12  /// <summary>13   /// 开放平台所使用的分配给客户的OPENID14   /// </summary>15   [JsonProperty]16   public string openId17   {18 19    get;20 21    set;22   }23   /// <summary>24   /// 获取签名25   /// </summary>26   public override string checkedSign27   {28    get29    {30     var orgin = singContent;31    32     return EntitySign.To32Md5(orgin);33    }34   }35 36 37   /// <summary>38   /// 用户ID 登入人ID39   /// </summary>40   [JsonIgnore]41   public string singContent42   {43    get { return openKey+ this.time.ToString() + JsonConvert.SerializeObject(@object); }44   }/// <summary>45   /// 签名验证46   /// </summary>47   /// <returns></returns>48   public Result CheckedSign()49   {50    Result r = new Result();51   52   if (this.sign == checkedSign)53    {54     r.code = 1;55     return r;56    }57    else58    {59     r.code = 0;60    61     r.message = "签名验证失败!";62     LogService.Default.Debug("签名验证失败---"+"框架签名" + checkedSign.ToSafeString("")+"-------网络签名:"+ sign.ToSafeString("") + "--------签名信息:" + singContent);63    }64    return r;65   }66  }

    View Code
  • 服务端拦截器改造:
     1 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)] 2  public class CentralSign: ActionFilterAttribute 3  { 4  5  6  7   private Type ISingRealization { get; set; } 8  9   private ISingSecret singRealization { get; set; } //关键代码:由服务端实现通过openid 查出openkey 的具体逻辑.10 11   public CentralSign(Type ISingSecret) // 关键代码: 定义带构造函数的 接口标签属性 . 12   {13    this.ISingRealization = ISingSecret;14    if (ISingRealization != null)15    {16     //获取类的初始化参数信息17     ConstructorInfo obj = ISingRealization.GetConstructor(System.Type.EmptyTypes);18     singRealization = (ISingSecret)Activator.CreateInstance(ISingRealization); //实例化对象19 20    }21   }22 23   public override void OnActionExecuting(ActionExecutingContext actionContext)24   {25    var content = actionContext.HttpContext.Request;26    var gloablkey = string.Empty;27 28     ResultRequset resultRequset = new ResultRequset();29     foreach (KeyValuePair<string, object> obj in actionContext.ActionArguments)30     {31      resultRequset = (ResultRequset)obj.Value;32     }33 34 35     Result re = new Result();36     if (resultRequset == null)37     {38      re.code = 0;39      re.message = "传值不能为空";40      actionContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;41      actionContext.HttpContext.Response.WriteAsync(JsonConvert.SerializeObject(re));42 43     }44     else45     {46      if (singRealization != null)47      {48       var openId = singRealization.OpenId(actionContext.HttpContext.Request); // 关键代码: 通过 ISingSecret.OpenId() 方法,获取到对应调用方传送过来的 openid49 50       resultRequset.publicApikey = singRealization.OpenKey(openId); // 关键代码: 通过 ISingSecret.OpenId() 方法,获取到对应调用方传送过来的 openid51 52      }53      re = resultRequset.CheckedSign();54      if (re.code == 1)55      {56       base.OnActionExecuting(actionContext);57      }58      else59      {60 61       HandleUnauthorizedRequest(actionContext);62 63      }64     }65 66    67   }68 69   protected void HandleUnauthorizedRequest(ActionExecutingContext actionContext)70   {71    var r = new JsonResult("签名失败,访问受限.");72 73    r.StatusCode = (int)HttpStatusCode.BadRequest;74    actionContext.Result =r;75    return;76   }77  }

    View Code
  • 服务端接口定义改造:
    1 [HttpPost]2 [CentralSign(typeof(OpenSign))]3 public Result SignatureSample([FromBody]ResultRequset result)4  {5    var str = result.@object.ToSafeString("");6    Result re = new Result() { code = 1,message="签名验证成功!"};7    re.@object = str;8    return re;9 }

    View Code

    上面接口定义 打上了  [CentralSign(typeof(OpenSign))] 标签,CentralSign 接收了一个 OpenSign Type  对象类型。根据上面的代码,我们知道,OpenSign 实现了  ISingSecret 逻辑。我们具体看下 OpenSign  具体实现:

  • OpenSign  实现 ISingSecret 逻辑代码:
     1 public class OpenSign : ISingSecret 2  { 3   public string OpenId(HttpRequest request) 4   { 5    return Header.GetHeaderValue(request,"openId"); 6   }  7  8   public string OpenKey(string OpenId) 9   {10    return ConfigManage.JsonConfigMange.GetInstance().AppSettings[OpenId];11   }12  }

    View Code

这样我们就整体上完成了我们所需要的 框架性 服务接口签名认证代码。 上面的代码 在Bitter.Frame 框架 服务签名模块中有, Bitter.Frame 代码还在整理中 。后续会贴出来给大家。

 









原文转载:http://www.shaoqun.com/a/520011.html

跨境电商:https://www.ikjzd.com/

焦点科技:https://www.ikjzd.com/w/1831

马士基集团:https://www.ikjzd.com/w/1296


在看下面文章之前,我们先问几个问题rest服务为什么需要签名?签名的几种方式?我认为的比较方便的快捷的签名方式(如果有大神持不同意见,可以交流!)?怎么实现验签过程?开放式openapisign怎么设计(openkey和openid的设计)?在一个服务中,有些接口不需要签名,接口怎么滤过签名?我认为好的签名设计,应该要解决以上问题。一:Rest服务为什么需要签名?在介绍签名之前,我们先对服务进行分
hemingway:hemingway
一淘网比价平台:一淘网比价平台
这个宠物品牌,是如何做到年营收过亿美金的?:这个宠物品牌,是如何做到年营收过亿美金的?
讨论丨我的listing又被无故删除,怎么办?:讨论丨我的listing又被无故删除,怎么办?
亚马逊选品干货:10大维度突破亚马逊选品难关:亚马逊选品干货:10大维度突破亚马逊选品难关

MPPA携手Blibli平台,扩大其食品、家用产品业务

在疫情的笼罩下,2021年真真切切地到来了,不少企业为了有更好的未来,均选择与其他企业或平台合作,强强联合共同发展。


近日,零售商MPPA正在将连锁超市Hypermart、Foodmart、Primo和Hyfresh扩展到电子商务平台Blibli,为消费者提供更多种类的产品。据悉,2021年,MPPA计划将在线上平台推出更多商店。


MPPA经理和公司秘书Danny Kojongian称,这与消费者现代数字生活方式的增长趋势一致。


MPPA与Blibli平台达成合作后,消费者可以从该网站或应用程序购买到新鲜的食品、杂货及其他家用产品,同时,平台还提供在线支付和极速交付服务,能够将杂货直接送至消费者家门口。


值得一提的是,MPPA保证提供与公司实体店相同的质量、价格和优惠。此外,线上消费者在2月5日之前购买的所有商品均可享受 10%的折扣及现金返还。


Danny Kojongian称,这是 MPPA发展的关键一步,疫情期间,消费者居家时间增多,外出次数减少,我们在确保消费者安全购物、保持购物习惯的同时,也能充分满足需求,安全是MPPA最主要的承诺。


Blibli执行副总裁Fransisca Krisantia Nugraha表示"Blibli与MPPA之间的战略合作关系是基于公司的使命,能够为印尼消费者提供更好的体验,满足他们的日常需求


他说:"Blibli将客户的满意度放在首位,提供免费送货、快速交付、100%优质产品、安全付款、15天退货政策以及24小时客户服务。"


此外,MPPA还在所有业务部门运营中实施其清真保证系统,去年,印度尼西亚乌里玛委员会食品和药物分析局(LPPOM MUI)给MPPA颁发了清真证书。


另一方面,MPPA还表示,未来定会增加更多的在线商店,并与印尼其他领先的企业或平台达成更多新合作。





原文转载:http://www.shaoqun.com/a/520007.html

跨境电商:https://www.ikjzd.com/

noon:https://www.ikjzd.com/w/259

oklink:https://www.ikjzd.com/w/1362


在疫情的笼罩下,2021年真真切切地到来了,不少企业为了有更好的未来,均选择与其他企业或平台合作,强强联合共同发展。近日,零售商MPPA正在将连锁超市Hypermart、Foodmart、Primo和Hyfresh扩展到电子商务平台Blibli,为消费者提供更多种类的产品。据悉,2021年,MPPA计划将在线上平台推出更多商店。MPPA经理和公司秘书DannyKojongian称,这与消费者现代数
拍拍网服装:拍拍网服装
慧聪商务网:慧聪商务网
独立站优势是什么?如何做独立站?:独立站优势是什么?如何做独立站?
悬崖边的试探?产品侵权受警告,心疼库存仍想售卖!:悬崖边的试探?产品侵权受警告,心疼库存仍想售卖!
2020黑五网一在即!船长BI带你解锁旺季制胜大招:2020黑五网一在即!船长BI带你解锁旺季制胜大招

redis数据类型之string,list

  redis是干啥的就不多说了,我这里使用windows版的redis,redis是基于内存的,单进程单线程的非关系型数据库,不需要考虑什么线程安全;

  想要慢慢的深入redis就要耐下心来从最基本的命令开始慢慢敲一遍,害

1. redis启动脚本

  下载完之后目录应该是下图这样的,我们启动一般是redis-server.exe redis.windows.conf启动的,这样可以根据不同配置文件启动的redis服务也是不同的

  便于后期的测试,我们写一个启动的脚本,就把上面那一行命令复制到一个txt文件,然后修改文件后缀为.bat,以后只需要双击这个bat文件就能启动redis服务端,然后点击redis-cli.exe就能连接上了;

 

2.数据类型

  redis中有五种数据类型,分别是zset,set,list,hash和string,其实就是和java中那几种集合差不多

  下面我们分别看看这几种数据的用法;

  2.1 string

  字符串是最常用的数据类型了,操作的命令:

 

  set/get:存放/获取键值对

 

  getset: 首先获取key对应的值,并且覆盖原来的值;

 

  mset/mget: 可以一次性保存/获取多个键值对

 

  strlen: 获取键对应的值得长度

 

  append: 给键对应的值附加字符串,返回的是最终字符串的长度 

 

  getrange:字符串切割

 

  setex/psetex: 和set命令一样使用,只不过这里可以设置超时时间,时间过了就删除这个键值对,前者单位事秒,后者是毫秒

 

  setnx: 这个命令真的很重要!!!redis实现分布式锁就是基于这个命令的,当redis没有指定的key的时候,就存我们传进去的键值对;有指定key就啥也不干

 

 

  msetnx: 这是setnx强化版,可以同时设置多个键值对

 

  decr/incr: 自减一和自加一,就是i--和i++

  

  decrby/incrby: 上面的命令每次只能减一/加一,这个命令可以指定减数/加数

 

  2.2 list

  很多个人觉得这个list像java中的List<T>,其实我觉得像java中List<List<T>>这种类型才对,而且redis中的list可以从头部插入元素lpush,从尾部插入元素rpush

  特点:元素有序,可重复

 

 

 

  lpush:创建一个list,并每次从头部(或者说左边)向其中添加多个元素,元素可以重复

  lrange: 遍历list中所有元素

 

  rpush: 每次从尾部向list添加元素

 

  lpushx/rpushx: 向list添加元素之前,要保证这个list必须存在,用法和lpush/rpush一样;(这个x是exist的简写)

 

 

  lpop/rpop: 拿到头部/尾部元素,并删除list中对应的该元素

 

  llen: 获取指定list中元素的数量

 

 

  lset: 修改列表中指定位置的值

 

  lindex: 获取列表中指定位置的值

 

 

  lrem: 删除指定数量的重复元素

 

  ltrim:切割一部分的列表为我所用

 

 

  linsert: 从头到尾匹配到指定元素,在这个元素之前/之后 插入指定元素  ,下面的before是之前,用after是之后 

 









原文转载:http://www.shaoqun.com/a/520000.html

跨境电商:https://www.ikjzd.com/

淘粉吧:https://www.ikjzd.com/w/1725

c2c模式:https://www.ikjzd.com/w/1576


redis是干啥的就不多说了,我这里使用windows版的redis,redis是基于内存的,单进程单线程的非关系型数据库,不需要考虑什么线程安全;  想要慢慢的深入redis就要耐下心来从最基本的命令开始慢慢敲一遍,害1.redis启动脚本  下载完之后目录应该是下图这样的,我们启动一般是redis-server.exeredis.windows.conf启动的,这样可以根据不同配置文件启动的r
aeo:aeo
优1宝贝:优1宝贝
掌握运营诀窍、玩转社交媒体,就是这么简单!:掌握运营诀窍、玩转社交媒体,就是这么简单!
论Review对于一条listing的重要性,该怎样获取?:论Review对于一条listing的重要性,该怎样获取?
竞价推广人员每天需要做什么? 每天必做什么?:竞价推广人员每天需要做什么? 每天必做什么?