persist相关知识
-
spark中cache和persist的区别昨天面试被问到了cache和persist区别,当时只记得是其中一个调用了另一个,但没有回答出二者的不同,所以回来后重新看了源码,算是弄清楚它们的区别了。cache和persist都是用于将一个RDD进行缓存的,这样在之后使用的过程中就不需要重新计算了,可以大大节省程序运行时间。cache和persist的区别基于Spark 1.4.1 的源码,可以看到/** Persist this RDD with the default storage level (`MEMORY_ONLY`). */def cache(): this.type = persist()说明是cache()调用了persist(), 想要知道二者的不同还需要看一下persist函数:/** Persist this RDD with the&nbs
-
HDFS内存存储原理(Lazy Persist)介绍图一HDFS支持由Data Node管理的写入到堆栈内存的功能。Data Node会异步的将数据从内存持久化至磁盘,从而在性能敏感的IO Path中移去昂贵的磁盘IO和校验,因此我们称之为Lazy Persist。HDFS尽可能的保证在Lazy Persist策略下的持久性。在副本还未持久化至磁盘,节点重启了,则有可能会发生罕见的数据遗失。我们可以选择Lazy Persist Writes的策略来减少延迟,但可能会损失一定的持久性。上文描述的原理在图一的表示其实是4,6的步骤.写数据的RAM,然后异步的写到Disk.前面几个步骤是如何设置StorageType的操作,这个在下文种会具体提到.所以上图所示的大体步骤可以归纳为如下:对目标文件目录设置StoragePolicy为LAZY_PERSIST的内存存储策略.客户端进程向NameNode发起创建/写文件的请求.请求到具体的DataNode,DataNode会把这些数据块写入RAM内存中,同时启动异步线程服务将内存数据持久化到磁盘上.内存的异步持久化存
-
Spark 持久化(cache和persist的区别)我的原创地址:https://dongkelun.com/2018/06/03/sparkCacheAndPersist/1、RDD 持久化Spark 中一个很重要的能力是将数据持久化(或称为缓存),在多个操作间都可以访问这些持久化的数据。当持久化一个 RDD 时,每个节点的其它分区都可以使用 RDD 在内存中进行计算,在该数据上的其他 action 操作将直接使用内存中的数据。这样会让以后的 action 操作计算速度加快(通常运行速度会加速 10 倍)。缓存是迭代算法和快速的交互式使用的重要工具。RDD 可以使用 persist() 方法或 cache() 方法进行持久化。数据将会在第一次 action 操作时进行计算,并缓存在节点的内存中。Spark 的缓存具有容错机制,如果一个缓存的 RDD 的某个分区丢失了,Spark 将按照原来的计算过程,自动重新计算并进行缓存。在 shuffle 操作中(例如 reduceByKey),即便是用户没有调用 persist 方法,Spark 也会自动缓存部分中间
-
Redis之MISCONF Redis is configured to save RDB snapshots错误操作redis过程中并没有修改什么配置,出现如下错误, Redis之MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.问题java操作插入数据:package redis;import redis.clients.jedis.Jedis;import java.io.BufferedReader;import java.io.FileReader;import java.io.IOException;public class insert_data { &nbs
persist相关课程
persist相关教程
- 3.1 save() 和 persist() 方法 saveOrUpdate( ) 方法很好理解,是 save( ) 和 update( ) 方法的综合简化版,内在本质没改变。save() 和 persist() 方法有细节上的区别。save() 方法原型:public Serializable save(Object object);上一段 save ( ) 方法的测试实例:try { Student stu = new Student("save()方法", "男"); Serializable stuId = session.save(stu); System.out.println("----------输出学生编号Id---------"); System.out.println(stu.getStuId()); System.out.println(stuId); System.out.println("----------事务在后面-------"); transaction = session.beginTransaction(); transaction.commit();} catch (Exception e) { transaction.rollback(); } finally { session.close();} 输出结果:Hibernate: insert into Student (stuName, stuPassword, stuPic, stuSex) values (?, ?, ?, ?)----------输出学生编号Id---------4040----------事务在后面------- 结果即结论:Save() 方法可以在事务之外执行;有一个关键点需要引起重视:无论是在事务之内还是事务之外,save() 方法都会向数据库发送了一条 Sql 语句请求,控制台输出结果是一样的。但是:如果程序中 Hibernate 不显示发送事务提交指令,数据会回滚(丢失);只有当数据库系统接收到程序中发送过来的事务提交指令后,才会真正意义上保存。很好理解,因为事务是交给 Hibernate 管理的,数据库接收到插入指令后,在没有明确事务提交指令之前,只会把数据缓存在内存中。也就是说,虽然 save() 方法看起来不依赖事务就可插入数据,但,没有事务组件的指令,最后也是虚行一场。persist() 方法原型:public void persist(Object object); 上一段 persist() 测试实例:try { Student stu = new Student("persist()方法", "男"); session.persist(stu); System.out.println("----------输出学生编号Id---------"); System.out.println(stu.getStuId()); System.out.println("----------事务在后面-------"); transaction = session.beginTransaction(); System.out.println("-------------事务提交---------------"); transaction.commit(); System.out.println(stu.getStuId());} catch (Exception e) { transaction.rollback();} finally { session.close();}输出结果:----------输出学生编号Id---------null----------事务在后面--------------------事务提交---------------Hibernate: insert into Student (stuName, stuPassword, stuPic, stuSex) values (?, ?, ?, ?)39 persist() 方法只有当事务提交后,才会发送 Sql 请求,数据直接写入数据库,方法本身没有返回值。save() 和 persist() 方法区别:在事务之内调用时,两者区别不大;事务之外,区别明显。save() 返回主键值,persist() 方法没有返回值;persist() 完全依赖事务组件,否则不会提交 Sql 请求;persist() 方法除了可进行 save 操作,还可以进行 update 操作。
- 2.2 更新、删除 添加数据的代码前面课程中已经使用多次,现在讨论更新、删除。更新、删除的前提条件:更新、删除数据一定是数据库中的数据;更新、删除包括一个前置操作,查询操作。Session 提供了 public void delete(Object obj) 方法用来删除数据。编写删除测试实例,先查询,再删除:@Test public void testDelete() { Session session = sessionFactory.openSession(); Transaction transaction = null; try { transaction = session.beginTransaction(); //查询学号为1的学生 Student stu=(Student)session.load(Student.class, new Integer(1)); System.out.println(stu); session.delete(stu); transaction.commit(); } catch (Exception e) { transaction.rollback(); } finally { session.close(); } } 运行后,结果很明显,数据库中数据被删除。事务问题:事务是一个较复杂的主题(后有专题课程),原生 JDBC 中,事务管理方式有:数据库管理;JDBC API 管理。Hibernate 提供了 Transaction 对象,用来对事务进行管理。默认:autoCommit=false,意思是底层 JDBC 把事务交给 Hibernate 管理。查询时,可以忽略事务。使用 Hibernate 进行增、删、改时。须显示调用 Transaction 的 commit() 或 rollback() 方法。Session 提供了 public void update(Object object) 方法用于数据更新。编写更新的测试代码:@Test public void testUpdate() { //会话对象 Session session = sessionFactory.openSession(); // 事务对象 Transaction transaction = null; try { // 打开事务 transaction = session.beginTransaction(); //查询学号为1的学生 Student stu=(Student)session.load(Student.class, new Integer(1)); stu.setStuName("session同学"); session.update(stu); transaction.commit(); } catch (Exception e) { transaction.rollback(); } finally { session.close(); }} 结果没有什么意外,在程序中修改的数据通过 update() 方法同步到数据库。如果查询 API 文档,会发现除了这些语义上很明确的方法外,还有其它几个方法public void saveOrUpdate(Object object);public Object merge(Object object);public void persist(Object object);可以使用测试方式得到基本结论,如编写一个添加数据的实例时,使用 save、saveOrUpdate、persist 都可达到相同结果。@Testpublic void testAdd() { Session session = sessionFactory.openSession(); // 事务对象 Transaction transaction = null; try { // 打开事务 transaction = session.beginTransaction(); //添加新学生 Student stu=new Student("慕课网", "男"); //可换成saveOrUpdate方法,save方法 session.persist(stu); transaction.commit(); } catch (Exception e) { transaction.rollback(); } finally { session.close(); } } 本节课,只从语义层面做区分,其内在差异性留到后续课程中慢慢揭晓,算是留下一个悬念。休息一下,小结一下:Get()、Load()方法可用于查询;Save()可用于添加;Update()可用于更新数据;Delete()可用于删除;saveOrUpdate()有两重性,没有数据时添加数据,有数据时更新数据;persist()方法可用于更新、添加数据;merge()方法可用于更新、添加数据。是不是有点上头了,心累呀!Hibernate 不地道呀,搞出这么多方法,这是要逼得有选择困难症的人哭,其实每一个方法都有特定的应用场景,Hibernate 总是体贴入微的想着为开发者解决每一种开发场景的需求。记住刚开始说的,抓住主分支(知道层面),不管细节(内部机制层面)。
- 3.2 merge() 方法 方法原型: public Object merge(Object object); merge() 方法和 persist() 方法类似, 区别在于:merge() 方法接收一个 PO 作为参数,创建并返回此 PO 的副本对象;此副本对象具有对象持久化能力。这一点是 merge() 方法与其他方法最大的不同。上一段实例:try{ transaction = session.beginTransaction(); //查询出来的stu具有持久化能力 Student stu = (Student) session.get(Student.class, new Integer(2)); //转stu对象持久化状态转变成游离状态 session.clear(); //stu_对象具有持久化能力 Student stu_ = (Student) session.merge(stu); //这个操作不能同步到数据库 stu.setStuName("我已经不具有持久化能力"); //这个操作能同步到数据库 stu_.setStuName("我具有持久化能力"); transaction.commit();} catch(Exception e) { transaction.rollback();} finally { session.close();} merge() 方法返回的 stu 对象的副本 stu_,此对象具有持久化能力。执行下面代码,数据能同步到数据库中。stu_.setStuName("我具有持久化能力"); Session 中提供的每一个方法都有其实际意义。特别是 merge() 方法,既可以保护原对象中的数据不被污染,又能行使数据库同步操作。在很多场景里都会有这个需求。
- 4. 一对多关联映射中的级联操作 什么是级联操作?关系型数据库中由主外键维系的两张表,具有主从关系。如学生表和班级表,班级班是主表,学生表是从表。类似于删除某一个班级的信息,则需要先删除所在班的学生信息,再删除班级信息,这个操作就是级联操作。所谓级联操作,指操作一张表时,是否会牵连到与之有关联的其它表。现在,咱们是使用 Hibernate 进行数据操作,不可能还要劳驾自己亲力亲为吧。只需要做些简单配置,就可以让 Hibernate 自动做级联操作。进入班级类,修改代码如下:@OneToMany(targetEntity=Student.class,mappedBy="classRoom",cascade=CascadeType.REMOVE) public Set<Student> getStudents() { return students; }很简单,只需要使用 @OneToMany 的 cascade 属性,就能让 Hibernate 明白如何做级联操作。默认情况下,没有级联效应。cascade 是一个枚举类型:public enum CascadeType { ALL, PERSIST, MERGE, REMOVE, REFRESH, DETACH}ALL: 级联所有操作;PERSIST: 级联新增;MERGE: 级联更新或者新增;REMOVE: 级联删除;REFRESH: 级联刷新;DETACH: 级联分离。测试删除班级实例:HibernateTemplate<ClassRoom> hibernateTemplate = new HibernateTemplate<ClassRoom>(); hibernateTemplate.template(new Notify<ClassRoom>() { @Override public ClassRoom action(Session session) { ClassRoom classRoom=(ClassRoom)session.get(ClassRoom.class, new Integer(1)); session.delete(classRoom); return null; } });如果不添加 cascade 相关说明,因为有学生引用班级信息,班级信息是不能被删除的。添加后再测试,查看表中内容:班级以及班级所在学生信息全部删除!删除班级时能级联删除学生,反过来,删除学生能删除班级吗?想法很好,实践是检验真理的唯一手段,学生类中修改成如下代码:@ManyToOne(targetEntity=ClassRoom.class,cascade=CascadeType.REMOVE) @JoinColumn(name="classRoomId") public ClassRoom getClassRoom() { return classRoom; }测试实例:HibernateTemplate<Student> hibernateTemplate = new HibernateTemplate<Student>(); hibernateTemplate.template(new Notify<Student>() { @Override public Student action(Session session) { Student stu=(Student)session.get(Student.class, new Integer(2)); session.delete(stu); return stu; } });结果很残酷!学生被删除了,班级也被删除了!级联级联,只要设置了级联,不管删除学生还是班级,只要在对应表中有引用关系的数据就会被删除。现在,学生类、班级类中的级联删除都打开了。如果对下面情形的数据(编号 1、2 的学生的班级编号都为 1)进行删除操作,则会发生什么事情?数据库中的数据如下:测试删除编号为 1 的学生:HibernateTemplate<Student> hibernateTemplate = new HibernateTemplate<Student>(); hibernateTemplate.template(new Notify<Student>() { @Override public Student action(Session session) { Student stu=(Student)session.get(Student.class, new Integer(1)); session.delete(stu); return stu; } });进入 MySql,查看一下:天呀!这是级联还是株连呀,太让人后怕,数据都没有了。删除学生时,会级联删除和学生有关的班级,班级删除时,又会查看学生表中是否还存在与班级有关联的学生,有,则一刀下去,连根拔起。Hibernate 有点刹不住车,产生了级联连锁反应。针对上面的测试,如果班级表的级联关闭,执行测试代码,请问结果又会怎样?本节课程,讲解了级联删除,级联添加的内容留到下节课继续展开。
- 2.2 get() 方法 接下来我们要追踪一下 requests.get() 请求的完整过程。首先是找到相应的 get() 方法:# 源码位置: requests/api.pyfrom . import sessionsdef request(method, url, **kwargs): with sessions.Session() as session: return session.request(method=method, url=url, **kwargs) def get(url, params=None, **kwargs): kwargs.setdefault('allow_redirects', True) return request('get', url, params=params, **kwargs)def options(url, **kwargs): kwargs.setdefault('allow_redirects', True) return request('options', url, **kwargs)def head(url, **kwargs): kwargs.setdefault('allow_redirects', False) return request('head', url, **kwargs)def post(url, data=None, json=None, **kwargs): return request('post', url, data=data, json=json, **kwargs)def put(url, data=None, **kwargs): return request('put', url, data=data, **kwargs)def patch(url, data=None, **kwargs): return request('patch', url, data=data, **kwargs)def delete(url, **kwargs): return request('delete', url, **kwargs)可以看到,所有的请求最后都是调用同一个 session.request() 方法,我们继续追进去:# 源码位置:requests/sessions.py# ...class Session(SessionRedirectMixin): # ... # 有了这两个方法就可以使用 with 语句了: # with Session() as session: # pass def __enter__(self): return self def __exit__(self, *args): self.close() # ... def request(self, method, url, params=None, data=None, headers=None, cookies=None, files=None, auth=None, timeout=None, allow_redirects=True, proxies=None, hooks=None, stream=None, verify=None, cert=None, json=None): # Create the Request. req = Request( method=method.upper(), url=url, headers=headers, files=files, data=data or {}, json=json, params=params or {}, auth=auth, cookies=cookies, hooks=hooks, ) prep = self.prepare_request(req) proxies = proxies or {} settings = self.merge_environment_settings( prep.url, proxies, stream, verify, cert ) # Send the request. send_kwargs = { 'timeout': timeout, 'allow_redirects': allow_redirects, } send_kwargs.update(settings) # 核心地方,发送 http 请求 resp = self.send(prep, **send_kwargs) return resp # ... 我们不过多陷入细节,这些细节函数由读者自行去跟踪和调试。我们从上面的代码中可以看到核心发送 http 请求的代码如下:resp = self.send(prep, **send_kwargs)prep 是一个 PreparedRequest 类实例,它和 Request 类非常像。我们继续追踪这个 send() 方法的源码:# 源码位置:requests/sessions.py:# ...class Session(SessionRedirectMixin): # ... def send(self, request, **kwargs): """Send a given PreparedRequest. :rtype: requests.Response """ # Set defaults that the hooks can utilize to ensure they always have # the correct parameters to reproduce the previous request. kwargs.setdefault('stream', self.stream) kwargs.setdefault('verify', self.verify) kwargs.setdefault('cert', self.cert) kwargs.setdefault('proxies', self.proxies) # It's possible that users might accidentally send a Request object. # Guard against that specific failure case. if isinstance(request, Request): raise ValueError('You can only send PreparedRequests.') # Set up variables needed for resolve_redirects and dispatching of hooks allow_redirects = kwargs.pop('allow_redirects', True) stream = kwargs.get('stream') hooks = request.hooks # Get the appropriate adapter to use adapter = self.get_adapter(url=request.url) # Start time (approximately) of the request start = preferred_clock() # Send the request r = adapter.send(request, **kwargs) # Total elapsed time of the request (approximately) elapsed = preferred_clock() - start r.elapsed = timedelta(seconds=elapsed) # Response manipulation hooks r = dispatch_hook('response', hooks, r, **kwargs) # Persist cookies if r.history: # If the hooks create history then we want those cookies too for resp in r.history: extract_cookies_to_jar(self.cookies, resp.request, resp.raw) extract_cookies_to_jar(self.cookies, request, r.raw) # Resolve redirects if allowed. if allow_redirects: # Redirect resolving generator. gen = self.resolve_redirects(r, request, **kwargs) history = [resp for resp in gen] else: history = [] # Shuffle things around if there's history. if history: # Insert the first (original) request at the start history.insert(0, r) # Get the last request made r = history.pop() r.history = history # If redirects aren't being followed, store the response on the Request for Response.next(). if not allow_redirects: try: r._next = next(self.resolve_redirects(r, request, yield_requests=True, **kwargs)) except StopIteration: pass if not stream: r.content return r代码会有点长,大家需要自行看看这个方法的逻辑,不要陷入细节。从上面的代码我们可以发现两个关键语句:adapter = self.get_adapter(url=request.url):获取合适的请求适配器;r = adapter.send(request, **kwargs):发送请求,获取响应结果;第一个 adapter 怎么来的呢?继续看那个 self.get_adapter() 方法:# 源码位置:requests/sessions.py:# ...class Session(SessionRedirectMixin): # ... def __init__(self): # ... # Default connection adapters. self.adapters = OrderedDict() self.mount('https://', HTTPAdapter()) self.mount('http://', HTTPAdapter()) # ... def get_adapter(self, url): """ Returns the appropriate connection adapter for the given URL. :rtype: requests.adapters.BaseAdapter """ for (prefix, adapter) in self.adapters.items(): if url.lower().startswith(prefix.lower()): return adapter # Nothing matches :-/ raise InvalidSchema("No connection adapters were found for {!r}".format(url)) # ...其实仔细在分析下,就可以知道我们在初始化 (__init__.py) 中添加了请求前缀 prefix (https:// 和 http://) 对应的连接适配器 (HTTPAdapter()),因此这里 adapter 对应的就是 HTTPAdapter 类实例。此时要找发送 http 请求的 send() 方法就需要去 ``HTTPAdapter` 中查找:# 源码位置:requests/adapters.py# ...class BaseAdapter(object): """The Base Transport Adapter""" def __init__(self): super(BaseAdapter, self).__init__() def send(self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None): raise NotImplementedError def close(self): """Cleans up adapter specific items.""" raise NotImplementedError class HTTPAdapter(BaseAdapter): # ... def send(self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None): try: conn = self.get_connection(request.url, proxies) # 自行加上一个打印语句,查看conn类型 # print('conn:', type(conn)) except LocationValueError as e: raise InvalidURL(e, request=request) self.cert_verify(conn, request.url, verify, cert) url = self.request_url(request, proxies) self.add_headers(request, stream=stream, timeout=timeout, verify=verify, cert=cert, proxies=proxies) chunked = not (request.body is None or 'Content-Length' in request.headers) # ... try: if not chunked: resp = conn.urlopen( method=request.method, url=url, body=request.body, headers=request.headers, redirect=False, assert_same_host=False, preload_content=False, decode_content=False, retries=self.max_retries, timeout=timeout ) # Send the request. else: # ... except (ProtocolError, socket.error) as err: raise ConnectionError(err, request=request) except MaxRetryError as e: # ... except ClosedPoolError as e: raise ConnectionError(e, request=request) except _ProxyError as e: raise ProxyError(e) except (_SSLError, _HTTPError) as e: # ... return self.build_response(request, resp)就我们前面的请求而言,request.body 往往为 None,所以 chunked 一般为 False。那么最终的请求走的就是conn.urlopen() 方法。注意:这里最关键的步骤是得到连接远端服务的信息 conn,后面发送数据都是通过 conn 走的。# 源码位置:requests/adapters.py# ...class BaseAdapter(object): """The Base Transport Adapter""" def get_connection(self, url, proxies=None): """Returns a urllib3 connection for the given URL. This should not be called from user code, and is only exposed for use when subclassing the :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. :param url: The URL to connect to. :param proxies: (optional) A Requests-style dictionary of proxies used on this request. :rtype: urllib3.ConnectionPool """ proxy = select_proxy(url, proxies) if proxy: # 使用代理 # ... else: # Only scheme should be lower case parsed = urlparse(url) url = parsed.geturl() conn = self.poolmanager.connection_from_url(url) return conn我们可以运行并打印这个 conn 变量。这里需要改源代码,在源码位置加上一行 print() 方法:>>> import requests>>> payload = {'key1': 'value1', 'key2': ['value2', 'value3']}>>> r = requests.get('https://httpbin.org/get', params=payload)conn: <class 'urllib3.connectionpool.HTTPSConnectionPool'>>>>我们终于看到,最后 requests 库其实就是封装 Python 内置的 urllib3 模块来完成 http 请求的。上面获取 conn 值的代码比较多且绕,有兴趣的读者可以自行跟踪下,限于篇幅,这里就不过多描述了。
- Kotlin-Android 环境搭建 Kotlin 是安卓开发的官方语言
persist相关搜索
-
pack
package
package文件
padding
pages
page对象
panda
panel
panel控件
param
parameter
parcel
parent
parentnode
parents
parse
parse error
parseint
partition
pascal