get and post differ's

GET和POST两种基本请求方法的区别

最直观的区别就是GET把参数包含在URL中,POST通过request body传递参数

你轻轻松松的给出了一个“标准答案”:

GET在浏览器回退时是无害的,而POST会再次提交请求。

GET产生的URL地址可以被Bookmark,而POST不可以。

GET请求会被浏览器主动cache,而POST不会,除非手动设置。

GET请求只能进行url编码,而POST支持多种编码方式。

GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。

GET请求在URL中传送的参数是有长度限制的,而POST么有。

对参数的数据类型,GET只接受ASCII字符,而POST没有限制。

GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。

GET参数通过URL传递,POST放在Request body中。

让我们扒下GET和POST的外衣,坦诚相见吧!

GET和POST是什么?HTTP协议中的两种发送请求的方法。

HTTP是什么?HTTP是基于TCP/IP的关于数据如何在万维网中如何通信的协议。

HTTP的底层是TCP/IP。所以GET和POST的底层也是TCP/IP,也就是说,GET/POST都是TCP链接。GET和POST能做的事情是一样一样的。你要给GET加上request body,给POST带上url参数,技术上是完全行的通的。

在我大万维网世界中,TCP就像汽车,我们用TCP来运输数据,它很可靠,从来不会发生丢件少件的现象。但是如果路上跑的全是看起来一模一样的汽车,那这个世界看起来是一团混乱,送急件的汽车可能被前面满载货物的汽车拦堵在路上,整个交通系统一定会瘫痪。为了避免这种情况发生,交通规则HTTP诞生了。HTTP给汽车运输设定了好几个服务类别,有GET, POST, PUT, DELETE等等,HTTP规定,当执行GET请求的时候,要给汽车贴上GET的标签(设置method为GET),而且要求把传送的数据放在车顶上(url中)以方便记录。如果是POST请求,就要在车上贴上POST的标签,并把货物放在车厢里。当然,你也可以在GET的时候往车厢内偷偷藏点货物,但是这是很不光彩;也可以在POST的时候在车顶上也放一些数据,让人觉得傻乎乎的。HTTP只是个行为准则,而TCP才是GET和POST怎么实现的基本。

但是,我们只看到HTTP对GET和POST参数的传送渠道(url还是requrest body)提出了要求。“标准答案”里关于参数大小的限制又是从哪来的呢?

在我大万维网世界中,还有另一个重要的角色:运输公司。不同的浏览器(发起http请求)和服务器(接受http请求)就是不同的运输公司。 虽然理论上,你可以在车顶上无限的堆货物(url中无限加参数)。但是运输公司可不傻,装货和卸货也是有很大成本的,他们会限制单次运输量来控制风险,数据量太大对浏览器和服务器都是很大负担。业界不成文的规定是,(大多数)浏览器通常都会限制url长度在2K个字节,而(大多数)服务器最多处理64K大小的url。超过的部分,恕不处理。如果你用GET服务,在request body偷偷藏了数据,不同服务器的处理方式也是不同的,有些服务器会帮你卸货,读出数据,有些服务器直接忽略,所以,虽然GET可以带request body,也不能保证一定能被接收到哦。

好了,现在你知道,GET和POST本质上就是TCP链接,并无差别。但是由于HTTP的规定和浏览器/服务器的限制,导致他们在应用过程中体现出一些不同。

我们的大BOSS还等着出场呢。。。

这位BOSS有多神秘?当你试图在网上找“GET和POST的区别”的时候,那些你会看到的搜索结果里,从没有提到他。他究竟是什么呢。。。

GET和POST还有一个重大区别,简单的说:

GET产生一个TCP数据包;POST产生两个TCP数据包。

长的说:

对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);

而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。

也就是说,GET只需要汽车跑一趟就把货送到了,而POST得跑两趟,第一趟,先去和服务器打个招呼“嗨,我等下要送一批货来,你们打开门迎接我”,然后再回头把货送过去。

因为POST需要两步,时间上消耗的要多一点,看起来GET比POST更有效。因此Yahoo团队有推荐用GET替换POST来优化网站性能。但这是一个坑!跳入需谨慎。为什么?

  1. GET与POST都有自己的语义,不能随便混用。

  2. 据研究,在网络环境好的情况下,发一次包的时间和发两次包的时间差别基本可以无视。而在网络环境差的情况下,两次包的TCP在验证数据包完整性上,有非常大的优点。

  3. 并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次。

现在,当面试官再问你“GET与POST的区别”的时候,你的内心是不是这样的?

React Props and State

@octocat :+1: Props looks great - it’s ready to mount! :shipit:

#

###The data in React flows from top to down(parent to child) and store in Props and state, when flow between cpmponnets it is in Props while in the component inside it is in the component.

###Props: for a component, it can acepts some params from outside, which is so called Props(either from parents or store).

###Property of Props: props used to decrate the component, so when the component is initialed and got instance, the props is unchangable and readable only. because when the props is changed during mounting the componet, if the props is changed, the component will be unpreditable.
所以只有通过父组件渲染方式才可以把props传进去。
Example:

1
2
3
4
5
6
7
8
9
import Item from "./item";
export default class ItemList extends React.Component{
const itemList = data.map(item => <Item item=item />);
render(){
return (
{itemList}
)
}
}

In the child Component:

1
2
3
4
5
6
7
export default class Item extends React.Component{
render(){
return (
<li>{this.props.item}</li>
)
}
}

在render函数中可以看出,组件内部是使用this.props来获取传递到该组件的所有数据,它是一个对象,包含了所有你对这个组件的配置,现在只包含了一个item属性,所以通过this.props.item来获取即可。

默认参数
在组件中,我们最好为props中的参数设置一个defaultProps,并且制定它的类型。比如,这样:

##总结:props是一个从外部传进组件的参数,主要作为就是从父组件向子组件传递数据,它具有可读性和不变性,只能通过外部组件主动传入新的props来重新渲染子组件,否则子组件的props以及展现形式不会改变。

1
2
3
4
5
6
7
Item.defaultProps = {
item: 'Hello Props',
};

Item.propTypes = {
item: PropTypes.string,
};

关于propTypes,可以声明为以下几种类型:

1
2
3
4
5
6
7
optionalArray: PropTypes.array,
optionalBool: PropTypes.bool,
optionalFunc: PropTypes.func,
optionalNumber: PropTypes.number,
optionalObject: PropTypes.object,
optionalString: PropTypes.string,
optionalSymbol: PropTypes.symbol,

what about state?? State is similar to props, but it is private and fully controlled by the component.

###一个组件的显示形态可以由数据状态和外部参数所决定,外部参数也就是props,而数据状态就是state

1
2
3
4
5
6
7
8
9
10
11
12
13
export default class ItemList extends React.Component{
constructor(){
super();
this.state = {
itemList:'一些数据',
}
}
render(){
return (
{this.state.itemList}
)
}
}

首先,在组件初始化的时候,通过this.state给组件设定一个初始的state,在第一次render的时候就会用这个数据来渲染组件。

state不同于props的一点是,state是可以被改变的。不过,不可以直接通过this.state=的方式来修改,而需要通过this.setState()方法来修改state。

比如,我们经常会通过异步操作来获取数据,我们需要在didMount阶段来执行异步操作

1
2
3
4
5
6
  fetch('url')
.then(response => response.json())
.then((data) => {
this.setState({itemList:item});
}
}

setState接受一个对象或者函数作为第一个参数,只需要传入需要更新的部分即可,不需要传入整个对象,比如:

default class ItemList extends React.Component{
1
2
3
4
5
6
7
8
9
10
11
  constructor(){
super();
this.state = {
name:'axuebin',
age:25,
}
}
componentDidMount(){
this.setState({age:18})
}
}

在执行完setState之后的state应该是{name:’axuebin’,age:18}。

setState还可以接受第二个参数,它是一个函数,会在setState调用完成并且组件开始重新渲染时被调用,可以用来监听渲染是否完成:

1
2
3
this.setState({
name:'xb'
},()=>console.log('setState finished'))

##总结
state的主要作用是用于组件保存、控制以及修改自己的状态,它只能在constructor中初始化,它算是组件的私有属性,不可通过外部访问和修改,只能通过组件内部的this.setState来修改,修改state属性会导致组件的重新渲染

##Summary

###1.state是组件自己管理数据,控制自己的状态,可变;

###2.props是外部传入的数据参数,不可变;

###3.没有state的叫做无状态组件,有state的叫做有状态组件;

###4.多用props,少用state。也就是多写无状态组件。

JavaBeans Definition

Definition:
JavaBean 是一种JAVA语言写成的可重用组件。为写成JavaBean,类必须是具体的和公共的,并且具有无参数的构造器。JavaBean 通过提供符合一致性设计模式的公共方法将内部域暴露成员属性,long和class方法获取。众所周知,属性名称符合这种模式,其他Java 类可以通过自省机制发现和操作这些JavaBean 的属性。

Description:
JavaBean在MVC设计模型中是model,又称模型层,在一般的程序中,我们称它为数据层,就是用来设置数据的属性和一些行为,然后我会提供获取属性和设置属性的get/set方法.

MVC:
MVC的概念,即M-model-模型:JavaBean;V-view-表现:JSP页面;C-control-控制和处理:Servlet.

Disadvantage:
1.提高代码的可复用性:对于通用的事务处理逻辑,数据库操作等都可以封装在JavaBean中,通过调用JavaBean的属性和方法可快速进行程序设计。
2.程序易于开发维护:实现逻辑的封装,使事务处理和显示互不干扰。
3.支持分布式运用:多用JavaBean,尽量减少java代码和html的混编。
4.可以便捷地传递数据

Rule: Javabean类必须是public类 2、提供给JSP页面的调用方法必须富裕public访问权限 3、bean中属性必须给get和set方法 4、必须由空构造方法.

Example:

package Server;

import java.io.Serializable;
public class Product implements Serializable
{
private static final long serialVersionUID = 1L;
private String product_id;
private String product_name;
private double price;
private String info;

public Product()
{
    super();
}

public void setPrice(double price) {
    this.price = price;
}

public double getPrice() {
    return price;
}

public void setInfo(String info) {
    this.info = info;
}
public String getInfo() {
    return info;
}


public void setProduct_id(String product_id) {
    this.product_id = product_id;
}


public String getProduct_id() {
    return product_id;
}


public void setProduct_name(String product_name) {
    this.product_name = product_name;
}

public String getProduct_name() {
    return product_name;
}

}
Example Usage:

在页面中要导入相应的Bean类,并用jsp:usebean标签获取Bean对象
<jsp:useBean id=”自定义该Bean名字” class=”Bean类位置” scope=”Bean有效范围”/>
Bean有效范围:page、request、session、application
设置Bean属性jsp:setProperty,获取Bean属性jsp:getProperty
<jsp:setProperty name=”Bean的id” property=”Bean类属性名” param=”表单参数名”/>
<jsp:getProperty property=”Bean类属性名” name=”Bean的id”/>

Example:
<%@ page language=”java” contentType=”text/html; charset=utf-8”
pageEncoding=”utf-8”%>
<%@ page import=”java.util.*” %>
<%request.setCharacterEncoding(“utf-8”); %>
<jsp:useBean id=”product” class=”Server.Product” scope=”page” />
<!DOCTYPE html PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN” “http://www.w3.org/TR/html4/loose.dtd">




通过表单参数设置Bean属性值





输入产品名称:

输入产品编号:

输入产品价格:

输入产品信息:




<jsp:setProperty property=”product_name” name=”product” value=”struts开发教程”/>

产品名称是:

<jsp:getProperty property=”product_name” name=”product”/>
<%=product.getProduct_name() %>




<jsp:setProperty property=”product_id” name=”product” value=”111100123689”/>

产品编号是:

<jsp:getProperty property=”product_id” name=”product”/>
<%=product.getProduct_id() %>



<%
double price=68.23;
%>
<jsp:setProperty property=”price” name=”product” value=”<%=price +23.67%>”/>

产品价格是:

<jsp:getProperty property=”price” name=”product”/>




<jsp:setProperty property=”info” name=”product” value=”Structs开发教程是一本介绍秿Struct的专业书籍….”/>

产品信息:

<jsp:getProperty property=”info” name=”product”/>

Cons:
其实所有的程序都可以写在jsp页面里,但是存在以下问题:
1、执行效率低下;
2、不安全,所有的程序都在jsp文件中可见,毫无知识保护可言;
3、逻辑混乱。这样让JSP文件的逻辑很难懂。
于是提出了MVC模式,即将一些处理用的程序从JSP中分离出来,让JSP页面只负责显示,几乎是html,只不过可以动态的读取数据和进行少量的逻辑处理,比如循环、判断等。
可能不举例说你还是不懂,我就举个最简单的例子——留言板。
JSP的职责:从数据库取出数据,显示所有的留言信息(当中要用少量的,简单的逻辑处理:循环)、显示签写留言的页面(几乎全部都是html)。
Servlet的职责:接受签写留言页面提交过来的标单数据,进行数据检验,如果正确,则存入数据库并返回留言的显示页面;如果数据有误,给出错误提示后返回签写留言的页面。可以看到,这个就叫做逻辑处理。这些你也完全可以放在JSP中实现,但是用Servlet,其效率和安全性高多了,也让JSP页面变得很简洁明了。
JavaBean的职责:其实一般的留言板是不需要用到JavaBean的,但在这里,为了让你明白,还是牵强的把JavaBean用进来。所谓JavaBean,就是一个很简单的Java类,比如说,网上商城的所有商品是一个商品类,论坛中所有的帖子是一个帖子类,这里,留言板的所有留言是一个留言类,叫做Message类。每个类有着它特定的属性和方法。对于Message类,其属性有主题、内容、日期、留言者等,其方法可以有添加留言、删除留言、修改留言等。使用JavaBean,主要是为了让JSP编程能够适应Java程序员的习惯,直接对类和实例进行操作,而不是直接去操作数据库。

JavaSpringApp

Java Springframework简单模型:

  1. jar file: need to down load and put in the exernal lib file on local
  2. xml: need to using Springframework to load and parsing into bean object

  3. java 普通类: inject to beans

  4. javabeans: The model level of MVC, provide get/set proberty
  5. springframework: load jar file and xml file to be beans

StdinStdout

Interview Question for STDIN and STDOUT(java)

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String = line br.readLine();
int N = Integer.parseInt(line);

or:
Scanner n = new Scanner(System.in);
int N = n.nextInt();
and so one…

KMP_algorithm

//Fromhttps://www.geeksforgeeks.org/kmp-algorithm-for-pattern-searching/
KMP Algorithm for Pattern Searching
Given a text txt[0..n-1] and a pattern pat[0..m-1], write a function search(char pat[], char txt[]) that prints all occurrences of pat[] in txt[]. You may assume that n > m.

Pattern searching is an important problem in computer science. When we do search for a string in notepad/word file or browser or database, pattern searching algorithms are used to show the search results.

We have discussed Naive pattern searching algorithm in the previous post. The worst case complexity of the Naive algorithm is O(m(n-m+1)). The time complexity of KMP algorithm is O(n) in the worst case.

Most important part is that: use a helper int[] to preprocess the pattern.
Matching Overview
txt = “AAAAABAAABA”
pat = “AAAA”

We compare first window of txt with pat
txt = "AAAAABAAABA"
pat = "AAAA"  [Initial position]
We find a match. This is same as Naive String Matching.

In the next step, we compare next window of txt with pat.
    txt = "AAAAABAAABA"
    pat =  "AAAA" [Pattern shifted one position]
    This is where KMP does optimization over Naive. In this
    second window, we only compare fourth A of pattern
    with fourth character of current window of text to decide
    whether current window matches or not. Since we know
    first three characters will anyway match, we skipped
    matching first three characters.

Need of Preprocessing?
    An important question arises from the above explanation,
    how to know how many characters to be skipped. To know this,
    we pre-process pattern and prepare an integer array
    lps[] that tells us the count of characters to be skipped.

//Preprocessing Overview:

KMP algorithm preprocesses pat[] and constructs an auxiliary lps[] of size m (same as size of pattern) which is used to skip characters while matching.
name lps indicates longest proper prefix which is also suffix.. A proper prefix is prefix with whole string not allowed. For example, prefixes of “ABC” are “”, “A”, “AB” and “ABC”. Proper prefixes are “”, “A” and “AB”. Suffixes of the string are “”, “C”, “BC” and “ABC”.
We search for lps in sub-patterns. More clearly we focus on sub-strings of patterns that are either prefix and suffix.
For each sub-pattern pat[0..i] where i = 0 to m-1, lps[i] stores length of the maximum matching proper prefix which is also a suffix of the sub-pattern pat[0..i].

//Note :
lps[i] could also be defined as longest prefix which is also proper suffix. We need to use properly at one place to make sure that the whole substring is not considered.
EX: Examples of lps[] construction:
For the pattern “AAAA”,
lps[] is [0, 1, 2, 3]

For the pattern “ABCDE”,
lps[] is [0, 0, 0, 0, 0]

For the pattern “AABAACAABAA”,
lps[] is [0, 1, 0, 1, 2, 0, 1, 2, 3, 4, 5]

For the pattern “AAACAAAAAC”,
lps[] is [0, 1, 2, 0, 1, 2, 3, 3, 3, 4]

For the pattern “AAABAAA”,
lps[] is [0, 1, 2, 0, 1, 2, 3]

Searching Algorithm:
Unlike Naive algorithm, where we slide the pattern by one and compare all characters at each shift, we use a value from lps[] to decide the next characters to be matched. The idea is to not match a character that we know will anyway match.
How to use lps[] to decide next positions (or to know a number of characters to be skipped)?

We start comparison of pat[j] with j = 0 with characters of current window of text.
We keep matching characters txt[i] and pat[j] and keep incrementing i and j while pat[j] and txt[i] keep matching.
When we see a mismatch
We know that characters pat[0..j-1] match with txt[i-j+1…i-1] (Note that j starts with 0 and increment it only when there is a match).
We also know (from above definition) that lps[j-1] is count of characters of pat[0…j-1] that are both proper prefix and suffix.
From above two points, we can conclude that we do not need to match these lps[j-1] characters with txt[i-j…i-1] because we know that these characters will anyway match. Let us consider above example to understand this.

txt[] = “AAAAABAAABA”
pat[] = “AAAA”
lps[] = {0, 1, 2, 3}

i = 0, j = 0
txt[] = “AAAAABAAABA”
pat[] = “AAAA”
txt[i] and pat[j] match, do i++, j++

i = 1, j = 1
txt[] = “AAAAABAAABA”
pat[] = “AAAA”
txt[i] and pat[j] match, do i++, j++

i = 2, j = 2
txt[] = “AAAAABAAABA”
pat[] = “AAAA”
pat[i] and pat[j] match, do i++, j++

i = 3, j = 3
txt[] = “AAAAABAAABA”
pat[] = “AAAA”
txt[i] and pat[j] match, do i++, j++

i = 4, j = 4
Since j == M, print pattern found and reset j,
j = lps[j-1] = lps[3] = 3

Here unlike Naive algorithm, we do not match first three
characters of this window. Value of lps[j-1] (in above
step) gave us index of next character to match.
Example Process:
Most important thing here easy to understand
i = 4, j = 3
txt[] = “AAAAABAAABA”
pat[] = “AAAA”
txt[i] and pat[j] match, do i++, j++

i = 5, j = 4
Since j == M, print pattern found and reset j,
j = lps[j-1] = lps[3] = 3

Again unlike Naive algorithm, we do not match first three
characters of this window. Value of lps[j-1] (in above
step) gave us index of next character to match.
i = 5, j = 3
txt[] = "AAAAABAAABA"
pat[] =   "AAAA"
txt[i] and pat[j] do NOT match and j > 0, change only j
j = lps[j-1] = lps[2] = 2

i = 5, j = 2
txt[] = "AAAAABAAABA"
pat[] =    "AAAA"
txt[i] and pat[j] do NOT match and j > 0, change only j
j = lps[j-1] = lps[1] = 1

i = 5, j = 1
txt[] = "AAAAABAAABA"
pat[] =     "AAAA"
txt[i] and pat[j] do NOT match and j > 0, change only j
j = lps[j-1] = lps[0] = 0

i = 5, j = 0
txt[] = "AAAAABAAABA"
pat[] =      "AAAA"
txt[i] and pat[j] do NOT match and j is 0, we do i++.

i = 6, j = 0
txt[] = "AAAAABAAABA"
pat[] =       "AAAA"
txt[i] and pat[j] match, do i++ and j++

i = 7, j = 1
txt[] = "AAAAABAAABA"
pat[] =       "AAAA"
txt[i] and pat[j] match, do i++ and j++

We continue this way…
Don’t talk, Show the code:(java)
class KMP_String_Matching{
void KMPSearch(String pat, String txt){
int m = pat.length();
int n = txt.length();
int[] lps = new int[m]; //preprocess array
computeLPSArray(pat, m, lps);
int i = 0;
while(i < n){
if(pat.charAt(j)==txt.charAt(i)){
j++;
i++;
}
if(j==m){
System.out.println(“Found pattern at index”);
j = lps[j-1];
}
else if(i < N && pat.charAt(j) != txt.charAt(i)){
if(j != 0)
j = lps[j-1];
else
i = i+1;
}
}
}
void computeLPSArray(String pat, int m, int lps[]){
int len = 0;
int i = 1;
lps[0] = 0;
while(i<m){
if(pat.charAt(i) == pat.charAt(len)){
len++;
lps[i] = len;
i++;
}else{
if(len != 0){
len = lps[len-1];
}else{
lps[i] = len;
i++;
}
}
}
}
public static void main(String args[]){
String txt = “ABABDABACDABABCABAB”;
String pat = “ABABCABAB”;
new KMP_String_Matching().KMPSearch(pat, txt);
}
}

spring_depend_injection

Two Types of Dependency injection types

1. the setter injection

The setter injection is used to inject the dependencies through setter methods. In the following example, the instance of DataService uses the setter injection:

1
2
3
4
5
6
7
 public class BusinessServiceImpl {
private DataService dataService;
@Autowired
public void setDataService(DataService dataService) {
this.dataService = dataService;
}
}

Actually, in order to use the setter injection, you do not even need to declare a setter method. If you specify @Autowired on the variable, Spring automatically uses the setter injection. So, the following code is all that you need for the setter injection for DataService:

1
2
3
4
public class BusinessServiceImpl {
@Autowired
private DataService dataService;
}

2. the constructor injection

The constructor injection, on the other hand, uses a constructor to inject dependencies. The following code shows how to use a constructor for injecting in DataService:

1
2
3
4
5
6
7
8
   public class BusinessServiceImpl {
private DataService dataService;
@Autowired
public BusinessServiceImpl(DataService dataService) {
super();
this.dataService = dataService;
}
}

When you run the code with the preceding implementation of BusinessServiceImpl, you will see this statement in the log, asserting that autowiring took place using the constructor:
Autowiring by type from bean name ‘businessServiceImpl’ via
constructor to bean named ‘dataServiceImpl’

From

Persistence

Understanding the meaning of persistence is important for evaluating different data store system

Given the importance of the data store in most modern applications, making a poorly informed choice could mean substantial downtime or loss of data.

Persistence is “the continuance of an effect after its cause is removed”. In the context of storing data in a computer system, this means that the data survives after the process with which it was created has ended. In other words, for a data store to be considered persistent, it must write to non-volatile storage.

If you need persistence in your data store, then you need to also understand the four main design approaches that a data store can take and how (or if) these designs provide persistence:

Pure in-memory, no persistence at all, such as memcached or Scalaris
In-memory with periodic snapshots, such as Oracle Coherence or Redis
Disk-based with update-in-place writes, such as MySQL ISAM or MongoDB
Commitlog-based, such as all traditional OLTP databases (Oracle,
SQL Server, etc.)

In-memory approaches can achieve blazing speed, but at the cost of being limited to a relatively small data set. Most workloads have relatively small “hot” (active) subset of their total data; systems that require the whole dataset to fit in memory rather than just the active part are fine for caches but a bad fit for most other applications. Because the data is in memory only, it will not survive process termination. Therefore these types of data stores are not considered persistent.

The easiest way to add persistence to an in-memory system is with periodic snapshots to disk at a configurable interval. Thus, you can lose up to that interval’s worth of updates.

Update-in-place and commitlog-based systems store to non-volatile memory immediately, but only commitlog-based persistence provides Durability – the D in ACID – with every write persisted before success is returned to the client.
Reference from below link.
https://www.datastax.com/dev/blog/what-persistence-and-why-does-it-matter