首页 文章 精选 留言 我的

精选列表

搜索[整理],共9147篇文章
优秀的个人博客,低调大师

MindSpore 社区整理救援锦囊望扩散

7月17日以来,河南省遭遇极端强降雨。20日8时至17时,部分地区强降雨天气仍在持续。持续强降雨已造成河南多地道路、地铁等公共设施被淹,人员被困。国家防总将防汛应急响应提升至ΙΙ级。 图片来源:央视财经 洪涝灾害不仅会影响出行,造成财物损失,更会带来不同程度的健康隐患。现阶段只能趋利避害,尽量做好防灾减灾工作。 MSG在行动 MindSpore社区希望可以为河南抗灾贡献自己的一份力量! 1. 社区的小伙伴如果有求助或者提供帮助的需求,可以直接联系MSG河南组织者: 张东豪 18236568776 移动 15611863936 联通 2. 社区紧急建立了救援互助信息的收集与共享通道: https://gitee.com/mindspore/community/issues 大家可以点击上方链接跳转浏览器进入社区提交求助信息、分享互助物资、补充救援信息,MindSpore社区的MSG河南组织者以及社区运营团队会有专人通过社区wiki页面来不定期跟进并维护整体信息: https://gitee.com/mindspore/community/wikis/ 希望这个共享通道可以帮助有需要的人,MindSpore社区全体与大家共渡难关。在这里感谢奋斗在抢险救灾一线的城市守护者们,郑州人民,无必要不出门,MindSpore社区全体成员希望大家一切安好,河南加油! 洪水来袭应注意 1. 步行时 我们希望洪水来临时不要步行出门!不要步行出门!不要低估洪水上涨的速度,也要知道水流可以让原来的井盖、雨水篦子离位,脚下危险重重。更不要在海岸边或者河边步行。 如果洪水上涨过快,你正在步行路上,可以尽快向上坡、高地等地势高的地方转移,甚至可以爬上屋顶、大树暂避风险。已无法转移至高处时,尽可能利用手边的门板、木床等漂浮物。 2. 开车时 有洪水来袭风险时,不要开车!不要开车!开车并不能让你有更多保护。如果在开车,请迅速开向高处,不要盲目驶入桥下、隧道等容易积水的地方。一旦熄火马上下车步行转移,不要在车中等待救援。 3. 室内安全 用胶带纸封住门窗尽量减少进水。房间进水后保证关闭电源,如果要使用自来水,一定要煮沸。进入房间地势较高的部分收听广播等及时获取信息。不要接触污水,尤其是已被污水污染的食物。已被水浸泡的电器也尽量远离。 4. 食物安全 ①不喝生水。饮用水和用来做饭的水,都要进行氯化消毒或者煮沸处理。也注意不要用洪水洗菜、洗水果、洗碗或洗漱。 ②不要吃被洪水淹死或者死因不明的禽畜,不要捡食死掉的鱼虾贝类。 ③被水浸的叶类、根茎类蔬菜,如果没有腐烂,可用清水洗干净后煮熟煮透食用。 ④提倡用炖煮、焖烧等长时间加热的烹调方法将食物煮熟、煮透。 ⑤不要吃不明的食物,或者使用不明、外观类似盐、糖的 「调味料」,以免发生中毒。 ⑥尽量不吃剩饭剩菜,如果剩饭剩菜要留到下一餐食用,需要冷藏保存,下一餐食用前一定要彻底加热。 ⑦断电后的冰箱冷藏大约可以维持 4 小时的温度,冷冻通常可以保持 24 小时内。此时存放的食物尚且安全。 洪水来袭紧急救援 1. 溺水急救 如果遇到有人溺水,不要控水!不要控水!不要控水!正确急救方法是这样的: ① 清醒,有呼吸和脉搏 呼叫 120后,陪在溺水者身边,可以换上干衣服,裹上毯子,注意保暖,然后等待救援人员。 ② 无反应,有呼吸 清理溺水者口鼻中的异物,并使其保持在侧卧位,等待救援人员。等待过程要密切观察呼吸和脉搏情况,呼吸脉搏消失时进行心肺复苏。 ③ 无反应,无呼吸 立刻清理口鼻异物,保持呼吸道通畅,进行心肺复苏。 2. 防触电及触电急救 能避开积水路面就避开积水路面,实在避不开的,远离高压线塔、变压器、配电设施、各种疑似有电的装置。 万一行进过程有脚麻的感觉,迅速并脚跳原路退回。 一旦发现有人触电倒地,不要冒然上前施救。能关闭电源就关闭电源,或者用干燥木棍将人挪至安全范围再进行施救。 3.河南暴雨紧急求助通道 人民日报新媒体为河南暴雨受灾群众提供信息救助通道,如果您或您的家人因洪灾有紧急救援需求,请点击下图,填写信息↓↓↓ 图片来源:人民日报 附上一些救援电话,大家可以转发!让更多人能够得到救援 郑州市5支 1.郑州市红十字水上义务救援队 牛振西13938568990 2.郑州红十字蓝天应急救援队 李志鹏13838332525 3.河南省应急救援协会 陈水全13838336788 4.新郑市神鹰救援队 吴国钦13253381110 5.新郑市蓝天救援队 秦军峰13733199101 开封市3支 1.开封蓝天救援队 张海祥13837835001 2.开封市无线电协会应急通信大队 康伟18503781818 3.开封市红豹救援队 柴倩倩18803789668 洛阳市3支 1.洛阳市神龙水上义务搜救队 杨红山15670399937 2.洛阳市神鹰救援队 张超伟15538837110 3.伊川县神鹰救援队 梁绪伟15036999699 平顶山市3支 1.平顶山市永安应急救援队 杜全甫13949469283 2.救援协会郏县应急队 何邵舟13383999505 3.义工联合蓝天救援队 李伟峰17335236002 安阳市4支 1.红旗渠应急救援中心 杨永峰18567769958 2.内黄县枣乡应急救援中心 朱志刚15890758666 3.林州市蓝天救援队 杨志军13603461315 4.滑县应急救援协会 赵彦军18637288000 鹤壁市2支 1.淇县斑马救援队 韦玉其17630396099 2.山城区无疆公益救援协会 钱宏滔17719900007 新乡市2支 1.新乡市斑马应急救援中心 柴守勇13333804449 2.退役军人应急救援中心 刘海军13525022282 焦作市2支 1.焦作市应急救援协会 张昊18623911479 2.温县应急救援服务中心 张彦兵15036520006 风雨同舟,共度难关。 愿河南人民平安。

优秀的个人博客,低调大师

PostgreSQL全网博文、学习系列、资料、案例等整理

2 --> PostgreSQL学习仓库:https://gitee.com/AiShiYuShiJiePingXing/postgres 一、仓库说明 本来是想直接同步德哥的pg仓库,但是奈何德哥的仓库太大了,都无法直接从GitHub迁移到gitee。但是看到德哥的许多笔记十分有用,于是花了很久时间,把德哥的笔记都过了两遍。 第一遍,发现德哥有很多私人笔记在里面,并不是有关于PostgreSQL相关的,手动做了剔除。 第二遍,发现笔记太过于混乱,不太好明确的找到相应的内容,遂自己做了一个简单的目录。 同时,也将该仓库作为自己学习和研究PostgreSQL的仓库,会不断积累和分享有关PostgreSQL的内容。 德哥PostgreSQL仓库地址:https://github.com/digoal/blog 1.1 德哥是谁? digoal(德哥) PostgreSQL 中国社区发起人之一。负责PostgreSQL数据库在中国的技术落地与推广、人才培养。 中国开源软件推进联盟PostgreSQL分会,特聘资深领域专家。 中国信息通信研究院主办、中国通信标准化协会支持的"OSCAR云计算开源产业大会"评选:2018届OSCAR开源尖峰人物之一 阿里云数据库首席专家团队成员,提供数据库首席专家服务。 阿里巴巴钻石布道师 42项数据库专利 1.1.1 贡献 专利(截至2020-01): 201210121337.9;102708158B - 一种PostgreSQL云存储归档调度系统 201410207285.6;104166666B - PostgreSQL高并发流式大数据多维度准实时统计的方法 201410548447.2;104503965B - PostgreSQL高弹性的高可用及负载均衡实现方法 201410550641.4;104503966B - PostgreSQL大数据高效免维护自动分区方法 201410652026.4;104572809B - 一种分布式关系数据库自由扩展方法 201410652028.3;104503974B - 一种基于云平台的关系数据库自动优化方法 201410751853.9;104536988B - MonetDB分布式计算存储方法 201410754052.8;104503865B - PostgreSQL快速恢复到任意时间点的方法 201410780380.5;104750573B - 分布式数据系统数据节点的全局一致性备份和还原方法 201510078225.3;104731863B - 简化PostgreSQL分区代码的方法 201510083556.6 - 一种使用keepalived软件实现数据库HA应用的方法[驳回] 201510107904.9;104809152B - 一种节约PostgreSQL共享内存的方法及系统 201510724098.X - 用于资源调度的方法和设备 201510835059.7 - 用于主备数据一致性校验的方法和设备 201510875827.1 - 一种用于实现主备同步模式下事务提交的方法与设备 201510900751.3 - 用于创建主备数据库的方法和设备 201510904243.2 - 一种提高数据安全的方法与设备 201511001289.X - 用于数据发送、限制发送进程占用带宽的方法和装置 201511019216.3 - 数据库心跳检测方法以及装置 201511026756.4 - 一种用于更改秘钥的方法、装置及设置秘钥的方法、装置 201610101944.7 - 数据库读写分离方法、装置和系统 201611183503.2 - 一种数据库死锁的处理方法、装置和数据库系统 201710093376.5 - 数据同步方法及设备 201710093382.0 - 一种查询唯一值的方法及设备 201710488500.8 - 一种数据容错的方法及设备 201710492419.7 - 一种重做日志持久化方法及设备 201710581818.0 - 数据库宕机后的访问方法、装置和系统 201710643448.9 - 数据的存储、处理及读取方法、数据存储设备和系统 201710813987.2 - 一种数据操作方法及设备 201710860627.8 - 创建索引的方法和装置 201710860628.2 - 数据获取模型建立的方法和数据获取的方法及装置 201710862401.1 - 一种索引创建方法、装置及数据库系统 201710862402.6 - 数据库的检索方法及装置 201710862403.0 - 数据库处理方法及装置、系统 201711105172.5 - 数据查询方法和装置 201711117230.6 - 数据处理方法、装置及设备 201711195546.7 - 数据写入方法及设备 201711239837.1 - 一种用于实现数据库高可用性的方法及装置 201711275922.3 - 一种数据库更新的方法及装置 201711482536.1 - 一种数据库系统以及查询数据库的方法和装置 201810182191.6 - 数据处理方法和数据处理装置 201810982558.2 - 一种数据跟踪处理方法及装置 1.1.2 社区贡献 自2008年开始,坚持开源PostgreSQL数据库的布道,负责PostgreSQL数据库在中国的技术落地与推广、人才培养。 加入阿里后的一些布道经历​2015-09-12 PG象行中国上海站-PG回归测试 2015-10-23 开源中国广州站技术分享 - PG企业特性 2015-11-15 开源中国源创会广州站2015-PG企业特性 2015-11-20 2015 PG峰会分享-一位PGer的安全修养 2016-05-13 2016dtcc- 从Oracle DBA到PostgreSQL布道者 2016-05-17 云栖大会-武汉-PostgreSQL物联网独孤九式 2016-09-24 全球敏捷运维峰会-阿里云PostgreSQL介绍 2016-10-27 PG 2016全国峰会-PostgreSQL 数据库前世今生 2016-10-27 PG2016全国峰会-PostgreSQL应用开发最佳实践 2016-10-27 PG2016全国峰会-sharding单元化(based on postgres_fdw)最佳实践 2017-03-18 SDCC 数据库核心技术与应用实战峰会-数据库超体 2017-05-27 2017 PG 象行中国社区会议-武汉站-PostgreSQL在阿里的应用 2017-06-24 开源中国源创会-杭州-自动驾驶背后到数据库 2017-08-23 2017 ODF会议,分享PG时空数据管理案例 2017-10-20 开源中国PG分会场,分享,阿里云RDS PG多维存储与流计算实践 2017-10-21 2017 PG峰会-阿里云RDS、HDB PG 多维存储特性与案例 2018-03-17 空间数据库应用峰会-北京师范 - PostgreSQL空间数据业务 优化实践 2018-07-01 开源联盟 - PG HTAP展望 2018-09-01 云栖TechDay - PG天天象上活动 - 杭州站第一期组织+分享 2018-09-07 ODF - 数据库华山论剑 PG vs MySQL 2018-09-09 云栖TechDay - PG天天象上活动 - 北京站组织+分享 2018-10-13 云栖techday - 全栈数据库PG天天象上活动 - 郑州站组织+分享 2018-10-14 ruby summit 2018 郑州- PG开发者特性分享 2018-10-14 中国开发者大会-郑州-高并发和大数据下的PG实战 2018-10-27 云栖TechDay - PG天天象上活动 - 广州站组织+分享 2018-10-28 云栖TechDay - PG天天象上活动 - 深圳站组织+分享 2018-11-24 云栖TechDay - PG天天象上活动 - 上海站组织+分享 2018-12-22 云栖TechDay - PG天天象上活动 - 南京站组织+分享 2019-01-12 云栖TechDay - PG天天象上活动 - 合肥站组织+分享 2019-03-23 云栖TechDay - PG天天象上活动 - 长沙站组织+分享 2019-04-19 云栖TechDay - PG天天象上数据库沙龙 - 成都站组织+分享 2019-05-11 dtcc 2019-PG数据库实战深度培训 2019-05-25 云栖TechDay - PG天天象上活动 - 杭州站组织+分享 2019-06-01 PG象行中国杭州站-PG11,12新特性分享 2019-06-22 阿里云开发者技术沙龙 - PG天天象上活动 - 武汉站组织+分享 2019-07-03 PG社区走进名企-平安集团-分享PG使用的正确姿势 2019-07-07 PG CONF 2019中国峰会,出席分享、培训 2019-07-13 PG天天象上-济南站-1天PG技术分享 2019-07-20 DAMS中国数据库智能管理峰会-PG去O非你莫属 2019-08-17 福州,象行中国- PG的生态、新特性与Oracle迁移介绍 2019-08-24 PostgreSQL 11 与 12 用户最关心的特性解读 2019-09-27 云栖大会2019-开发者进阶-技术影响力 -从技术深度到产品广度的裂变 2019-11-16 数据库嘉年华-PG为什么这么火 2019-11-23 第十八届全国软件与应用学术会议(NASAC 2019)-PostgreSQL的社会价值 2019-11-29 PG12 新特性与路标 2019-11-30 PG峰会-PG 诊断方法2019-12-07 PG社区走进中兴企业交流-分享《PG的社会价值&企业如何融入PG社区》 2020-01-04 pg+mongo助力企业去O 2020-01-11 PG天天象上2020.1.11杭州站-实时精准营销系统设计2020-01-18 PostgreSQL+MySQL 联合解决方案课程14讲2020-07-18 PG SSL安全链路分析 2020-08-15 CUUG PG数据库高校行启动会, 分享AliPG2020-09-10 亿级用户量的实时推荐数据库到底要几毛钱?2020-09-13 在数据库中跑全文检索、模糊查询SQL会不会被开除?2020-09-17 百城汇:云栖线下高校合作专场 , 宁夏大学2020-09-19 刷脸支付会不会刷到别人的钱包?2020-09-26 为什么打车和宇宙大爆炸有关?2020-09-26 大话数据库终局之战2020-10-18 为什么饿了么网上订餐不会凉凉 & 牛顿发现万有引力有关?2020-11-01 PG中文社区 & Hello bike & 阿里云 联合沙龙活动2020-11-17 PG分会-解密下一代云数据库mybase2020-11-22 数据库嘉年华分享-解密下一代云数据库mybase2020-12-18 大型企业数据库与应用实践-dsg,阿里云,pg社区,上海开源信息技术协会 联合主办2021-01-15 PG中文社区2020年度峰会-2021,别让你的企业输在起跑线2021-01-18 阿里云PG创新训练营 1.2 最佳阅读方式 因为文章全部是md格式的,所以建议采用Typora阅读。 git clone https://gitee.com/AiShiYuShiJiePingXing/postgres.git 使用Typora打开克隆后的项目 阅读学习 二、德哥的PostgreSQL, Greenplum 学习视频 1、视频下载链接: https://pan.baidu.com/s/1Q5u5NSrb0gL5-psA9DCBUQ (提取码:5nox 如果链接失效请通知我, 谢谢) PostgreSQL 9.3 数据库管理与优化 4天 PostgreSQL 9.3 数据库管理与优化 5天 PostgreSQL 9.1 数据库管理与开发 1天 PostgreSQL 9.3 数据库优化 3天 PostgreSQL 专题讲座 PostgreSQL Greenplum 培训视频分享:http://pan.baidu.com/s/1pKVCgHX 三、PostgreSQL资料(持续更新) 3.1 PostgreSQL学习系列 3.1.1 不睡觉的怪叔叔的PostGIS教程 PostGIS介绍 PostGIS安装 创建空间数据库 加载空间数据 数据 简单的SQL语句 几何图形(Geometry) 关于几何图形的练习 空间关系 空间连接 空间索引 投影数据 地理 几何图形创建函数 更多的空间连接 有效性 相等 线性参考 维数扩展的9交集模型 索引集群 3-D 最近邻域搜索 3.1.2 菜鸟教程-PostgreSQL系列 1.PostgreSQL 学习系列 2.PostgreSQL 优势 3.PostgreSQL 笔记 4.PostgreSQL 课程 5.PostgreSQL 案例 6.PostgreSQL PostGIS GIST 7.PostgreSQL 推荐系统 8.PostgreSQL 应用开发解决方案 9.PostgreSQL 插件 10.PostgreSQL 配置文件 11.PostgreSQL PDF资料文档 12.PostgreSQL 安装与部署 13.PostgreSQL Alter,Truncate Table 14.PostgreSQL视图、事务、锁 15.PostgreSQL子查询,Auto Increment 16.PostgreSQL权限Privileges 17.PostgreSQL时间日期函数和操作符 18.PostgreSQL常用函数 19.PostgreSQL的模式、表、空间、用户间的关系 3.2 PostgreSQL优势 企业数据库选型规则 为什么数据库选型和找对象一样重要 为什么选择开源数据库、如何选择、需要做哪些准备 学生为什么应该学PG, PG与其他数据库有哪些独特性, 为什么PG是数据库的未来 3.3 PostgreSQL笔记 3.4 PostgreSQL课程 3.5 PostgreSQL案例 阿里云PostgreSQL案例精选1 - 实时精准营销、人群圈选 阿里云PostgreSQL案例精选2 - 图像识别、人脸识别、相似特征检索、相似人群圈选 PostgreSQL 物流轨迹系统数据库需求分析与设计 - 包裹侠实时跟踪与召回 PostgreSQL数据库应用:基于GIS的实时车辆位置查询 3.6 PostgreSQL PostGIS GIST 3.6.1 德哥PostGIS GIST相关笔记 基于PG与PostGIS搭建实时矢量瓦片服务 PostGIS总结 PostgreSQL存储地理信息数据的注意点 postgresql 创建gis空间数据库,shp数据入库 PostGIS基本使用 3.7 PostgreSQL推荐系统 社交、电商、游戏等 推荐系统 (相似推荐) 推荐系统, 已阅读过滤, 大量CPU和IO浪费的优化思路2 用户喜好推荐系统 - PostgreSQL 近似计算应用 PostgreSQL 推荐系统优化总计 PostgreSQL 相似人群圈选,人群扩选,向量相似 使用实践 - cube 3.8 PostgreSQL应用开发解决方案 PostgreSQL 应用开发解决方案最佳实践系列课程 - 1. 中文分词与模糊查询 PostgreSQL 应用开发解决方案最佳实践系列课程 - 2. 短视频业务实时推荐 PostgreSQL 应用开发解决方案最佳实践系列课程 - 3. 人脸识别和向量相似搜索 PostgreSQL 应用开发解决方案最佳实践系列课程 - 4. 出行相关调度系统 PostgreSQL 应用开发解决方案最佳实践系列课程 - 5. 配送相关调度系统 PostgreSQL 应用开发解决方案最佳实践系列课程 - 6. 时空、时态、时序、日志等轨迹系统 PostgreSQL 应用开发解决方案最佳实践系列课程 - 8. 树状图谱关系系统 PostgreSQL 应用开发解决方案最佳实践系列课程 - 9. 数据存储冷热分离 3.9 PostgreSQL插件与工具 PostgreSQL 用户最喜爱的扩展插件功能 PostgreSQL 有价值的插件、可改进功能 PostgreSQL 最常用的插件 PostgreSQL工具 3.10 PostgreSQL配置文件 PostgreSQL 11 postgresql.conf 参数模板 3.11 PostgreSQL PDF资料及文档 PG的社会价值.pdf PostgreSQL思维导图 开发者PG TOP18问.pdf 3.12 PostgreSQL安装与部署 Linux中PostgreSQL和PostGIS的安装和使用 PostgreSQL+PostGIS安装部署 PostgreSQL的Docker安装与部署 3.13 PostgreSQL开发与使用 3.13.1 PostgreSQL规范 1.PostgreSQL 命名规范 2.PostgreSQL 设计规范 3.PostgreSQL QUERY规范 4.PostgreSQL 管理规范 5.PostgreSQL 稳定性与性能规范 6.PostgreSQL 阿里云RDS PostgreSQL 使用规范 Geotools连接PostgreSQL数据库 PostgreSQL常用SQL JDBC与PostgreSQL(一) 四、已归类文档 ——此部分请访问德哥github查阅 因为此部分,我看了有些内容没有,遂直接做了删减。 digoal's PostgreSQL 文章 归类 1 应用开发 2 日常维护 3 监控 4 备份,恢复,容灾 5 高可用 6 安全与审计 7 问题诊断与性能优化 8 流式复制 9 读写分离 10 水平分库 11 OLAP(MPP...) 12 数据库扩展插件 13 版本新特性 14 内核原理与开发 15 经典案例 16 HTAP 17 流式计算 18 时序、时空、对象多维处理 19 图式搜索 20 GIS 21 Oracle兼容性 22 数据库选型 23 Benchmark 24 最佳实践 25 DaaS 26 垂直行业应用 27 标准化(规约、制度、流程) 28 版本升级 29 同、异构数据同步 30 数据分析 31 系列课程 32 其他 33 招聘与求职信息 34 沙龙、会议、培训 35 思维精进 36 视频回放 五、批评指正 因大部分资料都是互联网资源,如有侵权,请联系删除。 对于错误或者不当之处,劳烦及时指正,会尽快更改。 再次多谢PG大佬们的辛勤付出!!!

优秀的个人博客,低调大师

整理了5个JavaScript怪异行为及其原因

如果你用 JavaScript 写过项目或者参加过面试,那一定遇到过不少令人匪夷所思的问题。JavaScript 早期的规范不统一,也没有严格的标准,再加上它的语法灵活多样,有些看起来就不正确的代码却能正常执行,一些看起来符合逻辑的代码,运行结果却相差十万八千里。这些问题在日常开发中经常会导致 BUG,更重要的是,很多面试官会把它们拿出来当考验咱们 JS 工程师的能力。那么这篇文章就总结了 5 个 JavaScript 比较坑的问题,以及它们出现的原因和解决方法。 1、可选分号 问题: functionfoo(){return{value:1};}console.log(typeoffoo()); 你可能会认为它的输出结果是 "Object",但是结果却是 undefined。乍一看代码好像没什么问题,但是细心一点可以看到 return 语句返回的对象放到了下一行,那么问题就来了:JavaScript 的分号是可选的,return 语句在换行后,JavaScript 会自动给它的结尾加上分号,而在 return 之后的代码都不会执行,所以 foo() 的返回结果是 undefined。解决方法是在每行结尾都写上分号,这样就能清楚的知道代码在哪里结束。 2、this 指向 问题: vara=5;varobj={a:3,foo:function(){console.log(this.a);}}varobjFoo=obj.foo;objFoo(); 答案为 5。在调用函数时,它内部的 this 指向的是调用对象,例如 obj.foo() this 指向的是 obj 对象。如果在全局调用函数时, this 指向的是全局对象,在浏览器中为 window。objFoo 相当于是在获取了 obj 对象的 foo 方法引用后,在全局进行调用,所以 this 指向的是 window 对象。使用 var 在顶级作用域中定义的变量会添加到 window 中,所以 objFoo() 调用打印的是全局中的 a,即 5。 3、数组长度 问题: constarr=[1,2,3,4];arr.length=0;console.log(arr[0]); 结果为 undefined, 因为 array 的 length 属性同时也能反过来控制数组的元素数量,在给 arr.length 设置为 0 时,arr 就变成了空数组,再访问里边的元素就都是 undefined 了。 4、提升(Hoisting) 问题: functionbar(){returnfoo;foo=10;functionfoo(){}varfoo='11';}console.log(typeofbar()); 结果为 function。使用 var 声明的变量和使用 funtion 定义的函数会提升到当前作用域的顶部,所以变量可以先赋值,后使用 var 进行声明,而函数则可以先调用后定义。「但是要注意的是,使用 var 定义(指在声明的同时进行赋值)的变量,只会提升声明部分,赋值部分不会被提升,例如示例中的」 var foo = '11' 会提升 var foo,但 foo = 11 保留在原位。在定义 bar() 函数时,同时会创建一个作用域,提升会把相关变量和函数放到 bar() 函数的第一行。综合上边的规则,可以知道 foo() 函数和 foo 变量的声明进行了提升,因为 foo 变量与同名,但是只有声明,所以不会覆盖函数的值,foo 仍然指向的是函数。之后就直接使用 return 语句返回了结果,后边的代码就不会再执行了。bar() 中的代码其实是下边这种形式: functionbar(){functionfoo(){}varfoo;returnfoo;foo=10;varfoo='11';} 5、作用域与闭包 问题: for(vari=0;i<3;i++){setTimeout(()=>{console.log(i);});} 你可能会认为上方代码的结果为 0 1 2,但实际上是 3 3 3,这是因为使用 var 关键字定义的变量没有块级作用域,在 for 循环中定义的 i 相当于是全局变量,它会添加到 window 变量中,即使在 for 循环退出后也能访问 i 的值。这样就导致了一个问题,使用 setTimeout() 推迟的函数会在 for 循环结束后才执行,此时 i 的值已经变成 3 了,所以 3 个 setTimeout() 中的函数都会打印出 3。要解决这个问题有两种方法。 第 1 种是使用 let 关键字定义变量 i,这样在每次循环时,都会创建一个新的作用域,因此每个作用域中的 i 是相互独立的,这样就能打印出 0 1 2。 第 2 种方法是使用自执行函数,例如下边代码这样: for(vari=0;i<3;i++){(function(i){setTimeout(()=>{console.log(i);})})(i)} 这时,i 通过参数传递给了匿名的自执行函数,同时自执行函数创建了一个闭包,所以它会捕获 i 的值,相当于在内部复制了参数 i 的值,所以无论外边的 i 怎么变化,它内部的值都不会发生改变。这样也能打印出 0 1 2。 小结 这 5 个问题揭露了 JavaScript 中常见的一些坑,稍微不注意就会留下隐患,并且难以察觉,例如一个简单的换行、 this 指向的改变、意外修改数组的长度、变量和函数提升、作用域的创建都有可能出现异外的情况。这些问题可能在日常开发中并不多见,但是经常会出现在 JS 笔试和面试中,用于考察面试者对 JS 的熟悉程度。另外, JS 中的坑远不止这些,所以需要在日常中多积累,另外也可关注本博客,我会不定时的更新 JavaScript 使用上的问题,感谢! 本文分享自微信公众号 - 峰华前端工程师(qiantu_me)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

Andrioid中高级面试题目归纳整理

1. ThreadLocal的理解 可以保证线程的安全。在多个线程共享相同的数据的时候,会为每个线程创建单独的副本,在单独的副本上进行数据的操作,不会对其它线程的数据产生影响,保证了线程安全。 2. HashMap HashSet HashTable的区别? 都是集合,底层都是Hash算法实现的。HashMap是Hashtable的替代品,这两个都是双列集合,而HashSet是单列集合。HashMap线程不安全、效率高、可以存储null键和null值;Hashtable线程安全,效率低,不可以存储null键和null值。 3. 如何让HashMap可以线程安全? HashMap 在并发执行 put 操作时会引起死循环,导致 CPU 利用率接近100%。因为多线程会导致 HashMap 的 Node 链表形成环形数据结构,一旦形成环形数据结构,Node 的 next 节点永远不为空,就会在获取 Node 时产生死循环。使用下面三种替换方式:HashtableConcurrentHashMapSynchronized Map 4. Android对HashMap做了优化后推出的新的容器类是什么? SparseArray它要比 HashMap 节省内存,某些情况下比HashMap性能更好,按照官方问答的解释,主要是因为SparseArray不需要对key和value进行auto-boxing(将原始类型封装为对象类型,比如把int类型封装成Integer类型),结构比HashMap简单(SparseArray内部主要使用两个一维数组来保存数据,一个用来存key,一个用来存value)不需要额外的额外的数据结构(主要是针对HashMap中的HashMapEntry而言的)。 5. Java多线程之间如何通信 等待唤醒机制 6. 线程池的实现机制 向线程池提交任务,会依次启动核心线程,如果提交的任务数超过了核心线程数,会将任务保存到阻塞队列中,如果阻塞队列也满了,且继续提交任务,则会创建新线程执行任务,直到任务数达到最大线程数。此时如果再提交任务的话会抛出异常或者直接丢弃任务。通过Executor.execute()无法得到返回值,通过ExecutorService.submit()可以得到返回值。 7. RxJava中map和flatmap操作符的区别及底层实现 Map返回的是结果集,flatmap返回的是包含结果集的Observable。Map只能一对一,flatmap可以一对多、多对多。RxJava是通过观察者模式实现的。 8. 对消息机制中Looper的理解 Looper在消息机制中扮演的角色是创造无限循环从Messagequeue中取得消息然后分发。 9. 单例模式有哪些实现方式 饿汉模式(线程安全,调用效率高,但是不能延时加载)懒汉模式(线程安全,调用效率不高,但是能延时加载)双重检测锁模式(由于JVM底层模型原因,偶尔会出问题,不建议使用)静态内部类式(线程安全,调用效率高,可以延时加载)枚举类(线程安全,调用效率高,不能延时加载,可以天然的防止反射和反序列化调用) 10. 通过静态内部类实现单例模式有哪些优点 线程安全,调用效率高,可以延时加载 11. synchronized volatile关键字有什么区别?以及还有哪些同样功能的关键字 (1) volatile是变量修饰符,而synchronized则作用于一段代码或者方法。(2) volatile只是在线程内存和main memory(主内存)间同步某个变量的值;而synchronized通过锁定和解锁某个监视器同步所有变量的值。显然synchronized要比volatile消耗更多资源。const、final、lock 12. 界面卡顿的原因有哪些? UI线程(main)有耗时操作视图渲染时间过长,导致卡顿 13. 造成OOM/ANR 的原因? OOM: (1)不恰当地使用static关键字 (2)内部类对Activity的引用 (3)大量Bitmap的使用会导致程序包运行时的内存消耗变大 (4)游标Cursor对象用完应该及时关闭 (5)加载对象过大 (6)相应资源过多,来不及释放。ANR: (1)在5秒内没有响应输入的事件(IO操作耗时、数据库操作复杂耗时、主线程非主线程产生死锁等待、网络加载/图片操作耗时、硬件操作耗时) (2)BroadcastReceiver在10秒内没有执行完毕(Service binder数量达到上限、Service忙导致超时无响应) 14. Activity与Fragment生命周期有何联系 在创建的过程中,是Activity带领着Fragment,在销毁的过程中,是Fragment带领着Activity。这里写图片描述 15. Glide三级缓存 内存缓存,磁盘缓存、网络缓存(由于网络缓存严格来说不算是缓存的一种,故也称为二级缓存)。缓存的资源分为两种:原图(SOURCE)、处理图(RESULT)(默认)。内存缓存:默认开启的,可以通过调用skipMemoryCache(true)来设置跳过内存缓存,缓存最大空间:每个进程可用的最大内存*0.4。(低配手机0.33)磁盘缓存:分为四种:ALL(缓存原图)、NONE(什么都不缓存)、SOURCE(只缓存原图)、RESULT(之后处理图),通过diskCacheStrategy(DiskCacheStrategy.ALL)来设置,缓存大小250M。 16. MVC、MVP、MVVM的原理 (1) MVC,Model View Controller,是软件架构中最常见的一种框架,简单来说就是通过controller的控制去操作model层的数据,并且返回给view层展示。当用户发出事件的时候,view层会发送指令到controller层,接着controller去通知model层更新数据,model层更新完数据以后直接显示在view层上,这就是MVC的工作原理。这里写图片描述(2) MVP是MVC的演化。MVP的model层相对于MVC是一样的,而activity和fragment不再是controller层,而是纯粹的view层,所有关于用户事件的转发全部交由presenter层处理。presenter层充当了桥梁的作用,用于操作view层发出的事件传递到presenter层中,presenter层去操作model层,并且将数据返回给view层。这里写图片描述(3) MVVM和MVP的区别貌似不大,只不过是presenter层换成了viewmodel层,还有一点就是view层和viewmodel层是相互绑定的关系,这意味着当你更新viewmodel层的数据的时候,view层会相应的变动ui。这里写图片描述 17. 数据库的操作类型有哪些,如何导入外部数据库? (1) 增删改查(2) 将外部数据库放在项目的res/raw目录下。因为安卓系统下数据库要放在data/data/packagename/databases的目录下,然后要做的就是将外部数据库导入到该目录下,操作方法是通过FileInputStream读取外部数据库,再用FileOutputStrean把读取到的东西写入到该目录下。 18. 是否使用过 IntentService,作用是什么, AIDL 解决了什么问题? (1) IntentService继承自Service。由于Service运行在主线程,无法进行耗时操作。所以你需要在Service中开启一个子线程,并且在子线程中运行。为了简化这一操作,Android中提供了IntentService来进行这一处理。通过查看IntentService的源码可以看到,在onCreate中,我们开启了一个HandlerThread线程,之后获取HandlerThread线程中的Looper,并通过这个Looper创建了一个Handler。然后在onStart方法中通过这个Handler将intent与startId作为Message的参数进行发送到消息队列中,然后交由Handler中的handleMessage中进行处理。由于在onStart方法是在主线程内运行的,而Handler是通过工作者线程HandlerThread中的Looper创建的。所以也就是在主线程中发送消息,在工作者接收到消息后便可以进行一些耗时的操作。(2) 进程间通信 19. 是否使用过本地广播,和全局广播有什么差别? 本地广播的数据在本应用范围内传播,不用担心隐私数据泄露的问题。不用担心别的应用伪造广播,造成安全隐患。相比在系统内发送全局广播,它更高效。 20. Activity、 Window、 View 三者的差别, fragment 的特点? (1) Activity像一个工匠(控制单元),Window像窗户(承载模型),View像窗花(显示视图) LayoutInflater像剪刀,Xml配置像窗花图纸。(2) a. Fragment可以作为Activity界面的一部分组成出现; 可以在一个Activity中同时出现多个Fragment,并且一个Fragment也可以在多个Activity中使用; 在Activity运行过程中,可以添加、移除或者替换Fragment; Fragment可以响应自己的输入事件,并且有自己的生命周期,它们的生命周期会受宿主Activity的生命周期影响。 21. Handler、 Thread 和 HandlerThread 的差别 从Android中Thread(java.lang.Thread -> java.lang.Object)描述可以看出,Android的Thread没有对Java的Thread做任何封装,但是Android提供了一个继承自Thread的类HandlerThread(android.os.HandlerThread -> java.lang.Thread),这个类对Java的Thread做了很多便利Android系统的封装。android.os.Handler可以通过Looper对象实例化,并运行于另外的线程中,Android提供了让Handler运行于其它线程的线程实现,也是就HandlerThread。HandlerThread对象start后可以获得其Looper对象,并且使用这个Looper对象实例Handler。 22. 低版本 SDK 实现高版本 api 自己实现或使用注解@TargetApi annotation 23. launch mode 应用场景 (1) standard:标准的启动模式。 这里写图片描述(2) singleTop:单一顶部模式 如果Activity已经被开启,并且处于任务栈的栈顶,就不会创建新的Activity,而是复用这个已经开启的Activity。为了防止出现一些奇怪的用户体验,推荐使用单一顶部模式,整个任务栈可以有多个实例存在.应用场景:短信发送界面.这里写图片描述(3)singletask:单一任务栈 在整个任务栈里面只允许有一个当前Activity的实例存在如果要开启的Activity在任务栈中已经存在,直接复用这个已经存在的Activity,并且把这个Activity上面的所有的其他Activity给清空应用场景:如果一个Activity非常消耗内存和cpu资源,建议把这个Activity做成singletask的模式。浏览器的browserActivity这里写图片描述(4)singleinstance:单一实例. 整个手机操作系统只有一个实例存在,并且是运行在自己单独的任务栈里面.应用场景:通话界面的Activity这里写图片描述 24. touch 事件传递流程 事件处理包括三种情况,分别为:传递—-dispatchTouchEvent()函数、拦截——onInterceptTouchEvent()函数、消费—-onTouchEvent()函数和OnTouchListener。Android事件传递流程:(1) 事件都是从Activity.dispatchTouchEvent()开始传递(2) 事件由父View传递给子View,ViewGroup可以通过onInterceptTouchEvent()方法对事件拦截,停止其向子view传递(3) 如果事件从上往下传递过程中一直没有被停止,且最底层子View没有消费事件,事件会反向往上传递,这时父View(ViewGroup)可以进行消费,如果还是没有被消费的话,最后会到Activity的onTouchEvent()函数。(4) 如果View没有对ACTION_DOWN进行消费,之后的其他事件不会传递过来,也就是说ACTION_DOWN必须返回true,之后的事件才会传递进来(5) OnTouchListener优先于onTouchEvent()对事件进行消费 View不处理事件流程图View不处理事件流程图 View处理事件流程图View处理事件流程图 事件拦截事件拦截 25.Android性能优化 一、代码优化 1.使用AndroidLint分析结果进行相应优化2.不使用枚举及IOC框架,反射性能低3.常量加static4.静态方法5.减少不必要的对象、成员变量6.尽量使用线程池7.适当使用软引用和弱引用8.尽量使用静态内部类,避免潜在的内存泄露9.图片缓存,采用内存缓存LRUCache和硬盘缓存DiskLRUCache10.Bitmap优化,采用适当分辨率大小并及时回收 二、布局优化 避免OverDraw过渡绘制优化布局层级避免嵌套过多无用布局当我们在画布局的时候,如果能实现相同的功能,优先考虑相对布局,然后在考虑别的布局,不要用绝对布局。使用标签把复杂的界面需要抽取出来使用标签,因为它在优化UI结构时起到很重要的作用。目的是通过删减多余或者额外的层级,从而优化整个Android Layout的结构。核心功能就是减少冗余的层次从而达到优化UI的目的!ViewStub 是一个隐藏的,不占用内存空间的视图对象,它可以在运行时延迟加载布局资源文件。 三、ListView和GridView优化 1.采用ViewHolder复用convertView2.避免在getView中执行耗时操作3.列表在滑动状态时不加载图片4.开启硬件加速 26.Android内存泄漏 内存泄漏简单地说就是申请了一块内存空间,使用完毕后没有释放掉。它的一般表现方式是程序运行时间越长,占用内存越多,最终用尽全部内存,整个系统崩溃。由程序申请的一块内存,且没有任何一个指针指向它,那么这块内存就泄露了。可能的原因有:1.注册没取消造成内存泄露,如:广播2.静态变量持有Activity的引用3.单例模式持有Activity的引用4.查询数据库后没有关闭游标cursor5.构造Adapter时,没有使用 convertView 重用6.Bitmap对象不在使用时调用recycle()释放内存7.对象被生命周期长的对象引用,如activity被静态集合引用导致activity不能释放8.使用Handler造成的内存泄露 原文地址:http://cloud.yundashi168.com/archives/964

优秀的个人博客,低调大师

整理一些计算机基础知识!

本文来自云栖社区官方钉群“Python技术进阶”,了解相关信息可以关注“Python技术进阶”。 1、网络层次划分 为了使不同计算机厂家生产的计算机能够相互通信,以便在更大的范围内建立计算机网络,国际标准化组织(ISO)在1978年提出了“开放系统互联参考模型”,即著名的OSI/RM模型(Open System Interconnection/Reference Model)。它将计算机网络体系结构的通信协议划分为七层,自下而上依次为:物理层(Physics Layer)、数据链路层(Data Link Layer)、网络层(Network Layer)、传输层(Transport Layer)、会话层(Session Layer)、表示层(Presentation Layer)、应用层(Application Layer)。其中第四

优秀的个人博客,低调大师

整理收集的一些常用java工具类

1.json转换工具 [java] view plain copy packagecom.taotao.utils; importjava.util.List; importcom.fasterxml.jackson.core.JsonProcessingException; importcom.fasterxml.jackson.databind.JavaType; importcom.fasterxml.jackson.databind.JsonNode; importcom.fasterxml.jackson.databind.ObjectMapper; /** *json转换工具类 */ publicclassJsonUtils{ //定义jackson对象 privatestaticfinalObjectMapperMAPPER=newObjectMapper(); /** *将对象转换成json字符串。 *<p>Title:pojoToJson</p> *<p>Description:</p> *@paramdata *@return */ publicstaticStringobjectToJson(Objectdata){ try{ Stringstring=MAPPER.writeValueAsString(data); returnstring; }catch(JsonProcessingExceptione){ e.printStackTrace(); } returnnull; } /** *将json结果集转化为对象 * *@paramjsonDatajson数据 *@paramclazz对象中的object类型 *@return */ publicstatic<T>TjsonToPojo(StringjsonData,Class<T>beanType){ try{ Tt=MAPPER.readValue(jsonData,beanType); returnt; }catch(Exceptione){ e.printStackTrace(); } returnnull; } /** *将json数据转换成pojo对象list *<p>Title:jsonToList</p> *<p>Description:</p> *@paramjsonData *@parambeanType *@return */ publicstatic<T>List<T>jsonToList(StringjsonData,Class<T>beanType){ JavaTypejavaType=MAPPER.getTypeFactory().constructParametricType(List.class,beanType); try{ List<T>list=MAPPER.readValue(jsonData,javaType); returnlist; }catch(Exceptione){ e.printStackTrace(); } returnnull; } } 2.cookie的读写 [java] view plain copy packagecom.taotao.common.utils; importjava.io.UnsupportedEncodingException; importjava.net.URLDecoder; importjava.net.URLEncoder; importjavax.servlet.http.Cookie; importjavax.servlet.http.HttpServletRequest; importjavax.servlet.http.HttpServletResponse; /** * *Cookie工具类 * */ publicfinalclassCookieUtils{ /** *得到Cookie的值,不编码 * *@paramrequest *@paramcookieName *@return */ publicstaticStringgetCookieValue(HttpServletRequestrequest,StringcookieName){ returngetCookieValue(request,cookieName,false); } /** *得到Cookie的值, * *@paramrequest *@paramcookieName *@return */ publicstaticStringgetCookieValue(HttpServletRequestrequest,StringcookieName,booleanisDecoder){ Cookie[]cookieList=request.getCookies(); if(cookieList==null||cookieName==null){ returnnull; } StringretValue=null; try{ for(inti=0;i<cookieList.length;i++){ if(cookieList[i].getName().equals(cookieName)){ if(isDecoder){ retValue=URLDecoder.decode(cookieList[i].getValue(),"UTF-8"); }else{ retValue=cookieList[i].getValue(); } break; } } }catch(UnsupportedEncodingExceptione){ e.printStackTrace(); } returnretValue; } /** *得到Cookie的值, * *@paramrequest *@paramcookieName *@return */ publicstaticStringgetCookieValue(HttpServletRequestrequest,StringcookieName,StringencodeString){ Cookie[]cookieList=request.getCookies(); if(cookieList==null||cookieName==null){ returnnull; } StringretValue=null; try{ for(inti=0;i<cookieList.length;i++){ if(cookieList[i].getName().equals(cookieName)){ retValue=URLDecoder.decode(cookieList[i].getValue(),encodeString); break; } } }catch(UnsupportedEncodingExceptione){ e.printStackTrace(); } returnretValue; } /** *设置Cookie的值不设置生效时间默认浏览器关闭即失效,也不编码 */ publicstaticvoidsetCookie(HttpServletRequestrequest,HttpServletResponseresponse,StringcookieName, StringcookieValue){ setCookie(request,response,cookieName,cookieValue,-1); } /** *设置Cookie的值在指定时间内生效,但不编码 */ publicstaticvoidsetCookie(HttpServletRequestrequest,HttpServletResponseresponse,StringcookieName, StringcookieValue,intcookieMaxage){ setCookie(request,response,cookieName,cookieValue,cookieMaxage,false); } /** *设置Cookie的值不设置生效时间,但编码 */ publicstaticvoidsetCookie(HttpServletRequestrequest,HttpServletResponseresponse,StringcookieName, StringcookieValue,booleanisEncode){ setCookie(request,response,cookieName,cookieValue,-1,isEncode); } /** *设置Cookie的值在指定时间内生效,编码参数 */ publicstaticvoidsetCookie(HttpServletRequestrequest,HttpServletResponseresponse,StringcookieName, StringcookieValue,intcookieMaxage,booleanisEncode){ doSetCookie(request,response,cookieName,cookieValue,cookieMaxage,isEncode); } /** *设置Cookie的值在指定时间内生效,编码参数(指定编码) */ publicstaticvoidsetCookie(HttpServletRequestrequest,HttpServletResponseresponse,StringcookieName, StringcookieValue,intcookieMaxage,StringencodeString){ doSetCookie(request,response,cookieName,cookieValue,cookieMaxage,encodeString); } /** *删除Cookie带cookie域名 */ publicstaticvoiddeleteCookie(HttpServletRequestrequest,HttpServletResponseresponse, StringcookieName){ doSetCookie(request,response,cookieName,"",-1,false); } /** *设置Cookie的值,并使其在指定时间内生效 * *@paramcookieMaxagecookie生效的最大秒数 */ privatestaticfinalvoiddoSetCookie(HttpServletRequestrequest,HttpServletResponseresponse, StringcookieName,StringcookieValue,intcookieMaxage,booleanisEncode){ try{ if(cookieValue==null){ cookieValue=""; }elseif(isEncode){ cookieValue=URLEncoder.encode(cookieValue,"utf-8"); } Cookiecookie=newCookie(cookieName,cookieValue); if(cookieMaxage>0) cookie.setMaxAge(cookieMaxage); if(null!=request){//设置域名的cookie StringdomainName=getDomainName(request); System.out.println(domainName); if(!"localhost".equals(domainName)){ cookie.setDomain(domainName); } } cookie.setPath("/"); response.addCookie(cookie); }catch(Exceptione){ e.printStackTrace(); } } /** *设置Cookie的值,并使其在指定时间内生效 * *@paramcookieMaxagecookie生效的最大秒数 */ privatestaticfinalvoiddoSetCookie(HttpServletRequestrequest,HttpServletResponseresponse, StringcookieName,StringcookieValue,intcookieMaxage,StringencodeString){ try{ if(cookieValue==null){ cookieValue=""; }else{ cookieValue=URLEncoder.encode(cookieValue,encodeString); } Cookiecookie=newCookie(cookieName,cookieValue); if(cookieMaxage>0) cookie.setMaxAge(cookieMaxage); if(null!=request){//设置域名的cookie StringdomainName=getDomainName(request); System.out.println(domainName); if(!"localhost".equals(domainName)){ cookie.setDomain(domainName); } } cookie.setPath("/"); response.addCookie(cookie); }catch(Exceptione){ e.printStackTrace(); } } /** *得到cookie的域名 */ privatestaticfinalStringgetDomainName(HttpServletRequestrequest){ StringdomainName=null; StringserverName=request.getRequestURL().toString(); if(serverName==null||serverName.equals("")){ domainName=""; }else{ serverName=serverName.toLowerCase(); serverName=serverName.substring(7); finalintend=serverName.indexOf("/"); serverName=serverName.substring(0,end); finalString[]domains=serverName.split("\\."); intlen=domains.length; if(len>3){ //www.xxx.com.cn domainName="."+domains[len-3]+"."+domains[len-2]+"."+domains[len-1]; }elseif(len<=3&&len>1){ //xxx.comorxxx.cn domainName="."+domains[len-2]+"."+domains[len-1]; }else{ domainName=serverName; } } if(domainName!=null&&domainName.indexOf(":")>0){ String[]ary=domainName.split("\\:"); domainName=ary[0]; } returndomainName; } } 3.HttpClientUtil 相关包及文档下载 [java] view plain copy packagecom.taotao.utils; importjava.io.IOException; importjava.net.URI; importjava.util.ArrayList; importjava.util.List; importjava.util.Map; importorg.apache.http.NameValuePair; importorg.apache.http.client.entity.UrlEncodedFormEntity; importorg.apache.http.client.methods.CloseableHttpResponse; importorg.apache.http.client.methods.HttpGet; importorg.apache.http.client.methods.HttpPost; importorg.apache.http.client.utils.URIBuilder; importorg.apache.http.entity.ContentType; importorg.apache.http.entity.StringEntity; importorg.apache.http.impl.client.CloseableHttpClient; importorg.apache.http.impl.client.HttpClients; importorg.apache.http.message.BasicNameValuePair; importorg.apache.http.util.EntityUtils; publicclassHttpClientUtil{ publicstaticStringdoGet(Stringurl,Map<String,String>param){ //创建Httpclient对象 CloseableHttpClienthttpclient=HttpClients.createDefault(); StringresultString=""; CloseableHttpResponseresponse=null; try{ //创建uri URIBuilderbuilder=newURIBuilder(url); if(param!=null){ for(Stringkey:param.keySet()){ builder.addParameter(key,param.get(key)); } } URIuri=builder.build(); //创建httpGET请求 HttpGethttpGet=newHttpGet(uri); //执行请求 response=httpclient.execute(httpGet); //判断返回状态是否为200 if(response.getStatusLine().getStatusCode()==200){ resultString=EntityUtils.toString(response.getEntity(),"UTF-8"); } }catch(Exceptione){ e.printStackTrace(); }finally{ try{ if(response!=null){ response.close(); } httpclient.close(); }catch(IOExceptione){ e.printStackTrace(); } } returnresultString; } publicstaticStringdoGet(Stringurl){ returndoGet(url,null); } publicstaticStringdoPost(Stringurl,Map<String,String>param){ //创建Httpclient对象 CloseableHttpClienthttpClient=HttpClients.createDefault(); CloseableHttpResponseresponse=null; StringresultString=""; try{ //创建HttpPost请求 HttpPosthttpPost=newHttpPost(url); //创建参数列表 if(param!=null){ List<NameValuePair>paramList=newArrayList<>(); for(Stringkey:param.keySet()){ paramList.add(newBasicNameValuePair(key,param.get(key))); } //模拟表单 UrlEncodedFormEntityentity=newUrlEncodedFormEntity(paramList); httpPost.setEntity(entity); } //执行http请求 response=httpClient.execute(httpPost); resultString=EntityUtils.toString(response.getEntity(),"utf-8"); }catch(Exceptione){ e.printStackTrace(); }finally{ try{ response.close(); }catch(IOExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); } } returnresultString; } publicstaticStringdoPost(Stringurl){ returndoPost(url,null); } publicstaticStringdoPostJson(Stringurl,Stringjson){ //创建Httpclient对象 CloseableHttpClienthttpClient=HttpClients.createDefault(); CloseableHttpResponseresponse=null; StringresultString=""; try{ //创建HttpPost请求 HttpPosthttpPost=newHttpPost(url); //创建请求内容 StringEntityentity=newStringEntity(json,ContentType.APPLICATION_JSON); httpPost.setEntity(entity); //执行http请求 response=httpClient.execute(httpPost); resultString=EntityUtils.toString(response.getEntity(),"utf-8"); }catch(Exceptione){ e.printStackTrace(); }finally{ try{ response.close(); }catch(IOExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); } } returnresultString; } } 4.FastDFSClient工具类 相关包以及文档下载 [java] view plain copy packagecn.itcast.fastdfs.cliennt; importorg.csource.common.NameValuePair; importorg.csource.fastdfs.ClientGlobal; importorg.csource.fastdfs.StorageClient1; importorg.csource.fastdfs.StorageServer; importorg.csource.fastdfs.TrackerClient; importorg.csource.fastdfs.TrackerServer; publicclassFastDFSClient{ privateTrackerClienttrackerClient=null; privateTrackerServertrackerServer=null; privateStorageServerstorageServer=null; privateStorageClient1storageClient=null; publicFastDFSClient(Stringconf)throwsException{ if(conf.contains("classpath:")){ conf=conf.replace("classpath:",this.getClass().getResource("/").getPath()); } ClientGlobal.init(conf); trackerClient=newTrackerClient(); trackerServer=trackerClient.getConnection(); storageServer=null; storageClient=newStorageClient1(trackerServer,storageServer); } /** *上传文件方法 *<p>Title:uploadFile</p> *<p>Description:</p> *@paramfileName文件全路径 *@paramextName文件扩展名,不包含(.) *@parammetas文件扩展信息 *@return *@throwsException */ publicStringuploadFile(StringfileName,StringextName,NameValuePair[]metas)throwsException{ Stringresult=storageClient.upload_file1(fileName,extName,metas); returnresult; } publicStringuploadFile(StringfileName)throwsException{ returnuploadFile(fileName,null,null); } publicStringuploadFile(StringfileName,StringextName)throwsException{ returnuploadFile(fileName,extName,null); } /** *上传文件方法 *<p>Title:uploadFile</p> *<p>Description:</p> *@paramfileContent文件的内容,字节数组 *@paramextName文件扩展名 *@parammetas文件扩展信息 *@return *@throwsException */ publicStringuploadFile(byte[]fileContent,StringextName,NameValuePair[]metas)throwsException{ Stringresult=storageClient.upload_file1(fileContent,extName,metas); returnresult; } publicStringuploadFile(byte[]fileContent)throwsException{ returnuploadFile(fileContent,null,null); } publicStringuploadFile(byte[]fileContent,StringextName)throwsException{ returnuploadFile(fileContent,extName,null); } } [java] view plain copy <spanstyle="font-size:14px;font-weight:normal;">publicclassFastDFSTest{ @Test publicvoidtestFileUpload()throwsException{ //1、加载配置文件,配置文件中的内容就是tracker服务的地址。 ClientGlobal.init("D:/workspaces-itcast/term197/taotao-manager-web/src/main/resources/resource/client.conf"); //2、创建一个TrackerClient对象。直接new一个。 TrackerClienttrackerClient=newTrackerClient(); //3、使用TrackerClient对象创建连接,获得一个TrackerServer对象。 TrackerServertrackerServer=trackerClient.getConnection(); //4、创建一个StorageServer的引用,值为null StorageServerstorageServer=null; //5、创建一个StorageClient对象,需要两个参数TrackerServer对象、StorageServer的引用 StorageClientstorageClient=newStorageClient(trackerServer,storageServer); //6、使用StorageClient对象上传图片。 //扩展名不带“.” String[]strings=storageClient.upload_file("D:/Documents/Pictures/images/200811281555127886.jpg","jpg",null); //7、返回数组。包含组名和图片的路径。 for(Stringstring:strings){ System.out.println(string); } } }</span> 5.获取异常的堆栈信息 [java] view plain copy packagecom.taotao.utils; importjava.io.PrintWriter; importjava.io.StringWriter; publicclassExceptionUtil{ /** *获取异常的堆栈信息 * *@paramt *@return */ publicstaticStringgetStackTrace(Throwablet){ StringWritersw=newStringWriter(); PrintWriterpw=newPrintWriter(sw); try{ t.printStackTrace(pw); returnsw.toString(); }finally{ pw.close(); } } } 6.easyUIDataGrid对象返回值 [java] view plain copy packagecom.taotao.result; importjava.util.List; /** *easyUIDataGrid对象返回值 *<p>Title:EasyUIResult</p> *<p>Description:</p> *<p>Company:www.itcast.com</p> *@author入云龙 *@date2015年7月21日下午4:12:52 *@version1.0 */ publicclassEasyUIResult{ privateIntegertotal; privateList<?>rows; publicEasyUIResult(Integertotal,List<?>rows){ this.total=total; this.rows=rows; } publicEasyUIResult(longtotal,List<?>rows){ this.total=(int)total; this.rows=rows; } publicIntegergetTotal(){ returntotal; } publicvoidsetTotal(Integertotal){ this.total=total; } publicList<?>getRows(){ returnrows; } publicvoidsetRows(List<?>rows){ this.rows=rows; } } 7.ftp上传下载工具类 [java] view plain copy packagecom.taotao.utils; importjava.io.File; importjava.io.FileInputStream; importjava.io.FileNotFoundException; importjava.io.FileOutputStream; importjava.io.IOException; importjava.io.InputStream; importjava.io.OutputStream; importorg.apache.commons.net.ftp.FTP; importorg.apache.commons.net.ftp.FTPClient; importorg.apache.commons.net.ftp.FTPFile; importorg.apache.commons.net.ftp.FTPReply; /** *ftp上传下载工具类 *<p>Title:FtpUtil</p> *<p>Description:</p> *<p>Company:www.itcast.com</p> *@author入云龙 *@date2015年7月29日下午8:11:51 *@version1.0 */ publicclassFtpUtil{ /** *Description:向FTP服务器上传文件 *@paramhostFTP服务器hostname *@paramportFTP服务器端口 *@paramusernameFTP登录账号 *@parampasswordFTP登录密码 *@parambasePathFTP服务器基础目录 *@paramfilePathFTP服务器文件存放路径。例如分日期存放:/2015/01/01。文件的路径为basePath+filePath *@paramfilename上传到FTP服务器上的文件名 *@paraminput输入流 *@return成功返回true,否则返回false */ publicstaticbooleanuploadFile(Stringhost,intport,Stringusername,Stringpassword,StringbasePath, StringfilePath,Stringfilename,InputStreaminput){ booleanresult=false; FTPClientftp=newFTPClient(); try{ intreply; ftp.connect(host,port);//连接FTP服务器 //如果采用默认端口,可以使用ftp.connect(host)的方式直接连接FTP服务器 ftp.login(username,password);//登录 reply=ftp.getReplyCode(); if(!FTPReply.isPositiveCompletion(reply)){ ftp.disconnect(); returnresult; } //切换到上传目录 if(!ftp.changeWorkingDirectory(basePath+filePath)){ //如果目录不存在创建目录 String[]dirs=filePath.split("/"); StringtempPath=basePath; for(Stringdir:dirs){ if(null==dir||"".equals(dir))continue; tempPath+="/"+dir; if(!ftp.changeWorkingDirectory(tempPath)){ if(!ftp.makeDirectory(tempPath)){ returnresult; }else{ ftp.changeWorkingDirectory(tempPath); } } } } //设置上传文件的类型为二进制类型 ftp.setFileType(FTP.BINARY_FILE_TYPE); //上传文件 if(!ftp.storeFile(filename,input)){ returnresult; } input.close(); ftp.logout(); result=true; }catch(IOExceptione){ e.printStackTrace(); }finally{ if(ftp.isConnected()){ try{ ftp.disconnect(); }catch(IOExceptionioe){ } } } returnresult; } /** *Description:从FTP服务器下载文件 *@paramhostFTP服务器hostname *@paramportFTP服务器端口 *@paramusernameFTP登录账号 *@parampasswordFTP登录密码 *@paramremotePathFTP服务器上的相对路径 *@paramfileName要下载的文件名 *@paramlocalPath下载后保存到本地的路径 *@return */ publicstaticbooleandownloadFile(Stringhost,intport,Stringusername,Stringpassword,StringremotePath, StringfileName,StringlocalPath){ booleanresult=false; FTPClientftp=newFTPClient(); try{ intreply; ftp.connect(host,port); //如果采用默认端口,可以使用ftp.connect(host)的方式直接连接FTP服务器 ftp.login(username,password);//登录 reply=ftp.getReplyCode(); if(!FTPReply.isPositiveCompletion(reply)){ ftp.disconnect(); returnresult; } ftp.changeWorkingDirectory(remotePath);//转移到FTP服务器目录 FTPFile[]fs=ftp.listFiles(); for(FTPFileff:fs){ if(ff.getName().equals(fileName)){ FilelocalFile=newFile(localPath+"/"+ff.getName()); OutputStreamis=newFileOutputStream(localFile); ftp.retrieveFile(ff.getName(),is); is.close(); } } ftp.logout(); result=true; }catch(IOExceptione){ e.printStackTrace(); }finally{ if(ftp.isConnected()){ try{ ftp.disconnect(); }catch(IOExceptionioe){ } } } returnresult; } publicstaticvoidmain(String[]args){ try{ FileInputStreamin=newFileInputStream(newFile("D:\\temp\\image\\gaigeming.jpg")); booleanflag=uploadFile("192.168.25.133",21,"ftpuser","ftpuser","/home/ftpuser/www/images","/2015/01/21","gaigeming.jpg",in); System.out.println(flag); }catch(FileNotFoundExceptione){ e.printStackTrace(); } } } 8.各种id生成策略 [java] view plain copy packagecom.taotao.utils; importjava.util.Random; /** *各种id生成策略 *<p>Title:IDUtils</p> *<p>Description:</p> *@date2015年7月22日下午2:32:10 *@version1.0 */ publicclassIDUtils{ /** *图片名生成 */ publicstaticStringgenImageName(){ //取当前时间的长整形值包含毫秒 longmillis=System.currentTimeMillis(); //longmillis=System.nanoTime(); //加上三位随机数 Randomrandom=newRandom(); intend3=random.nextInt(999); //如果不足三位前面补0 Stringstr=millis+String.format("%03d",end3); returnstr; } /** *商品id生成 */ publicstaticlonggenItemId(){ //取当前时间的长整形值包含毫秒 longmillis=System.currentTimeMillis(); //longmillis=System.nanoTime(); //加上两位随机数 Randomrandom=newRandom(); intend2=random.nextInt(99); //如果不足两位前面补0 Stringstr=millis+String.format("%02d",end2); longid=newLong(str); returnid; } publicstaticvoidmain(String[]args){ for(inti=0;i<100;i++) System.out.println(genItemId()); } } 9.上传图片返回值 [java] view plain copy packagecom.result; /** *上传图片返回值 *<p>Title:PictureResult</p> *<p>Description:</p> *<p>Company:www.itcast.com</p> *@author入云龙 *@date2015年7月22日下午2:09:02 *@version1.0 */ publicclassPictureResult{ /** *上传图片返回值,成功:0失败:1 */ privateIntegererror; /** *回显图片使用的url */ privateStringurl; /** *错误时的错误消息 */ privateStringmessage; publicPictureResult(Integerstate,Stringurl){ this.url=url; this.error=state; } publicPictureResult(Integerstate,Stringurl,StringerrorMessage){ this.url=url; this.error=state; this.message=errorMessage; } publicIntegergetError(){ returnerror; } publicvoidsetError(Integererror){ this.error=error; } publicStringgetUrl(){ returnurl; } publicvoidsetUrl(Stringurl){ this.url=url; } publicStringgetMessage(){ returnmessage; } publicvoidsetMessage(Stringmessage){ this.message=message; } } 10.自定义响应结构 [java] view plain copy packagecom.result; importjava.util.List; importcom.fasterxml.jackson.databind.JsonNode; importcom.fasterxml.jackson.databind.ObjectMapper; /** *自定义响应结构 */ publicclassTaotaoResult{ //定义jackson对象 privatestaticfinalObjectMapperMAPPER=newObjectMapper(); //响应业务状态 privateIntegerstatus; //响应消息 privateStringmsg; //响应中的数据 privateObjectdata; publicstaticTaotaoResultbuild(Integerstatus,Stringmsg,Objectdata){ returnnewTaotaoResult(status,msg,data); } publicstaticTaotaoResultok(Objectdata){ returnnewTaotaoResult(data); } publicstaticTaotaoResultok(){ returnnewTaotaoResult(null); } publicTaotaoResult(){ } publicstaticTaotaoResultbuild(Integerstatus,Stringmsg){ returnnewTaotaoResult(status,msg,null); } publicTaotaoResult(Integerstatus,Stringmsg,Objectdata){ this.status=status; this.msg=msg; this.data=data; } publicTaotaoResult(Objectdata){ this.status=200; this.msg="OK"; this.data=data; } //publicBooleanisOK(){ //returnthis.status==200; //} publicIntegergetStatus(){ returnstatus; } publicvoidsetStatus(Integerstatus){ this.status=status; } publicStringgetMsg(){ returnmsg; } publicvoidsetMsg(Stringmsg){ this.msg=msg; } publicObjectgetData(){ returndata; } publicvoidsetData(Objectdata){ this.data=data; } /** *将json结果集转化为TaotaoResult对象 * *@paramjsonDatajson数据 *@paramclazzTaotaoResult中的object类型 *@return */ publicstaticTaotaoResultformatToPojo(StringjsonData,Class<?>clazz){ try{ if(clazz==null){ returnMAPPER.readValue(jsonData,TaotaoResult.class); } JsonNodejsonNode=MAPPER.readTree(jsonData); JsonNodedata=jsonNode.get("data"); Objectobj=null; if(clazz!=null){ if(data.isObject()){ obj=MAPPER.readValue(data.traverse(),clazz); }elseif(data.isTextual()){ obj=MAPPER.readValue(data.asText(),clazz); } } returnbuild(jsonNode.get("status").intValue(),jsonNode.get("msg").asText(),obj); }catch(Exceptione){ returnnull; } } /** *没有object对象的转化 * *@paramjson *@return */ publicstaticTaotaoResultformat(Stringjson){ try{ returnMAPPER.readValue(json,TaotaoResult.class); }catch(Exceptione){ e.printStackTrace(); } returnnull; } /** *Object是集合转化 * *@paramjsonDatajson数据 *@paramclazz集合中的类型 *@return */ publicstaticTaotaoResultformatToList(StringjsonData,Class<?>clazz){ try{ JsonNodejsonNode=MAPPER.readTree(jsonData); JsonNodedata=jsonNode.get("data"); Objectobj=null; if(data.isArray()&&data.size()>0){ obj=MAPPER.readValue(data.traverse(), MAPPER.getTypeFactory().constructCollectionType(List.class,clazz)); } returnbuild(jsonNode.get("status").intValue(),jsonNode.get("msg").asText(),obj); }catch(Exceptione){ returnnull; } } } 11.jedis操作 [java] view plain copy packagecom.taotao.jedis; publicinterfaceJedisClient{ Stringset(Stringkey,Stringvalue); Stringget(Stringkey); Booleanexists(Stringkey); Longexpire(Stringkey,intseconds); Longttl(Stringkey); Longincr(Stringkey); Longhset(Stringkey,Stringfield,Stringvalue); Stringhget(Stringkey,Stringfield); Longhdel(Stringkey,String...field); } [java] view plain copy packagecom.taotao.jedis; importorg.springframework.beans.factory.annotation.Autowired; importredis.clients.jedis.JedisCluster; publicclassJedisClientClusterimplementsJedisClient{ @Autowired privateJedisClusterjedisCluster; @Override publicStringset(Stringkey,Stringvalue){ returnjedisCluster.set(key,value); } @Override publicStringget(Stringkey){ returnjedisCluster.get(key); } @Override publicBooleanexists(Stringkey){ returnjedisCluster.exists(key); } @Override publicLongexpire(Stringkey,intseconds){ returnjedisCluster.expire(key,seconds); } @Override publicLongttl(Stringkey){ returnjedisCluster.ttl(key); } @Override publicLongincr(Stringkey){ returnjedisCluster.incr(key); } @Override publicLonghset(Stringkey,Stringfield,Stringvalue){ returnjedisCluster.hset(key,field,value); } @Override publicStringhget(Stringkey,Stringfield){ returnjedisCluster.hget(key,field); } @Override publicLonghdel(Stringkey,String...field){ returnjedisCluster.hdel(key,field); } } [java] view plain copy packagecom.taotao.jedis; importorg.springframework.beans.factory.annotation.Autowired; importredis.clients.jedis.Jedis; importredis.clients.jedis.JedisPool; publicclassJedisClientPoolimplementsJedisClient{ @Autowired privateJedisPooljedisPool; @Override publicStringset(Stringkey,Stringvalue){ Jedisjedis=jedisPool.getResource(); Stringresult=jedis.set(key,value); jedis.close(); returnresult; } @Override publicStringget(Stringkey){ Jedisjedis=jedisPool.getResource(); Stringresult=jedis.get(key); jedis.close(); returnresult; } @Override publicBooleanexists(Stringkey){ Jedisjedis=jedisPool.getResource(); Booleanresult=jedis.exists(key); jedis.close(); returnresult; } @Override publicLongexpire(Stringkey,intseconds){ Jedisjedis=jedisPool.getResource(); Longresult=jedis.expire(key,seconds); jedis.close(); returnresult; } @Override publicLongttl(Stringkey){ Jedisjedis=jedisPool.getResource(); Longresult=jedis.ttl(key); jedis.close(); returnresult; } @Override publicLongincr(Stringkey){ Jedisjedis=jedisPool.getResource(); Longresult=jedis.incr(key); jedis.close(); returnresult; } @Override publicLonghset(Stringkey,Stringfield,Stringvalue){ Jedisjedis=jedisPool.getResource(); Longresult=jedis.hset(key,field,value); jedis.close(); returnresult; } @Override publicStringhget(Stringkey,Stringfield){ Jedisjedis=jedisPool.getResource(); Stringresult=jedis.hget(key,field); jedis.close(); returnresult; } @Override publicLonghdel(Stringkey,String...field){ Jedisjedis=jedisPool.getResource(); Longresult=jedis.hdel(key,field); jedis.close(); returnresult; } } 相关话题:JAVA初级、中级、高级,你是什么级别,你觉得不同级别应该要对哪些技能呢? 与阿里巴巴JAVA大神一起进行JAVA互动交流吧!

优秀的个人博客,低调大师

Linux探索之路1---CentOS入坑笔记整理

前言 上次跟运维去行方安装行内环境,发现linux命令还是不是很熟练。特别是用户权限分配以及vi下的快捷操作。于是决定在本地安装一个CentOS虚拟机,后面有时间就每天学习一点Linux常用命令。 作为一个小白正式入坑CentOS了,于是就有了CentOS摸索系列。后续我会根据自己的摸索情况不间断更新。 安装 安装VMWare WorkStation:直接百度搜索下载安装即可,我这里安装的版本是VMware® Workstation 14 Pro。正版需要序列号,否则只能试用30天。这里我给出一些该版本的序列号: CG54H-D8D0H-H8DHY-C6X7X-N2KG6 ZC3WK-AFXEK-488JP-A7MQX-XL8YF AC5XK-0ZD4H-088HP-9NQZV-ZG2R4 ZC5XK-A6E0M-080XQ-04ZZG-YF08D ZY5H0-D3Y8K-M89EZ-AYPEG-MYUA8 安装CentOS: 直接进入CentOS官网https://www.centos.org/, 点击上方的Get CentOS.并且选择DVD版,我这里下载的版本是: CentOS-7-x86_64-DVD-1708.iso 创建新的虚拟机: 打开VMWare WorkStation, 点击“创建新的虚拟机”---》典型---》选择"安装程序光盘映像文件",选择刚刚下载的iso镜像文件,后续安装过程这里直接跳过 修改root密码 ​ 前面迷迷糊糊的安装完成之后,我需要下载一个东西,于是我使用yum install命令,发现需要root权限,于是我使用su root命令进行用户切换,需要输入root密码,我输入我创建的用户密码一致显示认证失败,完了。看来必须要改一次密码了...... ​ 好在修改密码并不复杂,这里给出一个正确可行的链接:https://linux.cn/article-3962-1.html。 总结了下,基本步骤也就包含以下几个: 启动的时候按e进入grab模式 找到fi后面那一行,将ro替换为rw init=/sysroot/bin/sh 按下Control + X 键,使用单用户模式启动 执行chroot命令,然后执行passwd开始进行密码修改 执行touch /.autorelabel更新系统信息,并执行exit退出chroot模式 执行reboot重启即可 网络连接不上 ​ 修改了root密码之后,切换到root模式下,我想使用yum install 命令下载,发现报了个网络连接不上的错误。于是我试了下: ping www.baidu.com, 竟然报了个name or service not know。无赖继续搜索解决方案,最终发现https://www.cnblogs.com/Lin-Yi/p/7787392.html所说的方案能够正常解决我的问题,这里将关键点列举一下: 添加DNS服务器: root用户执行vi /ect/resolv.conf, 在文件中添加如下两行: nameserver 8.8.8.8 nameserver 8.8.4.4 保存退出后重启虚拟机 修改网络配置: 执行命令vi /etc/sysconfig/network-scprits/ifcfg-ens33(文件名称ifcfg-ens33后面的数字可能不同,最好先进到对应目录ls看下),将文件中的onboot=no替换成onboot=yes .保存并退出 重启网络: root下执行service network restart 重启网络 注意网络配置: 一般情况下执行完前面步骤之后应该可以正常ping通,如果还不行的话,需确认虚拟机的网络适配器配置的是NAT模式 无法鼠标选中复制 ​ 这些基本的问题解决之后,发现鼠标在centOS中无法选中复制文字,于是继续搜索解决。最终解决方案如下: 安装gpm: 执行yum install gpm* 启动gpm服务: 执行service gpm start 将gpm服务添加为后台服务: 执行systemctl enable gpm.service 这里给出CentOS服务启用停用的相关方法: systemctl start [服务文件名] systemctl restart [服务文件名] systemctl stop [服务文件名] systemctl status [服务文件名] 设置开机启动 systemctl enable [服务文件名] systemctl disable [服务文件名] 安装VMTools ​ 安装了gpm之后文字可以在CentOS内部复制粘贴了,但是无法在虚拟机和主机之间进行复制。网上搜索说要安装VMTools,好吧开始安装。 主要参考下面两个链接: https://blog.csdn.net/warnerwu/article/details/73718901 https://www.cnblogs.com/mylinux/p/5612168.html ​ 本地XShell连接虚拟机 ​ 开始准备在CentOS中安装各种软件以方便虚拟机操作,后续一搜才发现,可以直接通过XShell连接CentOS。那直接通过XShell连接CentOS操作比打开丑陋的CentOS操作不是要爽的多。于是开始摸索XShell连接CentOS。 ​ 本来想通过固定虚拟机的IP,这样每次连接CentOS就不用修改IP。但是参照了网上的固定IP教程之后,蛋疼的事情发生了: 虚拟机连接不到网络......而且本机telnet虚拟机的22端口一直不通!! ​ 只有最后还原网络设置,折腾了几个小时终于又能ping通百度了。。 ​ 这里总结下XShell连接CentOS的相关设置: 开启CentOS的SSH服务: 默认情况下CentOS是默认自带SSH的,使用命令rpm -qa|grep ssh查看 是否安装了SSH,如果安装了话输出会大致如下: openssh-7.4p1-11.el7.x86_64 openssh-server-7.4p1-11.el7.x86_64 openssh-clients-7.4p1-11.el7.x86_64 libssh2-1.4.3-10.el7_2.1.x86_64 如果未安装则执行yum install openssh*安装对应的ssh服务。安装完成后通过命令systemctl status sshd查看该服务是否开启。如果未开启,则执行命令service sshd restart . 启动之后通过命令netstat -ant | grep 22进一步确认是否开启ssh的22号端口是否开启 关闭防火墙: systemctl stop firewalld.service #停止firewall systemctl disable firewalld.service #禁止firewall开机启动 firewall-cmd --state #查看默认防火墙状态(关闭后显示notrunning,开启后显示running) 关闭iptables: 如果未安装iptables这里直接跳过,如果安装了iptables这使用下面命令来关闭iptables: systemctl stop iptables.service #重启防火墙使配置生效 systemctl disable iptables.service #设置防火墙开机启动 ​ 之后就可以愉快地使用XShell来连接CentOS了 安装rzsz软件 ​ 刚安装的CentOS是不支持rz/sz命令的,这里直接使用yum install lrzsz进行安装 安装JDK ​ 网上一般给的安装步骤如下: 查找有哪些可安装的JDK: 执行命令 yum search jdk|grep java 安装JDK: 找到想要装的JDK版本,用对应的yum命令进行安装,我这里执行的是yum install java-1.8.0-openjdk.x86_64 ​ 需要注意的是这种情况下,只是安装了JRE。此时不管怎样都是无法启用javac命令的。这里还需要正确安装jdk: 使用rpm -qa | grep jdk查找刚刚安装的jdk,我这里查询的结果如下 java-1.8.0-openjdk-1.8.0.161-0.b14.el7_4.x86_64 java-1.8.0-openjdk-headless-1.8.0.161-0.b14.el7_4.x86_64 针对刚刚查询出来的jdk依次删除: yum -y remove java java-1.8.0-openjdk-1.8.0.161-0.b14.el7_4.x86_64 yum -y remove java java-1.8.0-openjdk-headless-1.8.0.161-0.b14.el7_4.x86_64 使用yum install java-devel直接安装原生的jdk即可 配置环境变量: sudo vi /ect/profile, 在文件最后两行之前加入如下配置: export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.161-0.b14.el7_4.x86_64 export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar export PATH=$JAVA_HOME/bin:$PATH 重新启用配置文件: 执行命令 source /etc/profile 安装tomcat 安装wget支持: 执行yum install wget 下载tomcat安装包: 直接去tomcat官网找到tomcat的下载链接,然后通过wget命令去获取,我这里执行的命令如下:wget http://mirrors.shu.edu.cn/apache/tomcat/tomcat-9/v9.0.11/bin/apache-tomcat-9.0.11.tar.gz 解压刚下载的tomcat: 执行命令tar -zxvf apache-tomcat-9.0.7.tar.gz 验证: 进入tomcat的bin目录执行:sh startup.sh, 本机通过虚拟机IP:端口访问看是否成功 修改目录的所有者 ​ 在开始安装tomcat的过程中,我开始在创建tomcat目录是在root用户下操作的。后续我切换到tomcat用户发现wget没有权限写这个tomcat目录。于是通过以下命令将该目录以及其下的子目录权限全部改为tomcat用户: chown -R tomcat:tomcat tomcat 其中-R表示递归旗下的所有子目录 如何返回上一次输入的目录 ​ 直接执行cd - 即可返回上一次操作的目录。输入cd或者cd ~ 即可进入当前用户的根目录 黎明前最黑暗,成功前最绝望!

优秀的个人博客,低调大师

android例子程序(ApiDemo)的简单分类整理

总览: -App(应用) -Content(字体样式) -Graphics(图像) -Media(媒体) -OS(操作系统) -Text(文本显示样式) -Views(视图) -App(应用) --Activity ---Animation(教你以怎样的动态效果显示一个新ACTIVITY) ---Custom Dialog(教你如何定制对话框DIALOG) ---Custom Title(教你如何改变程序的标题栏信息) ---Dialog(教你如何打开一个标准的对话框DIALOG) ---Forwarding(直接跳转,并不保存当前ACTIVITY,所以当你跳转后点返回的时候不会回到当前ACTIVITY) ---Hello World(这个地球人都知道) ---Persistent State(教你如何使保存在某个ACTIVITY中的信息不因ACTIVITY的切换而消失。)(所谓的有状态和无状态?) ---QuickContactsDemo(教你如何对联系人进行快速操作) ---Receive Result(从另一个ACTIVITY中得到数据返回给当前ACTIVITY) ---Redirection(从一个ACTIVITY获得用户数据传给下一个ACTIVITY,注意和前一个的区别) ---Reorder Activities(在四个ACTIVITY间进行切换,这个不知道用来干嘛的?) ---Save & Restore State(在onSaveInstanceState()方法中保存状态信息,在onCreate()中恢复状态信息。不太明白这个) ---SetWallpaper(教你如何修改和设置墙纸) ---Translucent(教你如何设置半透明背景,此处背景为前一个ACTIVITY) ---Translucent Blur(同上,只是增加了背景模糊处理) ---Wallpaper(同Translucent,只是此处背景为墙纸) --Alarm(任务安排,闹钟的处理) --Dialog(对话框) ---确定、取消对话框 ---确定、取消、外加一段描述信息的对话框 ---下拉选择框 ---进度条对话框 ---单选下拉列表框 ---多选下拉列表框 ---带文本输入的对话框 --Intents(加载数据?不是很明白) --Laucher Shortcuts(加载快捷键,具体使用有待跟进) --Menu(教你如何给自己的程序添加菜单) --Notification(通知) ---IncomingMessage(来电信息通知) ---Notifying Service Controller(通知服务控制器设置) ---NotifyWithText(文本形式的通知) ---Status Bar(通过修改状态栏来实现通知) 本文转自java豆子博客园博客,原文链接:http://www.cnblogs.com/error404/archive/2011/10/10/2205173.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

iOS ReactiveCocoa 最全常用API整理(可做为手册查询)

本文适合有一定RAC基础的童鞋做不时的查询,所以本文不做详细解释。 一、常见类 1、RACSiganl 信号类。 RACEmptySignal :空信号,用来实现 RACSignal 的 +empty 方法; RACReturnSignal :一元信号,用来实现 RACSignal 的 +return: 方法; RACDynamicSignal :动态信号,使用一个 block - 来实现订阅行为,我们在使用 RACSignal 的 +createSignal: 方法时创建的就是该类的实例; RACErrorSignal :错误信号,用来实现 RACSignal 的 +error: 方法; RACChannelTerminal :通道终端,代表 RACChannel 的一个终端,用来实现双向绑定。 2、RACSubscriber 订阅者 3、RACDisposable 用于取消订阅或者清理资源,当信号发送完成或者发送错误的时候,就会自动触发它。 RACSerialDisposable :作为 disposable 的容器使用,可以包含一个 disposable 对象,并且允许将这个 disposable 对象通过原子操作交换出来; RACKVOTrampoline :代表一次 KVO 观察,并且可以用来停止观察; RACCompoundDisposable :它可以包含多个 disposable 对象,并且支持手动添加和移除 disposable 对象 RACScopedDisposable :当它被 dealloc 的时候调用本身的 -dispose 方法。 4、RACSubject 信号提供者,自己可以充当信号,又能发送信号。 RACGroupedSignal :分组信号,用来实现 RACSignal 的分组功能; RACBehaviorSubject :重演最后值的信号,当被订阅时,会向订阅者发送它最后接收到的值; RACReplaySubject :重演信号,保存发送过的值,当被订阅时,会向订阅者重新发送这些值。 5、RACTuple 元组类,类似NSArray,用来包装值. 6、RACSequence RAC中的集合类 7、RACCommand RAC中用于处理事件的类,可以把事件如何处理,事件中的数据如何传递,包装到这个类中,他可以很方便的监控事件的执行过程。 8、RACMulticastConnection 用于当一个信号,被多次订阅时,为了保证创建信号时,避免多次调用创建信号中的block,造成副作用,可以使用这个类处理。 9、RACScheduler RAC中的队列,用GCD封装的。 RACImmediateScheduler :立即执行调度的任务,这是唯一一个支持同步执行的调度器; RACQueueScheduler :一个抽象的队列调度器,在一个 GCD 串行列队中异步调度所有任务; RACTargetQueueScheduler :继承自 RACQueueScheduler ,在一个以一个任意的 GCD 队列为 target 的串行队列中异步调度所有任务; RACSubscriptionScheduler :一个只用来调度订阅的调度器。 二、常见用法 rac_signalForSelector : 代替代理 rac_valuesAndChangesForKeyPath: KVO rac_signalForControlEvents:监听事件 rac_addObserverForName 代替通知 rac_textSignal:监听文本框文字改变 rac_liftSelector:withSignalsFromArray:Signals:当传入的Signals(信号数组),每一个signal都至少sendNext过一次,就会去触发第一个selector参数的方法。 三、常见宏 RAC(TARGET, [KEYPATH, [NIL_VALUE]]):用于给某个对象的某个属性绑定 RACObserve(self, name) :监听某个对象的某个属性,返回的是信号。 @weakify(Obj)和@strongify(Obj) RACTuplePack :把数据包装成RACTuple(元组类) RACTupleUnpack:把RACTuple(元组类)解包成对应的数据 RACChannelTo 用于双向绑定的一个终端 四、常用操作方法 flattenMap map 用于把源信号内容映射成新的内容。 concat 组合 按一定顺序拼接信号,当多个信号发出的时候,有顺序的接收信号 then 用于连接两个信号,当第一个信号完成,才会连接then返回的信号。 merge 把多个信号合并为一个信号,任何一个信号有新值的时候就会调用 zipWith 把两个信号压缩成一个信号,只有当两个信号同时发出信号内容时,并且把两个信号的内容合并成一个元组,才会触发压缩流的next事件。 combineLatest:将多个信号合并起来,并且拿到各个信号的最新的值,必须每个合并的signal至少都有过一次sendNext,才会触发合并的信号。 reduce聚合:用于信号发出的内容是元组,把信号发出元组的值聚合成一个值 filter:过滤信号,使用它可以获取满足条件的信号. ignore:忽略完某些值的信号. distinctUntilChanged:当上一次的值和当前的值有明显的变化就会发出信号,否则会被忽略掉。 take:从开始一共取N次的信号 takeLast:取最后N次的信号,前提条件,订阅者必须调用完成,因为只有完成,就知道总共有多少信号. takeUntil:(RACSignal *):获取信号直到某个信号执行完成 skip:(NSUInteger):跳过几个信号,不接受。 switchToLatest:用于signalOfSignals(信号的信号),有时候信号也会发出信号,会在signalOfSignals中,获取signalOfSignals发送的最新信号。 doNext: 执行Next之前,会先执行这个Block doCompleted: 执行sendCompleted之前,会先执行这个Block timeout:超时,可以让一个信号在一定的时间后,自动报错。 interval 定时:每隔一段时间发出信号 delay 延迟发送next。 retry重试 :只要失败,就会重新执行创建信号中的block,直到成功. replay重放:当一个信号被多次订阅,反复播放内容 throttle节流:当某个信号发送比较频繁时,可以使用节流,在某一段时间不发送信号内容,过了一段时间获取信号的最新内容发出。 五、UI - Category(常用汇总) 1、rac_prepareForReuseSignal: 需要复用时用 相关UI: MKAnnotationView、UICollectionReusableView、UITableViewCell、UITableViewHeaderFooterView 2、rac_buttonClickedSignal:点击事件触发信号 相关UI:UIActionSheet、UIAlertView 3 、rac_command:button类、刷新类相关命令替换 相关UI:UIBarButtonItem、UIButton、UIRefreshControl 4、rac_signalForControlEvents: control event 触发 相关UI:UIControl 5、rac_gestureSignal UIGestureRecognizer 事件处理信号 相关UI:UIGestureRecognizer 6、rac_imageSelectedSignal 选择图片的信号 相关UI:UIImagePickerController 7、rac_textSignal 相关UI:UITextField、UITextView 8、可实现双向绑定的相关API rac_channelForControlEvents: key: nilValue: 相关UI:UIControl类 rac_newDateChannelWithNilValue: 相关UI:UIDatePicker rac_newSelectedSegmentIndexChannelWithNilValue: 相关UI:UISegmentedControl rac_newValueChannelWithNilValue: 相关UI:UISlider、UIStepper rac_newOnChannel 相关UI:UISwitch rac_newTextChannel 相关UI:UITextField 六、Foundation - Category (常用汇总) 1、NSArray rac_sequence 信号集合 2、NSData rac_readContentsOfURL: options: scheduler: 比oc多出线程设置 3、NSDictionary rac_sequence 不解释 rac_keySequence key 集合 rac_valueSequence value 集合 4、NSEnumerator rac_sequence 不解释 5、NSFileHandle rac_readInBackground 见名知意 6、NSIndexSet rac_sequence 不解释 7、NSInvocation rac_setArgument: atIndex: 设置参数 rac_argumentAtIndex 取某个参数 rac_returnValue 所关联方法的返回值 8、NSNotificationCenter rac_addObserverForName: object:注册通知 9、NSObject rac_willDeallocSignal 对象销毁时发动的信号 rac_description debug用 rac_observeKeyPath: options: observer: block:监听某个事件 rac_liftSelector: withSignals: 全部信号都next在执行 rac_signalForSelector: 代替某个方法 rac_signalForSelector:(SEL)selector fromProtocol:代替代理 10、NSOrderedSet rac_sequence 不解释 11、NSSet rac_sequence 不解释 12、NSString rac_keyPathComponents 获取一个路径所有的部分 rac_keyPathByDeletingLastKeyPathComponent 删除路径最后一部分 rac_keyPathByDeletingFirstKeyPathComponent 删除路径第一部分 rac_sequence 不解释 (character) rac_readContentsOfURL: usedEncoding: scheduler: 比之OC多线程调用 13、NSURLConnection rac_sendAsynchronousRequest 发起异步请求 14、NSUserDefaults rac_channelTerminalForKey 用于双向绑定,此乃一 作者:王隆帅 来源:51CTO

优秀的个人博客,低调大师

给 Java 学习者的超全教程整理

Java 在编程语言排行榜中一直位列前排,可知 Java 语言的受欢迎程度了。 网上有很多 Java 教程,无论是基础入门还是开发小项目的教程都比比皆是,可是系统的很少,对于Java 学习者来说找到系统、完整、可学性较强的教程其实并不是那么容易。实验楼上有很多 Java 教程,从基础入门、J2SE 开发、SSH 框架到实战项目都有,因此,这里就把这些课程总结一下,希望对 Java 学习者有所帮助~ 一、Java基础 Java 基础不必多说了,下面的5门课程就可以带你动手学习,入门Java。 Java编程语言 这个课程介绍了 Java 基本语法、Java 平台应用、 Java 的核心概念:JVM、JDK、JRE以及 java 面向对象思想。非常适合 Java 入门学习。 Java 8 新特性指南 Java 8是近年来一个Java编程语言发行版本,由Oracle 2014年3月发布。该版本为Java带来许多新特性,是一个具有重大改变的版本。 这个课程适用于Java初学者或者是具有一定编程经验的开发者,主要是学习 Java 8 的一些新特性,为自己的技能升级打补丁。如果你想学习java可以来这个群,首先是二二零,中间是一四二,最后是九零六,里面有大量的学习资料可以下载。 JDBC 入门教程 这个教程学习 JDBC 定义和架构,回顾 SQL 语法,搭建 JDBC 的环境,通过实例来深入学习 JDBC。 JDK 核心 API 这个课程学习包括 java.lang 包,java.util 包,java.io 包以及泛型的相关知识。 Java进阶之设计模式 这个课程介绍常用的设计模式以及 Java 语言的实现实例来学习 java 设计模式。通过这个课程可以学习到很多类型的设计模式,其中包括工厂模式、抽象工厂模式、单例模式、适配器模式、观察者模式、装饰者模式等等。 二、J2SE 开发 J2SE,全称为Java 2 Standard Edition。Java 2平台包括:标准版(J2SE)、企业版(J2EE)和微缩版(J2ME)三个版本。J2SE即Java 2的标准版,主要用于桌面应用软件的开发。 下面这段话是ORACLE对于Java SE的官方描述: Java Platform, Standard Edition (Java SE) 可以让您在桌面和服务器以及目前要求较高的嵌入式环境中开发和部署 Java 应用程序。 Java 提供了当今应用程序所需要的丰富的用户界面、良好的性能、多功能性、可移植性和安全性。 J2SE与J2EE、J2ME之间的关系可以通过下图来表示: J2SE的架构 J2SE的架构如下图所示,它主要包含了UI、集成库、语言和工具基础库、其他基础库、Java虚拟机等组件。 综上所述,将J2SE压缩一点再加上一些CLDC等方面的特性就是J2ME;将其扩充一点再增加一些EJB等企业应用方面的特性就是J2EE。因此J2SE是J2EE的基础,建议从事Java的开发人员从J2SE开始学习。 以下是学习J2SE的教程: J2SE核心开发实战 这个课程主要讲解IO、Util等常用类库的使用、Swing图形化编程、多线程编程等知识点。 J2SE网络通信实践 这个课程介绍怎么使用 J2SE 常用网络通信 API 以及 Socket 编程。可以学习到网络基础知识、获取URL资源的大小、Swing图形界面编程、套接字编程。 三、Java SSH框架 SSH(Spring + Struts + Hibernate)集成框架,是应用十分广泛的一种 Java Web 应用程序开发框架。SSH 框架也体现了典型的分层结构,分层有很多好处,例如项目整体的构架更加清晰,代码也更易维护和扩展。 通常来说,SSH 整体上大致可以用下图描述: 以下是教程: Spring框架入门教程 这个课程主要是介绍 Spring 框架。 Struts框架教程 这个课程主要是介绍 Struts 框架。 Hibernate框架教程 这个课程主要是介绍 Hibernate 框架。 SSH 框架应用实例 这个课程学习 SSH(Spring + Struts + Hibernate)集成框架的应用,并用 SSH 框架开发一个简单的用户管理网站。 四、Java 实战项目 当然,我们在学习了Java各种基础知识之后,最需要做的就是学会应用,开发一些项目把所学的知识应用起来,下面的8个实战项目就是比较好的练手教程。 1、Java开发简单的计算器 这个项目一看名字就知道,开发一个常见的计算器。 2、Java实现记事本 这也是一个常见的Java项目,开发记事本。 3、Java实现电子通讯录 用Java实现电子通讯录功能。 4、Java实现简单的支付平台业务流程 这个项目编写简单的 PayPlatform 程序模拟支付平台流程,主要涉及到 Java 线程与同步。 5、自己的Java编辑器 项目使用 Eclipse 开发,配合 Java 语言完成一个 Java 编辑器。它的主要功能:1、Java代码的编辑 2、编译及运行Java程序。 6、Java实现MD5文件校验 项目使用 Java 语言编写对文件进行MD5值的校验程序。可以学习到MD5的加密逻辑以及Swing插件的安装方法和Java界面编程等知识。 7、Java和WebSocket开发网页聊天室 8、结合七牛搭建个人相册 项目基于七牛云存储的 SDK 实现个人相册服务,学习并实践 Java Web 开发基本方法及七牛云存储 Java API 接口。 最后 ,以上,就是总结的Java学习教程,无论是Java初学者,还是想找项目练手的,都可以找到合适的教程。 当然,教程是有了,剩下的就是自己多动手学习啦!

优秀的个人博客,低调大师

关于MySQL常见的所有锁,已汇总整理完毕

我,小Y。 又来面试了,还是之前那家公司,即将和之前那个老面试官进行第二次 battle,心情还是xue微有点忐忑。 没看过第一次 battle 的同学可以看这里,一个MVCC和面试官大战三十回合 又一抹光亮闪过,面试官推门而入,我抬头望去,没错,还是那味儿。 看到面试官头上那“傲然矗立”的头发,差点又想站起来给他敬了个礼,算了先稳住,低调一点。 面试官瞥了我一眼:来吧,咱们继续面试,上次没办法,女朋友就是粘人,这次问 MySQL InnoDB 的锁喔。 我:.....(行,我知道你有女朋友了),好的面试官,您请。 面试官:MySQL InnoDB 的锁 和 MyISAM 的锁有什么区别? 我:MyISAM 只支持表锁,一锁就锁整张表,而 InnoDB 不仅支持表锁,还支持粒度更低的行锁,仅对相关的记录上锁即可,所以对于写入操作来说 InnoDB 的性能更高。 面试官:那不论表锁还是行锁,其实有分为两类的,你知道是哪两类吗? 我:你指的是 shared (S) locks 和 exclusive (X) locks 吗? S锁,称为共享锁,事务在读取记录的时候获取 S 锁,它允许多个事务同时获取 S 锁,互相之间不会冲突。 X锁,称为独占锁,事务在修改记录的时候获取 X 锁,且只允许一个事务获取 X 锁,其它事务需要阻塞等待。 所以 S 锁之间不冲突,X 锁则为独占锁,所以 X 之间会冲突, X 和 S 也会冲突。 冲突 S X S 不冲突 冲突 X 冲突 冲突 不论是表级别锁还是行级别锁,S 和 X 的特性都是一样的。 面试官:你说事务在读取记录的时候需要获取 S 锁?这不对吧? 我:确实不准确。益与 MVCC 的功劳,普通的 select 是不需要加锁的。 而 SELECT ... LOCK IN SHARE MODE; 这种读取需要对记录上 S 锁。 SELECT ... FOR UPDATE; 这种需要对记录上 X 锁。 面试官:对了,你刚提到表级锁,那你平时用过 InnoDB 的表锁吗? 我:没用过,InnoDB 的表锁很鸡肋,我知道: LOCK TABLES yes READ 是对 yes 这个表上 S 锁。 LOCK TABLES yes WRITE 是对 yes 这个表上 X 锁。 但是基本上没用。 面试官:噢?怎么个鸡肋了? 我:平日的 update 、select 要用也是用行锁了,不可能用粒度粗的表锁。唯一能想到用上表锁的就是 DDL 语句了,比如 ALTER TABLE 的时候,应该锁定整个表,防止查询和修改。 但是这个 server 已经提供了一个叫 MDL 的东西,即 Metadata Locks,所以已经用 MDL 来阻塞了,表锁也就排不上用场了。 真要用表锁,估计也就是数据恢复的时候,手动锁表还原数据了。 面试官摸了摸头上的反光处:可以,但是如果真要到用表锁的时候,那表锁和行锁之间不是会冲突的吗?如果表里面已经加了行锁怎么办?得一条记录一条记录遍历过去找行锁吗? 我:这确实是一种实现方式,但是性能太差了,假设数据库里有上千万的数据,这加个表锁得找死。 所以有了个叫意向锁(Intention Locks)的东西。 IS(Intention Shared Lock),共享意向锁 IX(Intention Exclusive Lock),独占意向锁。 这两个锁是表级别的锁,当需要对表中的某条记录上 S 锁的时候,先在表上加个 IS 锁,表明此时表内有 S 锁。当需要对表中的某条记录上 X 锁的时候,先在表上加个 IX 锁,表明此时表内有 X 锁。 这样操作之后,如果要加表锁,就不需要遍历所有记录去找了,直接看看表上面有没有 IS 和 IX 锁。 比如,此时要上表级别的 S 锁,如果表上没有 IX ,说明表中没有记录有独占锁,其实就可以直接上表级 S 锁。 如果此时要上表级别的 X 锁,如果表上没有 IX 和 IS ,说明表中的所有记录都没加锁,其实就可以直接上表级 X 锁。 因此 IS 和 IX 的作用就是在上表级锁的时候,可以快速判断是否可以上锁,而不需要遍历表中的所有记录。 所以 IS 和 IX 互相之间是不会冲突的,因为它们的作用只是打个标记,来丰富一下上面的表格: 冲突 S X IS IX S 不冲突 冲突 不冲突 冲突 X 冲突 冲突 冲突 冲突 IS 不冲突 冲突 不冲突 不冲突 IX 冲突 冲突 不冲突 不冲突 面试官:行,那再来说说行锁吧,InnoDB 有几类行锁? 我:有记录锁(Record Locks)、间隙锁(Gap Locks)、Next-Key Locks。 面试官:详细说说看? 我:记录锁顾名思义就是锁住当前的记录,它是作用到索引上的。我们都知道 innodb 是肯定有索引的,即使没有主键也会创建隐藏的聚簇索引,所以记录锁总是锁定索引记录。 比如,此时一个事务 A 执行 SELECT * FROM yes WHERE name = 'xx' FOR UPDATE; 那么 name = xx 这条记录就被锁定了,其他事务无法插入、删除、修改 name = xx 的记录。 此时事务 A 还未提交,另一个事务 B 要执行 insert into yes (name) values ('xx'),此时会被阻塞,这个很好理解。 但是,如果另一个事务 C 执行了 insert into yes (name) values ('aa'),这个语句会被阻塞吗? 看情况。 如果 name 没有索引。前面提到记录锁是加到索引上的,但是 name 没索引啊,那只能去找聚簇索引,但聚簇索引上面只有主键啊,它哪知道各自的 name 是什么,所以咋办?都锁了呗! 因此,如果 name 没有索引,那么事务 C 会被阻塞,如果有索引,则不会被阻塞! 所以这里要注意,没索引的列不要轻易的锁,不要以为有行锁就可以为所欲为,并不是这样滴。 面试官:哟,有点东西,继续继续。 我:然后是间隙锁,这个东西它有点东西。 前面说了,记录锁需要加到记录上,但是如果要给此时还未存在的记录加锁怎么办?也就是要预防幻读的出现! 这时候间隙锁就派上用场了,它是给间隙加上锁。 比如此时有 1、3、5、10 这四条记录,之前的文章分析过,数据页中还有两条虚拟的记录,分别是 Infimum 和 Supremum。 可以看到,记录之前都有间隙,那间隙锁呢,锁的就是这个间隙! 比如我把 3 和 5 之间的间隙锁了,此时要插入 id = 4 的记录,就会被这个间隙锁给阻塞了,这样就避免了幻读的产生!也就实现了锁定未插入的记录的需求! 还有个 Next-Key Locks 就是记录锁+间隙锁,像上面间隙锁的举例,只能锁定(3,5) 这个区间,而 Next-Key Locks 是一个前开后闭的区间(3,5],这样能防止查询 id=5 的这个幻读。 面试官:那间隙锁之间会不会冲突? 我 :不会,间隙锁的唯一目的就是防止其他事务插入数据到间隙中 ,所以即使两个间隙锁要锁住相同的间隙也没有关系,因为它们的目的是一致的,所以不冲突。 面试官:那间隙锁可以显式禁用吗? 我 :可以的。间隙锁是在事务隔离级别为可重复读的时候生效的,如果将事务隔离级别更改为 READ COMMITTED,就会禁用了,此时,间隙锁对于搜索和索引扫描是禁用的,仅用于外键约束检查和重复键检查。 面试官:说到间隙锁,那你知道什么是插入意向锁吗? 我:插入意向锁,即 Insert Intention Locks,它也是一类间隙锁,但是它不是锁定间隙,而是等待某个间隙。比如上面举例的 id = 4 的那个事务 C ,由于被间隙锁给阻塞了,所以事务 C 会生成一个插入意向锁,表明等待这个间隙锁的释放。 并且插入意向锁之间不会阻塞,因为它们的目的也是只等待这个间隙被释放,所以插入意向锁之间没有冲突。 面试官:所以这个插入意向锁其实没什么用的? 我:确实,它的目的不在于锁定资源防止别人访问,我个人觉得更像是为了遵循 MySQL 的锁代码实现而为之。 锁其实就是内存里面的一个结构,每个事务为某个记录或者间隙上锁就是创建一个锁对象来争抢资源。 如果某个事务没有抢到资源,那也会生成一个锁对象,只是状态是等待的,而当拥有资源的事务释放锁之后,就会寻找正在等待当前资源的锁结构,然后选一个让它获得资源并唤醒对应的事务使之得以执行。 所以按照这么个逻辑,那些在等待间隙锁的插入事务,也需要对应的建立一个锁结构,然后锁类型是插入意向锁。 这样一来,间隙锁的事务在释放间隙锁的时候,才能得以找到那些等待插入的事务,然后进行唤醒,而由锁的类型也可以得知是插入意向锁,之间不需要阻塞,所以可以一起执行插入。 面试官:说到插入新记录我问你个问题,如果插入的事务还未提交,现在有另一个事务通过SELECT ... LOCK IN SHARE MODE 或者SELECT ... FOR UPDATE 打算读取这条记录怎么办?此时生效的是什么锁? 我:(我丢,面试官想给我挖坑?哼,但是这难不倒我霸中霸!) 插入的事务还未提交,此时普通 select 没问题,有 MVCC 在,所以读的是老版本。而 SELECT ... LOCK IN SHARE MODE或者SELECT ... FOR UPDATE` 是要获取记录 S 锁和 X 锁的,但是此时事务还未提交,因此这两类 select 会阻塞。 具体是怎么阻塞的呢?因为有事务ID!通过 MVCC 可以利用事务ID 来进行判断当前记录是否可见,这其实相当于一把隐式锁!知道当前记录不可见,于是这个查询事务会为之前未提交的插入的事务生成一个锁结构,然后查询事务自己也生成锁结构,接着等待插入事务的释放,这样就完成了阻塞! 面试官:(这小子,我要压不住他了!)行,那你知道什么是 AUTO-INC Locks 锁吗? 我:知道,Auto-Inc Lock 是一个特殊的表级锁,用于自增列插入数据时使用。在插入一条数据的时候,需要在表上加个 Auto-Inc Lock,然后为自增列分配递增的值,在语句插入结束之后,再释放 Auto-Inc Lock。 在 MySQL 5.1.22 版本之后,又弄了个互斥量来进行自增减的累加。互斥量的性能高于 Auto-Inc Lock,因为 Auto-Inc Lock是语句插入完毕之后才释放锁,而互斥量是在语句插入的时候,获得递增值之后,就可以释放锁,所以性能更好。 但是我们还需要考虑主从的情况,由于并发插入的情况,基于 statement -based binlog 复制时,自增的值顺序无法把控,可能会导致主从数据不一致。 所以 MySQL 有个 innodb_autoinc_lock_mode 配置,一共有三个值: 0,只用 Auto-Inc Lock。 1, 默认值,对于插入前已知插入行数的插入,用互斥量,对于插入前不知道具体插入数的插入,用 Auto-Inc Lock,这样即使基于 statement -based binlog 复制也是安全的。 2,只用互斥量。 面试官:那 MyISAM 有 AUTO-INC Locks 锁吗? 我:没啊,MyISAM 插入本来就用了表锁。 面试官:(这小子行啊,我得找回行子)那你还知道 MySQL 有什么锁吗? 我:(这还没问够??)表锁、IS、IX、MDL、记录锁、间隙锁、Next-key locks、插入意向锁、Auto-Inc Locks,还有啥? 面试官瞥了我一眼:(好小子,总算治了你了)不知道了? 我:(该怂的时候,还是得怂)知识盲区了,请面试官教教我。 面试官:还有个 Predicate Locks,谓词锁。 我:什么玩意? 面试官:InnoDB 是支持空间数据的,所以有空间索引,为了处理涉及空间索引的操作的锁定,next-key locking 不好使,因为多维数据中没有绝对排序的概念,因此不清楚“下一个” key 在哪。 所以为了支持具有空间索引的表的隔离级别,InnoDB使用谓词锁。 空间索引包含最小边界矩形(MBR)值,因此 InnodB 通过在用于查询的 MBR 值上设置谓词锁定,使得 InnoDB 在索引上执行一致性读, 其他事务无法插入或修改与查询条件匹配的行。 我:(.....果然超出了我的知识范围,这个B被他装到了)老面试官您真的是66666。 面试官:行吧,你今天答的马马虎虎还可以,下次再问问你啥 buffer pool、change buffer、doublewrite buffer 啥的。 我:(????还问呢),这是还继续面吗?这算三面吗? 面试官:你管我,我就想多面面你,充分了解一下,我们公司很严格的,人不是随便招的!赶紧回去等通知! 我:行行行,您老等着,就一堆 buffer 是吧,我回去好好准备准备哈~ 今天就到这儿,下篇我再画个图总结汇总一波今天的锁~ 欢迎关注我的公众号【yes的练级攻略】,更多硬核文章等你来读。 我是 yes,从一点点到亿点点,我们下篇见。 本文分享自微信公众号 - yes的练级攻略(yes_java)。 如有侵权,请联系 support@oschina.cn 删除。 本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。