当前位置: 首页 > 编程日记 > 正文

Cassandra数据模型设计最佳实践

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

本文是Cassandra数据模型设计第一篇(全两篇),该系列文章包含了eBay使用Cassandra数据模型设计的一些实践。其中一些最佳实践我们是通过社区学到的,有些对我们来说也是新知识,还有一些仍然具有争议性,可能在要通过进一步的实践才能从中获益。

本文中,我将会讲解一些基本的实践以及一个详细的例子。即使你不了解Cassandra,也应该能理解下面大多数内容。

说说Cassandra在ebay的使用情况

我们尝试使用Cassandra已经超过1年时间了。Cassandra现在正在服务一些用例,涉及到的业务从大量写操作的日志记录和跟踪,到一些混合工作。其中一项服务是我们的“Social Signal”项目,支撑着ebay的pruduct pages里like/own/want特性。我们开发的一些用例已经上线运行,但更多的还是处于开发阶段。

我们的Cassandra集群规模并不庞大,但正在稳步的增长中。在过去几个月里,我们共部署了几十个节点,它们分布在几个跨机房的小型集群中。你可能会问,为什么要多个集群?我们通过的职能部门和业务来划分集群。相同职能部门的相同业务的用例共享一个集群,但它们存在于不同的keyspaces中。

RedLaser, Hunch和其它ebay的合作伙伴也在尝试cassandra解决现实中各种问题。除了Cassandra,我们也在使用MongoDB和Hbase,本文中我不会讨论它们,但我相信它们都有各自的优点。

我相信此时你一定有很多问题,在这篇文章里暂时不会一一说明。在即将到来的Cassandra Summit大会,我将更详细的讲解我们每个用例场景,数据模型和多数据中心部署,以及经验教训和其它知识。

本文重点讲述我们在ebay应用的Cassandra数据模型设计最佳实践。下面让我们先看看这系列文章会用到的一些术语。

术语和约定

  • 术语“Column Name” 和 “Column Key”被认为是一样的。同样的,“Super Column Name” 和 “Super Column Key”也认为是相同的。

  • 下图表示一个 Column Family (简称CF)中的一个row

    10103621_MNfr.png

    • 下图表示一个 Super Column Family (简称SCF)中的一个row

      10103622_wlDq.png

    • 下图表示一个Column Family中一个row,它包含Composite Columns。Composite Columns的属性通过分隔符’|’连接。请注意,这里看到的只是数据的表现形式,Cassandra内置了Composite Column,它是一个对象,并不是使用’|’作为属性分隔符的字符串。(顺便说下,本文不要求你掌握Super Column和Composite Column方面知识。)

      10103622_skuz.png

    基于上面的内容,让我们开始第一个实践吧!

    不要把Cassandra model想象成关系型数据库table

    取而代之,应该把它想象成事一个有序的map结构。

    对于一个新手来说,下面关系型数据库术语常常被对应到Cassandra模型

    10103623_DzFb.png

    这种对比可以帮助我们从关系型数据库转换到非关系型数据库。但是当设计Cassandra column famiy的时候请不要这样去类比。取而代之,考虑它是一个map中嵌入另一个map:外部map的key为row key,内部map的key为column key,两个map的key都是有序的。如下:

    双击代码全选
    1
    SortedMap<RowKey, SortedMap<ColumnKey, ColumnValue>>

    why?

    将column family想象成嵌套的并排序的map比关系型数据库table描述的更为准确,它将帮助你正确的进行Cassandra模型设计。

    10103623_WW4W.png

    How?

    • Map可以进行高效查询,同时排序的特性可以进行高效column扫描。在Cassandra中,我们可以使用row key和column key做高效查找和范围扫描

    • Column key的数量是很庞大的(译者注:目前译者所使用的Cassandra1.2.5版本,每个row支持最多20亿个columns)。换句话说你,你可以拥有一个wide rows。

    • Column key自身可以存储值,即你可以拥有一个没有值的column。

    如果集群使用Order Preserving Partitioner (OOP)策略进行数据存储,就可以对row key进行范围查询。但是OOP大多数情况都不推荐使用(译者注:将rowkey按照顺序存储到节点上,如果分区不均匀,将导致数据读写不均衡),所以你可以认为外部的map是不排序的,如下:

    双击代码全选
    1
    Map<RowKey, SortedMap<ColumnKey, ColumnValue>>

    上面提到的”Super Column”,认为它们是一组column,这样的话,两级嵌套map就会像下面展示的一样变为三级嵌套map:

    双击代码全选
    1
    Map<RowKey, SortedMap<SuperColumnKey,
    双击代码全选
    1
    SortedMap<ColumnKey, ColumnValue>>>

    注意:

    • 你需要传递timestamp给每个column value,因为Cassandra使用它做内部的冲突处理机制。但在建模过程中你可以忽略它(译者注:在操作column的时候timestamp信息会自动添加到column)。同时,不要考虑在你的程序中使用column的timestamp,因为它不是为你设计的,与Hbase不同,它们不会生成新的version数据(译者注:在Hbase中相同rowkey和column key的数据会保存多个version,而Cassandra会将相同数据覆盖,timestamp只保存最后一次更新的时间)。

    • 因为Super Column的性能问题和缺乏二级索引支持问题,Cassandra社区对它的使用曾有过强烈争议。所以,推荐使用Composite Columns代替Super Column实现功能。(译者注:使用Super Column,如果你要获取其中一个columnvalue,则要扫描整个Super Column,这会导致查询性能很糟糕)

    围绕着查询模式进行Column Family建模

    建模尽量从实体和它们的关系开始

    • 与关系型数据库不同,在Cassandra中通过创建二级索引或者编写复杂SQL(使用joins, order by, group by)来新建或修改查询不是件容易的事情。因为Cassandra具有很高的分布式特性,所以要先考虑查询模式,然后再设计column family。

    • 牢记前面提到的嵌入排序map数据结构,在考虑如何组织你的数据到map,以满足快速查询/排序/分组/过滤/聚合的要求。

    在大部分情况下,实体和它们的关系是很重要的(特殊用例除外,如日志存储或者其它时间序列数据)。如果我给你一个查询模式,用于为一个电子商务网站创建Cassandra模型,但不告诉你任何实体和它们的关系。你会有意或者无意的从查询模式或者从你之前领域对象的理解找出实体和它们之间的关系(因为我们是通过实体和关系来描述真实世界)。在设计数据模型时最好从实体和关系开始,然后使用反范式化和冗余的方式继续围绕查询模式建模。如果这听起来有些让人困惑,通过后面的详细例子就可以理解。

    注意:在建模的时候考虑以下几点会很有帮助。区分频次大的查询和频次小的查询,有些查询可能只被查询几千次,其它可能被查询数十亿次;还要考虑哪些查询对数据延迟是敏感的。确保你的模型优先满足查询频次大的查询和重要查询。

    为提升读性能进行反范式化(De-normalize)和冗余

    根据实际情况,如果不需要就不要反范式化。

    在关系型数据库的世界里,范式化的优点是显而易见的:较少的数据冗余,较少的数据修改异常,概念更清晰,更容易维护等等;同样,它的缺点也十分明显:多表join查询会很慢等等。这两方面也会体现在Cassandra中,但是缺点会更明显,因为Cassandra数据是分布式存储,当然它也并不支持join操作。所以,对于一个完全范式化的schema,Cassandra读操作性能可能比RDBMS更糟糕,所以我们通常通过反范式化来提升查询性能。(译者注:Cassandra一次查询可能会请求多个节点并将结果汇总到客户端,而RDBMS查询只需从本地查询即可)。

    这个实践和上一个查询建模实践是非常重要的,我会在余下的文章中通过一个详细的例子做进一步说明。

    注意:下面我们要讨论的例子只是个演示,它不代表eBayCassandra项目的数据模型。

    实战:User和Item中间的’Like’关系

    这个示例是关于电子商务系统的一个功能,一个user可以喜欢多个item,同时一个item可以被多个user所喜爱,在关系型数据库中这个关系是通过many-to-many实现的,如下图所示:

    10103623_y9Ph.png

    通过上面的模型,我们可以进行如下查询:

    • 通过user id获取user

    • 通过item id获取item

    • 获取指定user喜欢的所有item

    • 查看指定item被那些user所喜爱

    下面将介绍几个通过Cassandra建模解决上面问题的现方案,反范式的顺序从低到高。你会发现最佳方案依赖于查询模式。

    方案1:完全按照关系数据库模型设计

    10103625_eMNJ.png

    这个模型支持通过user id查询user和通过item id查询item。但无法简单查询某个user喜爱的所有item或者某个item被那些user所喜爱。

    对于这个用例来说,这是最糟糕的设计,主要是因为User_Item_Like没有设计好。

    注意:为了简单起见,关系型数据模型中的timestamp字段没有体现到Cassandra模型中(这个字段用于存储user何时喜爱某个item),我会在后面介绍它。

    方案2:使用自定义索引范式化实体

    10103625_DgrG.png

    这个模型中User和Item是范式化实体,user id 和item id被映射存储两次,第一次是通过item id存储user id(User_By_Item),第二次通过item id存储user id(Item_By_User)。

    这样,我们很容易可以通过Item_By_User查询某个user喜欢的全部item,还可以通过User_By_Item查询某个item被哪些user所喜爱。这里我们使用了,Item_By_User和User_By_Item这两个column family作为自定义二级索引。(译者注:Cassandra column family也有二级索引功能,它的作用是通过创建column key索引快速查询到column value)。

    有这样一个场景,我们总是希望通过指定user查询其喜爱的item,同时要获取item title信息。在当前模型下,我们首先要通过Item_By_User获取指定user关联的item id,然后根据这些item id依次查询Item模型获取title信息,反之亦然。一个item有可能被几百个user所喜爱,或者一个活跃user可能喜爱许多item,基于当前的模型设计,将会导致很多额外的查询。所以,最好通过反范式‘Item_by_User’ 中的itemtitle和’ User_by_Item’中的username信息来优化查询,方案3将会向大家展示。

    注意:即使你可以批量读取(译者注:在Cassandra Java客户端hector中可以MultigetSliceQuery类实现一次查询传入多个rowkey),但它们将仍然很慢,因为Cassandra底层仍然会单独查询每个rowkey,然后通过Coordinator 节点(译者注:Coordinator 节点为Cassandra客户端直接请求的节点,可以理解为它是一个代理)汇总到客户端。批量读取可以避免请求的往返耗时,它是个不错的选择,你可以去尝试它。

    方案三:范式化实体,并将它们反范式化到自定义索引

    10103626_k2cD.png

    在这个模型中,title和username被分别反范式到User_By_Item和Item_By_User。这样将允许我们高效查询指定user喜爱的所有item,以及喜爱指定item所有的user。这样我们就为整个用例做了很大的反范式化工作。

    问题又来了,如何获取指定user喜爱item的具体信息(title,desc,price等等)?首先我们要问问自己我们是否真的需要这个查询。还是上面的例子,当用户希望获取item额外信息的时候,我们可以在页面上展示所有的item title,当点击item title时,在打开的新页面显示这个item的具体信息。所以,在这个用例中我们最好不要极端反范式化。(item title列表中通常还会显示title和price信息,这也很容易实现,这个就留给大家做练习)

    让我们考虑下面两个查询:

    • 通过所给item id,获取具体item信息(title, desc等等),并一同查询喜欢这个item的user name

    • 通过所给的user id,获取具体user信息,并一同查询user喜欢的所有item titile

    上面两个查询出现在查询item和user的详情页面是很正常的,这些在当前模型中可以很好的实现。两者都需要两次查询,一次查询item(或者user)信息,另一次查询user name(或者item title)。User变得更加活跃的(喜欢上千个items)或者item变得很热门(被几百万user喜爱),查询的次数不会随之增加,仍然为两次。这很好,当我们从方案2到方案3,反范式化并没有让我们变糟糕。让我们看看方案4如何做更进一步的优化。


    方案4:范式化部分实体

    10103627_R3ml.png

    很明显,方案4看起来有些凌乱。在数据存储结构上,它与方案3也不同。

    如果User和Item之间是高度关联的实体(类似ebay),相比当前方案我将更倾向于方案3。

    因为我们不打算反范式化所有item属性到User实体或者反范式化所有user属性到Item实体,所以这里我们使用了部分范式化。我不会打算进行极限反范式化(让所有time属性到User实体和所有user属性到Item实体),因为在这个用例中那样做是没有意义的。

    注意:这里我使用Super Column只是为了给展示。大多情况,应该倾向于使用composite columns,而不是Super Column。

    最佳模型

    在本文的用例中方案3是优胜者。上面的方案中我们忽略了timestamp信息,下面我们将把它以timeuuid(type-1 uuid)形式添加到最终模型上。注意,在User_By_Item实体中timeuuid和userid合并为一个composite column key,在Item_By_user实体中timeuuid和item id合并为一个composite column key。

    回想一下,column key是有序存储的。这里我们的User_By_Item 和 Item_By_User两个实体的column keys通过timeuid排序后被存储到磁盘,这使得基于时间的范围查询非常高效。在这个模型中,我们不需要读取一个row中所有column,就可以高效的查询某个item最近被哪些user所喜爱,以及某个用户最近喜欢了哪些item。

    最终模型如下:

    10103628_8MBo.png

    总结

    我们通过一些基本的实践和详细例子帮你开启Cassandra数据建模之旅。下面是一些关键点:

    • 当设计Cassandra列族时,不要把它想成是关系表,要把它想成是嵌套的、排序的map数据结构。

    • 要围绕着查询来设计列族,从设计实体及其关系开始。

    • 在需要的时候,通过反范式化和冗余来提升读性能。

    • 记住有多种方式创建模型,最佳的方式依赖于你的用例和查询模式。

    这里我没有提到其它常用的用例,如日志记录、监控、实时分析(rollups, counters),或者时间序列。但是,我们讨论的实践也适用于它们。此外,有些众所周知的技术和模式用于时间序列的模型设计。在eBay,我们也使用这些技术,也乐于在后续的文章中分享这些。关于时间序列数据建模,我推荐你阅读 Advanced time series with Cassandra 和 Metric collection and storage,如果你是Cassandra新手,请先阅读DataStax documentation。

    1.2文档

    http://www.datastax.com/documentation/cassandra/1.2/pdf/cassandra12.pdf

    原文链接:http://www.ebaytechblog.com/2012/07/16/cassandra-data-modeling-best-practices-part-1/

转载于:https://my.oschina.net/laigous/blog/167599

相关文章:

矩阵相关概念的物理意义

参考链接&#xff1a; 矩阵乘法的本质是什么&#xff1f; 条件数 病态矩阵与条件数&#xff08;&& 与特征值和SVD的关系&#xff09;矩阵的物理意义&#xff1a;https://blog.csdn.net/NightkidLi_911/article/details/38178533https://blog.csdn.net/NightkidLi_911/a…

Linux 下 进程运行时内部函数耗时的统计 工具:pstack,strace,perf trace,systemtap

简单记录一些 在linux下 统计进程内部函数运行耗时的统计工具&#xff0c;主要是用作性能瓶颈分析。当然以下工具除了pstack功能单一之外&#xff0c;其他的工具都非常强大&#xff0c;这里仅仅整理特定场景的特定用法&#xff0c;用作协同分析。 以下工具需要追踪具体的进程&…

c语言作业扩展名通常为什么,C语言的源程序通常的扩展名是( )

C语言的源程序通常的扩展名是( )更多相关问题【C20】A&#xff0e;asB&#xff0e;afterC&#xff0e;untilD&#xff0e;whenAlthough I spoke to her about the matter several times, she took little ______ of what I s“以质取胜”战略包括三个方面内容&#xff0c;分别是…

VS中C#读取app.config数据库配置字符串的三种方法(转)

关于VS2008或VS2005中数据库配置字符串的三种取法 VS2008建立Form程序时,如果添加数据源会在配置文件 app.config中自动写入连接字符串,这个字符串将会在你利用DataSet,SqlDataAparter,SqlConnection等控件时如影随行地提示你让去选择,或者是新建字符串。如果要用代码的方式取得…

获取线程中抛出的异常信息

1 ScheduledExecutorService service Executors.newScheduledThreadPool(10);2 // 从现在开始delay毫秒之后&#xff0c;每隔一天执行一次&#xff0c;转换为毫秒3 // service.scheduleAtFixedRate(this, delay, period, TimeUnit.MILLISECONDS);4 …

浅谈批处理获取管理员运行权限的几种方法

很多用了Win10版本系统的人都会发现&#xff0c;Windows对程序的运行权限是控制得更加严格了&#xff0c;即使你将UAC控制放至最低&#xff0c;如果没有特别赋予外来程序管理员运行权限的话&#xff0c;很多程序都会运行出错&#xff0c;包括很多用于系统维护的批处理程序由于运…

使用 sched_setaffinity 将线程绑到CPU核上运行

linux 提供CPU调度函数&#xff0c;可以将CPU某一个核和指定的线程绑定到一块运行。 这样能够充分利用CPU&#xff0c;且减少了不同CPU核之间的切换&#xff0c;尤其是在IO密集型压力之下能够提供较为友好的性能。 通过sched_setaffinity 设置 CPU 亲和力的掩码&#xff0c;从…

Objective C内存管理之理解autorelease------面试题

Objective C内存管理之理解autorelease Autorelease实际上只是把对release的调用延迟了&#xff0c;对于每一个Autorelease&#xff0c;系统只是把该Object放入了当前的Autorelease pool中&#xff0c;当该pool被释放时&#xff0c;该pool中的所有Object会被调用Release。 &…

c语言子程序return,c语言return返回到哪

c语言return返回到哪c语言return&#xff0c;返回给了上一级&#xff0c;比如一个递归程序&#xff0c;从第三层返回到第二层&#xff1b;又比如一个普通的子程序&#xff0c;那就返回到主程序中去。主程序中return返回给了操作系统。比如下面一个c程序int sum(int a, int b) {…

有关 schema

2019独角兽企业重金招聘Python工程师标准>>> 主要分析2点 &#xff1a;schema含义 以及 多schema下的XA处理 A schema is a collection of database objects (used by a user.). Schema objects are the logical structures that directly refer to the database’…

关于查询ios的app更新的历史版本记录

https://www.qimai.cn 推荐七麦数据 可以查询app的各种版本更新内容 由于历史久远忘记了自己app第一次上架的时间 通过这个可以查询 转载于:https://www.cnblogs.com/ccw-congcong/p/10593917.html

关于 Rocksdb 性能分析 需要知道的一些“小技巧“ -- perf_context的“内功” ,systemtap、perf、 ftrace的颜值

文章目录内部工具包含头文件接口使用核心指标Perf ContextIOStats Context外部工具Systemtap 工具Perf工具Ftrace 工具2020.8.20 23:23 &#xff0c;又到了夜深人静学习时&#xff0c;不断得思考总结总会让繁忙一天的大脑得到舒缓。作为单机存储引擎&#xff0c;Rocksdb总会被嵌…

一维数组求平均值c语言编程软件,c语言编程:用数组名作函数参数,编写一个对一维数组求平均值的函数,并在主函数中调用它...

#includeincludeint main(){void sort1(char*p1);void print(char*p2);static char*name[]{"zhangwww.book1234.com防采集请勿采集本网。#include #include #include float b(float arr[],int n); //<<<不知道你说的第2&#xff0c;4&#xff0c;5语句对应的是什…

2014年10月18日

我姐一个一点追求都没有弄的我气死了.女人管不住自己的臭嘴就让人烦死/ 还能不能嫁出去 蠢 女人说一个男的没追求没出息就是找枪口撞 蠢死转载于:https://www.cnblogs.com/wangduqiang/p/4180892.html

接口响应慢?那是你没用 CompletableFuture 来优化!

大多数程序员在平时工作中,都是增删改查。这里我跟大家讲解如何利用CompletableFuture优化项目代码,使项目性能更佳!

SQL Server 2012入门T-SQL基础篇:(8)Delete语句

基本的语法格式如下:Deleteform表名[where条件语句]此语句将删除表的部分或者全部记录;(1)带WHERE条件子句,将删除符合条件的记录:可以看到已经删除了"EmployeeKey1"的记录;(2)不带条件的delete的语句,将表中删除所有记录;转载于:https://blog.51cto.com/281816327/1…

30张图带你彻底理解红黑树

当在10亿数据进行不到30次比较就能查找到目标时,不禁感叹编程之魅力!人类之伟大呀!—— 学红黑树有感。终于,在学习了几天的红黑树相关的知识后,我想把我所学所想和所感分享给大家。红黑树是一种比较难的数据结构,要完全搞懂非常耗时耗力,红黑树怎么自平衡?什么时候需要左旋或右旋?插入和删除破坏了树的平衡后怎么处理?等等一连串的问题在学习前困扰着我。如果你在学习过程中也会存在我的疑问,那么本文对你会有帮助,本文帮助你全面、彻底地理解红黑树!

Linux内核分析--理解进程调度时机、跟踪分析进程调度和进程切换的过程

学号后三位:426 原创作品转载请注明出处 https://github.com/mengning/linuxkernel/ 1.进程的创建 除了0号进程&#xff08;系统创建的&#xff09;之外&#xff0c;linux系统中都是由其他进程创建的。创建新进程的进程&#xff0c;即调用fork函数的进程为父进程&#xff0c;…

数据结构 -- 散列表

散列表作为一种能够提供高效插入&#xff0c;查找&#xff0c;删除 以及遍历的数据结构&#xff0c;被应用在很多不同的存储组件之中。 就像rocksdb中的hashskiplist&#xff0c;redis的有序集合&#xff0c;java的 LinkedHashMap 等 都是一些非常有特色的核心数据结构&#xf…

c语言编程题餐饮服务打分,求详细分析C语言题餐饮服务质量调查打分题和答案..._质量员考试_帮考网...

bangsaizhuo新兵答主11-09TA获得超过6761个赞二、填空题1. &#xff3f;&#xff3f;&#xff3f;变量&#xff3f;&#xff3f;是指在程序运行过程中&#xff0c;值可以发生变化的量。2.C语言是一种&#xff3f;&#xff3f;&#xff3f;&#xff3f;区分&#xff3f;(区分/不…

为什么阿里巴巴修正了HashMap关于1024个元素扩容的次数?(典藏版)

此番修正主要是每个人对「扩容」定义存在了分歧,在JDK1.8中如果没有给HashMap设置初始容量,那么在第一次put()操作的时候会进行resize()。而有的人认为这算一次扩容,有的人认为这不是一次扩容,这只是HashMap容量的初始化。所以存储1024的元素时:前者的人认为扩容次数为8次。后者的人认为扩容次数为7次。孤尽老师说对此分歧,希望用没有「二义性」的语言来表示,所以「扩容次数」修正为「resize次数」。

【转】每天一个linux命令(31): /etc/group文件详解

原文网址&#xff1a;http://www.cnblogs.com/peida/archive/2012/12/05/2802419.html Linux /etc/group文件与/etc/passwd和/etc/shadow文件都是有关于系统管理员对用户和用户组管理时相关的文件。linux /etc/group文件是有关于系统管理员对用户和用户组管理的文件,linux用户组…

C#设计模式(7)——适配器模式(Adapter Pattern)

一、引言在实际的开发过程中&#xff0c;由于应用环境的变化&#xff08;例如使用语言的变化&#xff09;&#xff0c;我们需要的实现在新的环境中没有现存对象可以满足&#xff0c;但是其他环境却存在这样现存的对象。那么如果将“将现存的对象”在新的环境中进行调用呢&#…

强烈建议你不要再使用Date类了!!!

这里就不细说修改流程了,主要说一下我们在改造的时候遇到的一些问题。(Date从现在开始)是一个糟糕的类型,这解释了为什么它的大部分内容在 Java 1.1 中被弃用(但不幸的是仍在使用)。只能说这种基础的类改起来牵一发动全身,需要从DO实体类看起,然后就是各种Converter,最后是DTO。这个改造难度不高,但是复杂度非常高,一个地方没改好,轻则接口报错,重则启动失败,非常耗费精力,真不想改。我们要改的原因很简单,我们的代码缺陷扫描规则认为这是一个必须修改的缺陷,否则不给发布,不改不行,服了。

windows 安装MySQL服务 zip解压程序

1&#xff1a;配置 my.ini 文件 如下&#xff1a; [mysql] default-character-setutf8[mysqld] port3306basedirD:\\Program Files\\databases\\mysql-5.7.24datadirD:\\Program Files\\databases\\mysql-5.7.24\\datamax_connections200max_connections200character-set-serve…

数据结构 -- 图与图存储

我们在使用像QQ &#xff0c;微信&#xff0c;微博&#xff0c;快手&#xff0c;抖音等社交软件的过程中经常需要添加好友&#xff0c;关注好友和被好友关注。这个过程中 这样的社交网络中的好友关系就需要被存储下来&#xff0c;存储在各个公司的后台服务器之上&#xff0c;都…

Struts2 验证规则配置文件

1. Action级别校验命名格式&#xff1a; ActionClassName-validation.xml 2. Action中某个方法的校验命名格式&#xff1a; ActionClassName-ActionAliasName-validation.xml 注意&#xff1a;这里的ActionAliasName(action别名)指的是struts.xml中Action name"XX"的…

c语言中手机系统,一种手机课堂C语言编程系统的制作方法

技术特征&#xff1a;1.一种手机课堂C语言编程系统&#xff0c;其特征在于&#xff1a;该系统由手机端C语言编译运行单元、嵌入式主机端传输单元、台式机端显示单元和投影仪端显示单元组成&#xff1b;所述手机端C语言编译运行单元、嵌入式主机端传输单元、台式机端显示单元和投…

cpp中sizeof与指针

一直不清楚c的sizeof&#xff0c;现在通过实验得到了一些了解。 1 #include<iostream>2 3 using namespace std;4 5 class A{6 private:7 char * a1;8 // ! static int totalPeople0; //error: ISO C forbids in-class initialization of non-const static me…

利用Python制作简单的小程序:IP查看器

前言 说实话&#xff0c;查看电脑的IP&#xff0c;也挺无聊的&#xff0c;但是够简单&#xff0c;所以就从这里开始吧。IP地址在操作系统里就可以直接查看。但是除了IP地址&#xff0c;我们也想通过IP获取地理地址和网络运营商情况。IP地址和地理地址并没有固定的关系&#xff…