前端技术
HTML
CSS
Javascript
前端框架和UI库
VUE
ReactJS
AngularJS
JQuery
NodeJS
JSON
Element-UI
Bootstrap
Material UI
服务端和客户端
Java
Python
PHP
Golang
Scala
Kotlin
Groovy
Ruby
Lua
.net
c#
c++
后端WEB和工程框架
SpringBoot
SpringCloud
Struts2
MyBatis
Hibernate
Tornado
Beego
Go-Spring
Go Gin
Go Iris
Dubbo
HessianRPC
Maven
Gradle
数据库
MySQL
Oracle
Mongo
中间件与web容器
Redis
MemCache
Etcd
Cassandra
Kafka
RabbitMQ
RocketMQ
ActiveMQ
Nacos
Consul
Tomcat
Nginx
Netty
大数据技术
Hive
Impala
ClickHouse
DorisDB
Greenplum
PostgreSQL
HBase
Kylin
Hadoop
Apache Pig
ZooKeeper
SeaTunnel
Sqoop
Datax
Flink
Spark
Mahout
数据搜索与日志
ElasticSearch
Apache Lucene
Apache Solr
Kibana
Logstash
数据可视化与OLAP
Apache Atlas
Superset
Saiku
Tesseract
系统与容器
Linux
Shell
Docker
Kubernetes
[数据库持久化存储在Docker中 ]的搜索结果
这里是文章列表。热门标签的颜色随机变换,标签颜色没有特殊含义。
点击某个标签可搜索标签相关的文章。
点击某个标签可搜索标签相关的文章。
Go Gin
...全双工通信,满足实时数据传输的需求。 WebSocket , WebSocket是一种全双工通信协议,允许客户端和服务器之间保持持久连接,从而实现双向实时通信。在文章中,WebSocket被用来构建实时应用,例如在线聊天室或股票行情推送。Gin通过集成gorilla/websocket库,提供了对WebSocket的支持。开发者可以通过Gin的中间件将HTTP连接升级为WebSocket连接,并在连接上处理消息的收发。这种方式相较于传统的轮询机制,能够显著降低延迟,提高数据传输效率。 sync.Pool , sync.Pool是Go语言标准库提供的一个工具,用于复用对象以减少内存分配和垃圾回收的压力。在文章中,sync.Pool被用来优化处理HTTP请求时的内存使用。通过定义一个包含固定大小缓冲区的Pool,每次处理请求时可以从Pool中获取已有的缓冲区,处理完成后将其放回Pool以便后续使用。这种方式避免了频繁创建和销毁临时对象,从而提升了程序的性能和稳定性。文中提到的示例展示了如何使用sync.Pool来存储和复用字节切片,模拟了在高并发环境下对内存资源的有效管理。
2025-04-07 16:03:11
66
时光倒流
ElasticSearch
...方法: 比如你的底层数据库用的是sql数据库(比如mysql):你可能会想到在对应字段上使用field1 like '%?%',?即用户输出的关键词 比如你的底层数据库用的是mongo:你可能会想到在对应字段上使用db.collection.find({ "field1": { $regex: /aaa/ } })做查询,aaa即用户输入的关键词 比如你的底层数据库用的是elasticsearch:那厉害了,专业全文搜索神奇,全文搜索或搜索相关的需求使用elasticsearch绝对是最合适的选择 比如你的底层数据库用的是hive、impala、clickhouse等大数据计算引擎:鸟枪换炮,其实用作全文索引和搜索的场景并不合适,你可能依旧会使用sql数据库那样用like做交互 2. 方案选择 调研之后,可能会发现对于数据量相对大一点的搜索场景,在当下流行的数据库或计算引擎中,elasticsearch是其中最合适的解决方案。 无论是sql的like、还是mongo的regex,在线上环境下,数据量较多的情况下,都不是很高效的查询,甚至有的公司的dba会禁止在线上使用类似的查询语法。 与elasticsearch是“亲戚”的,大家还常提到lucene、solr,但是无论从现在的发展趋势还是公司运维人才的储备(不得不说当下的运维人才中,对es熟悉的人才会更多一些),elasticsearch是相对较合适的选择。 一些大数据计算引擎,其实更多的适合OLAP场景。当然也完全可以使用,因为比如clickhouse、starrocks等的查询速度已经发展的非常快。但你会发现在中文分词搜索上,实现起来有一定困扰。 所以,如果你不差机器,首选方案还是elasticsearch。 3. elasticsearch的适用场景 3.1 经典的日志搜索场景 提到elasticsearch不得不提到它的几个好朋友: 一些公司里经常用elasticsearch来收集日志,然后用kibana来展示和分析。 展开来说,举个例子,你的app打印日志打印到了线上日志文件,当app出现故障你需要做定位筛查的时候,可能需要登录线上机器用grep命令各种查看。 但如果你不差机器资源,可以搭建上述架构,app的日志会被收集到elasticsearch中,最终你可以在kibana中查看日志,kibana里面可以很方面的做各种筛查操作。 这个流畅大概是这样的: 3.2 通用搜索场景 但是没有上图的beats、logstash、kibana,elasticsearch可以自己工作吗?完全可以的! elasticsearch也支持单机部署,数据规模不是很大的情况下,表现也是不错的。所以,你也不用担心因为自己机器资源不够而对elasticsearch望而却步。当然,单机部署的情况下,更多的适合自己玩,对于可靠性的要求就不能太苛刻了。 如果你在用宝塔,那你可以在宝塔面板,左侧“软件商店”中直接找到elasticsearch,并“没有痛苦”的安装。 本篇文章主要讨论选型,所以不涉及安装细节。 3.2.1 性能顾虑 上面提到了“表现”,其实性能只是elasticsearch的一个方面,主要你的机器资源足够(机器资源?对,包括你的机器个数,elasticsearch可以非常方便的横向扩展,以及单机的配置,cpu+内存,内存越高越好,elasticsearch比较吃内存!),它一定会给你很好的性能反应。试想,公司里的app打印线上日志的行数其实可比一般业务系统产生的订单数量要大很多很多,elasticsearch都可以常在日志的实时分析,所以如果你要做通用场景,而且机器资源不是问题,这是完全行得通的。 3.2.2 易用性和可玩性 此外,在使用elasticsearch的时候,会有很多的可玩性。这里不引经据典,呈现很多elasticsearch官方文章的列举优秀特性(当然,确实很优秀!)。 这里举几个例子: (1)中文分词:第一章提到的其它引擎几乎很难实现,elasticsearch对分词器的支持是原生的,因为elasticsearch天生就为全文索引而生,elasticsearch的汉语名字就是“弹性搜索”。这家伙可是专门搞搜索的! 有的朋友可能不了解分词器,比如你的一个字段里存储“今天我要吃冰激凌”,在分词器的加持下,es最终会存储为“今天|我|要|吃|冰激凌”,并且使用倒排索引的形式进行存储。当你搜索“冰激凌”的时候,可以很快的反馈回来。 关于elasticsearch的原理,这里不展开说明,分词器和倒排索引是elasticsearch的最基本的概念。如果有不了解的朋友,可以自行百度一下。而且这两个概念,与elasticsearch其实不挂钩,是搜索中的通用概念。 关于倒排索引,其核心表现如下图: 如果你要用mysql、mongo实现中文分词,这......其实挺麻烦的,可能在后面的版本支持中会实现的很好,但在当前的流行版本中,它们对中文分词是不够友好的。 mysql5.7之后支持外挂第三方分词器,支持中文分词。而在数据量较大的情况下,mysql的多机器部署几乎很难实现,elasticsearch可以很容易的水平扩展。 mongo支持西方语言的分词,但不支持中文、日语、汉语等东方语言,你需要在自己的逻辑代码中实现分词器。 ngram分词,你看看效果:依旧是“今天我要吃冰激凌”,ngram二元分词后即将得到结果“今天、天我、我要、要吃、吃冰、冰激、激凌”。这....,那你搜索冰激凌就搜不出来!咋办呢,当然可以使用三元分词。但是更好的解决方案还是中文分词器,但它们原生并不支持的。 (2)自定义排名场景:比如你的搜索“冰激凌”,结果中返回了有10条,这10条应该有你想对它指定的顺序。最简单的就是用默认的得分,但是如果你想人为干预这个得分怎么办? elasticsearch支持function_score功能(可以不用,这个是增强功能),es会在计算最终得分之前回调这个你指定的function_score回调函数,传入原始得分、行的原始数据,你可以在里面做计算,比如查询其它参考表、或查看是否是广告位,以得到新的score返回给用户。 function_scrore的功能不展开描述,是一个在自定义得分场景下十分有用又简单易用的功能!下面是一个使用示例,不仅如此,它是支持自定义函数的,自由度非常高。 (3)文本高亮:你用mysql或mongo也可以实现,比如用户搜索“冰激凌”,你只需要在逻辑代码中对“冰激凌”替换为“<span class='highlight-term'>冰激凌</span>”,然后前端做样式即可。但如果用户搜索了“好吃的冰激凌”咋办呢?还有就是英文大小写的场景,用户搜索"MAIN",那结果及时匹配到了“main”(小写的),这个单词是否应该高亮呢?也许这时候你会用业务代码实现toLowerCase下基于位置下标的匹配。 挺麻烦的吧,elasticsearch,自动可以返回高亮字段!并且可以自由指定高亮的html前后标签。 (4)实在太多了....这家伙天生为索引而生,而且版本还在不断地迭代。不差机器的话,用用吧! 4. 退而求其次 4.1 普通数据库 尽管elasticsearch在搜索场景下,是非常好用的利器!但是它比较消耗机器资源,如果你的数据规模并不大,而且想快速实现功能。你可以使用mysql或mongo来代替,完全没有问题。 技术是为了解决特定业务场景下的问题,结合当前手头的资源,适合自己的才是最好的。也许你搞了一个单机器的elasticsearch,单机器内存只有2G,它的表现并不会比mysql、mongo来的好。 当然,如果你为了使用上边提到的一些优秀的独有的特性,那elasticsearch一定还是最佳选择! 对于mysql(关系型数据库)和mongo(文档数据库)的区别这里不展开描述了,但对于搜索而言,两种都合适。有时候选型也不用很纠结,其实都是差不太多的东西,适合自己的、自己熟悉的、运维起来顺手的,就是最好的。 4.2 普通数据库实现中文分词搜索的原理 尽管mysql在5.7以后支持外挂第三方分词器,mongo在截止目前的版本中也不支持中文分词(你可能会看到一些文章中说可以指定language为chinese,但其实会报错的)。 其实当你选择普通数据库,你就不得不在逻辑代码中自己实现一套索引分词+搜索分词逻辑。 索引分词+搜索分词?为什么分开写,如果你有用过elasticsearch或solr,你会知道,在指定字段的时候,需要指定index分词器和search分词器。 下面以mongo为例做简要说明。 4.2.1 index分词器 意思是当数据“索引”截断如何分词。首先,这里必须要承认,数据之后存储了,才能被查询。在搜索中,这句话可以换成是“数据只有被索引了,才能被搜索”。 这时候请求打过来了,要索引一条数据,其中某字段是“今天我要吃冰激凌”,分词后得到“今天|我|要|吃|冰激凌”,这个就可以入库了。 如果你使用elasticsearch或solr,这个过程是自动的。如果你使用不支持外观分词器的常规数据库,这个过程你就要手动了,并把分词后的结果用空格分开(最好使用空格,因为西方语言的分词规则就是按空格拆分,以及逗号句号),存入数据库的一个待搜索的字段上。 效果如下图: 本站的其它博文中有介绍IKAnalyzer:https://www.52itw.com/java/6268.html 4.2.2 search分词器 当用户的查询请求打过来,用户输入了“好吃的冰激凌”,分词后得到“好吃|冰激凌”(“的”作为停用词stopwords,被自动忽略了,IKAnalyzer可以指定停用词表)。 于是这时候就回去上图的数据库表里面搜索“好吃 冰激凌”(与index分词器结果统一,还是用空格分隔)。 当然,对于mongo而言,你需要事先开启全文索引db.xxx.ensureIndex({content: "text"}),xxx是集合名,content是字段名,text是全文索引的标识。 mongo搜索的时候用这个语法:db.xxx.find( { $text: { $search: "好吃 冰激凌" } },{ score: { $meta: "textScore" } }).sort( { score: { $meta: "textScore" } } ) 4.2.3 索引库和存储库分开 为了减少单表的大小,为了让普通的列表查询、普通筛选可以跑的更快,你可以对原有的数据原封不动的做一张表。 然后对于搜索场景,再单独对需要被搜索的字段单独拎一张表出来! 然后二者之间做增量信号同步或定时差额同步,可能会有延迟,这个就看你能容忍多长时间(悄悄告诉你,elasticsearch也需要指定这个refresh时间,一般是1s到几秒、甚至分钟级。当然,二者的这个时间对饮的底层目的是不一样的)。 这样,搜索的时候先查询搜索库,拿到一个指针id的列表,然后拿到指针id的列表区存储里把数据一次性捞出来。当然,也是支持分页的,你查询搜索库其实也是普通的数据库查询嘛,支持分页参数的。 4.3 存储库和索引库的延伸阅读 很多有名的开源软件也是使用的存储库与索引库分离的技术方案,如apache atlas: apache atlas对于大数据领域的数据资产元数据管理、数据血缘上可谓是专家,也涉及资产搜索的特性,它的实现思路就是:从搜索库中做搜索、拿到key、再去存储库中做查询。 搜索库:上图右下角,可以看到使用的是elasticsearch、solr或lucene,多个选一个 存储库:上图左下角,可以看到使用的是Cassandra、HBase或BerkeleyDB,多个选一个 虽然apache atlas在只有搜索库或只有存储库的时候也可以很好的工作,但只针对于数据量并不大的场景。 搜索库,擅长搜索!存储库,擅长海量存储!搜索库多样化搜索,然后去存储库做点查。 当你的数据达到海量的时候,es+hbase也是一种很好的解决方案,不在这里展开说明了。
2024-01-27 17:49:04
540
admin-tim
Apache Solr
...松地集成外部服务,如数据存储、计算能力、机器学习模型等。这些服务的即时可用性和全球分布特性,使得应用能够在面临网络延迟或服务中断时,快速转向其他可用资源,从而显著提升了应用的韧性和用户体验。 边缘计算则是云计算的延伸,它将计算和数据存储能力推向离用户更近的位置,例如智能设备、物联网节点或数据中心的边缘位置。这种部署方式减少了数据在中心云之间传输的距离,降低了延迟,同时提高了数据处理速度和实时性。边缘计算特别适用于需要低延迟响应的应用场景,如实时视频流处理、自动驾驶系统等,通过本地化计算和决策,显著提高了系统的整体性能和可靠性。 结合Apache Solr的应用场景,边缘计算和云计算的融合为优化网络连接、提高搜索性能提供了新路径。例如,通过在边缘节点部署轻量级Solr实例,结合云端提供的外部服务,可以实现数据的就近处理和快速响应,同时利用云端的弹性扩展能力应对突发流量或服务需求。此外,边缘计算还能作为数据预处理的节点,减少向云中心传输的数据量,进一步优化网络带宽使用和加速查询响应时间。 总之,云计算和边缘计算的结合,为构建更加稳定、高效且具有弹性的依赖外部服务的系统提供了丰富的技术和实践路径。它们不仅能够改善网络连接问题,还能够促进数据分析、机器学习等高级功能的部署,为用户提供更高质量的服务体验。随着技术的不断进步,未来在优化Apache Solr等搜索引擎性能方面,我们可以期待更多创新的解决方案和实践。
2024-09-21 16:30:17
40
风轻云淡
Mongo
... 引言 在数据库的世界里,MongoDB以其独特的NoSQL特性,为开发者提供了灵活性极高的数据存储解决方案。哎呀,兄弟!你想想看,咱们要是碰上一堆数据要处理,那些老一套的查询方法啊,那可真是不够用,捉襟见肘。就像你手头一堆零钱,想买个大蛋糕,结果发现零钱不够,还得再跑一趟银行兑换整钞。那时候,你就得琢磨琢磨,是不是有啥更省力、效率更高的办法了。哎呀,你知道的,MapReduce就像一个超级英雄,专门在大数据的世界里解决难题。它就像个大厨,能把一大堆食材快速变成美味佳肴。以前,处理海量数据就像是给蜗牛搬家,慢得让人着急。现在有了MapReduce,就像给搬家公司装了涡轮增压,速度嗖嗖的,效率那叫一个高啊!无论是分析市场趋势、优化业务流程还是挖掘用户行为,MapReduce都成了我们的好帮手,让我们的工作变得更轻松,效率也蹭蹭往上涨!本文将带你深入了解MongoDB中的MapReduce,从基础概念到实际应用,再到优化策略,一步步带你掌握这门技术。 1. MapReduce的基础概念 MapReduce是一种编程模型,用于大规模数据集的并行运算。在MongoDB中,我们可以通过map()和reduce()函数实现数据的分组、转换和聚合。基本流程如下: - Map阶段:数据被分割成多个分片,每个分片经过map()函数处理,产生键值对形式的数据流。 - Shuffle阶段:键相同的数据会被合并在一起,为reduce()阶段做准备。 - Reduce阶段:针对每个键,执行reduce()函数,合并所有相关值,产生最终的结果集。 2. MongoDB中的MapReduce实践 为了让你更好地理解MapReduce在MongoDB中的应用,下面我将通过一个具体的例子来展示如何使用MapReduce处理数据。 示例代码: 假设我们有一个名为sales的集合,其中包含销售记录,每条记录包含product_id和amount两个字段。我们的目标是计算每个产品的总销售额。 javascript // 首先,我们定义Map函数 db.sales.mapReduce( function() { // 输出键为产品ID,值为销售金额 emit(this.product_id, this.amount); }, function(key, values) { // 将所有销售金额相加得到总销售额 var total = 0; for (var i = 0; i < values.length; i++) { total += values[i]; } return total; }, { "out": { "inline": 1, "pipeline": [ {"$group": {"_id": "$_id", "total_sales": {$sum: "$value"} }} ] } } ); 这段代码首先通过map()函数将每个销售记录映射到键为product_id和值为amount的键值对。哎呀,这事儿啊,就像是这样:首先,你得有个列表,这个列表里头放着一堆商品,每一项商品下面还有一堆数字,那是各个商品的销售价格。然后,咱们用一个叫 reduce() 的魔法棒来处理这些数据。这个魔法棒能帮咱们把每一样商品的销售价格加起来,就像数钱一样,算出每个商品总共卖了多少钱。这样一来,我们就能知道每种商品的总收入啦!哎呀,你懂的,我们用out这个参数把结果塞进了一个临时小盒子里面。然后,我们用$group这个魔法棒,把数据一通分类整理,看看哪些地方数据多,哪些地方数据少,这样就给咱们的数据做了一次大扫除,整整齐齐的。 3. 性能优化与注意事项 在使用MapReduce时,有几个关键点需要注意,以确保最佳性能: - 数据分区:合理的数据分区可以显著提高MapReduce的效率。通常,我们会根据数据的分布情况选择合适的分区策略。 - 内存管理:MapReduce操作可能会消耗大量内存,特别是在处理大型数据集时。合理设置maxTimeMS选项,限制任务运行时间,避免内存溢出。 - 错误处理:在实际应用中,处理潜在的错误和异常情况非常重要。例如,使用try-catch块捕获并处理可能出现的异常。 4. 进阶技巧与高级应用 对于那些追求更高效率和更复杂数据处理场景的开发者来说,以下是一些进阶技巧: - 使用索引:在Map阶段,如果数据集中有大量的重复键值对,使用索引可以在键的查找过程中节省大量时间。 - 异步执行:对于高并发的应用场景,可以考虑将MapReduce操作异步化,利用MongoDB的复制集和分片集群特性,实现真正的分布式处理。 结语 MapReduce在MongoDB中的应用,为我们提供了一种高效处理大数据集的强大工具。哎呀,看完这篇文章后,你可不光是知道了啥是MapReduce,啥时候用,还能动手在自己的项目里把MapReduce用得溜溜的!就像是掌握了新魔法一样,你学会了怎么给这玩意儿加点料,让它在你的项目里发挥出最大效用,让工作效率蹭蹭往上涨!是不是感觉整个人都精神多了?这不就是咱们追求的效果嘛!嘿,兄弟!听好了,掌握新技能最有效的办法就是动手去做,尤其是像MapReduce这种技术。别光看书上理论,找一个你正在做的项目,大胆地将MapReduce实践起来。你会发现,通过实战,你的经验会大大增加,对这个技术的理解也会更加深入透彻。所以,行动起来吧,让自己的项目成为你学习路上的伙伴,你肯定能从中学到不少东西!让我们继续在数据处理的旅程中探索更多可能性!
2024-08-13 15:48:45
150
柳暗花明又一村
DorisDB
...》 引言:数据之海的波涛 在数据管理的世界里,DorisDB无疑是一艘载满现代数据处理技术的巨轮。哎呀,这家伙可真是个宝啊!不仅性能杠杠的,稳定性也是没得说,而且还能轻松升级扩容,怪不得那么多大公司都离不开它,用它来做数据的存储和分析,简直是如虎添翼!然而,就像任何航海之旅,DorisDB航行中也会遭遇风浪——“写入失败”。嘿,兄弟!这篇文章就像是一场探险之旅,带你深入揭秘这个棘手问题的真相。咱们不只停留在表面,而是要挖出问题的根儿,然后一起找寻解决的钥匙。想象一下,我们是在大海捞针,但有了指南针和渔网,这场寻找就变得既刺激又充满乐趣。跟着我,咱们在数据的汪洋里畅游,找到属于你的那片宁静海港,让你不再被信息的洪流淹没,而是能稳稳驾驭,轻松自在地航行。准备好了吗?出发吧! 第一章:写入失败的初探 现象描述:当你尝试向DorisDB表中插入数据时,突然间,一切变得静止。查询返回一个错误信息,告诉你“写入失败”。这不仅让你感到沮丧,还可能影响了业务流程的连续性。 原因分析:写入失败可能是由多种因素引起的,包括但不限于网络延迟、资源限制(如磁盘空间不足)、事务冲突、以及数据库配置问题等。理解这些原因有助于我们对症下药。 第二章:案例研究:网络延迟引发的写入失败 场景还原:假设你正使用Python的dorisdb库进行数据插入操作。代码如下: python from dorisdb import DorisDBClient client = DorisDBClient(host='your_host', port=your_port, database='your_db') cursor = client.cursor() 插入数据 cursor.execute("INSERT INTO your_table (column1, column2) VALUES ('value1', 'value2')") 问题浮现:执行上述代码后,你收到了“写入失败”的消息,同时发现网络连接偶尔会中断。 解决方案:首先,检查网络连接稳定性。确保你的服务器与DorisDB实例之间的网络畅通无阻。其次,优化SQL语句的执行效率,减少网络传输的数据量。例如,可以考虑批量插入数据,而不是逐条插入。 第三章:资源限制:磁盘空间不足的挑战 场景还原:你的DorisDB实例运行在一个资源有限的环境中,某天,当你试图插入大量数据时,系统提示磁盘空间不足。 问题浮现:尽管你已经确保了网络连接稳定,但写入仍然失败。 解决方案:增加磁盘空间是显而易见的解决方法,但这需要时间和成本。哎呀,兄弟,你得知道,咱们手头的空间那可是个大问题啊!要是想在短时间内搞定它,我这儿有个小妙招给你。首先,咱们得做个大扫除,把那些用不上的数据扔掉。就像家里大扫除一样,那些过时的文件、照片啥的,该删就删,别让它占着地方。其次呢,咱们可以用更牛逼的压缩工具,比如ZIP或者RAR,它们能把文件压缩得更小,让硬盘喘口气。这样一来,不仅空间大了,还能节省点资源,挺划算的嘛!试试看,说不定你会发现自己的设备运行起来比以前流畅多了!嘿,兄弟!你听说过 DorisDB 的分片和分布式功能吗?这玩意儿超级厉害!它就像个大仓库,能把咱们的数据均匀地摆放在多个小仓库里(那些就是节点),这样不仅能让数据更高效地存储起来,还能让我们的系统跑得更快,用起来更顺畅。试试看,保管让你爱不释手! 第四章:事务冲突与并发控制 场景还原:在高并发环境下,多个用户同时尝试插入数据到同一表中,导致了写入失败。 问题浮现:即使网络连接稳定,磁盘空间充足,事务冲突仍可能导致写入失败。 解决方案:引入适当的并发控制机制是关键。在DorisDB中,可以通过设置合理的锁策略来避免或减少事务冲突。例如,使用行级锁或表级锁,根据具体需求选择最合适的锁模式。哎呀,兄弟,咱们在优化程序的时候,得注意一点,别搞那些没必要的同时进行的操作,这样能大大提升系统的稳定性。就像是做饭,你要是同时炒好几个菜,肯定得忙得团团转,而且容易出错。所以啊,咱们得一个个来,稳扎稳打,这样才能让系统跑得又快又稳! 结语:从困惑到解决的旅程 面对“写入失败”,我们需要冷静分析,从不同的角度寻找问题所在。哎呀,你知道嘛,不管是网速慢了点、硬件不够给力、操作过程中卡壳了,还是设置哪里没对劲,这些事儿啊,都有各自的小妙招来解决。就像是遇到堵车了,你得找找是哪段路的问题,然后对症下药,说不定就是换个路线或者等等红绿灯,就能顺畅起来呢!哎呀,你知道不?咱们要是能持续地学习和动手做,那咱处理问题的能力就能慢慢上个新台阶。就像给水管通了塞子,数据的流动就更顺畅了。这样一来,咱们的业务跑起来也快多了,就像是有了个贴身保镖,保护着业务高效运转呢!嘿!听好了,每回遇到难题都不是白来的,那可是让你升级打怪的好机会!咱们就一起手牵手,勇闯数据的汪洋大海,去发现那些藏在暗处的新世界吧!别怕,有我在你身边,咱俩一起探险,一起成长!
2024-10-07 15:51:26
124
醉卧沙场
Tornado
...r,这是一个专门用来存储敏感信息(比如 API 密钥、数据库密码啥的)的服务。对开发者而言,安全这事得放首位,要是还用那种硬编码或者直接把密钥啥的写进配置文件的老办法,那简直就是在玩火自焚啊!Google Cloud Secret Manager 提供了加密存储、访问控制等功能,简直是保护秘钥的最佳选择之一。 所以,当我把这两者放在一起的时候,脑海里立刻浮现出一个画面:Tornado 快速响应前端请求,而 Secret Manager 在背后默默守护着那些珍贵的秘密。是不是很带感?接下来我们就一步步深入探索它们的合作方式吧! --- 2. 初识Tornado 搭建一个简单的Web服务 既然要玩转 Tornado,咱们得先搭个基础框架才行。好嘞,接下来我就简单搞个小网页服务,就让它回一句暖心的问候就行啦!虽然看起来简单,但这可是后续一切的基础哦! python import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.write("Hello, Tornado!") def make_app(): return tornado.web.Application([ (r"/", MainHandler), ]) if __name__ == "__main__": app = make_app() app.listen(8888) print("Server started at http://localhost:8888") tornado.ioloop.IOLoop.current().start() 这段代码超级简单对不对?我们定义了一个 MainHandler 类继承自 tornado.web.RequestHandler,重写了它的 get 方法,当收到 GET 请求时就会执行这个方法,并向客户端返回 "Hello, Tornado!"。然后呢,就用 make_app 这个函数把路由和这个处理器绑在一起,最后再启动服务器,让它开始监听 8888 端口。 运行后打开浏览器输入 http://localhost:8888,就能看到页面显示 "Hello, Tornado!" 了。是不是特别爽?不过别急着高兴,这只是万里长征的第一步呢! --- 3. 引入Google Cloud Secret Manager:让秘密不再裸奔 现在我们知道如何用 Tornado 做点事情了,但问题是,如果我们的应用程序需要用到一些敏感信息(例如数据库连接字符串),该怎么办呢?直接写在代码里吗?当然不行!这就是为什么我们要引入 Google Cloud Secret Manager。 3.1 安装依赖库 首先需要安装 Google Cloud 的官方 Python SDK: bash pip install google-cloud-secret-manager 3.2 获取Secret Manager中的值 假设我们在 Google Cloud Console 上已经创建了一个名为 my-secret 的密钥,并且它里面保存了我们的数据库密码。我们可以这样从 Secret Manager 中读取这个值: python from google.cloud import secretmanager def access_secret_version(project_id, secret_id, version_id): client = secretmanager.SecretManagerServiceClient() name = f"projects/{project_id}/secrets/{secret_id}/versions/{version_id}" response = client.access_secret_version(name=name) payload = response.payload.data.decode('UTF-8') return payload 使用示例 db_password = access_secret_version("your-project-id", "my-secret", "latest") print(f"Database Password: {db_password}") 这段代码做了什么呢?很简单,它实例化了一个 SecretManagerServiceClient 对象,然后根据提供的项目 ID、密钥名称以及版本号去访问对应的密钥内容。注意这里的 version_id 参数可以设置为 "latest" 来获取最新的版本。 --- 4. 将两者结合起来 构建更安全的应用 那么问题来了,怎么才能让 Tornado 和 Google Cloud Secret Manager 协同工作呢?其实答案很简单——我们可以将从 Secret Manager 获取到的敏感数据注入到 Tornado 的配置对象中,从而在整个应用范围内使用这些信息。 4.1 修改Tornado应用以支持从Secret Manager加载配置 让我们修改之前的 MainHandler 类,让它从 Secret Manager 中加载数据库密码并用于某种操作(比如查询数据库)。为了简化演示,这里我们假设有一个 get_db_password 函数负责完成这项任务: python from google.cloud import secretmanager def get_db_password(): client = secretmanager.SecretManagerServiceClient() name = f"projects/{YOUR_PROJECT_ID}/secrets/my-secret/versions/latest" response = client.access_secret_version(name=name) return response.payload.data.decode('UTF-8') class MainHandler(tornado.web.RequestHandler): def initialize(self, db_password): self.db_password = db_password def get(self): self.write(f"Connected to database with password: {self.db_password}") def make_app(): db_password = get_db_password() return tornado.web.Application([ (r"/", MainHandler, {"db_password": db_password}), ]) 在这个例子中,我们在 make_app 函数中调用了 get_db_password() 来获取数据库密码,并将其传递给 MainHandler 的构造函数作为参数。这样一来,每个 MainHandler 实例都会拥有自己的数据库密码属性。 --- 5. 总结与展望 好了朋友们,今天的分享就到这里啦!通过这篇文章,我们了解了如何利用 Tornado 和 Google Cloud Secret Manager 来构建更加安全可靠的 Web 应用。虽然过程中遇到了不少挑战,但最终的效果还是让我感到非常满意。 未来的话,我还想尝试更多有趣的功能组合,比如结合 Redis 缓存提高性能,或者利用 Pub/Sub 实现消息队列机制。如果你也有类似的想法或者遇到什么问题,欢迎随时跟我交流呀! 最后祝大家 coding愉快,记得保护好自己的秘密哦~ 😊
2025-04-09 15:38:23
44
追梦人
转载文章
...统,它提供了更高效的数据存储和安全性特性。文中提到的NTFSInfo工具就是用来查看详细的NTFS分区信息,包括主文件表(MFT)、MFT区域大小与位置,以及NTFS元数据文件大小等重要信息。 Active Directory , Active Directory是Microsoft Windows Server操作系统的一部分,提供网络环境中的中央身份认证、授权与目录服务功能。管理员可以利用Active Directory管理域内的用户账户、计算机、组策略、安全设置等资源。文章提及AdRestore工具能够恢复Server 2003 Active Directory对象,表明该工具在AD故障恢复场景中有重要作用。 登录会话(Logon Sessions) , 在多用户操作系统的环境中,登录会话是指用户通过验证后,在系统上创建的一个独立的工作环境,其中包含了用户的配置、权限和其他相关状态信息。Sysinternals工具集中的LogonSessions工具则能列出当前系统上的所有活动登录会话,帮助管理员监控和管理用户登录情况。 动态磁盘分区(Dynamic Disk Partitioning) , 动态磁盘是Windows操作系统中相对于基本磁盘而言的一种更为灵活的磁盘管理方式,它可以支持诸如跨多个物理磁盘的卷扩展等功能。LDMDump工具在文章中被提及,作用是倾倒逻辑磁盘管理器在Windows 2000动态磁盘分区上的数据库内容,从而让管理员了解和分析动态磁盘的详细配置信息。
2024-01-22 15:44:41
103
转载
ZooKeeper
...,就容易出问题,要么数据变得乱七八糟,要么整个程序直接“崩了”,啥也干不了。比如说啊,你就想想这个场景——你在打理一家网上商店,突然好几个订单处理的小程序都跑来找你要更新同一个商品的库存,那场面就像好几个人同时抢着跟你说话,都想把自己的事儿赶紧办了,可这库存就那么点,你说这事儿咋整?要是没人管着点,就容易闹出乱子,比如商品明明已经没货了,可系统还傻乎乎地接着收订单,这不是坑人嘛! 分布式锁就是解决这个问题的神器之一。它用一种特别的法子,保证在任何时候都只有一个家伙能独享某个资源,别的小伙伴只能乖乖排队等着轮到自己。而ZooKeeper,作为一款经典的分布式协调工具,就提供了这样一种强大的锁机制。不过,光有锁还不够,我们还需要保证锁的可重用性——也就是说,这个锁不能是一次性的,而是可以被反复使用,就像一把能开很多门的万能钥匙一样。 那么问题来了,ZooKeeper是如何做到这一点的呢?接下来,咱们就一起深入探究一番! --- 二、ZooKeeper的基本原理 在正式讨论分布式锁之前,我们需要先搞清楚ZooKeeper的核心概念。简单说啊,ZooKeeper就像是一个分布式的小仓库,专门用来存东西的。不过呢,它可不只是个普通的储物柜,还能干不少酷炫的事儿,比如监听节点的变化,或者创建那种“限时有效”的临时小隔间啥的,功能特别强大!这些特性使得ZooKeeper成为构建复杂分布式算法的理想选择。 比如说,当你往ZooKeeper里创建一个节点时,可以选择让它变成“持久型”还是“临时型”。打个比方,持久型节点就像那种“铁打的营盘”,哪怕服务器突然重启了,它也能稳如泰山,啥事没有;而临时型节点呢,就有点像“过路的客人”,只要你一断开连接,它就自觉地“卷铺盖走人”了,连影子都不剩。这种灵活性为我们实现分布式锁提供了基础。 除此之外,还有一个非常重要的功能叫做“顺序节点”。这意味着当你创建一个节点时,ZooKeeper会自动为其分配一个唯一的序列号。这个功能简直太适合用来模拟排队或者搞定排序啦,而且还是实现分布式锁的核心法宝呢! --- 三、分布式锁的实现思路 现在我们明白了ZooKeeper的基本能力,接下来就该聊聊分布式锁的具体实现了。分布式锁这个东西啊,说白了原理还挺简单的:大家都想抢锁的时候,就都去创建一个临时的小节点,接着看看自己创建的那个节点是不是队列里排第一的小可爱。要是自己是“老大”,那锁就归你啦!如果是的话,那么它就获得了锁;如果不是,那就需要等待直到轮到自己为止。 听起来是不是有点抽象?没关系,让我用一段伪代码来帮你理清思路: python def acquire_lock(zookeeper_client, lock_path): 创建一个临时顺序节点 node = zookeeper_client.create(lock_path + "/lock-", ephemeral=True, sequence=True) 获取所有子节点并排序 children = sorted(zookeeper_client.get_children(lock_path)) 检查自己是否是最小的节点 if node.endswith(children[0]): print("I got the lock!") return True 如果不是,就监听前一个节点的变化 predecessor = children[children.index(node) - 1] zookeeper_client.wait_for_event(lock_path + "/" + predecessor) 当前节点变成了最小节点时再次尝试获取锁 return acquire_lock(zookeeper_client, lock_path) 这段代码展示了如何通过递归的方式来不断尝试获取锁。其实吧,表面上看这事不复杂,但真要弄好还挺讲究的。比如说,怎么在出错的时候不慌不忙地重试,而不是乱成一锅粥;还有啊,怎么才能防止那些烦人的死锁情况,不然程序一卡住就头疼了。这些问题都需要我们在实际开发过程中仔细考虑。 --- 四、可重用性的秘密武器 到这里,你可能会问:“既然每次获取锁都要重新创建一个新的节点,那怎么才能让锁变得可重用呢?”答案就在于ZooKeeper的“临时节点”特性。 还记得我说过临时节点会在客户端断开连接时自动删除吗?这就意味着我们可以设计一种模式,在客户端成功获取锁之后,保持与ZooKeeper的长连接状态。只要连接一直保持,锁就不会丢失,其他客户端也无法抢占它。等到任务完成或者需要释放锁的时候,再主动删除对应的节点即可。 为了更好地理解这一点,让我们看一个具体的例子。假设我们现在有一个任务队列系统,每个任务都需要加锁才能执行。以下是一个简化版的Python实现: python import time from kazoo.client import KazooClient zk = KazooClient(hosts='localhost:2181') zk.start() def process_task(task_id): lock_path = "/task_lock" lock_node = None try: 尝试获取锁 while not lock_node: lock_node = zk.create(lock_path + "/task-", ephemeral=True, sequence=True) print(f"Processing task {task_id}") time.sleep(5) 模拟任务耗时 finally: 确保无论如何都要释放锁 if lock_node: zk.delete(lock_node) process_task(1) process_task(2) 在这个例子中,我们定义了一个process_task函数来模拟处理任务的过程。每次调用该函数时,它都会尝试获取锁,并在任务完成后自动释放锁。你说的那个锁啊,因为它是个临时节点嘛,所以哪怕程序突然挂了或者被强制关闭了,这个锁自己就会乖乖消失,这样系统就不会乱套,挺靠谱的! --- 五、总结与展望 好了,到这里我们已经大致了解了ZooKeeper是如何实现分布式锁的可重用性的。其实吧,咱们从最开始琢磨分布式锁是干啥用的,然后一路研究它是怎么工作的、里面那些技术细节到底是啥,到现在为止,我觉得大家对这个话题应该已经搞得挺明白了,甚至可以说是心里有谱了! 当然啦,ZooKeeper的应用远不止于此。它还可以用来实现配置中心、Leader选举等功能。未来如果有机会的话,我很乐意继续跟大家分享更多关于它的精彩内容!如果你有任何疑问或者想法,也欢迎随时留言交流哦~编程之路漫漫,我们一起加油吧!
2025-05-16 16:15:57
83
百转千回
Nacos
...被用作配置中心,负责存储和提供服务所需的配置信息。当服务启动时,会从Nacos拉取相应的配置文件,但如果配置文件无法正确加载,则可能导致服务启动失败。因此,确保Nacos服务正常运行以及配置文件路径和权限设置正确是非常重要的。 配置中心 , 指集中管理和分发配置信息的系统或平台,旨在简化应用程序的配置管理工作。在微服务架构中,每个服务可能需要不同的配置参数,而传统的分散式配置方式难以满足大规模分布式系统的管理需求。配置中心通过统一管理所有服务的配置,可以显著降低配置管理的成本并提升效率。本文提到的Nacos就是一个典型的配置中心实例,它支持多种协议的数据交换,并且能够实时推送配置变更通知给订阅者。 微服务架构 , 一种将应用程序构建为一组小型独立部署单元的软件架构风格。每个微服务专注于完成某一项特定的功能,并通过轻量级通信机制与其他服务进行交互。相比于传统的单体架构,微服务架构具有更高的灵活性、可扩展性和容错能力。在本文中,作者正在开发一个基于微服务架构的应用程序,并利用Nacos作为配置中心来管理各个微服务的配置信息。由于微服务之间的依赖关系复杂,确保配置的一致性和可用性对于整个系统的稳定运行至关重要。
2025-04-06 15:56:57
68
清风徐来
Hive
... 大家好啊,我是你的数据工程师小A。嘿,今天咱们来聊个有点“叛逆”的事儿——你知道吗?在Hive里头,有些压缩格式虽然官方文档上明晃晃地写着“不支持”,但其实很多人还在偷偷用,像GZIP和BZIP2这些就挺典型的。这事儿听着是不是还挺有意思?相当于跟官方规矩唱反调嘛!哈哈,我知道这话听着可能有点“疯疯癫癫”的,但说实话,谁还没点被迫走出舒适区的时候呢?比如为了给硬盘腾地方,或者让数据库跑得更快一点,咱总得豁出去折腾折腾吧! 先简单介绍一下背景吧。Hive其实就像是个建在Hadoop上的“数据仓库”,它能帮我们把有条理的数据存到HDFS里,然后用类似SQL的语句去查询和处理这些数据,特别方便!Hive默认支持一些常见的压缩格式,比如Snappy、LZO等。哎呀,你要是想用GZIP或者BZIP2来存表,那可得小心点啊!没准Hive会直接给你整出个错误,连数据都不让你加载。这到底是咋回事儿呢?其实吧,这是因为这两种压缩方式的性格和Hive的理念不太合拍。简单来说,它们的玩法不一样,所以Hive就觉得有点不爽,干脆就不让你这么干了。 那么问题来了:既然Hive不支持它们,为什么我们还要去折腾这些“非主流”压缩格式呢?我的回答是:因为它们可能真的有用!比如,GZIP非常适合用于压缩单个文件,而BZIP2则在某些场景下能提供更高的压缩比。所以说嘛,官方案子虽然说了不让搞,但我们不妨大胆试试,看看这些玩意儿到底能整出啥名堂! --- 二、理论基础 GZIP vs BZIP2 vs Hive的“规则” 在深入讨论具体操作之前,我们得先搞清楚这三个东西之间的差异。嘿,先说个大家可能都知道的小秘密——GZIP可是个超火的压缩“神器”呢!它最大的特点就是又快又好用,压缩文件的速度嗖一下就搞定了,效果也还行,妥妥的性价比之王!而BZIP2则是另一种高级压缩算法,虽然压缩比更高,但速度相对较慢。相比之下,Hive好像更喜欢找那种“全能型选手”,就像Snappy这种,又快又能省资源,简直两全其美! 现在问题来了:既然Hive有自己的偏好,那我们为什么要挑战它的权威呢?答案很简单:现实世界中的需求往往比理想模型复杂得多。比如说啊,有时候我们有一堆小文件,东一个西一个的,看着就头疼,想把它们整整齐齐地打包成一个大文件存起来,这时候用GZIP就很方便啦!但要是你手头的数据量超级大,比如几百万张高清图片那种,而且你还特别在意压缩效果,希望能榨干每一丢丢空间,那BZIP2就更适合你了,它在这方面可是个狠角色! 当然,这一切的前提是我们能够绕过Hive对这些格式的限制。接下来,我们就来看看具体的解决方案。 --- 三、实践篇 如何让Hive接受GZIP和BZIP2? 3.1 GZIP的逆袭之路 让我们从GZIP开始说起。想象一下,你有个文件夹,专门用来存各种日志文件,里面的文件可多啦!不过呢,这些文件都特别小巧,大概就几百KB的样子,像是些小纸条,记录着各种小事。哎呀,要是直接把一堆小文件一股脑儿塞进HDFS里,那可就麻烦了!这么多小文件堆在一起,系统就会变得特别卡,整体性能直线下降,简直像路上突然挤满了慢吞吞的小汽车,堵得不行!要解决这个问题嘛,咱们可以先把文件用GZIP压缩一下,弄个小“压缩包”,然后再把它丢进Hive里头去。 下面是一段示例代码,展示了如何创建一个支持GZIP格式的外部表: sql -- 创建数据库 CREATE DATABASE IF NOT EXISTS log_db; -- 切换到数据库 USE log_db; -- 创建外部表并指定GZIP格式 CREATE EXTERNAL TABLE IF NOT EXISTS logs ( id STRING, timestamp STRING, message STRING ) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' STORED AS TEXTFILE -- 注意这里使用TEXTFILE而不是默认的SEQUENCEFILE LOCATION '/path/to/gzipped/files'; 看到这里,你可能会问:“为什么这里要用TEXTFILE而不是SEQUENCEFILE?”这是因为Hive默认不支持直接读取GZIP格式的数据,所以我们需要手动调整存储格式。此外,还需要确保你的Hadoop集群已经启用了GZIP解压功能。 3.2 BZIP2的高阶玩法 接下来轮到BZIP2登场了。相比于GZIP,BZIP2的压缩比更高,但它也有一个明显的缺点:解压速度较慢。因此,BZIP2更适合用于那些访问频率较低的大规模静态数据集。 下面这段代码展示了如何创建一个支持BZIP2格式的分区表: sql -- 创建数据库 CREATE DATABASE IF NOT EXISTS archive_db; -- 切换到数据库 USE archive_db; -- 创建分区表并指定BZIP2格式 CREATE TABLE IF NOT EXISTS archives ( file_name STRING, content STRING ) PARTITIONED BY (year INT, month INT) STORED AS RCFILE -- RCFILE支持BZIP2压缩 TBLPROPERTIES ("orc.compress"="BZIP2"); 需要注意的是,在这种情况下,你需要确保Hive的配置文件中启用了BZIP2支持,并且相关的JAR包已经正确安装。 --- 四、实战经验分享 踩过的坑与学到的东西 在这个过程中,我遇到了不少挫折。比如说吧,有次我正打算把一个GZIP文件塞进Hive里,结果系统直接给我整了个报错,说啥解码器找不着。折腾了半天才发现,哎呀,原来是服务器上那个GZIP工具的老版本太不给劲了,跟最新的Hadoop配不上,闹起了脾气!于是,我赶紧联系运维团队升级了相关依赖,这才顺利解决问题。 还有一个教训是关于文件命名规范的。一开始啊,我老是忘了在压缩完的文件后面加“.gz”或者“.bz2”这种后缀名,搞得 Hive 一脸懵逼,根本分不清文件是啥类型的,直接就报错不认账了。后来我才明白,那些后缀名可不只是个摆设啊,它们其实是给文件贴标签的,告诉你这个文件是啥玩意儿,是图片、音乐,还是什么乱七八糟的东西。 --- 五、总结与展望 总的来说,虽然Hive对GZIP和BZIP2的支持有限,但这并不意味着我们不能利用它们的优势。相反,只要掌握了正确的技巧,我们完全可以在这两者之间找到平衡点,满足不同的业务需求。 最后,我想说的是,作为一名数据工程师,我们不应该被工具的限制束缚住手脚。相反,我们应该敢于尝试新事物,勇于突破常规。毕竟,正是这种探索精神,推动着整个行业不断向前发展! 好了,今天的分享就到这里啦。如果你也有类似的经历或者想法,欢迎随时跟我交流哦~再见啦!
2025-04-19 16:20:43
47
翡翠梦境
转载文章
...d stub//进行数据校验,长度6~15位 if(username.trim().length()<6||username.trim().length()>15||username==null) {this.addFieldError("username", "用户名长度不合法!");}if(password.trim().length()<6||password.trim().length()>15||password==null) {this.addFieldError("password", "密码长度不合法!");} }//登陆业务逻辑public String loginMethod() {if(username.equals("chenghaoran")&&password.equals("12345678")) {ActionContext.getContext().getSession().put("user", username);return "loginOK";}else {this.addFieldError("err","用户名或密码不正确!");return "loginFail";} }//手动校验validateXxxpublic void validateLoginMethod() {//使用正则校验if(username==null||username.trim().equals("")) {this.addFieldError("username","用户名不能为空!");}else {if(!Pattern.matches("[a-zA-Z]{6,15}", username.trim())) {this.addFieldError("username", "用户名格式错误!");} }if(password==null||password.trim().equals("")) {this.addFieldError("password","密码不能为空!");}else {if(!Pattern.matches("\\d{6,15}", password.trim())) {this.addFieldError("password", "密码格式错误!");} }} } /20171105_shiyan_upanddown/src/nuc/sw/interceptor/LoginInterceptor.java package nuc.sw.interceptor;import com.opensymphony.xwork2.Action;import com.opensymphony.xwork2.ActionContext;import com.opensymphony.xwork2.ActionInvocation;import com.opensymphony.xwork2.ActionSupport;import com.opensymphony.xwork2.interceptor.AbstractInterceptor;public class LoginInterceptor extends AbstractInterceptor {@Overridepublic String intercept(ActionInvocation arg0) throws Exception {// TODO Auto-generated method stub//判断是否登陆,通过ActionContext访问SessionActionContext ac=arg0.getInvocationContext();String username=(String)ac.getSession().get("user");if(username!=null&&username.equals("chenghaoran")) {return arg0.invoke();//放行}else {((ActionSupport)arg0.getAction()).addActionError("请先登录!");return Action.LOGIN;} }} /20171105_shiyan_upanddown/src/struts.xml <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN""http://struts.apache.org/dtds/struts-2.1.7.dtd"><struts><constant name="struts.i18n.encoding" value="utf-8"/><package name="default" extends="struts-default"><interceptors><interceptor name="login" class="nuc.sw.interceptor.LoginInterceptor"></interceptor></interceptors> <action name="docUpload" class="nuc.sw.action.DocUploadAction"><!-- 使用fileUpload拦截器 --><interceptor-ref name="fileUpload"><!-- 指定允许上传的文件大小最大为50000字节 --><param name="maximumSize">50000</param></interceptor-ref><!-- 配置默认系统拦截器栈 --><interceptor-ref name="defaultStack"/><!-- param子元素配置了DocUploadAction类中savePath属性值为/upload --><param name="savePath">/upload</param><result>/showFile.jsp</result><!-- 指定input逻辑视图,即不符合上传要求,被fileUpload拦截器拦截后,返回的视图页面 --><result name="input">/uploadFile.jsp</result></action> <action name="docDownload" class="nuc.sw.action.DocDownloadAction"><!-- 指定结果类型为stream --><result type="stream"><!-- 指定下载文件的文件类型 text/plain表示纯文本 --><param name="contentType">application/msword,text/plain</param><!-- 指定下载文件的入口输入流 --><param name="inputName">inputStream</param><!-- 指定下载文件的处理方式与文件保存名 attachment表示以附件形式下载,也可以用inline表示内联即在浏览器中直接显示,默认值为inline --><param name="contentDisposition">attachment;filename="${downloadFileName}"</param><!-- 指定下载文件的缓冲区大小,默认为1024 --><param name="bufferSize">40960</param></result></action><action name="loginAction" class="nuc.sw.action.LoginAction" method="loginMethod"><result name="loginOK">/uploadFile.jsp</result><result name="loginFail">/login.jsp</result><result name="input">/login.jsp</result></action> </package></struts> /20171105_shiyan_upanddown/WebContent/login.jsp <%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%><%@ taglib prefix="s" uri="/struts-tags" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>登录页</title><s:head/></head><body><s:actionerror/><s:fielderror fieldName="err"></s:fielderror><s:form action="loginAction" method="post"> <s:textfield label="用户名" name="username"></s:textfield><s:password label="密码" name="password"></s:password><s:submit value="登陆"></s:submit></s:form></body></html> /20171105_shiyan_upanddown/WebContent/showFile.jsp <%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%><%@ taglib prefix="s" uri="/struts-tags" %><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>显示上传文档</title></head><body><center><font style="font-size:18px;color:red">上传者:<s:property value="name"/></font><table width="45%" cellpadding="0" cellspacing="0" border="1"><tr><th>文件名称</th><th>上传者</th><th>上传时间</th></tr><s:iterator value="uploadFileName" status="st" var="doc"><tr><td align="center"><a href="docDownload.action?downPath=upload/<s:property value="doc"/>"><s:property value="doc"/> </a></td><td align="center"><s:property value="name"/></td><td align="center"><s:date name="createTime" format="yyyy-MM-dd HH:mm:ss"/></td></tr></s:iterator></table></center></body></html> /20171105_shiyan_upanddown/WebContent/uploadFile.jsp <%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%><%@ taglib prefix="s" uri="/struts-tags" %><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>多文件上传</title></head><body><center><s:form action="docUpload" method="post" enctype="multipart/form-data"><s:textfield name="name" label="姓名" size="20"/><s:file name="upload" label="选择文档" size="20"/><s:file name="upload" label="选择文档" size="20"/><s:file name="upload" label="选择文档" size="20"/><s:submit value="确认上传" align="center"/></s:form></center></body></html> 本篇文章为转载内容。原文链接:https://blog.csdn.net/qq_34101492/article/details/78811741。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-11-12 20:53:42
142
转载
转载文章
...tainerID: docker://65183c1877aaec2e8427bc95609cc52677a454b56fcb24340dbd22917c23b10fexitCode: 137finishedAt: 2017-06-20T20:52:19Zreason: OOMKilledstartedAt: null 本实验里的容器可以自动重启,因此kubelet会再去启动它。输入多几次这个命令看看它是怎么 被杀掉又被启动的: kubectl get pod memory-demo-2 --namespace=mem-example 这个输出显示了容器被杀掉,被启动,又被杀掉,又被启动的过程: stevepe@sperry-1:~/steveperry-53.github.io$ kubectl get pod memory-demo-2 --namespace=mem-exampleNAME READY STATUS RESTARTS AGEmemory-demo-2 0/1 OOMKilled 1 37sstevepe@sperry-1:~/steveperry-53.github.io$ kubectl get pod memory-demo-2 --namespace=mem-exampleNAME READY STATUS RESTARTS AGEmemory-demo-2 1/1 Running 2 40s 查看Pod的历史详细信息: kubectl describe pod memory-demo-2 --namespace=mem-example 这个输出显示了Pod一直重复着被杀掉又被启动的过程: ... Normal Created Created container with id 66a3a20aa7980e61be4922780bf9d24d1a1d8b7395c09861225b0eba1b1f8511... Warning BackOff Back-off restarting failed container 查看集群里节点的详细信息: kubectl describe nodes 输出里面记录了容器被杀掉是因为一个超出内存的状况出现: Warning OOMKilling Memory cgroup out of memory: Kill process 4481 (stress) score 1994 or sacrifice child 删除Pod: kubectl delete pod memory-demo-2 --namespace=mem-example 配置超出节点能力范围的内存申请 内存的申请和限制是针对容器本身的,但是认为Pod也有容器的申请和限制是一个很有帮助的想法。 Pod申请的内存就是Pod里容器申请的内存总和,类似的,Pod的内存限制就是Pod里所有容器的 内存限制的总和。 Pod的调度策略是基于请求的,只有当节点满足Pod的内存申请时,才会将Pod调度到合适的节点上。 在这个实验里,我们创建一个申请超大内存的Pod,超过了集群里任何一个节点的可用内存资源。 这个容器申请了1000G的内存,这个应该会超过你集群里能提供的数量。 memory-request-limit-3.yaml apiVersion: v1kind: Podmetadata:name: memory-demo-3spec:containers:- name: memory-demo-3-ctrimage: vish/stressresources:limits:memory: "1000Gi"requests:memory: "1000Gi"args:- -mem-total- 150Mi- -mem-alloc-size- 10Mi- -mem-alloc-sleep- 1s 创建Pod: kubectl create -f https://k8s.io/docs/tasks/configure-pod-container/memory-request-limit-3.yaml --namespace=mem-example 查看Pod的状态: kubectl get pod memory-demo-3 --namespace=mem-example 输出显示Pod的状态是Pending,因为Pod不会被调度到任何节点,所有它会一直保持在Pending状态下。 kubectl get pod memory-demo-3 --namespace=mem-exampleNAME READY STATUS RESTARTS AGEmemory-demo-3 0/1 Pending 0 25s 查看Pod的详细信息包括事件记录 kubectl describe pod memory-demo-3 --namespace=mem-example 这个输出显示容器不会被调度因为节点上没有足够的内存: Events:... Reason Message------ -------... FailedScheduling No nodes are available that match all of the following predicates:: Insufficient memory (3). 内存单位 内存资源是以字节为单位的,可以表示为纯整数或者固定的十进制数字,后缀可以是E, P, T, G, M, K, Ei, Pi, Ti, Gi, Mi, Ki.比如,下面几种写法表示相同的数值:alue: 128974848, 129e6, 129M , 123Mi 删除Pod: kubectl delete pod memory-demo-3 --namespace=mem-example 如果不配置内存限制 如果不给容器配置内存限制,那下面的任意一种情况可能会出现: 容器使用内存资源没有上限,容器可以使用当前节点上所有可用的内存资源。 容器所运行的命名空间有默认内存限制,容器会自动继承默认的限制。集群管理员可以使用这个文档 LimitRange来配置默认的内存限制。 内存申请和限制的原因 通过配置容器的内存申请和限制,你可以更加有效充分的使用集群里内存资源。配置较少的内存申请, 可以让Pod跟任意被调度。设置超过内存申请的限制,可以达到以下效果: Pod可以在负载高峰时更加充分利用内存。 可以将Pod的内存使用限制在比较合理的范围。 清理 删除命名空间,这会顺便删除命名空间里的Pod。 kubectl delete namespace mem-example 译者:NickSu86 原文链接 本篇文章为转载内容。原文链接:https://blog.csdn.net/Aria_Miazzy/article/details/99694937。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-12-23 12:14:07
499
转载
Beego
...模块,包括路由管理、数据库 ORM、配置文件解析等,旨在帮助开发者快速构建高效稳定的 Web 应用。文中提到的配置文件解析错误主要涉及 Beego 框架对配置文件的加载和读取过程,当配置文件格式不正确时,会导致程序无法正常启动。Beego 提供了 LoadAppConfig 和 AppConfig 等工具,方便开发者管理和操作配置文件。 配置文件 , 配置文件是一种存储应用程序运行所需参数的文件,通常采用特定的格式(如 ini、json 或 yaml)。文中提到的配置文件是 Beego 框架使用的 ini 格式,包含键值对的形式定义各种配置项。例如,appname 和 port 分别定义了应用名称和监听端口号。配置文件的正确性和完整性直接影响程序的运行状态,因此需要严格检查其格式和内容。Beego 提供了专门的方法来加载和解析配置文件,确保程序能够顺利读取必要的参数。 日志记录 , 日志记录是指将程序运行过程中的重要信息(如错误、警告或调试信息)保存到文件或输出到控制台的过程。文中提到的日志记录主要用于监控配置文件加载是否成功。通过使用 Beego 提供的日志模块,开发者可以设置日志的格式和级别,例如记录日期、时间和错误发生的具体位置。当配置文件加载失败时,日志会输出详细的错误信息,帮助开发者快速定位问题。这种机制对于复杂系统的维护和故障排查至关重要,能够显著提高开发效率。
2025-04-13 15:33:12
25
桃李春风一杯酒
NodeJS
...年来,随着物联网和大数据技术的飞速发展,实时监控系统的需求日益增长。特别是在工业制造领域,企业需要对生产线上的各种参数进行实时监测,以确保产品质量和生产效率。例如,某知名汽车制造商近期宣布在其全球多个工厂部署基于 Node.js 和 WebSocket 的实时监控平台,该平台不仅能够实时采集生产设备的运行数据,还能通过智能算法预测潜在故障,从而大幅降低维护成本并提高生产稳定性。 此外,在医疗健康行业,类似的实时监控解决方案也开始崭露头角。一家专注于远程医疗的初创公司最近推出了一款基于 Node.js 的健康管理应用,用户可以通过佩戴智能手环等设备,将心率、血压等生理指标实时上传至云端,医生则可随时随地查看患者的健康状况并提供个性化建议。这一创新模式不仅改善了医疗服务的可及性,也为慢性病管理带来了新的可能性。 值得注意的是,随着《个人信息保护法》等相关法律法规的出台,企业在开发此类实时监控系统时必须格外注意数据安全与隐私保护。一方面,企业需要严格遵守数据收集、存储和传输的相关规定;另一方面,还需加强技术手段,如加密通信、匿名化处理等,以防止敏感信息泄露。正如某网络安全专家所言:“技术本身没有善恶之分,关键在于如何正确使用。”因此,在追求技术创新的同时,企业应当始终将合规性和安全性放在首位,确保技术进步真正造福于社会。 总之,Node.js 和 WebSocket 技术的应用前景十分广阔,但同时也面临着诸多挑战。只有不断探索新技术、新方法,同时坚守法律底线和社会责任,才能让这一技术更好地服务于各行各业的发展需求。
2025-05-06 16:24:48
82
清风徐来
转载文章
...以包含其他内容,例如数据表格、搜索表单或相关的logo图片。 我们可以使用该元素来写整个页面的标题部分: The most important heading on this page 同一个页面中,每一个内容区块都可以有自己的元素,例如: The most important heading on this page 在HTML5中,我们可以不使用div,而用更加语义化的footer来写: copyright sitemap contact to top 在同一个页面中可以使用多个元素,即可以用作页面整体的页脚,也可以作为一个内容区块的结尾,例如,我们可以将直接写在或是中: Section content appears here. Footer information for section. Article content appears here. Footer information for article. nav -- 作用 -- 导航栏 nav nav元素是一个可以用来作为页面导航的链接组;其中的导航元素链接到其他页面或当前页面的其他部分。并不是所有的链接组都要被放进元素;例如,在页脚中通常会有一组链接,包括服务条款、首页、版权声明等;这时使用元素是最恰当的,而不需要元素。 一直以来,我们都习惯用如下这种方式来定义导航条: Home About Blog 下面是W3C给出的一个代码示例: The Wiki Center Of Exampland Home Current Events ...more... Demos in Exampland Written by A. N. Other. Public demonstrations Demolitions ...more... Public demonstrations ...more... Demolitions ...more... ...more... Edit | Delete | Rename © copyright 1998 Exampland Emperor 关键自li,em,dl,ul,ol,footer,header,nav,aside,article section 版块 用于划分页面上的不同区域,或者划分文章里不同的节 header 页面头部或者版块(section)头部 footer 页面底部或者(section)底部 nav 导航 (包含链接 ... html5新特性-header,nav,footer,aside,article,section等各元素的详解 Html5新增了27个元素,废弃了16个元素,根据现有的标准规范,把HTML5的元素按优先级定义为结构性属性.级块性元素.行内语义性元素和交互性元素四大类. 下面是对各标签的详解,section.he ... h5中的结构元素header、nav、article、aside、section、footer介绍 结构元素不具有任何样式,只是使页面元素的的语义更加明确. header元素 header元素是一种具有引导和导航作用的的结构元素,该元素可以包含所有通常放在页面头部的内容.header元素通常用来放置 ... html5,html5教程 html5,html5教程 1.向后兼容 HTML5是这样被定义的:能向后兼容目前UA处理内容的方式.为了让语言更简单,一些老的元素和Attribute被舍弃.比如一些纯粹用于展现的元素(译注:即非语 ... 一步HTML5教程学会体系 HTML5是HTML最新的版本,万维网联盟. HTML5是下一代的HTML标准,HTML5是为了在移动设备上支持多媒体. 新特性: 绘画的canvas元素,用于媒介回放的video和audio元素,对 ... IT兄弟连 HTML5教程 了解HTML5的主流应用1 在很多人眼里,HTML5与互联网营销密切相关,但其实从开发者的角度而言,它是一种网页标准,定义了浏览器语言的编写规范.伴随HTML5标准尘埃落定,浏览器对HTML5特性的逐步支持,再加上国内对HTML ... 【转帖】39个让你受益的HTML5教程 39个让你受益的HTML5教程 闲话少说,本文作者为大家收集了网上学习HTML5的资源,期望它们可以帮助大家更好地学习HTML5. 好人啊! 不过,作者原来说的4 ... 【特别推荐】Web 开发人员必备的经典 HTML5 教程 对于我来说,Web 前端开发是最酷的职业之一,因为你可以用新的技术发挥,创造出一些惊人的东西.唯一的问题是,你需要跟上这个领域的发展脚步,因此,你必须不断的学习,不断的前进.本文将分享能够帮助您快速掌 ... HTML5教程之本地存储SessionStorage SessionStorage: 将数据保存在session对象中,所谓session是指用户在浏览某个网站时,从进入网站到浏览器关闭所经过的这段时间会话,也就是用户浏览这个网站所花费的时间就是sess ... 随机推荐 【转】MySQL索引背后的数据结构及算法原理 摘要 本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BT ... IIS7 / IIS7.5 URL 重写 HTTP 重定向到 HTTPS(转) 转自: http://www.cnblogs.com/yipu/p/3880518.html 1.购买SSL证书,参考:http://www.cnblogs.com/yipu/p/3722135. ... OpenGL的glViewPort窗口设置函数实现分屏 之前实现过全景图片查看(OpenGL的几何变换3之内观察全景图),那么我们需要进行分屏该如何实现呢?如下图: 没错就是以前提过的glViewPort函数,废话不多说了,我直接上代码: //从这里开始进 ... hdu 4764 Stone (巴什博弈,披着狼皮的羊,小样,以为换了身皮就不认识啦) 今天(2013/9/28)长春站,最后一场网络赛! 3~5分钟后有队伍率先发现伪装了的签到题(博弈) 思路: 与取石头的巴什博弈对比 题目要求第一个人取数字在[1,k]间的某数x,后手取x加[1,k] ... android报表图形引擎(AChartEngine)demo解析与源码 AchartEngine支持多种图表样式,本文介绍两种:线状表和柱状表. AchartEngine有两种启动的方式:一种是通过ChartFactory.getView()方式来直接获取到view ... CSS长度单位及区别 em ex px pt in 1. css相对长度单位 Ø em 元素的字体高度 Ø ex 字体x的高度 Ø px ... es6的箭头函数 1.使用语法 : 参数 => 函数语句; 分为以下几种形式 : (1) ()=>语句 ( )=> statement 这是一种简写方法省略了花括号和return 相当于 ()=&g ... pdfplumber库解析pdf格式 参考地址:https://github.com/jsvine/pdfplumber 简单的pdf转换文本: import pdfplumber with pdfplumber.open(path) a ... KMP替代算法——字符串Hash 很久以前写的... 今天来谈谈一种用来替代KMP算法的奇葩算法--字符串Hash 例题:给你两个字符串p和s,求出p在s中出现的次数.(字符串长度小于等于1000000) 字符串的Hash 根据字面意 ... SSM_CRUD新手练习(5)测试mapper 上一篇我们使用逆向工程生成了所需要的bean.dao和对应的mapper.xml文件,并且修改好了我们需要的数据库查询方法. 现在我们来测试一下DAO层,在test包下新建一个MapperTest.j ... 本篇文章为转载内容。原文链接:https://blog.csdn.net/weixin_35666639/article/details/118169985。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-07-16 11:42:34
254
转载
Sqoop
近期,随着大数据技术的快速发展,数据迁移工具的选择成为越来越多企业关注的重点。除了Sqoop之外,市场上涌现出了一系列新的工具和技术方案,比如Apache NiFi和Talend Data Integration,它们在数据流管理和实时处理方面展现出了更强的能力。NiFi以其直观的图形界面和灵活的数据路由功能受到开发者的青睐,而Talend则提供了更为全面的企业级支持和服务。这些工具不仅提升了数据迁移的效率,还增强了数据的安全性和可靠性,为企业在数字化转型过程中提供了更多选择。 此外,随着云计算的普及,云原生数据迁移工具也逐渐成为主流趋势。例如,AWS Database Migration Service(DMS)和Google Cloud Data Transfer Service等服务,允许用户在不同的云平台之间无缝迁移数据,同时提供自动化的监控和故障恢复机制。这种云原生解决方案大幅降低了传统本地部署工具的复杂度,使得中小企业也能轻松实现大规模数据迁移。 值得注意的是,数据隐私法规的变化对数据迁移工具提出了更高的合规要求。欧盟的《通用数据保护条例》(GDPR)和美国加州的《消费者隐私法》(CCPA)等法律框架,都对企业如何收集、存储和传输个人数据作出了严格规定。因此,企业在选用数据迁移工具时,不仅要考虑技术层面的兼容性和稳定性,还需要确保工具符合最新的法律法规,以避免潜在的法律风险。 在未来,随着人工智能和机器学习技术的进步,数据迁移工具将进一步智能化。例如,利用AI算法预测数据迁移过程中可能出现的问题,并提前采取措施优化流程,将成为行业发展的新方向。同时,开源社区的持续贡献也将推动工具的创新,为企业提供更多低成本、高效率的解决方案。总之,数据迁移领域的技术创新正在加速演进,为企业的数据管理带来了前所未有的机遇和挑战。
2025-03-22 15:39:31
94
风中飘零
Hadoop
...,朋友们!如果你对大数据处理感兴趣,那你一定听说过Hadoop这个名字。嘿,作为一个码农,我跟Hadoop的初次见面真的把我惊呆了!它的功能太牛了,感觉就像发现了一个全新的世界,简直太酷了吧!简单说呢,Hadoop就是一个开源的“大数据管家”,专门负责存东西、弄数据,而且不管数据多到啥程度,它都能应付得漂漂亮亮的!它就像是一个超级仓库,可以轻松应对各种规模的数据任务。 为什么Hadoop这么受欢迎呢?因为它解决了传统数据库在处理大规模数据时的瓶颈问题。比如说啊,你在一家电商公司当数据分析师,每天的工作就是跟上亿条用户的点击、浏览、下单这些行为记录打交道,简直就像在海量的信息海洋里淘宝一样!如果用传统的数据库,可能早就崩溃了。但Hadoop不一样,它可以将这些数据分散到多个服务器上进行并行处理,效率杠杠的! 不过,Hadoop的魅力远不止于此。嘿,大家好!今天我想跟你们分享一个关于Hadoop的超棒功能——它居然能让你在不同的访问控制协议之间轻松切换文件!是不是听着就很带感?哎呀,是不是觉得这事听着有点绕?别慌,我这就用大白话给你说道说道,保证你一听就明白! --- 二、什么是跨访问控制协议迁移? 首先,我们得明白什么是访问控制协议。简单说,就是规定谁可以访问你的数据以及他们能做些什么的规则。好比说啊,你有个公共文件柜,你想让一些人只能打开看看里面的东西,啥都不能动;但另外一些人呢,不仅能看,还能随便改,甚至直接把东西清空或者拿走。这就是访问控制协议的作用。 那么,“跨访问控制协议迁移”又是什么意思呢?想象一下,你有两个不同的系统,它们各自有自己的访问控制规则。比如说,一个是Linux那边的ACL(访问控制列表)系统,另一个则是Windows里的NTFS权限系统,两者各有各的玩法。现在,你要把文件从一个系统迁移到另一个系统,而且你还想保留原来的访问控制设置。这就需要用到跨访问控制协议迁移的技术了。 为什么要关心这个功能呢?因为现实世界中,企业往往会有多种操作系统和存储环境。要是你对文件的权限管理不当,那可就麻烦了,要么重要数据被泄露出去,要么一不小心就把东西给搞砸了。而Hadoop通过其强大的灵活性,完美地解决了这个问题。 --- 三、Hadoop如何实现跨访问控制协议迁移? 接下来,让我们来看看Hadoop是如何做到这一点的。其实,这主要依赖于Hadoop的分布式文件系统(HDFS)和它的API库。为了更好地理解,我们可以一步步来分析。 3.1 HDFS的基本概念 HDFS是Hadoop的核心组件之一,它是用来存储大量数据的分布式文件系统。这就像是一个超大号的硬盘,不过它有点特别,不是集中在一个地方存东西,而是把数据切成小块,分散到不同的“小房间”里去。这样做的好处是即使某个节点坏了,也不会影响整个系统的运行。 HDFS还提供了一套丰富的接口,允许开发者自定义文件的操作行为。这就为实现跨访问控制协议迁移提供了可能性。 3.2 实现步骤 实现跨访问控制协议迁移大致分为以下几个步骤: (1)读取源系统的访问控制信息 第一步是获取源系统的访问控制信息。比如,如果你正在从Linux系统迁移到Windows系统,你需要先读取Linux上的ACL配置。 java // 示例代码:读取Linux ACL import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import java.io.IOException; public class AccessControlReader { public static void main(String[] args) throws IOException { Path path = new Path("/path/to/source/file"); FileSystem fs = FileSystem.get(new Configuration()); // 获取ACL信息 String acl = fs.getAclStatus(path).toString(); System.out.println("Source ACL: " + acl); } } 这段代码展示了如何使用Hadoop API读取Linux系统的ACL信息。可以看到,Hadoop已经为我们封装好了相关的API,调用起来非常方便。 (2)转换为目标系统的格式 接下来,我们需要将读取到的访问控制信息转换为目标系统的格式。比如,将Linux的ACL转换为Windows的NTFS权限。 java // 示例代码:模拟ACL到NTFS的转换 public class AclToNtfsConverter { public static void convert(String linuxAcl) { // 这里可以编写具体的转换逻辑 System.out.println("Converting ACL to NTFS: " + linuxAcl); } } 虽然这里只是一个简单的打印函数,但实际上你可以根据实际需求编写复杂的转换算法。 (3)应用到目标系统 最后一步是将转换后的权限应用到目标系统上。这一步同样可以通过Hadoop提供的API来完成。 java // 示例代码:应用NTFS权限 public class NtfsPermissionApplier { public static void applyPermissions(Path targetPath, String ntfsPermissions) { try { // 模拟应用权限的过程 System.out.println("Applying NTFS permissions to " + targetPath.toString() + ": " + ntfsPermissions); } catch (Exception e) { e.printStackTrace(); } } } 通过这三个步骤,我们就完成了从源系统到目标系统的访问控制协议迁移。 --- 四、实战演练 一个完整的案例 为了让大家更直观地理解,我准备了一个完整的案例。好啦,想象一下,我们现在要干的事儿就是把一个文件从一台Linux服务器搬去Windows服务器,而且还得保证这个文件在新家里的“门禁权限”跟原来一模一样,不能搞错! 4.1 准备工作 首先,确保你的开发环境中已经安装了Hadoop,并且配置好相关的依赖库。此外,还需要准备两台机器,一台装有Linux系统,另一台装有Windows系统。 4.2 编写代码 接下来,我们编写代码来实现迁移过程。首先是读取Linux系统的ACL信息。 java // 读取Linux ACL Path sourcePath = new Path("/source/file.txt"); FileSystem linuxFs = FileSystem.get(new Configuration()); String linuxAcl = linuxFs.getAclStatus(sourcePath).toString(); System.out.println("Linux ACL: " + linuxAcl); 然后,我们将这些ACL信息转换为NTFS格式。 java // 模拟ACL到NTFS的转换 AclToNtfsConverter.convert(linuxAcl); 最后,将转换后的权限应用到Windows系统上。 java // 应用NTFS权限 Path targetPath = new Path("\\\\windows-server\\file.txt"); NtfsPermissionApplier.applyPermissions(targetPath, "Full Control"); 4.3 执行结果 执行完上述代码后,你会发现文件已经被成功迁移到了Windows系统,并且保留了原有的访问控制设置。是不是很神奇? --- 五、总结与展望 通过这篇文章,我相信你对Hadoop支持文件的跨访问控制协议迁移有了更深的理解。Hadoop不仅是一个强大的工具,更是一种思维方式的转变。它就像个聪明的老师,不仅教我们怎么用分布式的思路去搞定问题,还时不时敲打我们:嘿,别忘了数据的安全和规矩可不能丢啊! 未来,随着技术的发展,Hadoop的功能会越来越强大。我希望你能继续探索更多有趣的话题,一起在这个充满挑战的世界里不断前行! 加油吧,程序员们!
2025-04-29 15:54:59
80
风轻云淡
Redis
...你有个超大的储物间(数据库或者其他服务),里面塞满了各种好玩意儿(数据),想拿啥就能拿啥!嘿,想象一下,现在有一群小毛贼(服务实例)都盯上了你的那些值钱的小宝贝,可不能让他们随便进来顺手牵羊啊!所以呢,你就得准备一把“神奇的钥匙”(锁),谁要是想进去拿东西,就必须先拿到这把钥匙才行。没有钥匙?不好意思,请自觉退散吧! 为什么要用分布式锁呢?因为在线上系统里,多台机器可能会同时操作同一个资源,比如抢购商品这种场景。如果没有锁机制的话,就可能出现重复下单、库存超卖等问题。分布式锁嘛,简单说就是抢车位的游戏规则——在同一时间里,只能有一个家伙抢到那个“资源位”,别的家伙就只能乖乖排队等着轮到自己啦! 不过说起来容易做起来难啊,尤其是在分布式环境下,网络延迟、机器宕机等问题会带来各种意想不到的情况。嘿,今天咱们就来唠唠,在Redis这个超级工具箱里,怎么才能整出个靠谱的分布式锁! --- 2. Redis为什么适合用来做分布式锁? 嘿,说到Redis,相信很多小伙伴都对它不陌生吧?Redis是一个基于内存的高性能键值存储系统,速度贼快,而且支持多种数据结构,比如字符串、哈希表、列表等等。最重要的是,它提供了原子性的操作指令,比如SETNX(Set if Not Exists),这让我们能够轻松地实现分布式锁! 让我给你们讲个小故事:有一次我尝试用数据库来做分布式锁,结果发现性能特别差劲,查询锁状态的SQL语句每次都要扫描整个表,效率低得让人抓狂。换了Redis之后,简直像开了挂一样,整个系统都丝滑得不行!Redis这玩意儿不光跑得快,还自带一堆黑科技,像什么过期时间、消息订阅啥的,这些功能简直就是搞分布式锁的神器啊! 所以,如果你也在纠结选什么工具来做分布式锁,强烈推荐试试Redis!接下来我会结合实际案例给你们展示具体的操作步骤。 --- 3. 实现分布式锁的基本思路 首先,我们要明确分布式锁需要满足哪些条件: 1. 互斥性 同一时刻只能有一个客户端持有锁。 2. 可靠性 即使某个客户端崩溃了,锁也必须自动释放,避免死锁。 3. 公平性 排队等待的客户端应该按照请求顺序获取锁。 4. 可重入性(可选) 允许同一个客户端多次获取同一个锁。 现在我们就来一步步实现这些功能。 示例代码 1:最基本的分布式锁实现 python import redis import time def acquire_lock(redis_client, lock_key, timeout=10): 尝试加锁,设置过期时间为timeout秒 result = redis_client.set(lock_key, "locked", nx=True, ex=timeout) return bool(result) def release_lock(redis_client, lock_key): 使用Lua脚本来保证解锁的安全性 script = """ if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end """ redis_client.eval(script, keys=[lock_key], args=["locked"]) 这段代码展示了最基础的分布式锁实现方式。我们用set命令设置了两个参数:一个是NX,意思是“只在key不存在的时候才创建”,这样就能避免重复创建;另一个是EX,给这个锁加了个过期时间,相当于设了个倒计时,万一客户端挂了或者出问题了,锁也能自动释放,就不会一直卡在那里变成死锁啦。最后,解锁的时候我们用了Lua脚本,这样可以保证操作的原子性。 --- 4. 如何解决锁的隔离性问题? 诶,说到这里,问题来了——如果两个不同的业务逻辑都需要用到同一个锁怎么办?比如订单系统和积分系统都想操作同一个用户的数据,这时候就需要考虑锁的隔离性了。换句话说,我们需要确保不同业务逻辑之间的锁不会互相干扰。 示例代码 2:基于命名空间的隔离策略 python def acquire_namespace_lock(redis_client, namespace, lock_name, timeout=10): 构造带命名空间的锁名称 lock_key = f"{namespace}:{lock_name}" result = redis_client.set(lock_key, "locked", nx=True, ex=timeout) return bool(result) def release_namespace_lock(redis_client, namespace, lock_name): lock_key = f"{namespace}:{lock_name}" script = """ if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end """ redis_client.eval(script, keys=[lock_key], args=["locked"]) 在这个版本中,我们在锁的名字前面加上了命名空间前缀,比如orders:place_order和points:update_score。这样一来,不同业务逻辑就可以使用独立的锁,避免相互影响。 --- 5. 进阶 如何处理锁竞争与性能优化? 当然啦,现实中的分布式锁并不会总是那么顺利,有时候会出现大量请求同时争抢同一个锁的情况。这时我们可能需要引入队列机制或者批量处理的方式来降低系统的压力。 示例代码 3:使用Redis的List模拟队列 python def enqueue_request(redis_client, queue_key, request_data): redis_client.rpush(queue_key, request_data) def dequeue_request(redis_client, queue_key): return redis_client.lpop(queue_key) def process_queue(redis_client, lock_key, queue_key): while True: 先尝试获取锁 if not acquire_lock(redis_client, lock_key): time.sleep(0.1) 等待一段时间再重试 continue 获取队列中的第一个请求并处理 request = dequeue_request(redis_client, queue_key) if request: handle_request(request) 释放锁 release_lock(redis_client, lock_key) 这段代码展示了如何利用Redis的List结构来管理请求队列。想象一下,好多用户一起抢同一个东西,场面肯定乱哄哄的对吧?这时候,咱们就让他们老老实实排成一队,然后派一个专门的小哥挨个儿去处理他们的请求。这样一来,大家就不会互相“打架”了,事情也能更顺利地办妥。 --- 6. 总结与反思 兄弟们,通过今天的讨论,我相信大家都对如何在Redis中实现分布式锁有了更深刻的理解了吧?虽然Redis本身已经足够强大,但我们仍然需要根据实际需求对其进行适当的扩展和优化。比如刚才提到的命名空间隔离、队列机制等,这些都是非常实用的小技巧。 不过呢,我也希望大家能记住一点——技术永远不是一成不变的。业务越做越大,技术也日新月异的,咱们得不停地充电,学点新鲜玩意儿,试试新招数才行啊!就像今天的分布式锁一样,也许明天就会有更高效、更优雅的解决方案出现。所以,保持好奇心,勇于探索未知领域,这才是程序员最大的乐趣所在! 好了,今天就聊到这里啦,祝大家在编程的路上越走越远!如果有任何疑问或者想法,欢迎随时找我交流哦~
2025-04-22 16:00:29
59
寂静森林
转载文章
...calhost',数据库地址'DB_NAME':'douyu',数据库名称''DB_TABLE':'douyu'数据库表}MongoDB初始化client = pymongo.MongoClient(config['DB_URL'])mango_db = client[config['DB_NAME']]MongoDB存储def save_to_mango(result):if mango_db[config['DB_TABLE']].insert_one({'vid':result}):print('成功存储到MangoDB')return Truereturn FalseMongoDB验证重复def check_to_mongo(vid):count = mango_db[config['DB_TABLE']].find({'vid':vid}).count()if count==0:return Falsereturn True删除文件def del_file(page):if os.path.exists(page): 删除文件,可使用以下两种方法。os.remove(page) os.unlink(my_file)else:print('no such file:%s' % page)循环列表删除文件def loop_del_file(arr):for item in arr:del_file(item)请求器def get_content_requests(url):headers = {}headers['user-agent']='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36'headers['cookie'] = 'dy_did=07f83a57d1d2e22942e0883200001501; acf_did=07f83a57d1d2e22942e0883200001501; Hm_lvt_e99aee90ec1b2106afe7ec3b199020a7=1556514266,1557050422,1557208315; acf_auth=; acf_auth_wl=; acf_uid=; acf_nickname=; acf_username=; acf_own_room=; acf_groupid=; acf_notification=; acf_phonestatus=; _dys_lastPageCode=page_video,page_video; Hm_lpvt_e99aee90ec1b2106afe7ec3b199020a7=1557209469; _dys_refer_action_code=click_author_video_cate2'try:req_content = requests.get(url,headers = headers)if req_content.status_code == 200:return req_contentprint('请求失败:',url)return Noneexcept:print('请求失败:', url)return None把时间换算成秒def str_to_int(time):try:time_array = time.split(':')time_int = (int(time_array[0])60)+int(time_array[1])return time_intexcept:print('~~~~~计算视频时间失败~~~~~')return None提取需要采集的数据def get_list(html,type = 1):data = []try:list_json = json.loads(str(html))for om in list_json['data']['list']:gtime = str_to_int(om['video_str_duration'])if gtime > config['TIME_START'] and gtime < config['TIME_ENT']:if type == 2:data.append({'title': om['title'], 'vid': om['url'].split('show/')[1]})else:data.append({'title': om['title'], 'vid': om['hash_id']})return dataexcept:print('~~~~~数据提取失败~~~~~')return None解析playlist.m3u8def get_ts_list(m3u8):data = []try:html_m3u8_json = json.loads(m3u8)m3u8_text = get_content_requests(html_m3u8_json['data']['video_url'])m3u8_vurl =html_m3u8_json['data']['video_url'].split('playlist.m3u8?')[0]if m3u8_text:get_text = re.findall(',\n(.?).ts(.?)\n',m3u8_text.text,re.S)for item in get_text:data.append(m3u8_vurl+item[0]+'.ts'+item[1])return datareturn Noneexcept:print('~~~~~解析playlist.m3u8失败~~~~~')return None 杀死moviepy产生的特定进程def killProcess(): 处理python程序在运行中出现的异常和错误try: pids方法查看系统全部进程pids = psutil.pids()for pid in pids: Process方法查看单个进程p = psutil.Process(pid) print('pid-%s,pname-%s' % (pid, p.name())) 进程名if p.name() == 'ffmpeg-win64-v4.1.exe': 关闭任务 /f是强制执行,/im对应程序名cmd = 'taskkill /f /im ffmpeg-win64-v4.1.exe 2>nul 1>null' python调用Shell脚本执行cmd命令os.system(cmd)except:pass下载.ts文件def download_ts(m3u8_list,name):try:if not os.path.exists(config['FILE_PATH']):os.makedirs(config['FILE_PATH'])if not os.path.exists(config['TS_PATH']):os.makedirs(config['TS_PATH'])if os.path.exists(config['FILE_PATH']+name+'.mp4'):name = name+'_'+str(int(time.time()))print('开始下载:',name)L = []R = []for p in m3u8_list:ts_find = get_content_requests(p)file_ts = '{0}{1}.ts'.format(config['TS_PATH'],md5(ts_find.content).hexdigest())with open(file_ts,'wb') as f:f.write(ts_find.content)R.append(file_ts)hebing = VideoFileClip(file_ts)L.append(hebing)killProcess()print('下载完成:',file_ts)mp4file = '{0}{1}.mp4'.format(config['FILE_PATH'],name)final_clip = concatenate_videoclips(L)final_clip.to_videofile(mp4file, fps=24, remove_temp=True)killProcess()loop_del_file(R)print('\n下载完成:',name)print('')return Trueexcept:print('~~~~~合成.ts文件失败~~~~~')return None下载视频列表def list_get_kong(list_json):for item in list_json:y = Trueif config['CHECKID']:if check_to_mongo(item['vid']):print('~~~~~检测到重复项~~~~~')y = Falseif y:get_show_html = get_content_requests('https://vmobile.douyu.com/video/getInfo?vid=' + item['vid'])if get_show_html:m3u8_list = get_ts_list(get_show_html.text)if m3u8_list:download = download_ts(m3u8_list, item['title'])if download: save_to_mango(item['vid'])time.sleep(config['TIME_GE'])控制器def main(page):if config['TYPE']==1:print('~~~~~按用户ID采集~~~~~')listurl = 'https://v.douyu.com/video/author/getAuthorVideoListByNew?up_id={0}&cate2_id=0&limit=30&page={1}'.format(config['UID'],page)get_list_html = get_content_requests(listurl)if get_list_html:list_json = get_list(get_list_html.text,1)if list_json:list_get_kong(list_json)else:print('~~~~~按列表ID采集~~~~~')listurl = 'https://v.douyu.com/video/video/listData?page={1}&cate2Id={0}&action=new'.format(config['CID'],page)get_list_html = get_content_requests(listurl)if get_list_html:list_json = get_list(get_list_html.text,2)if list_json:list_get_kong(list_json)初始化if __name__=='__main__':if config['POOL']:groups = [x for x in range(config['PAGE_START'],config['PAGE_END']+1)]pool = Pool()pool.map(main, groups)else:for item in range(config['PAGE_START'],config['PAGE_END']+1):main(item)print('~~~~~已经完成【所有操作】~~~~~') 总结:众所周知,BiliBili是一个学习的网站! 本篇文章为转载内容。原文链接:https://blog.csdn.net/qq_35875470/article/details/89857445。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-12-18 11:34:00
120
转载
转载文章
...riadb 3.登录数据库,查看字符编码mysql -uroot -p输入 \s 查看编码 7. mysql常用命 desc 查看表结构create database 数据库名create table 表名查看如何创建db的show create database 库名 查看如何创建table结构的show create table 表名; 修改mysql的密码set password = PASSWORD('redhat'); 创建mysql的普通用户,默认权限非常低create user zhang@'%' identified by '123456'; 查询mysql数据库中的用户信息use mysql;select host,user,password from user; 7. 给用户添加权限命令 对所有库和所有表授权所有权限grant all privileges on . to 账户@主机名 给zhang用户授予所有权限grant all privileges on . to zhang@'%'; 刷新授权表flush privileges; 8. 给用户添加权限命令 给zhangsan用户授予所有权限grant all privileges on . to zhangsan@'%'; 给与root权限授予远程登录的命令 'centos这是密码随意设置grant all privileges on . to root@'%' identified by '123456'; 此时可以在windows登录linux的数据库 连接服务器的mysqlmysql -uyining -p -h 服务器的地址 9. 数据备份与恢复 导出当前数据库的所有db,到一个文件中1.mysqldump -u root -p --all-databases > /data/AllMysql.dump2.登录mysql 导入数据mysql -u root -p> source /data/AllMysql.dump3.通过命令导入数据 在登录时候,导入数据文件,一样可以写入数据mysql -uroot -p < /data/AllMysql.dump 10. 修改Mariadb存储路径 10.1 首先确定MariaDB数据库能正常运行,确定正常后关闭服务 systemctl stop mariadb 10.2 建立要更改数据存放的目录,如:我这单独分了一个区/data存放MariaDB的数据 mkdir /data/mysql_data chown -R mysql:mysql /data/mysql_data 10.3 复制默认数据存放文件夹到/data/mysql_data cp -a /var/lib/mysql /data/mysql_data 10.4 修改/etc/my.cnf.d/server.cnf vim /etc/my.cnf.d/server.cnf 在[mysqld]标签下添加如下内容 datadir=/data/mysql_data/mysqlsocket=/var/lib/mysql/mysql.sockdefault-character-set=utf8character_set_server=utf8slow_query_log=onslow_query_log_file=/data/mysql_data/slow_query_log.loglong_query_time=2 10.5 配置MariaDB慢查询 touch /data/mysql_data/slow_query_log.logchown mysql:mysql /data/mysql_data/slow_query_log.log 10.6 重启数据库 systemctl start mariadb 10.7 注意: 1、配置文件my.cnf存在,但是修改的并不是my.cnf,而是/etc/my.cnf.d/server.cnf; 2、并没有更改mysql.sock的路径配置; 3、没有修改/etc/init.d/mysql中的内容; 4、没有修改mysql_safe中的内容; 5、增加了数据库的慢查询配置。 11. Mariadb主从复制 11.1 主从库初始化 这条命令可以初始化mysql,删除匿名用户,设置root密码等等....mysql_secure_installation1.输入当前密码,初次安装后是没有密码的,直接回车2.询问是否使用 'unix_socket' 进行身份验证: n3.为 root 设置密码:y4.输入 root 的新密码: root5.确认输入 root 的新密码: root6.是否移除匿名用户,这个随意,建议删除: y7.拒绝用户远程登录,这个建议开启:n8.删除 test 库,可以保留:n9.重新加载权限表:y 11.2 修改主库配置 [root@mster mysql] grep -Ev "^$|^" /etc/my.cnf.d/server.cnf[server][mysqld]character-set-server=utf8collation-server=utf8_general_ciserver_id = 13 一组主从组里的每个id必须是唯一值。推荐用ip位数log-bin= mysql-bin 二进制日志,后面指定存放位置。如果只是指定名字,默认存放在/var/lib/mysql下lower_case_table_names=1 不区分大小写binlog-format=ROW 二进制日志文件格式log-slave-updates=True slave更新是否记入日志sync-master-info=1 值为1确保信息不会丢失slave-parallel-threads=3 同时启动多少个复制线程,最多与要复制的数据库数量相等即可binlog-checksum=CRC32 效验码master-verify-checksum=1 启动主服务器效验slave-sql-verify-checksum=1 启动从服务器效验[galera][embedded][mariadb][mariadb-10.6][root@mster-k8s mysql] 11.2 修改从库配置 [mysqld]character-set-server=utf8collation-server=utf8_general_ciserver_id=14log-bin= mysql-bin log-bin是二进制文件relay_log = relay-bin 中继日志, 后面指定存放位置。如果只是指定名字,默认存放在/var/lib/mysql下lower_case_table_names=1 11.3 重启主库和从库服务 systemctl restart mariad 11.4 master节点配置 MariaDB [huawei]> grant replication slave, replication client on . to 'liu'@'%' identified by '123456';Query OK, 0 rows affected (0.001 sec)MariaDB [huawei]> show master status;+------------------+----------+--------------+------------------+| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |+------------------+----------+--------------+------------------+| mysql-bin.000001 | 4990 | | |+------------------+----------+--------------+------------------+1 row in set (0.000 sec)MariaDB [huawei]> select binlog_gtid_pos('mysql-bin.000001', 4990 );+-------------------------------------------+| binlog_gtid_pos('mysql-bin.000001', 4990) |+-------------------------------------------+| 0-13-80 |+-------------------------------------------+1 row in set (0.000 sec)MariaDB [huawei]> flush privileges; 11.5 slave节点配置 MariaDB [(none)]> set global gtid_slave_pos='0-13-80';Query OK, 0 rows affected (0.004 sec)MariaDB [(none)]> change master to master_host='101.34.141.216',master_user='liu',master_password='123456',master_use_gtid=slave_pos;Query OK, 0 rows affected (0.008 sec)MariaDB [(none)]> start slave;Query OK, 0 rows affected (0.005 sec)MariaDB [(none)]> 11.6 验证salve状态 MariaDB [(none)]> show slave status\G 1. row Slave_IO_State: Waiting for master to send eventMaster_Host: 101.34.141.216Master_User: liuMaster_Port: 3306Connect_Retry: 60Master_Log_File: mysql-bin.000001Read_Master_Log_Pos: 13260Relay_Log_File: relay-bin.000002Relay_Log_Pos: 10246Relay_Master_Log_File: mysql-bin.000001Slave_IO_Running: YesSlave_SQL_Running: YesReplicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0Last_Error: Skip_Counter: 0Exec_Master_Log_Pos: 13260Relay_Log_Space: 10549Until_Condition: NoneUntil_Log_File: Until_Log_Pos: 0Master_SSL_Allowed: NoMaster_SSL_CA_File: 本篇文章为转载内容。原文链接:https://blog.csdn.net/l363130002/article/details/126121255。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-07-12 10:11:01
311
转载
转载文章
...02 复习 显示所有数据 show databases; 创建新数据库,设置编码方式utf8 create database demo2 default charset utf8; 显示创建数据的语句 show create database demo2; 删除数据库 drop database demo2; 选择使用指定的数据库 use demo1; 查看库中所有表 show tables; 创建表 create table book(bid int(4) primary key comment '书id', bname varchar(50) comment '书名',pub varchar(50) comment '出版社',author varchar(50) comment '作者' )engine=myisam charset=utf8; 所有字段名,使用,所有的字符串使用''或者"" 查看建表语句 show create table book; 查看表结构 desc book; 修改表名 rename table book to book1; 修改表属性 ,引擎和字符集 alter table book1 engine=innodb charset=utf8; 添加字段 first after alter table book1 add(type varchar(20) comment '类型',numinput int(10) comment '进货量',numstore int(10) comment '库存量'); 修改字段名 bid bno alter table book1 change bid bno int(4); 修改顺序 pub 放到author后面 alter table book1 modify pub varchar(50) after author; 修改数据类型 bno int(4) -->int(10) alter table book1 modify bno int(10); 删除字段 alter table book1 drop 字段名; 删除表 drop table 表名; 插入语句 insert into book1(bno,bname,author,type) values(1001,'斗破苍穹','天蚕土豆','玄幻');insert into book1(bno,bname,author,type) values(1002,'全职高手','蝴蝶兰','网游竞技');insert into book1(bno,bname,author,type) values(1003,'鬼吹灯','天下霸唱','恐怖');insert into book1(bno,bname,author,type)values(1004,'西游记','吴承恩','4大名著');insert into book1(bno,bname,author,type)values(1005,'java基础','王克晶','达内学习手册'); update语句 把1005号书,修改成'天线宝宝',作者不详,类型少儿 把1004号书修改成'天龙八部',作者金庸,类型武侠 update book1 set bname="天线宝宝",author="作者不详",type="少儿" where bno=1005; 删除类型是'恐怖'的所有书籍 删除全表记录 删除表格 修改book名称为book_item rename table book to book_item; 在表格尾部添加字段price double(7,2) alter table book_item add price double(7,2); 把price字段的位置放到author之后 alter table book_item modify price double(7,2) after author; 把表中存在的数据添加价格,每本书都在100~1000之间,自定 update book_item set price=199 where bno=1001; 修改1001的价格为500元 把所有字段的null字段补全 update book_item set pub="达内出版社",numinput=500,numstore=100 where pub is null; 删除价格小于150的所有条目 删除所有数据 SQL分类 数据定义语言 DDL 重点 数据操纵语言 DML 重点 增 删 改 数据查询语言 DQL select 查 事务控制语言 TCL 数据库控制语言 DCL 数据定义语言 DDL - 负责数据结构定义,与创建数据库对象的语言- 常用create alter drop- DDL不支持事务,DDL语句执行之后,不能回滚 数据操纵语言 DML - 对数据库中更改数据操作的语句- select insert update delete--> CRUD 增删改查- 通常把select相关操作,单独出来,称之为DQL- DML支持事务,在非自动提交模式时,可以利用rollback回滚操作. 数据查询语言 DQL - 筛选,分组,连表查询 面试重点 TCL 和 DCL - 事务控制语句TCL- 负责实现数据库中事务支持的语言,commit rollback savepoint等指令- DCL数据库控制语言- 管理数据库的授权,角色控制等,grant(授权),revoke(取消授权) 练习: 案例:创建一张表customer(顾客) create table customer(cid int(4) primary key comment '顾客编号',cname varchar(50) comment '顾客姓名',sex char(5) comment '顾客性别',address varchar(50) comment '地址',phone varchar(11) comment '手机',email varchar(50) comment '邮箱'); show create table customer; 插入5条数据 insert into customer values(1001,'小明','男','楼上18号','123','123@163.com');insert into customer values(1002,'小红','女','楼上17号','1234','1234@163.com');insert into customer values(1003,'老王','男','楼上18号隔壁','1234','1234@163.com');insert into customer values(1004,'老宋','男','楼上17号隔壁','1234','1234@163.com');insert into customer values(1005,'小马','女','楼上17号隔壁','1234','1234@163.com'); -1 修改一条数据的姓名 小红的姓名 -2 修改一条数据的性别 老王的性别 -3 修改一条数据的电话 1001号的电话 -4 修改一条数据的邮箱 邮箱为123@163.com,改成323@163.com -5 查询性别为 男的所有数据 select from customer where sex="男"; -6 自定义DDL操作的需求,5道题,可以同上面book表的操作 数据库数据类型 主要包括5大类 整数类型 int, big int 浮点数类型 double decimal 字符串类型 char varchar text 日期类型 date datetime timestamp time year... 其他数据类型 set.... 字符串 - char(固定长度) 定长字符串 最多255个字节- 定多少长度,就占用多少长度- 多了放不进去,少了用空格补全- 不认识内容尾部的空格- varchar(最大长度) 变长字符串 最大65535字节,但是使用一般不超过255- 只要不超过定的长度,都可以放进去- 以内容真实长度为准- 认识内容尾部的空格- text 最大65535字节- blob 大数据对象,以二进制(字节)的方式存储 整数 tinyint 1字节 smallint 2字节 int 4字节 bigint 8字节 int(6)影响的是查询时显示长度(zerofill)不影响数据的保存长度 create table t1(id1 int,id2 int(5)); insert into t1 values(111111,111111); alter table t1 modify id1 int zerofill; alter table t1 modify id2 int(5) zerofill; insert into t1 values (1,1); float 4字节 double 8字节 double(8,2) 可能会产生精度的缺失 10.0/3 3.3333333336 decimal 不会缺失精度,但是使用的时候需要指定总长度和小数位数 日期 - date 年月日- time 时分秒- datetime 年月日时分秒,到9999年,而且需要手动输入,如果没有手动输入,就显示null.- timestamp 年月日时分秒,在没有数据手动插入时,自动填入当前时间.最大值2038- bigint 1970-1-1 0:0:0 格林威治时间 案例:创建表t,字段d1 date,d2 time,d3 datetime,d4 timestamp create table t(id int,d1 date,d2 time,d3 datetime,d4 timestamp);insert into t (d1,d2) values ('1910-01-10','12:32:12');insert into t values(1,'2018-12-21','15:12:00','1995-02-10 12:08:12','2030-10-10 15:19:32');insert into t values(2,'3018-01-25','15:12:34','9234-12-31 12:12:12','2030-12-31 12:12:12');insert into t values(2,'3018-01-25','15:12:34','9999-12-31 23:59:59','2030-12-31 12:12:12'); 练习 创建人物表,插入,修改,查询 create table person(id int(4) primary key,name varchar(50),age int(3));insert into person values(1,"梅超风",36);insert into person values(2,"洪七公",96);insert into person values(3,"杨过",40);insert into person values(4,"令狐冲",28);insert into person values(5,"张三丰",100);insert into person values(6,"张翠山",27);insert into person values(7,"张无忌",27);insert into person values(8,"赵敏",18);insert into person values(9,"独孤求败",250);insert into person values(10,"楚留香",36);1.案例:修改张三丰的name为刘备,id为11update person set name="刘备",id=11 where name="张三丰";2.案例:修改2号人物的的name为夏侯渊update person set name="夏侯渊" where id=2;3.案例:根据条件修改person表中的数据,修改id是6的数据中,姓名改为'任我行', 年龄改为39update person set name="任我行",age=39 where id=6;4.案例:修改姓名是‘楚留香'的数据,把id改为20,年龄改为19update person set id=20,age=19 where name="楚留香";5.案例:把person所有的数据的年龄全部改为20 update person set age=20;6.案例:修改id为7的数据,把id改为100,姓名改为杨过,年龄改为21update person set id=100,name="杨过",age=21 where id=7;7.案例:修改姓名是独孤求败,把年龄改为35update person set age=35 where name="独孤求败";8.案例:修改id=8的信息,把姓名改为房玄龄update person set name="房玄龄" where id=8;9.案例 :修改id为20并且年龄为20的人的姓名为刘德华(郑少秋也行)提示 where...and...update person set name="郑少秋" where id=20 and age=20; 查询 没有条件的简单查询 select from 表名;查询表中所有的数据 select from person; select from t; select from emp; select from dept; 查询某些列中的值 select name as '姓名' from person; select name as '姓名',age as '年龄' from person; select id as '编号',name as '姓名',age as '年龄' from person; 学习过程的编程习惯select from 表; 工作中的编程习惯select id,name,age from person; 查询emp表中所有员工的姓名,上级领导的编号,职位,工资 select ename,mgr,job,sal from emp; 查询emp表中所有员工的编号,姓名,所属部门编号,工资 select empno,ename,deptno,sal from emp; 查询dept表中所有部门的名称和地址 select dname,loc from dept; 如果忘记了mysql的用户名和密码怎么办 卸载重新装 不重装软件如何修改密码 1.停止mysql服务 2.cmd中输入一个命令 mysqld --skip-grant-tables; -通过控制台,开启了一个mysql服务 3.开启一个新的cmd -mysql -u root -p 可以不使用密码进入数据库 show databases;----mysql 5. use mysql; 6. update user set password=password('新密码') where user="root"; 7. 关闭mysqld这个服务/进程 8. 重启mysql服务 作业 mysql02,一天的代码重新敲一遍,熟悉emp和dept列名 本篇文章为转载内容。原文链接:https://blog.csdn.net/sinat_41915844/article/details/79770973。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2024-02-16 12:44:07
545
转载
转载文章
...Java创建表 创建存储过程 创建触发器 环境说明 本实验环境基于Oracle 12C和JDK1.8,其中Oracle 12C支持多租户特性,相较于之前的Oracle版本,使用‘C用户名‘表示用户,例如如果数据库用户叫kevin,则登陆时使用Ckevin进行登陆。 一、Oracle高级消息队列AQ Oracle AQ是Oracle中的消息队列,是Oracle中的一种高级应用,每个版本都在不断的加强,使用DBMS_AQ系统包进行相应的操作,是Oracle的默认组件,只要安装了Oracle数据库就可以使用。使用AQ可以在多个Oracle数据库、Oracle与Java、C等系统中进行数据传输。 下面分步骤说明如何创建Oracle AQ 1. 创建消息负荷payload Oracle AQ中传递的消息被称为有效负荷(payloads),格式可以是用户自定义对象或XMLType或ANYDATA。本例中我们创建一个简单的对象类型用于传递消息。 create type demo_queue_payload_type as object (message varchar2(4000)); 2. 创建队列表 队列表用于存储消息,在入队时自动存入表中,出队时自动删除。使用DBMS_AQADM包进行数据表的创建,只需要写表名,同时设置相应的属性。对于队列需要设置multiple_consumers为false,如果使用发布/订阅模式需要设置为true。 begin dbms_aqadm.create_queue_table( queue_table => 'demo_queue_table', queue_payload_type => 'demo_queue_payload_type', multiple_consumers => false ); end; 执行完后可以查看oracle表中自动生成了demo_queue_table表,可以查看影响子段(含义比较清晰)。 3. 创建队列并启动 创建队列并启动队列: begin dbms_aqadm.create_queue ( queue_name => 'demo_queue', queue_table => 'demo_queue_table' ); dbms_aqadm.start_queue( queue_name => 'demo_queue' ); end; 至此,我们已经创建了队列有效负荷,队列表和队列。可以查看以下系统创建了哪些相关的对象: SELECT object_name, object_type FROM user_objects WHERE object_name != 'DEMO_QUEUE_PAYLOAD_TYPE'; OBJECT_NAME OBJECT_TYPE ------------------------------ --------------- DEMO_QUEUE_TABLE TABLE SYS_C009392 INDEX SYS_LOB0000060502C00030$$ LOB AQ$_DEMO_QUEUE_TABLE_T INDEX AQ$_DEMO_QUEUE_TABLE_I INDEX AQ$_DEMO_QUEUE_TABLE_E QUEUE AQ$DEMO_QUEUE_TABLE VIEW DEMO_QUEUE QUEUE 我们看到一个队列带出了一系列自动生成对象,有些是被后面直接用到的。不过有趣的是,创建了第二个队列。这就是所谓的异常队列(exception queue)。如果AQ无法从我们的队列接收消息,将记录在该异常队列中。 消息多次处理出错等情况会自动转移到异常的队列,对于异常队列如何处理目前笔者还没有找到相应的写法,因为我使用的场景并不要求消息必须一对一的被处理,只要起到通知的作用即可。所以如果消息转移到异常队列,可以执行清空队列表中的数据 delete from demo_queue_table; 4. 队列的停止和删除 如果需要删除或重建可以使用下面的方法进行操作: BEGIN DBMS_AQADM.STOP_QUEUE( queue_name => 'demo_queue' ); DBMS_AQADM.DROP_QUEUE( queue_name => 'demo_queue' ); DBMS_AQADM.DROP_QUEUE_TABLE( queue_table => 'demo_queue_table' ); END; 5. 入队消息 入列操作是一个基本的事务操作(就像往队列表Insert),因此我们需要提交。 declare r_enqueue_options DBMS_AQ.ENQUEUE_OPTIONS_T; r_message_properties DBMS_AQ.MESSAGE_PROPERTIES_T; v_message_handle RAW(16); o_payload demo_queue_payload_type; begin o_payload := demo_queue_payload_type('what is you name ?'); dbms_aq.enqueue( queue_name => 'demo_queue', enqueue_options => r_enqueue_options, message_properties => r_message_properties, payload => o_payload, msgid => v_message_handle ); commit; end; 通过SQL语句查看消息是否正常入队: select from aq$demo_queue_table; select user_data from aq$demo_queue_table; 6. 出队消息 使用Oracle进行出队操作,我没有实验成功(不确定是否和DBMS_OUTPUT的执行权限有关),代码如下,读者可以进行调试: declare r_dequeue_options DBMS_AQ.DEQUEUE_OPTIONS_T; r_message_properties DBMS_AQ.MESSAGE_PROPERTIES_T; v_message_handle RAW(16); o_payload demo_queue_payload_type; begin DBMS_AQ.DEQUEUE( queue_name => 'demo_queue', dequeue_options => r_dequeue_options, message_properties => r_message_properties, payload => o_payload, msgid => v_message_handle ); DBMS_OUTPUT.PUT_LINE( ' Browse message is [' || o_payload.message || ']' ); end; 二、Java使用JMS监听并处理Oracle AQ队列 Java使用JMS进行相应的处理,需要使用Oracle提供的jar,在Oracle安装目录可以找到:在linux中可以使用find命令进行查找,例如 find pwd -name 'jmscommon.jar' 需要的jar为: app/oracle/product/12.1.0/dbhome_1/rdbms/jlib/jmscommon.jar app/oracle/product/12.1.0/dbhome_1/jdbc/lib/ojdbc7.jar app/oracle/product/12.1.0/dbhome_1/jlib/orai18n.jar app/oracle/product/12.1.0/dbhome_1/jlib/jta.jar app/oracle/product/12.1.0/dbhome_1/rdbms/jlib/aqapi_g.jar 1. 创建连接参数类 实际使用时可以把参数信息配置在properties文件中,使用Spring进行注入。 package org.kevin.jms; / @author 李文锴 连接参数信息 / public class JmsConfig { public String username = "ckevin"; public String password = "a111111111"; public String jdbcUrl = "jdbc:oracle:thin:@127.0.0.1:1521:orcl"; public String queueName = "demo_queue"; } 2. 创建消息转换类 因为消息载荷是Oracle数据类型,需要提供一个转换工厂类将Oracle类型转换为Java类型。 package org.kevin.jms; import java.sql.SQLException; import oracle.jdbc.driver.OracleConnection; import oracle.jdbc.internal.OracleTypes; import oracle.jpub.runtime.MutableStruct; import oracle.sql.CustomDatum; import oracle.sql.CustomDatumFactory; import oracle.sql.Datum; import oracle.sql.STRUCT; / @author 李文锴 数据类型转换类 / @SuppressWarnings("deprecation") public class QUEUE_MESSAGE_TYPE implements CustomDatum, CustomDatumFactory { public static final String _SQL_NAME = "QUEUE_MESSAGE_TYPE"; public static final int _SQL_TYPECODE = OracleTypes.STRUCT; MutableStruct _struct; // 12表示字符串 static int[] _sqlType = { 12 }; static CustomDatumFactory[] _factory = new CustomDatumFactory[1]; static final QUEUE_MESSAGE_TYPE _MessageFactory = new QUEUE_MESSAGE_TYPE(); public static CustomDatumFactory getFactory() { return _MessageFactory; } public QUEUE_MESSAGE_TYPE() { _struct = new MutableStruct(new Object[1], _sqlType, _factory); } public Datum toDatum(OracleConnection c) throws SQLException { return _struct.toDatum(c, _SQL_NAME); } public CustomDatum create(Datum d, int sqlType) throws SQLException { if (d == null) return null; QUEUE_MESSAGE_TYPE o = new QUEUE_MESSAGE_TYPE(); o._struct = new MutableStruct((STRUCT) d, _sqlType, _factory); return o; } public String getContent() throws SQLException { return (String) _struct.getAttribute(0); } } 3. 主类进行消息处理 package org.kevin.jms; import java.util.Properties; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.MessageListener; import javax.jms.Queue; import javax.jms.QueueConnection; import javax.jms.QueueConnectionFactory; import javax.jms.Session; import oracle.jms.AQjmsAdtMessage; import oracle.jms.AQjmsDestination; import oracle.jms.AQjmsFactory; import oracle.jms.AQjmsSession; / @author 李文锴 消息处理类 / public class Main { public static void main(String[] args) throws Exception { JmsConfig config = new JmsConfig(); QueueConnectionFactory queueConnectionFactory = AQjmsFactory.getQueueConnectionFactory(config.jdbcUrl, new Properties()); QueueConnection conn = queueConnectionFactory.createQueueConnection(config.username, config.password); AQjmsSession session = (AQjmsSession) conn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); conn.start(); Queue queue = (AQjmsDestination) session.getQueue(config.username, config.queueName); MessageConsumer consumer = session.createConsumer(queue, null, QUEUE_MESSAGE_TYPE.getFactory(), null, false); consumer.setMessageListener(new MessageListener() { @Override public void onMessage(Message message) { System.out.println("ok"); AQjmsAdtMessage adtMessage = (AQjmsAdtMessage) message; try { QUEUE_MESSAGE_TYPE payload = (QUEUE_MESSAGE_TYPE) adtMessage.getAdtPayload(); System.out.println(payload.getContent()); } catch (Exception e) { e.printStackTrace(); } } }); Thread.sleep(1000000); } } 使用Oracle程序块进行入队操作,在没有启动Java时看到队列表中存在数据。启动Java后,控制台正确的输出的消息;通过Oracle程序块再次写入消息,发现控制台正确处理消息。Java的JMS监听不是立刻进行处理,可能存在几秒中的时间差,时间不等。 三、监控表记录变化通知Java 下面的例子创建一个数据表,然后在表中添加触发器,当数据变化后触发器调用存储过程给Oracle AQ发送消息,然后使用Java JMS对消息进行处理。 1. 创建表 创建student表,包含username和age两个子段,其中username时varchar2类型,age时number类型。 2. 创建存储过程 创建send_aq_msg存储过程,因为存储过程中调用dbms数据包,系统包在存储过程中执行需要进行授权(使用sys用户进行授权): grant execute on dbms_aq to ckevin; 注意存储过程中包含commit语句。 create or replace PROCEDURE send_aq_msg (info IN VARCHAR2) as r_enqueue_options DBMS_AQ.ENQUEUE_OPTIONS_T; r_message_properties DBMS_AQ.MESSAGE_PROPERTIES_T; v_message_handle RAW(16); o_payload demo_queue_payload_type; begin o_payload := demo_queue_payload_type(info); dbms_aq.enqueue( queue_name => 'demo_queue', enqueue_options => r_enqueue_options, message_properties => r_message_properties, payload => o_payload, msgid => v_message_handle ); commit; end send_aq_msg; 3. 创建触发器 在student表中创建触发器,当数据写入或更新时,如果age=18,则进行入队操作。需要调用存储过程发送消息,但触发器中不能包含事物提交语句,因此需要使用pragma autonomous_transaction;声明自由事物: CREATE OR REPLACE TRIGGER STUDENT_TR AFTER INSERT OR UPDATE OF AGE ON STUDENT FOR EACH ROW DECLARE pragma autonomous_transaction; BEGIN if :new.age = 18 then send_aq_msg(:new.username); end if; END; 创建完触发器后向执行插入或更新操作: insert into student (username,age) values ('jack.lee.3k', 18); update student set age=18 where username='jack003'; Java JMS可以正确的处理消息。 本篇文章为转载内容。原文链接:https://blog.csdn.net/weixin_42309178/article/details/115241521。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-12-17 14:22:22
140
转载
站内搜索
用于搜索本网站内部文章,支持栏目切换。
知识学习
实践的时候请根据实际情况谨慎操作。
随机学习一条linux命令:
date +%Y-%m-%d - 获取当前日期(YYYY-MM
-DD格式)。
推荐内容
推荐本栏目内的其它文章,看看还有哪些文章让你感兴趣。
2023-04-28
2023-08-09
2023-06-18
2023-04-14
2023-02-18
2023-04-17
2024-01-11
2023-10-03
2023-09-09
2023-06-13
2023-08-07
2023-03-11
历史内容
快速导航到对应月份的历史文章列表。
随便看看
拉到页底了吧,随便看看还有哪些文章你可能感兴趣。
时光飞逝
"流光容易把人抛,红了樱桃,绿了芭蕉。"