[{"content":"HTTP客户端 java.net 包中提供了一些基本的方法，使用过 http 协议来访问网络资源，但是操作起来比较繁琐不够灵活，因此诞生了一些优秀的HTTP客户端工具，包括 Apache HttpClient、OkHttp，在笔者接触过的项目里又以 OkHttp 使用更加广泛，所以本次重点介绍 OkHttp\nOkHttp 关于 OkHttp 这里直接贴官网介绍（https://square.github.io/okhttp/）\nHTTP is the way modern applications network. It’s how we exchange data \u0026amp; media. Doing HTTP efficiently makes your stuff load faster and saves bandwidth.OkHttp is an HTTP client that’s efficient by default: HTTP/2 support allows all requests to the same host to share a socket. Connection pooling reduces request latency (if HTTP/2 isn’t available). Transparent GZIP shrinks download sizes. Response caching avoids the network completely for repeat requests 如何使用OkHttp 这里依然贴官网 demo（https://square.github.io/okhttp/recipes/） 同步调用\nprivate final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { Request request = new Request.Builder() .url(\u0026#34;https://publicobject.com/helloworld.txt\u0026#34;) .build(); try (Response response = client.newCall(request).execute()) { if (!response.isSuccessful()) throw new IOException(\u0026#34;Unexpected code \u0026#34; + response); Headers responseHeaders = response.headers(); for (int i = 0; i \u0026lt; responseHeaders.size(); i++) { System.out.println(responseHeaders.name(i) + \u0026#34;: \u0026#34; + responseHeaders.value(i)); } System.out.println(response.body().string()); } } 异步调用\nprivate final OkHttpClient client = new OkHttpClient(); public void run() throws Exception { Request request = new Request.Builder() .url(\u0026#34;http://publicobject.com/helloworld.txt\u0026#34;) .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { e.printStackTrace(); } @Override public void onResponse(Call call, Response response) throws IOException { try (ResponseBody responseBody = response.body()) { if (!response.isSuccessful()) throw new IOException(\u0026#34;Unexpected code \u0026#34; + response); Headers responseHeaders = response.headers(); for (int i = 0, size = responseHeaders.size(); i \u0026lt; size; i++) { System.out.println(responseHeaders.name(i) + \u0026#34;: \u0026#34; + responseHeaders.value(i)); } System.out.println(responseBody.string()); } } }); } OkHttp实例创建 从 demo 里可以得知使用 OkHttp 之前需要 new 一个 OkHttpClient，至于如何创建，OkHttp 实际上提供了 Builder 方式进行个性化的配置，一份比较完整的配置通常是这样的（配置里的参数使用的是自带的默认值，OkHttp 版本3.11.0）：\npublic OkHttpClient buildOkHttpClient() { ExecutorService executor = new ThreadPoolExecutor(50, 200, 30, TimeUnit.SECONDS, new SynchronousQueue\u0026lt;\u0026gt;(), Util.threadFactory(\u0026#34;OkHttp Dispatcher\u0026#34;, false)); Dispatcher dispatcher = new Dispatcher(executor); dispatcher.setMaxRequests(64); dispatcher.setMaxRequestsPerHost(5); return new OkHttpClient.Builder() .connectTimeout(10_000, TimeUnit.MILLISECONDS) .readTimeout(10_000, TimeUnit.MILLISECONDS) .writeTimeout(10_000, TimeUnit.MILLISECONDS) .connectionPool(new ConnectionPool(5, 5, TimeUnit.MINUTES)) .dispatcher(dispatcher) .build(); } Dispatcher，直接查看源码注释\nPolicy on when async requests are executed. Each dispatcher uses an {@link ExecutorService} to run calls internally. If you supply your own executor, it should be able to run {@linkplain #getMaxRequests the configured maximum} number of calls concurrently.\n概括来说就是异步调用时 OkHttp 底层实际会使用一个默认的线程池，这个线程池源码为：\npublic synchronized ExecutorService executorService() { if (executorService == null) { executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS, new SynchronousQueue\u0026lt;Runnable\u0026gt;(), Util.threadFactory(\u0026#34;OkHttp Dispatcher\u0026#34;, false)); } return executorService; } 最大线程数为 Integer.MAX_VALUE，这个是不是太危险了？不过异步调用的时候实际是会经过以下方法的：\nsynchronized void enqueue(AsyncCall call) { if (runningAsyncCalls.size() \u0026lt; maxRequests \u0026amp;\u0026amp; runningCallsForHost(call) \u0026lt; maxRequestsPerHost) { runningAsyncCalls.add(call); executorService().execute(call); } else { readyAsyncCalls.add(call); } } 也就是在往这个线程池提交任务的时候是会先做判断的，这里涉及到 maxRequests 和 maxRequestsPerHost 两个配置参数，见名知意，maxRequests 是允许最大的并发数，maxRequestsPerHos 是每个调用域名允许最大的并发数，超过配置的并发数则进入一个就绪队列，后面细节就不具体展开讲，感兴趣可以查看网友的源码分析：https://www.jianshu.com/p/6166d28983a2\nConnectionPool 是指创建的连接池，用源码的注释来说\nManages reuse of HTTP and HTTP/2 connections for reduced network latency. HTTP requests that share the same {@link Address} may share a {@link Connection}. This class implements the policy of which connections to keep open for future use\n如果要复用 HTTP 连接，那么可以通过 maxIdleConnections 进行控制，即允许最大的空闲连接数，这个连接数只针对同一个host有效，并非针对总的连接数，需要注意的是当 response header 头里如果返回Connection: close，那么是无法复用连接的，不仅笔者踩过这个坑，也有网友踩过这个坑，具体可见具：https://stackoverflow.com/questions/41011287/why-okhttp-doesnt-reuse-its-connections\n而大部分人关注的更多的是 OkHttp 的几个超时时间：\nconnectTimeout 底层 socket 连接建立的超时时间，当连接 IP 不可达的情况下，需要等待很长一段时间(默认时长)\nreadTimeout 读超时时间，Source（类似 InputStream）的超时时间，这个时间也是大家普遍认为的第三方接口调用超时时间\nwriteTimeout 写超时时间， Sink（类似 OutputStream）超时时间，从远程获得数据后再往 socket 写的时间，这个耗时通常非常少，笔者人为打了断点才模拟触发\n总结 dispachter 异步调用时才有用，通过 maxRequests （允许最大的并发数），maxRequestsPerHos （每个调用域名允许最大的并发数）来进行并发控制 connectTimeout 与远程 host 建立连接的超时时间 readTimeout 通常意义上的从远程接口获取到数据的超时时间 writeTimeout 获得数据后往 socket 写的超时时间 connectionPool 用于管理HTTP连接，同一个 host 达到复用的效果降低开销，通过maxIdleConnections 控制同一个 host 允许的最大空闲连接数 response header头里返回Connection: close，那么是无法复用连接的 ","permalink":"http://bug1024.com/2020/06/06/okhttp/","summary":"\u003ch2 id=\"http客户端\"\u003eHTTP客户端\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003ejava.net\u003c/code\u003e 包中提供了一些基本的方法，使用过 http 协议来访问网络资源，但是操作起来比较繁琐不够灵活，因此诞生了一些优秀的HTTP客户端工具，包括 Apache HttpClient、OkHttp，在笔者接触过的项目里又以 OkHttp 使用更加广泛，所以本次重点介绍 OkHttp\u003c/p\u003e","title":"Java Http客户端之OkHttp"},{"content":"UNIX网络编程IO模型分类 阻塞IO 非阻塞IO IO复用（select/poll/epoll） 信号驱动 异步IO poll相比select优势 FD数目不受限制 IO效率不随着FD数目增加而线性下降 使用mmap加速内核与用户空间的消息传递 API更为简单 套接字read接口阻塞场景 有数据可读 可用数据已经读取完毕 发送空指针或者IO异常 伪异步IO（线程池方案）的问题 服务端处理缓慢，返回应答耗费60s，平时只需要10ms 线程读取故障节点由于读取输入流堵塞，因而会被阻塞60s 所有可用线程都被阻塞，后续消息只能在队列中排队等待 线程池通常采用阻塞队列实现，队列满之后，后续入队的操作将被阻塞 前端只有一个Acceptor接收客户端请求，新的客户端请求将会被拒绝，产生连接超时 几乎所有连接超时，调用方则认为系统已经崩溃 为何不使用原生NIO编程 API复杂，需要熟练掌握Selector，ServerSocketChannel，ByteBuffer等 需要具备其他技能铺垫，例如多线程编程，网络编程 可靠性低，工作量与难度都很大 JDK NIO本身也可能有bug Why Netty API简单 功能强大，预置多种安编码解码，支持多种协议 定制能力强，可通过ChannelHandler对框架灵活扩展 性能高 成熟稳定，社区活跃，经历大规模商业应用考验 TCP粘包和拆包 服务端一次性收到两个数据包，D1和D2粘合在一起，成为粘包 服务端分两次读取两个数据包，第一次读取了完整的D1和D2部分内容，第二次读取到了D2剩余内容，成为拆包 如果TCP滑动窗口笔记小，数据包又比较大，那么容易发生多次拆包 产生的原因：\n应用程序写入的字节大小大于套接字发送缓冲区大小 进行MSS大小的TCP分段 以太网帧的payload大于MTU进行IP分片 如何处理：\n消息定长，不够的话使用空格填充 包尾使用会车换行分割 消息头+消息体 更复杂协议 通常Netty使用LineBasedFrameDecoder和StringDecoder来解决粘包问题\nNetty高性能 异步非阻塞IO类库，基于Reactor模式实现 TCP接收和发送缓冲区使用直接内存代替堆内存，避免内存复制 支持通过内存池的方式循环利用ByteBuf，避免频繁创建和销毁ByteBuf带来额外开销 可配置的IO线程数，TCP参数等，满足不同应用场景需要 采用环形数组缓冲区实现无锁化并发编程 合理使用线程安全容器，原子类 关键资源处理使用线程串行方式，避免并发访问带来的锁竞争 通过引用计数器及时申请不再被引用的对象，细粒度的内存管理降低了GC频率 Netty可靠性 链路有效性检测 内存保护机制 优雅停机 ","permalink":"http://bug1024.com/2018/04/15/netty/","summary":"\u003ch2 id=\"unix网络编程io模型分类\"\u003eUNIX网络编程IO模型分类\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e阻塞IO\u003c/li\u003e\n\u003cli\u003e非阻塞IO\u003c/li\u003e\n\u003cli\u003eIO复用（select/poll/epoll）\u003c/li\u003e\n\u003cli\u003e信号驱动\u003c/li\u003e\n\u003cli\u003e异步IO\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"poll相比select优势\"\u003epoll相比select优势\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eFD数目不受限制\u003c/li\u003e\n\u003cli\u003eIO效率不随着FD数目增加而线性下降\u003c/li\u003e\n\u003cli\u003e使用mmap加速内核与用户空间的消息传递\u003c/li\u003e\n\u003cli\u003eAPI更为简单\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"套接字read接口阻塞场景\"\u003e套接字read接口阻塞场景\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e有数据可读\u003c/li\u003e\n\u003cli\u003e可用数据已经读取完毕\u003c/li\u003e\n\u003cli\u003e发送空指针或者IO异常\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"伪异步io线程池方案的问题\"\u003e伪异步IO（线程池方案）的问题\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e服务端处理缓慢，返回应答耗费60s，平时只需要10ms\u003c/li\u003e\n\u003cli\u003e线程读取故障节点由于读取输入流堵塞，因而会被阻塞60s\u003c/li\u003e\n\u003cli\u003e所有可用线程都被阻塞，后续消息只能在队列中排队等待\u003c/li\u003e\n\u003cli\u003e线程池通常采用阻塞队列实现，队列满之后，后续入队的操作将被阻塞\u003c/li\u003e\n\u003cli\u003e前端只有一个Acceptor接收客户端请求，新的客户端请求将会被拒绝，产生连接超时\u003c/li\u003e\n\u003cli\u003e几乎所有连接超时，调用方则认为系统已经崩溃\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"为何不使用原生nio编程\"\u003e为何不使用原生NIO编程\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eAPI复杂，需要熟练掌握Selector，ServerSocketChannel，ByteBuffer等\u003c/li\u003e\n\u003cli\u003e需要具备其他技能铺垫，例如多线程编程，网络编程\u003c/li\u003e\n\u003cli\u003e可靠性低，工作量与难度都很大\u003c/li\u003e\n\u003cli\u003eJDK NIO本身也可能有bug\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"why-netty\"\u003eWhy Netty\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eAPI简单\u003c/li\u003e\n\u003cli\u003e功能强大，预置多种安编码解码，支持多种协议\u003c/li\u003e\n\u003cli\u003e定制能力强，可通过ChannelHandler对框架灵活扩展\u003c/li\u003e\n\u003cli\u003e性能高\u003c/li\u003e\n\u003cli\u003e成熟稳定，社区活跃，经历大规模商业应用考验\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"tcp粘包和拆包\"\u003eTCP粘包和拆包\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e服务端一次性收到两个数据包，D1和D2粘合在一起，成为粘包\u003c/li\u003e\n\u003cli\u003e服务端分两次读取两个数据包，第一次读取了完整的D1和D2部分内容，第二次读取到了D2剩余内容，成为拆包\u003c/li\u003e\n\u003cli\u003e如果TCP滑动窗口笔记小，数据包又比较大，那么容易发生多次拆包\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e产生的原因：\u003c/p\u003e","title":"Netty学习笔记"},{"content":"转眼又一年，北漂的第一年。与往年类似，又到了年终总结的日子。\n过去一年达成的目标 成功转型Java，参与了亿级流量的业务系统重构，对于分布式服务的有了更全面的认识 开始学习PHP内核，初步掌握了开发简单扩展的能力 系统地重新学习了MySQL与Redis，对于数据持久化和缓存应用有了更深的了解 GitHub连击200天达成，最长记录从1月1日持续到8月5日，累计217天 搭建了独立的博客，共写了57篇博客 跑步连续100天达成，每周平均打一次篮球，体重与上一年持平 背了1000个左右的英语单词 编程 最重要的一件便是跟着团队转型从事做Java开发，曾经我是排斥Java的，因为在我看来那是拙笨的代表，而我个人是喜欢轻巧的，但到了最后我还是接受了Java，现在看来Java更多的是一种稳重。\n其次架构能力有所提升，初步掌握容量评估，风险把控，核心指标制定的基本方法，定位与修复线上问题的能力也有所加强。\n不足之处在于网络方面的知识稍有欠缺，根本原因上还是对于TCP/IP网络协议掌握的深度不够，在面对网络传输超时与丢包场景时显的有些不知所措。\n虽然目前已经能得心应手的使用Java开发项目，但是整体Java基础还是比较薄弱，框架依赖性过高，JVM调优与多线程方面的知识掌握的远远不够。\n此外在技术分享上做的也不足，技术影响力有所局限，团队内的认可度还有待提升。\n因此新的一年里优先需要提高以下几点：\n网络知识的巩固学习，掌握分析常见网络问题的方法 加强Java基础学习，熟练掌握JVM运行原理与多线程编程 提高文档能力，包括作图能力与PPT制作能力 生活 过去一年的运动量处于中等水平，我依旧保持原来的体重，篮球方面外线投射能力变强，突破能力有下降，整体的跑跳能力比之前有所减弱。白头发似乎又增多了，白头发一多让我觉得自己顿时变得颓废。\n去电影院看了6部电影，在网上看了50部左右的武侠电影（主要是狄龙的），电视剧1部（济公游记），动漫1部（七龙珠）。\n此外周末开始自己做饭，初中之后就没有给自己做过饭了，这次又重启这项技能，虽谈不上色香俱全但能果腹就行。\n对于新的一年，给自己指定了几个目标：\n提高篮球水平，增加控球能力做到紧逼不掉球，弹跳增加20厘米 适当减少影视剧的观看，重新回归纸质阅读，每个月至少1本非技术类书籍 提高厨艺，时间允许的话去参加一门厨艺培训的课程 更为规律的作息，没有特殊事情，12点前必须熄灯上床 英语 之所以单独把英语提出来是因为过去几年都制定了英语相关的计划，但是完成度极其不理想，过去一年的英文学习仅仅是局限在背单词上，并且新增的词汇量非常有限。\n在2018年必须改变这个现状，需要完成以下目标：\n新增词汇量2000+ 每日英语阅读与听力训练，要做到无障碍观看无字幕英文电影 加强口语练习，能达到与老外日常基本交流的水平 写在最后 过去一年的进步程度和心理预期还是有些落差，这主要和制定计划的合理性以及自身的执行力有关。\n而立之年近在眉睫，在这之前我能做的便是挖掘自己的潜能，用所谓的努力付出来麻痹自己，让自己不那么受到良心谴责。\n也许梦想最终难以实现，但是我能做的便是牢牢把控自己的人生，让生活轨迹尽可能地按照自己的计划运行，这种规律之美才是我应该追寻的。\n志不强者智不达，言不信者行不果！\n","permalink":"http://bug1024.com/2018/01/01/2017summary/","summary":"\u003cp\u003e转眼又一年，北漂的第一年。与往年类似，又到了年终总结的日子。\u003c/p\u003e\n\u003ch2 id=\"过去一年达成的目标\"\u003e过去一年达成的目标\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e成功转型Java，参与了亿级流量的业务系统重构，对于分布式服务的有了更全面的认识\u003c/li\u003e\n\u003cli\u003e开始学习PHP内核，初步掌握了开发简单扩展的能力\u003c/li\u003e\n\u003cli\u003e系统地重新学习了MySQL与Redis，对于数据持久化和缓存应用有了更深的了解\u003c/li\u003e\n\u003cli\u003eGitHub连击200天达成，最长记录从1月1日持续到8月5日，累计217天\u003c/li\u003e\n\u003cli\u003e搭建了独立的博客，共写了57篇博客\u003c/li\u003e\n\u003cli\u003e跑步连续100天达成，每周平均打一次篮球，体重与上一年持平\u003c/li\u003e\n\u003cli\u003e背了1000个左右的英语单词\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"编程\"\u003e编程\u003c/h2\u003e\n\u003cp\u003e最重要的一件便是跟着团队转型从事做Java开发，曾经我是排斥Java的，因为在我看来那是拙笨的代表，而我个人是喜欢轻巧的，但到了最后我还是接受了Java，现在看来Java更多的是一种稳重。\u003c/p\u003e","title":"2017年总结"},{"content":"新特性 标量类型声明 字符串(string), 整数 (int), 浮点数 (float), 以及布尔值 (bool)。它们扩充了PHP5中引入的其他类型：类名，接口，数组和 回调类型 返回值类型声明 类似于参数类型声明，返回类型声明指明了函数返回值的类型 null合并运算符 考虑到日常使用到大量三元表达式和isset()的情况，添加了null合并运算符??这个语法糖。如果变量存在且值不为NULL， 它就会返回自身的值，否则返回它的第二个操作数 太空船操作符(组合比较符) \u0026lt;=\u0026gt;用于比较两个表达式。当$a小于、等于或大于$b时它分别返回-1、0或1 通过define()定义常量数组 Array 类型的常量现在可以通过define() 来定义。在PHP5.6中仅能通过const定义 匿名类 现在支持通过new class 来实例化一个匿名类，这可以用来替代一些“用后即焚”的完整类定义 高性能 PHP7是一个比较底层升级，比起PHP5的变化比较大，通过减少内存分配次数，多使用栈内存，缓存数组hash值，字符串解析成参数改为宏展开，使用大块连续内存代替小块碎片内存等等，使得性能有很大提升，具体就性能优化层面，大致可以汇总如下：\n将基础变量从struct（结构体）变为union（联合体），节省内存空间，间接减少CPU在内存分配和管理上的开销。 部分基础变量（zend_array、zend_string等）采用内存空间连续分配的方式，降低CPU Cache Miss的发生的概率。CPU从CPU Cache获取数据和从内存获取，它们之间效率相差可以高达100倍。举一个近似的例子，系统从内存读取数据和从磁盘读取数据的效率差别很大，CPU Cache Miss类似遇到缺页中断。 通过宏定义和内联函数（inline），让编译器提前完成部分工作。无需在程序运行时分配内存，能够实现类似函数的功能，却没有函数调用的压栈、弹栈开销，效率会比较高。 参考 QQ会员活动运营平台PHP7升级实践 ","permalink":"http://bug1024.com/2017/12/16/php7/","summary":"\u003ch2 id=\"新特性\"\u003e新特性\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e标量类型声明 字符串(string), 整数 (int), 浮点数 (float), 以及布尔值 (bool)。它们扩充了PHP5中引入的其他类型：类名，接口，数组和 回调类型\u003c/li\u003e\n\u003cli\u003e返回值类型声明 类似于参数类型声明，返回类型声明指明了函数返回值的类型\u003c/li\u003e\n\u003cli\u003enull合并运算符 考虑到日常使用到大量三元表达式和isset()的情况，添加了null合并运算符\u003ccode\u003e??\u003c/code\u003e这个语法糖。如果变量存在且值不为NULL， 它就会返回自身的值，否则返回它的第二个操作数\u003c/li\u003e\n\u003cli\u003e太空船操作符(组合比较符) \u003ccode\u003e\u0026lt;=\u0026gt;\u003c/code\u003e用于比较两个表达式。当$a小于、等于或大于$b时它分别返回-1、0或1\u003c/li\u003e\n\u003cli\u003e通过\u003ccode\u003edefine()\u003c/code\u003e定义常量数组 Array 类型的常量现在可以通过\u003ccode\u003edefine()\u003c/code\u003e 来定义。在\u003ccode\u003ePHP5.6\u003c/code\u003e中仅能通过\u003ccode\u003econst\u003c/code\u003e定义\u003c/li\u003e\n\u003cli\u003e匿名类 现在支持通过new class 来实例化一个匿名类，这可以用来替代一些“用后即焚”的完整类定义\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"高性能\"\u003e高性能\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003ePHP7\u003c/code\u003e是一个比较底层升级，比起\u003ccode\u003ePHP5\u003c/code\u003e的变化比较大，通过减少内存分配次数，多使用栈内存，缓存数组hash值，字符串解析成参数改为宏展开，使用大块连续内存代替小块碎片内存等等，使得性能有很大提升，具体就性能优化层面，大致可以汇总如下：\u003c/p\u003e","title":"PHP7"},{"content":"硬件层相关优化 修改服务器BIOS设置\n选择DAPC（Performance Per Wait Optimized）模式，发挥CPU最大性能 Memory Frequency（内存频率）选择Maximum Performance（最佳性能） 内存设置菜单中，启用Node Interleaving，避免NUMA问题 磁盘I/O相关 使用SSD盘 如果是磁盘阵列存储，建议阵列卡配备CACHE和BBU模块，可提升IOPS raid级别尽量选择raid10，而不是raid5 文件系统层优化 使用deadline/noop这两种I/O调度器，别用cfq 使用xfs文件系统，别用ext3，ext4勉强可用，如果业务量大的话一定要用xfs 文件系统mount参数中增加noatime/nodiratime/nobarrier几个选项，其中nobarrier是xfs文件系统特有的 内核参数优化 优化vm.swappiness参数，降低swap使用率。RHEL7/centos7以上慎重设置为0，可能导致OOM 调整vm.dirty_background_ratio/vm.dirty_ratio，确保将脏数据持续刷到磁盘中，避免瞬间I/O过高，产生等待 调整net.ipv4.tcp_tw_recycle/net.ipv4.ctp_tw_reuse都设置为1，减少TIME_WAIT，提高TCP效率 MySQL参数优化 建议设置默认引擎为InnoDB，强烈不建议使用MyISAM引擎 调整innodb_buffer_pool_size的大小，如果单实例且绝大多数是InnoDB引擎表的话，可考虑设置为物理内存的50%-70% 设置innodb_file_per_table=1，使用独立表空间 调整innodb_data_file_path = ibdata1:1G:autoextend，不用默认的10M，在高并发场景下性能有很大提升 设置innodb_log_file_size=256M，设置innodb_log_file_in_group=2，可基本满足大部分应用场景 调整max_connection/max_connection_error，根据业务量大小进行设置 open_file_limit/innodb_open_files/table_open_cache/table_definitiion_cache可设置大约为max_connection的10倍左右大小 key_buffer_size/max_heap_table_size不用设置过大 sort_buffer_size/join_buffer_size/read_buffer_size/read_rmd_buffer_size也不要设置过大 MySQL高可用方案 MHA MHA（MySQL-Master-HA）是目前广泛使用的MySQL主从复制的高可用方案。MHA设计目标是自动实现主实例宕机后，从机切换为主，并尽量降低切换时延（通常在10-30s内切换完成）。同时，由MHA保证在切换过程中的数据一致性。MHA对MySQL的主从复制集群非常友好，没有对集群做任何侵入性的修改。 MHA的一个重点特性是：在主实例宕机后，MHA可以自动的判断主从复制集群中哪个从实例的relaylog是最新的，并将最新从实例的差异log“应用”到其余的从实例中，从而保证每个实例的数据一致。通常情况下，MHA需要10s左右检测主实例异常，并将主实例关闭从而避免脑裂。然后再用10s左右将差异的log event同步，并启用新的Master。整个MHA的RTO时间大约在30s。\n参考 比较全面的MySQL优化参考 MySQL 数据库的高可用性分析 ","permalink":"http://bug1024.com/2017/12/09/mysql-optimize/","summary":"\u003ch2 id=\"硬件层相关优化\"\u003e硬件层相关优化\u003c/h2\u003e\n\u003cp\u003e修改服务器BIOS设置\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e选择DAPC（Performance Per Wait Optimized）模式，发挥CPU最大性能\u003c/li\u003e\n\u003cli\u003eMemory Frequency（内存频率）选择Maximum Performance（最佳性能）\u003c/li\u003e\n\u003cli\u003e内存设置菜单中，启用Node Interleaving，避免NUMA问题\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"磁盘io相关\"\u003e磁盘I/O相关\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e使用SSD盘\u003c/li\u003e\n\u003cli\u003e如果是磁盘阵列存储，建议阵列卡配备CACHE和BBU模块，可提升IOPS\u003c/li\u003e\n\u003cli\u003eraid级别尽量选择raid10，而不是raid5\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"文件系统层优化\"\u003e文件系统层优化\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e使用deadline/noop这两种I/O调度器，别用cfq\u003c/li\u003e\n\u003cli\u003e使用xfs文件系统，别用ext3，ext4勉强可用，如果业务量大的话一定要用xfs\u003c/li\u003e\n\u003cli\u003e文件系统mount参数中增加noatime/nodiratime/nobarrier几个选项，其中nobarrier是xfs文件系统特有的\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"内核参数优化\"\u003e内核参数优化\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e优化vm.swappiness参数，降低swap使用率。RHEL7/centos7以上慎重设置为0，可能导致OOM\u003c/li\u003e\n\u003cli\u003e调整vm.dirty_background_ratio/vm.dirty_ratio，确保将脏数据持续刷到磁盘中，避免瞬间I/O过高，产生等待\u003c/li\u003e\n\u003cli\u003e调整net.ipv4.tcp_tw_recycle/net.ipv4.ctp_tw_reuse都设置为1，减少TIME_WAIT，提高TCP效率\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"mysql参数优化\"\u003eMySQL参数优化\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e建议设置默认引擎为InnoDB，强烈不建议使用MyISAM引擎\u003c/li\u003e\n\u003cli\u003e调整innodb_buffer_pool_size的大小，如果单实例且绝大多数是InnoDB引擎表的话，可考虑设置为物理内存的50%-70%\u003c/li\u003e\n\u003cli\u003e设置innodb_file_per_table=1，使用独立表空间\u003c/li\u003e\n\u003cli\u003e调整innodb_data_file_path = ibdata1:1G:autoextend，不用默认的10M，在高并发场景下性能有很大提升\u003c/li\u003e\n\u003cli\u003e设置innodb_log_file_size=256M，设置innodb_log_file_in_group=2，可基本满足大部分应用场景\u003c/li\u003e\n\u003cli\u003e调整max_connection/max_connection_error，根据业务量大小进行设置\u003c/li\u003e\n\u003cli\u003eopen_file_limit/innodb_open_files/table_open_cache/table_definitiion_cache可设置大约为max_connection的10倍左右大小\u003c/li\u003e\n\u003cli\u003ekey_buffer_size/max_heap_table_size不用设置过大\u003c/li\u003e\n\u003cli\u003esort_buffer_size/join_buffer_size/read_buffer_size/read_rmd_buffer_size也不要设置过大\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"mysql高可用方案\"\u003eMySQL高可用方案\u003c/h2\u003e\n\u003ch3 id=\"mha\"\u003eMHA\u003c/h3\u003e\n\u003cp\u003eMHA（MySQL-Master-HA）是目前广泛使用的MySQL主从复制的高可用方案。MHA设计目标是自动实现主实例宕机后，从机切换为主，并尽量降低切换时延（通常在10-30s内切换完成）。同时，由MHA保证在切换过程中的数据一致性。MHA对MySQL的主从复制集群非常友好，没有对集群做任何侵入性的修改。\nMHA的一个重点特性是：在主实例宕机后，MHA可以自动的判断主从复制集群中哪个从实例的relaylog是最新的，并将最新从实例的差异log“应用”到其余的从实例中，从而保证每个实例的数据一致。通常情况下，MHA需要10s左右检测主实例异常，并将主实例关闭从而避免脑裂。然后再用10s左右将差异的log event同步，并启用新的Master。整个MHA的RTO时间大约在30s。\u003c/p\u003e","title":"MySQL调优"},{"content":" RAID(Redundent Array of Inexpensive Disks)，廉价冗余磁盘阵列，后来RAID中的I被改作了Independent，就成了“独立冗余磁盘阵列”，但这只是名称的变化，实质性的内容并没有改变。可以把RAID理解成一种使用磁盘驱动器的方法，它将一组磁盘驱动器用某种逻辑方式联系起来，作为逻辑上的一个磁盘驱动器来使用。\nRAID0 无冗余无校验的磁盘阵列。数据同时分布在各个磁盘上，没有容错能力，读写速度在RAID中最快，但因为任何一个磁盘损坏都会使整个RAID系统失效，所以安全系数反倒比单个的磁盘还要低。一般用在对数据安全要求不高，但对速度要求很高的场合，如：大型游戏、图形图像编辑等。此种RAID模式至少需要2个磁盘，而更多的磁盘则能提供更高效的数据传输。\nRAID1 镜象磁盘阵列。每一个磁盘都有一个镜像磁盘，镜像磁盘随时保持与原磁盘的内容一致。RAID1具有最高的安全性，但只有一半的磁盘空间被用来存储数据。主要用在对数据安全性要求很高，而且要求能够快速恢复被损坏的数据的场合。此种RAID模式每组仅需要2个磁盘。\nRAID5 无独立校验盘的奇偶校验磁盘阵列。同样采用奇偶校验来检查错误，但没有独立的校验盘，而是使用了一种特殊的算法，可以计算出任何一个带区校验块的存放位置。这样就可以确保任何对校验块进行的读写操作都会在所有的RAID磁盘中进行均衡，既提高了系统可靠性也消除了产生瓶颈的可能，对大小数据量的读写都有很好的性能。为了能跨越数组里的所有磁盘来写入数据及校验码信息，RAID 5设定最少需要三个磁盘，因此在这种情况下，会有1/3的磁盘容量会被备份校验码占用而无法使用，当有四个磁盘时，则需要1/4的容量作为备份，才能让最坏情况的发生率 降到最低。当磁盘的数目增多时，每个磁盘上被备份校验码占用的磁盘容量就会降低，但是磁盘故障的风险率也同时增加了，一但同时有两个磁盘故障，则无法进行数据恢复。\nRAID6 RAID 6和RAID 5相似但它有两个分布式奇偶校验。大多用在大数量的阵列中。我们最少需要4个驱动器，即使有2个驱动器发生故障，我们依然可以更换新的驱动器后重建数据。 它比RAID 5慢，因为它将数据同时写到4个驱动器上。当我们使用硬件 RAID 控制器时速度就处于平均水准。如果我们有6个的1TB驱动器，4个驱动器将用于数据保存，2个驱动器将用于校验。\nRAID10 RAID 10可以被称为1 + 0或0 +1。它将做镜像+条带两个工作。在 RAID 10中首先做镜像然后做条带。在 RAID 01上首先做条带，然后做镜像。RAID 10比RAID 01好。\n比较 级别 RAID0 RAID1 RAID5 RAID6 RAID10 别名 条带 镜像 单磁盘分布奇偶位条带 双磁盘分布奇偶位条带 镜像阵列条带 容错性 无 有 有 有 有 冗余类型 无 镜像 奇偶校验 双奇偶校验 镜像 备份盘 无 有 有 有 有 读性能 高 低 高 高 中等 随机写性能 高 低 低 低 中等 连续写性能 高 低 低 低 中等 需要磁盘数 2+ 2N 3+ 4+ 4N 可用容量 100% 50% (N-1)/N (N-2)/N 50% 典型应用 无故障迅速读写，安全性要求不高 随机数据读写，安全性较高，例如数据库 随机数据传输，安全性高，例如金融 对读取性能要求高，安全性极高 数据量大，安全性高 参考 Raid级别结构知识浅析\n","permalink":"http://bug1024.com/2017/12/03/raid/","summary":"\u003cblockquote\u003e\n\u003cp\u003eRAID(Redundent Array of Inexpensive Disks)，廉价冗余磁盘阵列，后来RAID中的I被改作了Independent，就成了“独立冗余磁盘阵列”，但这只是名称的变化，实质性的内容并没有改变。可以把RAID理解成一种使用磁盘驱动器的方法，它将一组磁盘驱动器用某种逻辑方式联系起来，作为逻辑上的一个磁盘驱动器来使用。\u003c/p\u003e","title":"Raid级别"},{"content":"众所周知，当业务量达到一定程度时，单库单表已经无法hold住压力，这个时候往往需要根据业务进行分库分表。\n分表类型 垂直拆分 即大表拆小表，将不经常使用或者长度较大的字段拆分出去放到“副表”中 水平拆分 即横向分表，将表中不同的数据行按照一定规律分布到不同的数据库表中 分表规则 通常根据主键或者业务id等字段进行hash和取模，得到相应的db和table，当然也可以将id和库的Mapping关系记录在一个单独的库中，优点是Mapping算法可以随意更改， 缺点是引入额外的单点。此外，还有根据时间维度进行分表的。\n分库分表意义 分库通常是避免资源竞争，不同的库部署在不同的数据库实例上，某种程度上也可以缓解主从同步延迟，一般一个实例是一个IO线程进行binlog同步，如果只有一个库那么binlog量过大IO线程压力也会增大，从而影响主从同步。 分表通常是减少表容量，提升查询速度，单表500w到1000w数据量数据库性能往往比较可观。\n分库分表带来的问题 跨库join的问题 跨库事务（分布式事务）的问题 相关资料 大众点评订单系统分库分表实践 ","permalink":"http://bug1024.com/2017/11/21/db-sharding/","summary":"\u003cp\u003e众所周知，当业务量达到一定程度时，单库单表已经无法hold住压力，这个时候往往需要根据业务进行分库分表。\u003c/p\u003e\n\u003ch2 id=\"分表类型\"\u003e分表类型\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e垂直拆分 即大表拆小表，将不经常使用或者长度较大的字段拆分出去放到“副表”中\u003c/li\u003e\n\u003cli\u003e水平拆分 即横向分表，将表中不同的数据行按照一定规律分布到不同的数据库表中\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"分表规则\"\u003e分表规则\u003c/h2\u003e\n\u003cp\u003e通常根据主键或者业务id等字段进行hash和取模，得到相应的db和table，当然也可以将id和库的Mapping关系记录在一个单独的库中，优点是Mapping算法可以随意更改，\n缺点是引入额外的单点。此外，还有根据时间维度进行分表的。\u003c/p\u003e","title":"分库分表"},{"content":"工作3年多了，自己也算得上是一个合格的crud工程师。身边总是会听到类似的话语，写业务代码没有什么技术含量。不过确实也是如此，业务代码无非就是为了实现产品功能，写多了对自身水平提升帮助不大。 因此作为一个业务开发为主的工程师，在日常开发之余更应该去思考如何提高技术水平。借鉴了一些别人分享的人生经验，结合我自己的经历和理解，做了一个微小的的整理工作。\nLearning 看书、google、看视频、看别人的博客都可以，但要注意一点是“系统化”，特别是一些基础性的东西，例如JVM原理、Java编程、网络编程，HTTP协议等等，这些基础技术不能只通过google或者博客学习，我的做法一般是先完整的看完一本书全面的了解，然后再通过google、视频、博客去有针对性的查找一些有疑问的地方，或者一些技巧。\nTrying 形象来说就是“自己动手丰衣足食”，也就是自己去尝试搭建一些模拟环境，自己写一些测试程序。例如：\nJvm垃圾回收：可以自己写一个简单的测试程序，分配内存不释放，然后调整各种jvm启动参数，再运行的过程中使用jstack、jstat等命令查看jvm的堆内存分布和垃圾回收情况。这样的程序写起来很简单，简单一点的就几行，复杂一点的也就几十行。 Reactor原理：自己真正去尝试写一个Reactor模式的Demo，不要以为这个很难，最简单的Reactor模式代码量（包括注释）不超过200行（可以参考Doug Lee的PPT）。自己写完后，再去看看netty怎么做，一对比理解就更加深刻了。 MySQL：既然有线上的配置可以参考，那可以直接让DBA将线上配置发给我们直接学习，然后自己搭建一个MySQL环境，用线上的配置启动；要知道很多同学用了很多年MySQL，但是连个简单的MySQL环境都搭不起来。 框架封装了DAL层：可以自己用JDBC尝试去写一个分库分表的简单实现，然后与框架的实现进行对比，看看差异在哪里。 简单来说，就是要将学到的东西真正试试，才能理解更加深刻，印第安人有一句谚语：I hear and I forget. I see and I remember. I do and I understand ，而且“试试”其实可以比较简单，很多时候我们都可以自己动手做。 当然，如果能够在实际工作中使用，效果会更好，毕竟实际的线上环境和业务复杂度不是我们写个模拟程序就能够模拟的，但这样的机会可遇不可求，大部分情况我们还真的只能靠自己模拟，然后等到真正业务要用的时候，能够信手拈来。\nTeaching 一般来说，经过Learning和Trying，能掌握70%左右，但要真正掌握，我觉得一定要做到能够跟别人讲清楚。因为在讲的时候，我们既需要将一个知识点系统化，也需要考虑各种细节，这会促使我们进一步思考和学习。同时，讲出来后看或者听的人可以有不同的理解，或者有新的补充，这相当于继续完善了整个知识技能体系。\n最后 成为技术大牛梦想虽然很美好，但是要付出很多，都需要花费时间和精力，这个过程中可能很苦逼，也可能很枯燥，方法大家都懂，但真正起决定作用的，其实还是我们对技术的热情和兴趣！\n","permalink":"http://bug1024.com/2017/11/13/grow/","summary":"\u003cp\u003e工作3年多了，自己也算得上是一个合格的crud工程师。身边总是会听到类似的话语，写业务代码没有什么技术含量。不过确实也是如此，业务代码无非就是为了实现产品功能，写多了对自身水平提升帮助不大。\n因此作为一个业务开发为主的工程师，在日常开发之余更应该去思考如何提高技术水平。借鉴了一些别人分享的人生经验，结合我自己的经历和理解，做了一个微小的的整理工作。\u003c/p\u003e","title":"技术成长"},{"content":"基本概念 操作系统中 heap 和 stack 的区别 什么是基于注解的切面实现 什么是 对象/关系 映射集成模块 什么是 Java 的反射机制 什么是 ACID BS与CS的联系与区别 Cookie 和 Session的区别 fail-fast 与 fail-safe 机制有什么区别 get 和 post请求的区别 Interface 与 abstract 类的区别 IOC的优点是什么 IO 和 NIO的区别，NIO优点 Java 8 / Java 7 为我们提供了什么新功能 什么是竞态条件？ 举个例子说明。 JRE、JDK、JVM 及 JIT 之间有什么不同 MVC的各个部分都有那些技术来实现?如何实现? RPC 通信和 RMI 区别 什么是 Web Service（Web服务） JSWDL开发包的介绍。JAXP、JAXM的解释。SOAP、UDDI,WSDL解释。 WEB容器主要有哪些功能? 并请列出一些常见的WEB容器名字。 一个\u0026quot;.java\u0026quot;源文件中是否可以包含多个类（不是内部类）？有什么限制 简单说说你了解的类加载器。是否实现过类加载器 解释一下什么叫AOP（面向切面编程） 请简述 Servlet 的生命周期及其相关的方法 请简述一下 Ajax 的原理及实现步骤 简单描述Struts的主要功能 什么是 N 层架构 什么是CORBA？用途是什么 什么是Java虚拟机？为什么Java被称作是“平台无关的编程语言” 什么是正则表达式？用途是什么？哪个包使用正则表达式来实现模式匹配 什么是懒加载（Lazy Loading） 什么是尾递归，为什么需要尾递归 什么是控制反转（Inversion of Control）与依赖注入（Dependency Injection） 关键字 finalize 什么是finalize()方法 finalize()方法什么时候被调用 析构函数(finalization)的目的是什么 final 和 finalize 的区别 final final关键字有哪些用法 final 与 static 关键字可以用于哪里？它们的作用是什么 final, finally, finalize的区别 final、finalize 和 finally 的不同之处？ 能否在运行时向 static final 类型的赋值 使用final关键字修饰一个变量时，是引用不能变，还是引用的对象不能变 一个类被声明为final类型，表示了什么意思 throws, throw, try, catch, finally分别代表什么意义 Java 有几种修饰符？分别用来修饰什么 volatile volatile 修饰符的有过什么实践 volatile 变量是什么？volatile 变量和 atomic 变量有什么不同 volatile 类型变量提供什么保证？能使得一个非原子操作变成原子操作吗 能创建 volatile 数组吗？ transient变量有什么特点 super什么时候使用 public static void 写成 static public void会怎样 说明一下public static void main(String args[])这段声明里每个关键字的作用 请说出作用域public, private, protected, 以及不写时的区别 sizeof 是Java 的关键字吗 static static class 与 non static class的区别 static 关键字是什么意思？Java中是否可以覆盖(override)一个private或者是static的方法 静态类型有什么特点 main() 方法为什么必须是静态的？能不能声明 main() 方法为非静态 是否可以从一个静态（static）方法内部发出对非静态（non-static）方法的调用 静态变量在什么时候加载？编译期还是运行期？静态代码块加载的时机呢 成员方法是否可以访问静态变量？为什么静态方法不能访问成员变量 switch switch 语句中的表达式可以是什么类型数据 switch 是否能作用在byte 上，是否能作用在long 上，是否能作用在String上 while 循环和 do 循环有什么不同 操作符 \u0026amp;操作符和\u0026amp;\u0026amp;操作符有什么区别? a = a + b 与 a += b 的区别？ 3*0.1 == 0.3 将会返回什么？true 还是 false？ float f=3.4; 是否正确？ short s1 = 1; s1 = s1 + 1;有什么错? 数据结构 基础类型(Primitives) 基础类型(Primitives)与封装类型(Wrappers)的区别在哪里 简述九种基本数据类型的大小，以及他们的封装类 int 和 Integer 哪个会占用更多的内存？ int 和 Integer 有什么区别？parseInt()函数在什么时候使用到 float和double的默认值是多少 如何去小数四舍五入保留小数点后两位 char 型变量中能不能存贮一个中文汉字，为什么 类型转换 怎样将 bytes 转换为 long 类型 怎么将 byte 转换为 String 如何将数值型字符转换为数字 我们能将 int 强制转换为 byte 类型的变量吗？如果该值大于 byte 类型的范围，将会出现什么现象 能在不进行强制转换的情况下将一个 double 值赋值给 long 类型的变量吗 类型向下转换是什么 数组 如何权衡是使用无序的数组还是有序的数组 怎么判断数组是 null 还是为空 怎么打印数组？ 怎样打印数组中的重复元素 Array 和 ArrayList有什么区别？什么时候应该使用Array而不是ArrayList 数组和链表数据结构描述，各自的时间复杂度 数组有没有length()这个方法? String有没有length()这个方法 队列 队列和栈是什么，列出它们的区别 BlockingQueue是什么 简述 ConcurrentLinkedQueue LinkedBlockingQueue 的用处和不同之处。 ArrayList、Vector、LinkedList的存储性能和特性 String StringBuffer ByteBuffer 与 StringBuffer有什么区别 HashMap HashMap的工作原理是什么 内部的数据结构是什么 HashMap 的 table的容量如何确定？loadFactor 是什么？ 该容量如何变化？这种变化会带来什么问题？ HashMap 实现的数据结构是什么？如何实现 HashMap 和 HashTable、ConcurrentHashMap 的区别 HashMap的遍历方式及效率 HashMap、LinkedMap、TreeMap的区别 如何决定选用HashMap还是TreeMap 如果HashMap的大小超过了负载因子(load factor)定义的容量，怎么办 HashMap 是线程安全的吗？并发下使用的 Map 是什么，它们内部原理分别是什么，比如存储方式、 hashcode、扩容、 默认容量等 HashSet HashSet和TreeSet有什么区别 HashSet 内部是如何工作的 WeakHashMap 是怎么工作的？ Set Set 里的元素是不能重复的，那么用什么方法来区分重复与否呢？是用 == 还是 equals()？ 它们有何区别? TreeMap：TreeMap 是采用什么树实现的？TreeMap、HashMap、LindedHashMap的区别。TreeMap和TreeSet在排序时如何比较元素？Collections工具类中的sort()方法如何比较元素？ TreeSet：一个已经构建好的 TreeSet，怎么完成倒排序。 EnumSet 是什么 Hash算法 Hashcode 的作用 简述一致性 Hash 算法 有没有可能 两个不相等的对象有相同的 hashcode？当两个对象 hashcode 相同怎么办？如何获取值对象 为什么在重写 equals 方法的时候需要重写 hashCode 方法？equals与 hashCode 的异同点在哪里 a.hashCode() 有什么用？与 a.equals(b) 有什么关系 hashCode() 和 equals() 方法的重要性体现在什么地方 Object：Object有哪些公用方法？Object类hashcode,equals 设计原则？ sun为什么这么设计？Object类的概述 如何在父类中为子类自动完成所有的 hashcode 和 equals 实现？这么做有何优劣。 可以在 hashcode() 中使用随机数字吗？ LinkedHashMap LinkedHashMap 和 PriorityQueue 的区别是什么 List List, Set, Map三个接口，存取元素时各有什么特点 List, Set, Map 是否继承自 Collection 接口 遍历一个 List 有哪些不同的方式 LinkedList LinkedList 是单向链表还是双向链表 LinkedList 与 ArrayList 有什么区别 描述下 Java 中集合（Collections），接口（Interfaces），实现（Implementations）的概念。LinkedList 与 ArrayList 的区别是什么？ 插入数据时，ArrayList, LinkedList, Vector谁速度较快？ ArrayList ArrayList 和 HashMap 的默认大小是多数 ArrayList 和 LinkedList 的区别，什么时候用 ArrayList？ ArrayList 和 Set 的区别？ ArrayList, LinkedList, Vector的区别 ArrayList是如何实现的，ArrayList 和 LinkedList 的区别 ArrayList如何实现扩容 Array 和 ArrayList 有何区别？什么时候更适合用Array 说出ArraList,Vector, LinkedList的存储性能和特性 Map Map, Set, List, Queue, Stack Map 接口提供了哪些不同的集合视图 为什么 Map 接口不继承 Collection 接口 Collections 介绍Java中的Collection FrameWork。集合类框架的基本接口有哪些 Collections类是什么？Collection 和 Collections的区别？Collection、Map的实现 集合类框架的最佳实践有哪些 为什么 Collection 不从 Cloneable 和 Serializable 接口继承 说出几点 Java 中使用 Collections 的最佳实践？ Collections 中 遗留类 (HashTable、Vector) 和 现有类的区别 什么是 B+树，B-树，列出实际的使用场景。 接口 Comparator 与 Comparable 接口是干什么的？列出它们的区别 对象 拷贝(clone) 如何实现对象克隆 深拷贝和浅拷贝区别 深拷贝和浅拷贝如何实现激活机制 写clone()方法时，通常都有一行代码，是什么 比较 在比较对象时，\u0026quot;==\u0026quot; 运算符和 equals 运算有何区别 如果要重写一个对象的equals方法，还要考虑什么 两个对象值相同(x.equals(y) == true)，但却可有不同的hash code，这句话对不对 构造器 构造器链是什么 创建对象时构造器的调用顺序 不可变对象 什么是不可变象（immutable object） 为什么 Java 中的 String 是不可变的（Immutable） 如何构建不可变的类结构？关键点在哪里 能创建一个包含可变对象的不可变对象吗 如何对一组对象进行排序 方法 构造器（constructor）是否可被重写（override） 方法可以同时即是 static 又是 synchronized 的吗 abstract 的 method是否可同时是 static，是否可同时是 native，是否可同时是synchronized Java支持哪种参数传递类型 一个对象被当作参数传递到一个方法，是值传递还是引用传递 当一个对象被当作参数传递到一个方法后，此方法可改变这个对象的属性，并可返回变化后的结果，那么这里到底是值传递还是引用传递 我们能否重载main()方法 如果main方法被声明为private会怎样 GC 概念 GC是什么？为什么要有GC 什么时候会导致垃圾回收 GC是怎么样运行的 新老以及永久区是什么 GC 有几种方式？怎么配置 什么时候一个对象会被GC？ 如何判断一个对象是否存活 System.gc() Runtime.gc()会做什么事情？ 能保证 GC 执行吗 垃圾回收器可以马上回收内存吗？有什么办法主动通知虚拟机进行垃圾回收？ Minor GC 、Major GC、Young GC 与 Full GC分别在什么时候发生 垃圾回收算法的实现原理 如果对象的引用被置为null，垃圾收集器是否会立即释放对象占用的内存？ 垃圾回收的最佳做法是什么 GC收集器有哪些 垃圾回收器的基本原理是什么？ 串行(serial)收集器和吞吐量(throughput)收集器的区别是什么 Serial 与 Parallel GC之间的不同之处 CMS 收集器 与 G1 收集器的特点与区别 CMS垃圾回收器的工作过程 JVM 中一次完整的 GC 流程是怎样的？ 对象如何晋升到老年代 吞吐量优先和响应优先的垃圾收集器选择 GC策略 举个实际的场景，选择一个GC策略 JVM的永久代中会发生垃圾回收吗 收集方法 标记清除、标记整理、复制算法的原理与特点？分别用在什么地方 如果让你优化收集方法，有什么思路 JVM 参数 说说你知道的几种主要的jvm 参数 -XX:+UseCompressedOops 有什么作用 类加载器(ClassLoader) Java 类加载器都有哪些 JVM如何加载字节码文件 内存管理 JVM内存分哪几个区，每个区的作用是什么 一个对象从创建到销毁都是怎么在这些部分里存活和转移的 解释内存中的栈(stack)、堆(heap)和方法区(method area)的用法 JVM中哪个参数是用来控制线程的栈堆栈小 简述内存分配与回收策略 简述重排序，内存屏障，happen-before，主内存，工作内存 Java中存在内存泄漏问题吗？请举例说明 简述 Java 中软引用（SoftReferenc）、弱引用（WeakReference）和虚引用 内存映射缓存区是什么 jstack，jstat，jmap，jconsole怎么用 32 位 JVM 和 64 位 JVM 的最大堆内存分别是多数？32 位和 64 位的 JVM，int 类型变量的长度是多数？ 怎样通过 Java 程序来判断 JVM 是 32 位 还是 64 位 JVM自身会维护缓存吗？是不是在堆中进行对象分配，操作系统的堆还是JVM自己管理堆 什么情况下会发生栈内存溢出 双亲委派模型是什么 多线程 基本概念 什么是线程 多线程的优点 多线程的几种实现方式 用 Runnable 还是 Thread 什么是线程安全 Vector, SimpleDateFormat 是线程安全类吗 什么 Java 原型不是线程安全的 哪些集合类是线程安全的 多线程中的忙循环是什么 如何创建一个线程 编写多线程程序有几种实现方式 什么是线程局部变量 线程和进程有什么区别？进程间如何通讯，线程间如何通讯 什么是多线程环境下的伪共享（false sharing） 同步和异步有何异同，在什么情况下分别使用他们？举例说明 Current ConcurrentHashMap 和 Hashtable的区别 ArrayBlockingQueue, CountDownLatch的用法 ConcurrentHashMap的并发度是什么 CyclicBarrier 和 CountDownLatch有什么不同？各自的内部原理和用法是什么 Semaphore的用法 Thread 启动一个线程是调用 run() 还是 start() 方法？start() 和 run() 方法有什么区别 调用start()方法时会执行run()方法，为什么不能直接调用run()方法 sleep() 方法和对象的 wait() 方法都可以让线程暂停执行，它们有什么区别 yield方法有什么作用？sleep() 方法和 yield() 方法有什么区别 Java 中如何停止一个线程 stop() 和 suspend() 方法为何不推荐使用 如何在两个线程间共享数据 如何强制启动一个线程 如何让正在运行的线程暂停一段时间 什么是线程组，为什么在Java中不推荐使用 你是如何调用 wait（方法的）？使用 if 块还是循环？为什么 生命周期 有哪些不同的线程生命周期 线程状态，BLOCKED 和 WAITING 有什么区别 画一个线程的生命周期状态图 ThreadLocal 用途是什么，原理是什么，用的时候要注意什么 ThreadPool 线程池是什么？为什么要使用它 如何创建一个Java线程池 ThreadPool用法与优势 提交任务时，线程池队列已满时会发会生什么 newCache 和 newFixed 有什么区别？简述原理。构造函数的各个参数的含义是什么，比如 coreSize, maxsize 等 线程池的实现策略 线程池的关闭方式有几种，各自的区别是什么 线程池中submit() 和 execute()方法有什么区别？ 线程调度 Java中用到的线程调度算法是什么 什么是多线程中的上下文切换 你对线程优先级的理解是什么 什么是线程调度器 (Thread Scheduler) 和时间分片 (Time Slicing) 线程同步 请说出你所知的线程同步的方法 synchronized 的原理是什么 synchronized 和 ReentrantLock 有什么不同 什么场景下可以使用 volatile 替换 synchronized 有T1，T2，T3三个线程，怎么确保它们按顺序执行？怎样保证T2在T1执行完后执行，T3在T2执行完后执行 同步块内的线程抛出异常会发生什么 当一个线程进入一个对象的 synchronized 方法A 之后，其它线程是否可进入此对象的 synchronized 方法B 使用 synchronized 修饰静态方法和非静态方法有什么区别 如何从给定集合那里创建一个 synchronized 的集合 锁 Java Concurrency API 中 的 Lock 接口是什么？对比同步它有什么优势 Lock 与 Synchronized 的区别？Lock 接口比 synchronized 块的优势是什么 ReadWriteLock是什么？ 锁机制有什么用 什么是乐观锁（Optimistic Locking）？如何实现乐观锁？如何避免ABA问题 解释以下名词：重排序，自旋锁，偏向锁，轻量级锁，可重入锁，公平锁，非公平锁，乐观锁，悲观锁 什么时候应该使用可重入锁 简述锁的等级方法锁、对象锁、类锁 Java中活锁和死锁有什么区别？ 什么是死锁(Deadlock)？导致线程死锁的原因？如何确保 N 个线程可以访问 N 个资源同时又不导致死锁 死锁与活锁的区别，死锁与饥饿的区别 怎么检测一个线程是否拥有锁 如何实现分布式锁 有哪些无锁数据结构，他们实现的原理是什么 读写锁可以用于什么应用场景 Executors类是什么？ Executor和Executors的区别 什么是Java线程转储(Thread Dump)，如何得到它 如何在Java中获取线程堆栈 说出 3 条在 Java 中使用线程的最佳实践 在线程中你怎么处理不可捕捉异常 实际项目中使用多线程举例。你在多线程环境中遇到的常见的问题是什么？你是怎么解决它的 请说出与线程同步以及线程调度相关的方法 程序中有3个 socket，需要多少个线程来处理 假如有一个第三方接口，有很多个线程去调用获取数据，现在规定每秒钟最多有 10 个线程同时调用它，如何做到 如何在 Windows 和 Linux 上查找哪个线程使用的 CPU 时间最长 如何确保 main() 方法所在的线程是 Java 程序最后结束的线程 非常多个线程（可能是不同机器），相互之间需要等待协调才能完成某种工作，问怎么设计这种协调方案 你需要实现一个高效的缓存，它允许多个用户读，但只允许一个用户写，以此来保持它的完整性，你会怎样去实现它 异常 基本概念 Error 和 Exception有什么区别 UnsupportedOperationException是什么 NullPointerException 和 ArrayIndexOutOfBoundException 之间有什么相同之处 什么是受检查的异常，什么是运行时异常 运行时异常与一般异常有何异同 简述一个你最常见到的runtime exception(运行时异常) finally finally关键词在异常处理中如何使用 如果执行finally代码块之前方法返回了结果，或者JVM退出了，finally块中的代码还会执行吗 try里有return，finally还执行么？那么紧跟在这个try后的finally {}里的code会不会被执行，什么时候被执行，在return前还是后 在什么情况下，finally语句不会执行 throw 和 throws 有什么区别？ OOM你遇到过哪些情况？你是怎么搞定的？ SOF你遇到过哪些情况？ 既然我们可以用RuntimeException来处理错误，那么你认为为什么Java中还存在检查型异常 当自己创建异常类的时候应该注意什么 导致空指针异常的原因 异常处理 handle or declare 原则应该如何理解 怎么利用 JUnit 来测试一个方法的异常 catch块里别不写代码有什么问题 你曾经自定义实现过异常吗？怎么写的 什么是 异常链 在try块中可以抛出异常吗 JDBC 通过 JDBC 连接数据库有哪几种方式 阐述 JDBC 操作数据库的基本步骤 JDBC 中如何进行事务处理 什么是 JdbcTemplate 什么是 DAO 模块 使用 JDBC 操作数据库时，如何提升读取数据的性能？如何提升更新数据的性能 列出 5 个应该遵循的 JDBC 最佳实践 IO File File类型中定义了什么方法来创建一级目录 File类型中定义了什么方法来判断一个文件是否存在 流 为了提高读写性能，可以采用什么流 Java中有几种类型的流 JDK 为每种类型的流提供了一些抽象类以供继承，分别是哪些类 对文本文件操作用什么I/O流 对各种基本数据类型和String类型的读写，采用什么流 能指定字符编码的 I/O 流类型是什么 序列化 什么是序列化？如何实现 Java 序列化及注意事项 Serializable 与 Externalizable 的区别 Socket socket 选项 TCP NO DELAY 是指什么 Socket 工作在 TCP/IP 协议栈是哪一层 TCP、UDP 区别及 Java 实现方式 说几点 IO 的最佳实践 直接缓冲区与非直接缓冲器有什么区别？ 怎么读写 ByteBuffer？ByteBuffer 中的字节序是什么 当用System.in.read(buffer)从键盘输入一行n个字符后，存储在缓冲区buffer中的字节数是多少 如何使用扫描器类（Scanner Class）令牌化 面向对象编程（OOP） 解释下多态性（polymorphism），封装性（encapsulation），内聚（cohesion）以及耦合（coupling） 多态的实现原理 封装、继承和多态是什么 对象封装的原则是什么? 类 获得一个类的类对象有哪些方式 重载（Overload）和重写（Override）的区别。重载的方法能否根据返回类型进行区分？ 说出几条 Java 中方法重载的最佳实践 抽象类 抽象类和接口的区别 抽象类中是否可以有静态的main方法 抽象类是否可实现(implements)接口 抽象类是否可继承具体类(concrete class) 匿名类（Anonymous Inner Class） 匿名内部类是否可以继承其它类？是否可以实现接口 内部类 内部类分为几种 内部类可以引用它的包含类（外部类）的成员吗 请说一下 Java 中为什么要引入内部类？还有匿名内部类 继承 继承（Inheritance）与聚合（Aggregation）的区别在哪里 继承和组合之间有什么不同 为什么类只能单继承，接口可以多继承 存在两个类，B 继承 A，C 继承 B，能将 B 转换为 C 么？如 C = (C) B 如果类 a 继承类 b，实现接口c，而类 b 和接口 c 中定义了同名变量，请问会出现什么问题 接口 接口是什么 接口是否可继承接口 为什么要使用接口而不是直接使用具体类？接口有什么优点 泛型 泛型的存在是用来解决什么问题 泛型的常用特点 List\u0026lt;String\u0026gt;能否转为List\u0026lt;Object\u0026gt; 工具类 日历 Calendar Class的用途 如何在Java中获取日历类的实例 解释一些日历类中的重要方法 GregorianCalendar 类是什么 SimpleTimeZone 类是什么 Locale类是什么 如何格式化日期对象 如何添加小时(hour)到一个日期对象(Date Objects) 如何将字符串 YYYYMMDD 转换为日期 Math Math.round()什么作用？Math.round(11.5) 等于多少？Math.round(-11.5)等于多少？ XML XML文档定义有几种形式？它们之间有何本质区别？解析XML文档有哪几种方式？DOM 和 SAX 解析器有什么不同？ Java解析XML的方式 用 jdom 解析 xml 文件时如何解决中文问题？如何解析 你在项目中用到了 XML 技术的哪些方面？如何实现 动态代理 描述动态代理的几种实现方式，分别说出相应的优缺点 设计模式 什么是设计模式（Design Patterns）？你用过哪种设计模式？用在什么场合 你知道哪些商业级设计模式？ 哪些设计模式可以增加系统的可扩展性 单例模式 除了单例模式，你在生产环境中还用过什么设计模式？ 写 Singleton 单例模式 单例模式的双检锁是什么 如何创建线程安全的 Singleton 什么是类的单例模式 写出三种单例模式实现 适配器模式 适配器模式是什么？什么时候使用 适配器模式和代理模式之前有什么不同 适配器模式和装饰器模式有什么区别 什么时候使用享元模式 什么时候使用组合模式 什么时候使用访问者模式 什么是模板方法模式 请给出1个符合开闭原则的设计模式的例子 开放问题 用一句话概括 Web 编程的特点 Google是如何在一秒内把搜索结果返回给用户 哪种依赖注入方式你建议使用，构造器注入，还是 Setter方法注入 树（二叉或其他）形成许多普通数据结构的基础。请描述一些这样的数据结构以及何时可以使用它们 某一项功能如何设计 线上系统突然变得异常缓慢，你如何查找问题 什么样的项目不适合用框架 新浪微博是如何实现把微博推给订阅者 简要介绍下从浏览器输入 URL 开始到获取到请求界面之后 Java Web 应用中发生了什么 请你谈谈SSH整合 高并发下，如何做到安全的修改同一行数据 12306网站的订票系统如何实现，如何保证不会票不被超卖 网站性能优化如何优化的 聊了下曾经参与设计的服务器架构 请思考一个方案，实现分布式环境下的 countDownLatch 请思考一个方案，设计一个可以控制缓存总体大小的自动适应的本地缓存 在你的职业生涯中，算得上最困难的技术挑战是什么 如何写一篇设计文档，目录是什么 大写的O是什么？举几个例子 编程中自己都怎么考虑一些设计原则的，比如开闭原则，以及在工作中的应用 解释一下网络应用的模式及其特点 设计一个在线文档系统，文档可以被编辑，如何防止多人同时对同一份文档进行编辑更新 说出数据连接池的工作机制是什么 怎么获取一个文件中单词出现的最高频率 描述一下你最常用的编程风格 如果有机会重新设计你们的产品，你会怎么做 如何搭建一个高可用系统 如何启动时不需输入用户名与密码 如何在基于Java的Web项目中实现文件上传和下载 如何实现一个秒杀系统，保证只有几位用户能买到某件商品。 如何实现负载均衡，有哪些算法可以实现 如何设计一个购物车？想想淘宝的购物车如何实现的 如何设计一套高并发支付方案，架构如何设计 如何设计建立和保持 100w 的长连接 如何避免浏览器缓存。 如何防止缓存雪崩 如果AB两个系统互相依赖，如何解除依 如果有人恶意创建非法连接，怎么解决 如果有几十亿的白名单，每天白天需要高并发查询，晚上需要更新一次，如何设计这个功能 如果系统要使用超大整数（超过long长度范围），请你设计一个数据结构来存储这种超大型数字以及设计一种算法来实现超大整数加法运算） 如果要设计一个图形系统，请你设计基本的图形元件(Point,Line,Rectangle,Triangle)的简单实现 如果让你实现一个并发安全的链表，你会怎么做 应用服务器与WEB 服务器的区别？应用服务器怎么监控性能，各种方式的区别？你使用过的应用服务器优化技术有哪些 大型网站在架构上应当考虑哪些问题 有没有处理过线上问题？出现内存泄露，CPU利用率标高，应用无响应时如何处理的 最近看什么书，印象最深刻的是什么 描述下常用的重构技巧 你使用什么版本管理工具？分支（Branch）与标签（Tag）之间的区别在哪里 你有了解过存在哪些反模式（Anti-Patterns）吗 你用过的网站前端优化的技术有哪些 如何分析Thread dump 你如何理解AOP中的连接点（Joinpoint）、切点（Pointcut）、增强（Advice）、引介（Introduction）、织入（Weaving）、切面（Aspect）这些概念 你是如何处理内存泄露或者栈溢出问题的 你们线上应用的 JVM 参数有哪些 怎么提升系统的QPS和吞吐量 知识面 解释什么是 MESI 协议(缓存一致性) 谈谈 reactor 模型 Java 9 带来了怎样的新功能 Java 与 C++ 对比，C++ 或 Java 中的异常处理机制的简单原理和应用 简单讲讲 Tomcat 结构，以及其类加载器流程 虚拟内存是什么 阐述下 SOLID 原则 请简要讲一下你对测试驱动开发（TDD）的认识 CDN实现原理 Maven 和 ANT 有什么区别 UML中有哪些常用的图 Linux Linux 下 IO 模型有几种，各自的含义是什么。 Linux 系统下你关注过哪些内核参数，说说你知道的 Linux 下用一行命令查看文件的最后五行 平时用到哪些 Linux 命令 用一行命令输出正在运行的 Java 进程 使用什么命令来确定是否有 Tomcat 实例运行在机器上 什么是 N+1 难题 什么是 paxos 算法 什么是 restful，讲讲你理解的 restful 什么是 zab 协议 什么是领域模型(domain model)？贫血模型(anaemic domain model) 和充血模型(rich domain model)有什么区别 什么是领域驱动开发（Domain Driven Development） 介绍一下了解的 Java 领域的 Web Service 框架 Web Server、Web Container 与 Application Server 的区别是什么 微服务（MicroServices）与巨石型应用（Monolithic Applications）之间的区别在哪里 描述 Cookie 和 Session 的作用，区别和各自的应用范围，Session工作原理 你常用的持续集成（Continuous Integration）、静态代码分析（Static Code Analysis）工具有哪些 简述下数据库正则化（Normalizations） KISS,DRY,YAGNI 等原则是什么含义 分布式事务的原理，优缺点，如何使用分布式事务？ 布式集群下如何做到唯一序列号 网络 HTTPS 的加密方式是什么，讲讲整个加密解密流程 HTTPS和HTTP的区别 HTTP连接池实现原理 HTTP集群方案 Nginx、lighttpd、Apache三大主流 Web服务器的区别 是否看过框架的一些代码 持久层设计要考虑的问题有哪些？你用过的持久层框架有哪些 数值提升是什么 你能解释一下里氏替换原则吗 你是如何测试一个应用的？知道哪些测试框架 传输层常见编程协议有哪些？并说出各自的特点 编程题 计算加班费 加班10小时以下加班费是时薪的1.5倍。加班10小时或以上，按4元/时算。提示：（一个月工作26天，一天正常工作8小时）\n计算1000月薪，加班9小时的加班费 计算2500月薪，加班11小时的加班费 计算1000月薪，加班15小时的加班费 卖东西 一家商场有红苹果和青苹果出售。（红苹果5元/个，青苹果4元/个）。\n模拟一个进货。红苹果跟青苹果各进200个。 模拟一个出售。红苹果跟青苹果各买出10个。每卖出一个苹果需要进行统计。 提示：一个苹果是一个单独的实体。\n日期提取 有这样一个时间字符串：2008-8-8 20:08:08 ， 请编写能够匹配它的正则表达式，并编写Java代码将日期后面的时分秒提取出来，即：20:08:08\n线程 8设计4个线程，其中两个线程每次对j增加1，另外两个线程对j每次减少1。写出程序。 用Java写一个多线程程序，如写四个线程，二个加1，二个对一个变量减一，输出 wait-notify 写一段代码来解决生产者-消费者问题 数字 判断101-200之间有多少个素数，并输出所有素数 用最有效率的方法算出2乘以17等于多少 有 1 亿个数字，其中有 2 个是重复的，快速找到它，时间和空间要最优 2 亿个随机生成的无序整数,找出中间大小的值 10 亿个数字里里面找最小的 10 个 1到1亿的自然数，求所有数的拆分后的数字之和，如286 拆分成2、8、6，如1到11拆分后的数字之和 =\u0026gt; 1 + \u0026hellip; + 9 + 1 + 0 + 1 + 1 一个数如果恰好等于它的因子之和，这个数就称为 “完数 “。例如6=1＋2＋3.编程 找出1000以内的所有完数 一个数组中所有的元素都出现了三次，只有一个元素出现了一次找到这个元素 一球从100米高度自由落下，每次落地后反跳回原高度的一半；再落下，求它在 第10次落地时，共经过多少米？第10次反弹多高？ 求100－1000内质数的和 求1到100的和的平均数 求s=a+a+aaa+aaaa+aa…a的值，其中a是一个数字。例如2+22+222+2222+22222(此时共有5个数相加)，几个数相加有键盘控制。 求出1到100的和 算出1到40的质数，放进数组里 显示放组里的数 找出第[5]个数 删除第[9]个数，再显示删除后的第[9]个 有 3n+1 个数字，其中 3n 个中是重复的，只有 1 个是不重复的，怎么找出来。 有一组数1.1.2.3.5.8.13.21.34。写出程序随便输入一个数就能给出和前一组数字同规律的头5个数 计算指定数字的阶乘 开发 Fizz Buzz 给定一个包含 N 个整数的数组，找出丢失的整数 一个排好序的数组，找出两数之和为m的所有组合 将一个正整数分解质因数。例如：输入90,打印出90=2*3*3*5。 打印出所有的 “水仙花数 “，所谓 “水仙花数 “是指一个三位数，其各位数字立方和等于该数本身。例如：153是一个 “水仙花数 “，因为153=1的三次方＋5的三次方＋3的三次方 原地交换两个变量的值 找出4字节整数的中位数 找到整数的平方根 实现斐波那契 网络 用Java Socket编程，读服务器几个字符，再写入本地显示 反射 反射机制提供了什么功能？ 反射是如何实现的 哪里用到反射机制 反射中 Class.forName 和 ClassLoader 区别 反射创建类实例的三种方式是什么 如何通过反射调用对象的方法 如何通过反射获取和设置对象私有字段的值 反射机制的优缺点 数据库 写一段 JDBC 连Oracle的程序,并实现数据查询 算法 50个人围坐一圈，当数到三或者三的倍数出圈，问剩下的人是谁，原来的位置是多少 实现一个电梯模拟器用 写一个冒泡排序 写一个折半查找 随机产生20个不能重复的字符并排序 写一个函数，传入 2 个有序的整数数组，返回一个有序的整数数组 写一段代码在遍历 ArrayList 时移除一个元素 古典问题：有一对兔子，从出生后第3个月起每个月都生一对兔子，小兔子长到第四个月后每个月又生一对兔子，假如兔子都不死，问每个月的兔子总数为多少 约瑟芬环游戏 正则 请编写一段匹配IP地址的正则表达式 写出一个正则表达式来判断一个字符串是否是一个数字 字符串 写一个方法，入一个文件名和一个字符串，统计这个字符串在这个文件中出现的次数。 写一个程序找出所有字符串的组合，并检查它们是否是回文串 写一个字符串反转函数，输入abcde转换成edcba代码 小游戏，倒转句子中的单词 将GB2312编码的字符串转换为ISO-8859-1编码的字符串 请写一段代码来计算给定文本内字符“A”的个数。分别用迭代和递归两种方式 编写一个截取字符串的函数，输入为一个字符串和字节数，输出为按字节截取的字符串。 但是要保证汉字不被截半个，如“我ABC”4，应该截为“我AB”，输入“我ABC汉DEF”，6，应该输出为“我ABC”而不是“我ABC+汉的半个” 给定 2 个包含单词列表（每行一个）的文件，编程列出交集 打印出一个字符串的所有排列 将一个键盘输入的数字转化成中文输出(例如：输入1234567，输出:一百二拾三万四千五百六拾七) 在Web应用开发过程中经常遇到输出某种编码的字符，如从 GBK 到 ISO8859-1等，如何输出一个某种编码的字符串 日期 计算两个日期之间的差距 ","permalink":"http://bug1024.com/2017/11/01/java-interview/","summary":"\u003ch2 id=\"基本概念\"\u003e基本概念\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e操作系统中 heap 和 stack 的区别\u003c/li\u003e\n\u003cli\u003e什么是基于注解的切面实现\u003c/li\u003e\n\u003cli\u003e什么是 对象/关系 映射集成模块\u003c/li\u003e\n\u003cli\u003e什么是 Java 的反射机制\u003c/li\u003e\n\u003cli\u003e什么是 ACID\u003c/li\u003e\n\u003cli\u003eBS与CS的联系与区别\u003c/li\u003e\n\u003cli\u003eCookie 和 Session的区别\u003c/li\u003e\n\u003cli\u003efail-fast 与 fail-safe 机制有什么区别\u003c/li\u003e\n\u003cli\u003eget 和 post请求的区别\u003c/li\u003e\n\u003cli\u003eInterface 与 abstract 类的区别\u003c/li\u003e\n\u003cli\u003eIOC的优点是什么\u003c/li\u003e\n\u003cli\u003eIO 和 NIO的区别，NIO优点\u003c/li\u003e\n\u003cli\u003eJava 8 / Java 7 为我们提供了什么新功能\u003c/li\u003e\n\u003cli\u003e什么是竞态条件？ 举个例子说明。\u003c/li\u003e\n\u003cli\u003eJRE、JDK、JVM 及 JIT 之间有什么不同\u003c/li\u003e\n\u003cli\u003eMVC的各个部分都有那些技术来实现?如何实现?\u003c/li\u003e\n\u003cli\u003eRPC 通信和 RMI 区别\u003c/li\u003e\n\u003cli\u003e什么是 Web Service（Web服务）\u003c/li\u003e\n\u003cli\u003eJSWDL开发包的介绍。JAXP、JAXM的解释。SOAP、UDDI,WSDL解释。\u003c/li\u003e\n\u003cli\u003eWEB容器主要有哪些功能? 并请列出一些常见的WEB容器名字。\u003c/li\u003e\n\u003cli\u003e一个\u0026quot;.java\u0026quot;源文件中是否可以包含多个类（不是内部类）？有什么限制\u003c/li\u003e\n\u003cli\u003e简单说说你了解的类加载器。是否实现过类加载器\u003c/li\u003e\n\u003cli\u003e解释一下什么叫AOP（面向切面编程）\u003c/li\u003e\n\u003cli\u003e请简述 Servlet 的生命周期及其相关的方法\u003c/li\u003e\n\u003cli\u003e请简述一下 Ajax 的原理及实现步骤\u003c/li\u003e\n\u003cli\u003e简单描述Struts的主要功能\u003c/li\u003e\n\u003cli\u003e什么是 N 层架构\u003c/li\u003e\n\u003cli\u003e什么是CORBA？用途是什么\u003c/li\u003e\n\u003cli\u003e什么是Java虚拟机？为什么Java被称作是“平台无关的编程语言”\u003c/li\u003e\n\u003cli\u003e什么是正则表达式？用途是什么？哪个包使用正则表达式来实现模式匹配\u003c/li\u003e\n\u003cli\u003e什么是懒加载（Lazy Loading）\u003c/li\u003e\n\u003cli\u003e什么是尾递归，为什么需要尾递归\u003c/li\u003e\n\u003cli\u003e什么是控制反转（Inversion of Control）与依赖注入（Dependency Injection）\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"关键字\"\u003e关键字\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003efinalize\n\u003cul\u003e\n\u003cli\u003e什么是finalize()方法\n\u003cul\u003e\n\u003cli\u003efinalize()方法什么时候被调用\u003c/li\u003e\n\u003cli\u003e析构函数(finalization)的目的是什么\u003c/li\u003e\n\u003cli\u003efinal 和 finalize 的区别\u003c/li\u003e\n\u003cli\u003efinal\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003efinal关键字有哪些用法\n\u003cul\u003e\n\u003cli\u003efinal 与 static 关键字可以用于哪里？它们的作用是什么\u003c/li\u003e\n\u003cli\u003efinal, finally, finalize的区别\u003c/li\u003e\n\u003cli\u003efinal、finalize 和 finally 的不同之处？\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e能否在运行时向 static final 类型的赋值\n\u003cul\u003e\n\u003cli\u003e使用final关键字修饰一个变量时，是引用不能变，还是引用的对象不能变\u003c/li\u003e\n\u003cli\u003e一个类被声明为final类型，表示了什么意思\u003c/li\u003e\n\u003cli\u003ethrows, throw, try, catch, finally分别代表什么意义\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eJava 有几种修饰符？分别用来修饰什么\u003c/li\u003e\n\u003cli\u003evolatile\n\u003cul\u003e\n\u003cli\u003evolatile 修饰符的有过什么实践\u003c/li\u003e\n\u003cli\u003evolatile 变量是什么？volatile 变量和 atomic 变量有什么不同\u003c/li\u003e\n\u003cli\u003evolatile 类型变量提供什么保证？能使得一个非原子操作变成原子操作吗\u003c/li\u003e\n\u003cli\u003e能创建 volatile 数组吗？\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003etransient变量有什么特点\u003c/li\u003e\n\u003cli\u003esuper什么时候使用\u003c/li\u003e\n\u003cli\u003epublic static void 写成 static public void会怎样\u003c/li\u003e\n\u003cli\u003e说明一下public static void main(String args[])这段声明里每个关键字的作用\u003c/li\u003e\n\u003cli\u003e请说出作用域public, private, protected, 以及不写时的区别\u003c/li\u003e\n\u003cli\u003esizeof 是Java 的关键字吗\u003c/li\u003e\n\u003cli\u003estatic\n\u003cul\u003e\n\u003cli\u003estatic class 与 non static class的区别\u003c/li\u003e\n\u003cli\u003estatic 关键字是什么意思？Java中是否可以覆盖(override)一个private或者是static的方法\u003c/li\u003e\n\u003cli\u003e静态类型有什么特点\u003c/li\u003e\n\u003cli\u003emain() 方法为什么必须是静态的？能不能声明 main() 方法为非静态\u003c/li\u003e\n\u003cli\u003e是否可以从一个静态（static）方法内部发出对非静态（non-static）方法的调用\u003c/li\u003e\n\u003cli\u003e静态变量在什么时候加载？编译期还是运行期？静态代码块加载的时机呢\u003c/li\u003e\n\u003cli\u003e成员方法是否可以访问静态变量？为什么静态方法不能访问成员变量\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eswitch\n\u003cul\u003e\n\u003cli\u003eswitch 语句中的表达式可以是什么类型数据\u003c/li\u003e\n\u003cli\u003eswitch 是否能作用在byte 上，是否能作用在long 上，是否能作用在String上\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003ewhile 循环和 do 循环有什么不同\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"操作符\"\u003e操作符\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u0026amp;操作符和\u0026amp;\u0026amp;操作符有什么区别?\u003c/li\u003e\n\u003cli\u003ea = a + b 与 a += b 的区别？\u003c/li\u003e\n\u003cli\u003e3*0.1 == 0.3 将会返回什么？true 还是 false？\u003c/li\u003e\n\u003cli\u003efloat f=3.4; 是否正确？\u003c/li\u003e\n\u003cli\u003eshort s1 = 1; s1 = s1 + 1;有什么错?\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"数据结构\"\u003e数据结构\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e基础类型(Primitives)\n\u003cul\u003e\n\u003cli\u003e基础类型(Primitives)与封装类型(Wrappers)的区别在哪里\u003c/li\u003e\n\u003cli\u003e简述九种基本数据类型的大小，以及他们的封装类\u003c/li\u003e\n\u003cli\u003eint 和 Integer 哪个会占用更多的内存？ int 和 Integer 有什么区别？parseInt()函数在什么时候使用到\u003c/li\u003e\n\u003cli\u003efloat和double的默认值是多少\u003c/li\u003e\n\u003cli\u003e如何去小数四舍五入保留小数点后两位\u003c/li\u003e\n\u003cli\u003echar 型变量中能不能存贮一个中文汉字，为什么\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e类型转换\n\u003cul\u003e\n\u003cli\u003e怎样将 bytes 转换为 long 类型\u003c/li\u003e\n\u003cli\u003e怎么将 byte 转换为 String\u003c/li\u003e\n\u003cli\u003e如何将数值型字符转换为数字\u003c/li\u003e\n\u003cli\u003e我们能将 int 强制转换为 byte 类型的变量吗？如果该值大于 byte 类型的范围，将会出现什么现象\u003c/li\u003e\n\u003cli\u003e能在不进行强制转换的情况下将一个 double 值赋值给 long 类型的变量吗\u003c/li\u003e\n\u003cli\u003e类型向下转换是什么\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e数组\n\u003cul\u003e\n\u003cli\u003e如何权衡是使用无序的数组还是有序的数组\u003c/li\u003e\n\u003cli\u003e怎么判断数组是 null 还是为空\u003c/li\u003e\n\u003cli\u003e怎么打印数组？ 怎样打印数组中的重复元素\u003c/li\u003e\n\u003cli\u003eArray 和 ArrayList有什么区别？什么时候应该使用Array而不是ArrayList\u003c/li\u003e\n\u003cli\u003e数组和链表数据结构描述，各自的时间复杂度\u003c/li\u003e\n\u003cli\u003e数组有没有length()这个方法? String有没有length()这个方法\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e队列\n\u003cul\u003e\n\u003cli\u003e队列和栈是什么，列出它们的区别\u003c/li\u003e\n\u003cli\u003eBlockingQueue是什么\u003c/li\u003e\n\u003cli\u003e简述 ConcurrentLinkedQueue LinkedBlockingQueue 的用处和不同之处。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eArrayList、Vector、LinkedList的存储性能和特性\u003c/li\u003e\n\u003cli\u003eString\u003c/li\u003e\n\u003cli\u003eStringBuffer\n\u003cul\u003e\n\u003cli\u003eByteBuffer 与 StringBuffer有什么区别\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eHashMap\n\u003cul\u003e\n\u003cli\u003eHashMap的工作原理是什么\u003c/li\u003e\n\u003cli\u003e内部的数据结构是什么\u003c/li\u003e\n\u003cli\u003eHashMap 的 table的容量如何确定？loadFactor 是什么？ 该容量如何变化？这种变化会带来什么问题？\u003c/li\u003e\n\u003cli\u003eHashMap 实现的数据结构是什么？如何实现\u003c/li\u003e\n\u003cli\u003eHashMap 和 HashTable、ConcurrentHashMap 的区别\u003c/li\u003e\n\u003cli\u003eHashMap的遍历方式及效率\u003c/li\u003e\n\u003cli\u003eHashMap、LinkedMap、TreeMap的区别\u003c/li\u003e\n\u003cli\u003e如何决定选用HashMap还是TreeMap\u003c/li\u003e\n\u003cli\u003e如果HashMap的大小超过了负载因子(load factor)定义的容量，怎么办\u003c/li\u003e\n\u003cli\u003eHashMap 是线程安全的吗？并发下使用的 Map 是什么，它们内部原理分别是什么，比如存储方式、 hashcode、扩容、 默认容量等\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eHashSet\n\u003cul\u003e\n\u003cli\u003eHashSet和TreeSet有什么区别\u003c/li\u003e\n\u003cli\u003eHashSet 内部是如何工作的\u003c/li\u003e\n\u003cli\u003eWeakHashMap 是怎么工作的？\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eSet\n\u003cul\u003e\n\u003cli\u003eSet 里的元素是不能重复的，那么用什么方法来区分重复与否呢？是用 == 还是 equals()？ 它们有何区别?\u003c/li\u003e\n\u003cli\u003eTreeMap：TreeMap 是采用什么树实现的？TreeMap、HashMap、LindedHashMap的区别。TreeMap和TreeSet在排序时如何比较元素？Collections工具类中的sort()方法如何比较元素？\u003c/li\u003e\n\u003cli\u003eTreeSet：一个已经构建好的 TreeSet，怎么完成倒排序。\u003c/li\u003e\n\u003cli\u003eEnumSet 是什么\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eHash算法\n\u003cul\u003e\n\u003cli\u003eHashcode 的作用\u003c/li\u003e\n\u003cli\u003e简述一致性 Hash 算法\u003c/li\u003e\n\u003cli\u003e有没有可能 两个不相等的对象有相同的 hashcode？当两个对象 hashcode 相同怎么办？如何获取值对象\u003c/li\u003e\n\u003cli\u003e为什么在重写 equals 方法的时候需要重写 hashCode 方法？equals与 hashCode 的异同点在哪里\u003c/li\u003e\n\u003cli\u003ea.hashCode() 有什么用？与 a.equals(b) 有什么关系\u003c/li\u003e\n\u003cli\u003ehashCode() 和 equals() 方法的重要性体现在什么地方\u003c/li\u003e\n\u003cli\u003eObject：Object有哪些公用方法？Object类hashcode,equals 设计原则？ sun为什么这么设计？Object类的概述\u003c/li\u003e\n\u003cli\u003e如何在父类中为子类自动完成所有的 hashcode 和 equals 实现？这么做有何优劣。\u003c/li\u003e\n\u003cli\u003e可以在 hashcode() 中使用随机数字吗？\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eLinkedHashMap\n\u003cul\u003e\n\u003cli\u003eLinkedHashMap 和 PriorityQueue 的区别是什么\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eList\n\u003cul\u003e\n\u003cli\u003eList, Set, Map三个接口，存取元素时各有什么特点\u003c/li\u003e\n\u003cli\u003eList, Set, Map 是否继承自 Collection 接口\u003c/li\u003e\n\u003cli\u003e遍历一个 List 有哪些不同的方式\u003c/li\u003e\n\u003cli\u003eLinkedList\n\u003cul\u003e\n\u003cli\u003eLinkedList 是单向链表还是双向链表\u003c/li\u003e\n\u003cli\u003eLinkedList 与 ArrayList 有什么区别\u003c/li\u003e\n\u003cli\u003e描述下 Java 中集合（Collections），接口（Interfaces），实现（Implementations）的概念。LinkedList 与 ArrayList 的区别是什么？\u003c/li\u003e\n\u003cli\u003e插入数据时，ArrayList, LinkedList, Vector谁速度较快？\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eArrayList\n\u003cul\u003e\n\u003cli\u003eArrayList 和 HashMap 的默认大小是多数\u003c/li\u003e\n\u003cli\u003eArrayList 和 LinkedList 的区别，什么时候用 ArrayList？\u003c/li\u003e\n\u003cli\u003eArrayList 和 Set 的区别？\u003c/li\u003e\n\u003cli\u003eArrayList, LinkedList, Vector的区别\u003c/li\u003e\n\u003cli\u003eArrayList是如何实现的，ArrayList 和 LinkedList 的区别\u003c/li\u003e\n\u003cli\u003eArrayList如何实现扩容\u003c/li\u003e\n\u003cli\u003eArray 和 ArrayList 有何区别？什么时候更适合用Array\u003c/li\u003e\n\u003cli\u003e说出ArraList,Vector, LinkedList的存储性能和特性\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eMap\n\u003cul\u003e\n\u003cli\u003eMap, Set, List, Queue, Stack\u003c/li\u003e\n\u003cli\u003eMap 接口提供了哪些不同的集合视图\u003c/li\u003e\n\u003cli\u003e为什么 Map 接口不继承 Collection 接口\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eCollections\n\u003cul\u003e\n\u003cli\u003e介绍Java中的Collection FrameWork。集合类框架的基本接口有哪些\u003c/li\u003e\n\u003cli\u003eCollections类是什么？Collection 和 Collections的区别？Collection、Map的实现\u003c/li\u003e\n\u003cli\u003e集合类框架的最佳实践有哪些\u003c/li\u003e\n\u003cli\u003e为什么 Collection 不从 Cloneable 和 Serializable 接口继承\u003c/li\u003e\n\u003cli\u003e说出几点 Java 中使用 Collections 的最佳实践？\u003c/li\u003e\n\u003cli\u003eCollections 中 遗留类 (HashTable、Vector) 和 现有类的区别\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e什么是 B+树，B-树，列出实际的使用场景。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"接口\"\u003e接口\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eComparator 与 Comparable 接口是干什么的？列出它们的区别\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"对象\"\u003e对象\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e拷贝(clone)\n\u003cul\u003e\n\u003cli\u003e如何实现对象克隆\u003c/li\u003e\n\u003cli\u003e深拷贝和浅拷贝区别\u003c/li\u003e\n\u003cli\u003e深拷贝和浅拷贝如何实现激活机制\u003c/li\u003e\n\u003cli\u003e写clone()方法时，通常都有一行代码，是什么\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e比较\n\u003cul\u003e\n\u003cli\u003e在比较对象时，\u0026quot;==\u0026quot; 运算符和 equals 运算有何区别\u003c/li\u003e\n\u003cli\u003e如果要重写一个对象的equals方法，还要考虑什么\u003c/li\u003e\n\u003cli\u003e两个对象值相同(x.equals(y) == true)，但却可有不同的hash code，这句话对不对\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e构造器\n\u003cul\u003e\n\u003cli\u003e构造器链是什么\u003c/li\u003e\n\u003cli\u003e创建对象时构造器的调用顺序\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e不可变对象\n\u003cul\u003e\n\u003cli\u003e什么是不可变象（immutable object）\u003c/li\u003e\n\u003cli\u003e为什么 Java 中的 String 是不可变的（Immutable）\u003c/li\u003e\n\u003cli\u003e如何构建不可变的类结构？关键点在哪里\u003c/li\u003e\n\u003cli\u003e能创建一个包含可变对象的不可变对象吗\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e如何对一组对象进行排序\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"方法\"\u003e方法\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e构造器（constructor）是否可被重写（override）\u003c/li\u003e\n\u003cli\u003e方法可以同时即是 static 又是 synchronized 的吗\u003c/li\u003e\n\u003cli\u003eabstract 的 method是否可同时是 static，是否可同时是 native，是否可同时是synchronized\u003c/li\u003e\n\u003cli\u003eJava支持哪种参数传递类型\u003c/li\u003e\n\u003cli\u003e一个对象被当作参数传递到一个方法，是值传递还是引用传递\u003c/li\u003e\n\u003cli\u003e当一个对象被当作参数传递到一个方法后，此方法可改变这个对象的属性，并可返回变化后的结果，那么这里到底是值传递还是引用传递\u003c/li\u003e\n\u003cli\u003e我们能否重载main()方法\u003c/li\u003e\n\u003cli\u003e如果main方法被声明为private会怎样\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"gc\"\u003eGC\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e概念\n\u003cul\u003e\n\u003cli\u003eGC是什么？为什么要有GC\u003c/li\u003e\n\u003cli\u003e什么时候会导致垃圾回收\u003c/li\u003e\n\u003cli\u003eGC是怎么样运行的\u003c/li\u003e\n\u003cli\u003e新老以及永久区是什么\u003c/li\u003e\n\u003cli\u003eGC 有几种方式？怎么配置\u003c/li\u003e\n\u003cli\u003e什么时候一个对象会被GC？ 如何判断一个对象是否存活\u003c/li\u003e\n\u003cli\u003eSystem.gc()  Runtime.gc()会做什么事情？  能保证 GC 执行吗\u003c/li\u003e\n\u003cli\u003e垃圾回收器可以马上回收内存吗？有什么办法主动通知虚拟机进行垃圾回收？\u003c/li\u003e\n\u003cli\u003eMinor GC 、Major GC、Young GC 与 Full GC分别在什么时候发生\u003c/li\u003e\n\u003cli\u003e垃圾回收算法的实现原理\u003c/li\u003e\n\u003cli\u003e如果对象的引用被置为null，垃圾收集器是否会立即释放对象占用的内存？\u003c/li\u003e\n\u003cli\u003e垃圾回收的最佳做法是什么\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eGC收集器有哪些\n\u003cul\u003e\n\u003cli\u003e垃圾回收器的基本原理是什么？\u003c/li\u003e\n\u003cli\u003e串行(serial)收集器和吞吐量(throughput)收集器的区别是什么\u003c/li\u003e\n\u003cli\u003eSerial 与 Parallel GC之间的不同之处\u003c/li\u003e\n\u003cli\u003eCMS 收集器 与 G1 收集器的特点与区别\u003c/li\u003e\n\u003cli\u003eCMS垃圾回收器的工作过程\u003c/li\u003e\n\u003cli\u003eJVM 中一次完整的 GC 流程是怎样的？ 对象如何晋升到老年代\u003c/li\u003e\n\u003cli\u003e吞吐量优先和响应优先的垃圾收集器选择\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eGC策略\n\u003cul\u003e\n\u003cli\u003e举个实际的场景，选择一个GC策略\u003c/li\u003e\n\u003cli\u003eJVM的永久代中会发生垃圾回收吗\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e收集方法\n\u003cul\u003e\n\u003cli\u003e标记清除、标记整理、复制算法的原理与特点？分别用在什么地方\u003c/li\u003e\n\u003cli\u003e如果让你优化收集方法，有什么思路\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"jvm\"\u003eJVM\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e参数\n\u003cul\u003e\n\u003cli\u003e说说你知道的几种主要的jvm 参数\u003c/li\u003e\n\u003cli\u003e-XX:+UseCompressedOops 有什么作用\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e类加载器(ClassLoader)\n\u003cul\u003e\n\u003cli\u003eJava 类加载器都有哪些\u003c/li\u003e\n\u003cli\u003eJVM如何加载字节码文件\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e内存管理\n\u003cul\u003e\n\u003cli\u003eJVM内存分哪几个区，每个区的作用是什么\u003c/li\u003e\n\u003cli\u003e一个对象从创建到销毁都是怎么在这些部分里存活和转移的\u003c/li\u003e\n\u003cli\u003e解释内存中的栈(stack)、堆(heap)和方法区(method area)的用法\u003c/li\u003e\n\u003cli\u003eJVM中哪个参数是用来控制线程的栈堆栈小\u003c/li\u003e\n\u003cli\u003e简述内存分配与回收策略\u003c/li\u003e\n\u003cli\u003e简述重排序，内存屏障，happen-before，主内存，工作内存\u003c/li\u003e\n\u003cli\u003eJava中存在内存泄漏问题吗？请举例说明\u003c/li\u003e\n\u003cli\u003e简述 Java 中软引用（SoftReferenc）、弱引用（WeakReference）和虚引用\u003c/li\u003e\n\u003cli\u003e内存映射缓存区是什么\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003ejstack，jstat，jmap，jconsole怎么用\u003c/li\u003e\n\u003cli\u003e32 位 JVM 和 64 位 JVM 的最大堆内存分别是多数？32 位和 64 位的 JVM，int 类型变量的长度是多数？\u003c/li\u003e\n\u003cli\u003e怎样通过 Java 程序来判断 JVM 是 32 位 还是 64 位\u003c/li\u003e\n\u003cli\u003eJVM自身会维护缓存吗？是不是在堆中进行对象分配，操作系统的堆还是JVM自己管理堆\u003c/li\u003e\n\u003cli\u003e什么情况下会发生栈内存溢出\u003c/li\u003e\n\u003cli\u003e双亲委派模型是什么\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"多线程\"\u003e多线程\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e基本概念\n\u003cul\u003e\n\u003cli\u003e什么是线程\u003c/li\u003e\n\u003cli\u003e多线程的优点\u003c/li\u003e\n\u003cli\u003e多线程的几种实现方式\n\u003cul\u003e\n\u003cli\u003e用 Runnable 还是 Thread\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e什么是线程安全\n\u003cul\u003e\n\u003cli\u003eVector, SimpleDateFormat 是线程安全类吗\u003c/li\u003e\n\u003cli\u003e什么 Java 原型不是线程安全的\u003c/li\u003e\n\u003cli\u003e哪些集合类是线程安全的\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e多线程中的忙循环是什么\u003c/li\u003e\n\u003cli\u003e如何创建一个线程\u003c/li\u003e\n\u003cli\u003e编写多线程程序有几种实现方式\u003c/li\u003e\n\u003cli\u003e什么是线程局部变量\u003c/li\u003e\n\u003cli\u003e线程和进程有什么区别？进程间如何通讯，线程间如何通讯\u003c/li\u003e\n\u003cli\u003e什么是多线程环境下的伪共享（false sharing）\u003c/li\u003e\n\u003cli\u003e同步和异步有何异同，在什么情况下分别使用他们？举例说明\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eCurrent\n\u003cul\u003e\n\u003cli\u003eConcurrentHashMap 和 Hashtable的区别\u003c/li\u003e\n\u003cli\u003eArrayBlockingQueue, CountDownLatch的用法\u003c/li\u003e\n\u003cli\u003eConcurrentHashMap的并发度是什么\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eCyclicBarrier 和 CountDownLatch有什么不同？各自的内部原理和用法是什么\u003c/li\u003e\n\u003cli\u003eSemaphore的用法\u003c/li\u003e\n\u003cli\u003eThread\n\u003cul\u003e\n\u003cli\u003e启动一个线程是调用 run() 还是 start() 方法？start() 和 run() 方法有什么区别\u003c/li\u003e\n\u003cli\u003e调用start()方法时会执行run()方法，为什么不能直接调用run()方法\u003c/li\u003e\n\u003cli\u003esleep() 方法和对象的 wait() 方法都可以让线程暂停执行，它们有什么区别\u003c/li\u003e\n\u003cli\u003eyield方法有什么作用？sleep() 方法和 yield() 方法有什么区别\u003c/li\u003e\n\u003cli\u003eJava 中如何停止一个线程\u003c/li\u003e\n\u003cli\u003estop() 和 suspend() 方法为何不推荐使用\u003c/li\u003e\n\u003cli\u003e如何在两个线程间共享数据\u003c/li\u003e\n\u003cli\u003e如何强制启动一个线程\u003c/li\u003e\n\u003cli\u003e如何让正在运行的线程暂停一段时间\u003c/li\u003e\n\u003cli\u003e什么是线程组，为什么在Java中不推荐使用\u003c/li\u003e\n\u003cli\u003e你是如何调用  wait（方法的）？使用 if 块还是循环？为什么\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e生命周期\n\u003cul\u003e\n\u003cli\u003e有哪些不同的线程生命周期\u003c/li\u003e\n\u003cli\u003e线程状态，BLOCKED 和 WAITING 有什么区别\u003c/li\u003e\n\u003cli\u003e画一个线程的生命周期状态图\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eThreadLocal 用途是什么，原理是什么，用的时候要注意什么\u003c/li\u003e\n\u003cli\u003eThreadPool\n\u003cul\u003e\n\u003cli\u003e线程池是什么？为什么要使用它\u003c/li\u003e\n\u003cli\u003e如何创建一个Java线程池\u003c/li\u003e\n\u003cli\u003eThreadPool用法与优势\u003c/li\u003e\n\u003cli\u003e提交任务时，线程池队列已满时会发会生什么\u003c/li\u003e\n\u003cli\u003enewCache 和 newFixed 有什么区别？简述原理。构造函数的各个参数的含义是什么，比如 coreSize, maxsize 等\u003c/li\u003e\n\u003cli\u003e线程池的实现策略\u003c/li\u003e\n\u003cli\u003e线程池的关闭方式有几种，各自的区别是什么\u003c/li\u003e\n\u003cli\u003e线程池中submit() 和 execute()方法有什么区别？\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e线程调度\n\u003cul\u003e\n\u003cli\u003eJava中用到的线程调度算法是什么\u003c/li\u003e\n\u003cli\u003e什么是多线程中的上下文切换\u003c/li\u003e\n\u003cli\u003e你对线程优先级的理解是什么\u003c/li\u003e\n\u003cli\u003e什么是线程调度器 (Thread Scheduler) 和时间分片 (Time Slicing)\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e线程同步\n\u003cul\u003e\n\u003cli\u003e请说出你所知的线程同步的方法\u003c/li\u003e\n\u003cli\u003esynchronized 的原理是什么\u003c/li\u003e\n\u003cli\u003esynchronized 和 ReentrantLock 有什么不同\u003c/li\u003e\n\u003cli\u003e什么场景下可以使用 volatile 替换 synchronized\u003c/li\u003e\n\u003cli\u003e有T1，T2，T3三个线程，怎么确保它们按顺序执行？怎样保证T2在T1执行完后执行，T3在T2执行完后执行\u003c/li\u003e\n\u003cli\u003e同步块内的线程抛出异常会发生什么\u003c/li\u003e\n\u003cli\u003e当一个线程进入一个对象的 synchronized 方法A 之后，其它线程是否可进入此对象的 synchronized 方法B\u003c/li\u003e\n\u003cli\u003e使用 synchronized 修饰静态方法和非静态方法有什么区别\u003c/li\u003e\n\u003cli\u003e如何从给定集合那里创建一个 synchronized 的集合\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e锁\n\u003cul\u003e\n\u003cli\u003eJava Concurrency API 中 的 Lock 接口是什么？对比同步它有什么优势\u003c/li\u003e\n\u003cli\u003eLock 与 Synchronized 的区别？Lock 接口比 synchronized 块的优势是什么\u003c/li\u003e\n\u003cli\u003eReadWriteLock是什么？\u003c/li\u003e\n\u003cli\u003e锁机制有什么用\u003c/li\u003e\n\u003cli\u003e什么是乐观锁（Optimistic Locking）？如何实现乐观锁？如何避免ABA问题\u003c/li\u003e\n\u003cli\u003e解释以下名词：重排序，自旋锁，偏向锁，轻量级锁，可重入锁，公平锁，非公平锁，乐观锁，悲观锁\u003c/li\u003e\n\u003cli\u003e什么时候应该使用可重入锁\u003c/li\u003e\n\u003cli\u003e简述锁的等级方法锁、对象锁、类锁\u003c/li\u003e\n\u003cli\u003eJava中活锁和死锁有什么区别？\u003c/li\u003e\n\u003cli\u003e什么是死锁(Deadlock)？导致线程死锁的原因？如何确保 N 个线程可以访问 N 个资源同时又不导致死锁\u003c/li\u003e\n\u003cli\u003e死锁与活锁的区别，死锁与饥饿的区别\u003c/li\u003e\n\u003cli\u003e怎么检测一个线程是否拥有锁\u003c/li\u003e\n\u003cli\u003e如何实现分布式锁\u003c/li\u003e\n\u003cli\u003e有哪些无锁数据结构，他们实现的原理是什么\u003c/li\u003e\n\u003cli\u003e读写锁可以用于什么应用场景\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eExecutors类是什么？ Executor和Executors的区别\u003c/li\u003e\n\u003cli\u003e什么是Java线程转储(Thread Dump)，如何得到它\u003c/li\u003e\n\u003cli\u003e如何在Java中获取线程堆栈\u003c/li\u003e\n\u003cli\u003e说出 3 条在 Java 中使用线程的最佳实践\u003c/li\u003e\n\u003cli\u003e在线程中你怎么处理不可捕捉异常\u003c/li\u003e\n\u003cli\u003e实际项目中使用多线程举例。你在多线程环境中遇到的常见的问题是什么？你是怎么解决它的\u003c/li\u003e\n\u003cli\u003e请说出与线程同步以及线程调度相关的方法\u003c/li\u003e\n\u003cli\u003e程序中有3个 socket，需要多少个线程来处理\u003c/li\u003e\n\u003cli\u003e假如有一个第三方接口，有很多个线程去调用获取数据，现在规定每秒钟最多有 10 个线程同时调用它，如何做到\u003c/li\u003e\n\u003cli\u003e如何在 Windows 和 Linux 上查找哪个线程使用的 CPU 时间最长\u003c/li\u003e\n\u003cli\u003e如何确保 main() 方法所在的线程是 Java 程序最后结束的线程\u003c/li\u003e\n\u003cli\u003e非常多个线程（可能是不同机器），相互之间需要等待协调才能完成某种工作，问怎么设计这种协调方案\u003c/li\u003e\n\u003cli\u003e你需要实现一个高效的缓存，它允许多个用户读，但只允许一个用户写，以此来保持它的完整性，你会怎样去实现它\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"异常\"\u003e异常\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e基本概念\n\u003cul\u003e\n\u003cli\u003eError 和 Exception有什么区别\n\u003cul\u003e\n\u003cli\u003eUnsupportedOperationException是什么\u003c/li\u003e\n\u003cli\u003eNullPointerException 和 ArrayIndexOutOfBoundException 之间有什么相同之处\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e什么是受检查的异常，什么是运行时异常\u003c/li\u003e\n\u003cli\u003e运行时异常与一般异常有何异同\u003c/li\u003e\n\u003cli\u003e简述一个你最常见到的runtime exception(运行时异常)\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003efinally\n\u003cul\u003e\n\u003cli\u003efinally关键词在异常处理中如何使用\n\u003cul\u003e\n\u003cli\u003e如果执行finally代码块之前方法返回了结果，或者JVM退出了，finally块中的代码还会执行吗\u003c/li\u003e\n\u003cli\u003etry里有return，finally还执行么？那么紧跟在这个try后的finally {}里的code会不会被执行，什么时候被执行，在return前还是后\u003c/li\u003e\n\u003cli\u003e在什么情况下，finally语句不会执行\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003ethrow 和 throws 有什么区别？\u003c/li\u003e\n\u003cli\u003eOOM你遇到过哪些情况？你是怎么搞定的？\u003c/li\u003e\n\u003cli\u003eSOF你遇到过哪些情况？\u003c/li\u003e\n\u003cli\u003e既然我们可以用RuntimeException来处理错误，那么你认为为什么Java中还存在检查型异常\u003c/li\u003e\n\u003cli\u003e当自己创建异常类的时候应该注意什么\u003c/li\u003e\n\u003cli\u003e导致空指针异常的原因\u003c/li\u003e\n\u003cli\u003e异常处理 handle or declare 原则应该如何理解\u003c/li\u003e\n\u003cli\u003e怎么利用 JUnit 来测试一个方法的异常\u003c/li\u003e\n\u003cli\u003ecatch块里别不写代码有什么问题\u003c/li\u003e\n\u003cli\u003e你曾经自定义实现过异常吗？怎么写的\u003c/li\u003e\n\u003cli\u003e什么是 异常链\u003c/li\u003e\n\u003cli\u003e在try块中可以抛出异常吗\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"jdbc\"\u003eJDBC\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e通过 JDBC 连接数据库有哪几种方式\u003c/li\u003e\n\u003cli\u003e阐述 JDBC 操作数据库的基本步骤\u003c/li\u003e\n\u003cli\u003eJDBC 中如何进行事务处理\u003c/li\u003e\n\u003cli\u003e什么是 JdbcTemplate\u003c/li\u003e\n\u003cli\u003e什么是 DAO 模块\u003c/li\u003e\n\u003cli\u003e使用 JDBC 操作数据库时，如何提升读取数据的性能？如何提升更新数据的性能\u003c/li\u003e\n\u003cli\u003e列出 5 个应该遵循的 JDBC 最佳实践\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"io\"\u003eIO\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eFile\n\u003cul\u003e\n\u003cli\u003eFile类型中定义了什么方法来创建一级目录\n\u003cul\u003e\n\u003cli\u003eFile类型中定义了什么方法来判断一个文件是否存在\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e流\n\u003cul\u003e\n\u003cli\u003e为了提高读写性能，可以采用什么流\u003c/li\u003e\n\u003cli\u003eJava中有几种类型的流\u003c/li\u003e\n\u003cli\u003eJDK 为每种类型的流提供了一些抽象类以供继承，分别是哪些类\u003c/li\u003e\n\u003cli\u003e对文本文件操作用什么I/O流\u003c/li\u003e\n\u003cli\u003e对各种基本数据类型和String类型的读写，采用什么流\u003c/li\u003e\n\u003cli\u003e能指定字符编码的 I/O 流类型是什么\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e序列化\n\u003cul\u003e\n\u003cli\u003e什么是序列化？如何实现 Java 序列化及注意事项\u003c/li\u003e\n\u003cli\u003eSerializable 与 Externalizable 的区别\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eSocket\n\u003cul\u003e\n\u003cli\u003esocket 选项 TCP NO DELAY 是指什么\u003c/li\u003e\n\u003cli\u003eSocket 工作在 TCP/IP 协议栈是哪一层\u003c/li\u003e\n\u003cli\u003eTCP、UDP 区别及 Java 实现方式\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e说几点 IO 的最佳实践\u003c/li\u003e\n\u003cli\u003e直接缓冲区与非直接缓冲器有什么区别？\u003c/li\u003e\n\u003cli\u003e怎么读写 ByteBuffer？ByteBuffer 中的字节序是什么\u003c/li\u003e\n\u003cli\u003e当用System.in.read(buffer)从键盘输入一行n个字符后，存储在缓冲区buffer中的字节数是多少\u003c/li\u003e\n\u003cli\u003e如何使用扫描器类（Scanner Class）令牌化\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"面向对象编程oop\"\u003e面向对象编程（OOP）\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e解释下多态性（polymorphism），封装性（encapsulation），内聚（cohesion）以及耦合（coupling）\u003c/li\u003e\n\u003cli\u003e多态的实现原理\u003c/li\u003e\n\u003cli\u003e封装、继承和多态是什么\u003c/li\u003e\n\u003cli\u003e对象封装的原则是什么?\u003c/li\u003e\n\u003cli\u003e类\n\u003cul\u003e\n\u003cli\u003e获得一个类的类对象有哪些方式\u003c/li\u003e\n\u003cli\u003e重载（Overload）和重写（Override）的区别。重载的方法能否根据返回类型进行区分？\u003c/li\u003e\n\u003cli\u003e说出几条 Java 中方法重载的最佳实践\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e抽象类\n\u003cul\u003e\n\u003cli\u003e抽象类和接口的区别\u003c/li\u003e\n\u003cli\u003e抽象类中是否可以有静态的main方法\u003c/li\u003e\n\u003cli\u003e抽象类是否可实现(implements)接口\u003c/li\u003e\n\u003cli\u003e抽象类是否可继承具体类(concrete class)\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e匿名类（Anonymous Inner Class）\n\u003cul\u003e\n\u003cli\u003e匿名内部类是否可以继承其它类？是否可以实现接口\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e内部类\n\u003cul\u003e\n\u003cli\u003e内部类分为几种\u003c/li\u003e\n\u003cli\u003e内部类可以引用它的包含类（外部类）的成员吗\u003c/li\u003e\n\u003cli\u003e请说一下 Java 中为什么要引入内部类？还有匿名内部类\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e继承\n\u003cul\u003e\n\u003cli\u003e继承（Inheritance）与聚合（Aggregation）的区别在哪里\u003c/li\u003e\n\u003cli\u003e继承和组合之间有什么不同\u003c/li\u003e\n\u003cli\u003e为什么类只能单继承，接口可以多继承\u003c/li\u003e\n\u003cli\u003e存在两个类，B 继承 A，C 继承 B，能将 B 转换为 C 么？如 C = (C) B\u003c/li\u003e\n\u003cli\u003e如果类 a 继承类 b，实现接口c，而类 b 和接口 c 中定义了同名变量，请问会出现什么问题\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e接口\n\u003cul\u003e\n\u003cli\u003e接口是什么\u003c/li\u003e\n\u003cli\u003e接口是否可继承接口\u003c/li\u003e\n\u003cli\u003e为什么要使用接口而不是直接使用具体类？接口有什么优点\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"泛型\"\u003e泛型\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e泛型的存在是用来解决什么问题\u003c/li\u003e\n\u003cli\u003e泛型的常用特点\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eList\u0026lt;String\u0026gt;\u003c/code\u003e能否转为\u003ccode\u003eList\u0026lt;Object\u0026gt;\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"工具类\"\u003e工具类\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e日历\n\u003cul\u003e\n\u003cli\u003eCalendar Class的用途\u003c/li\u003e\n\u003cli\u003e如何在Java中获取日历类的实例\u003c/li\u003e\n\u003cli\u003e解释一些日历类中的重要方法\u003c/li\u003e\n\u003cli\u003eGregorianCalendar 类是什么\u003c/li\u003e\n\u003cli\u003eSimpleTimeZone 类是什么\u003c/li\u003e\n\u003cli\u003eLocale类是什么\u003c/li\u003e\n\u003cli\u003e如何格式化日期对象\u003c/li\u003e\n\u003cli\u003e如何添加小时(hour)到一个日期对象(Date Objects)\u003c/li\u003e\n\u003cli\u003e如何将字符串 YYYYMMDD 转换为日期\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eMath\n\u003cul\u003e\n\u003cli\u003eMath.round()什么作用？Math.round(11.5) 等于多少？Math.round(-11.5)等于多少？\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eXML\n\u003cul\u003e\n\u003cli\u003eXML文档定义有几种形式？它们之间有何本质区别？解析XML文档有哪几种方式？DOM 和 SAX 解析器有什么不同？\u003c/li\u003e\n\u003cli\u003eJava解析XML的方式\u003c/li\u003e\n\u003cli\u003e用 jdom 解析 xml 文件时如何解决中文问题？如何解析\u003c/li\u003e\n\u003cli\u003e你在项目中用到了 XML 技术的哪些方面？如何实现\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"动态代理\"\u003e动态代理\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e描述动态代理的几种实现方式，分别说出相应的优缺点\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"设计模式\"\u003e设计模式\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e什么是设计模式（Design Patterns）？你用过哪种设计模式？用在什么场合\u003c/li\u003e\n\u003cli\u003e你知道哪些商业级设计模式？\u003c/li\u003e\n\u003cli\u003e哪些设计模式可以增加系统的可扩展性\u003c/li\u003e\n\u003cli\u003e单例模式\n\u003cul\u003e\n\u003cli\u003e除了单例模式，你在生产环境中还用过什么设计模式？\u003c/li\u003e\n\u003cli\u003e写 Singleton 单例模式\u003c/li\u003e\n\u003cli\u003e单例模式的双检锁是什么\u003c/li\u003e\n\u003cli\u003e如何创建线程安全的 Singleton\u003c/li\u003e\n\u003cli\u003e什么是类的单例模式\u003c/li\u003e\n\u003cli\u003e写出三种单例模式实现\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e适配器模式\n\u003cul\u003e\n\u003cli\u003e适配器模式是什么？什么时候使用\u003c/li\u003e\n\u003cli\u003e适配器模式和代理模式之前有什么不同\u003c/li\u003e\n\u003cli\u003e适配器模式和装饰器模式有什么区别\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e什么时候使用享元模式\u003c/li\u003e\n\u003cli\u003e什么时候使用组合模式\u003c/li\u003e\n\u003cli\u003e什么时候使用访问者模式\u003c/li\u003e\n\u003cli\u003e什么是模板方法模式\u003c/li\u003e\n\u003cli\u003e请给出1个符合开闭原则的设计模式的例子\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"开放问题\"\u003e开放问题\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e用一句话概括 Web 编程的特点\u003c/li\u003e\n\u003cli\u003eGoogle是如何在一秒内把搜索结果返回给用户\u003c/li\u003e\n\u003cli\u003e哪种依赖注入方式你建议使用，构造器注入，还是 Setter方法注入\u003c/li\u003e\n\u003cli\u003e树（二叉或其他）形成许多普通数据结构的基础。请描述一些这样的数据结构以及何时可以使用它们\u003c/li\u003e\n\u003cli\u003e某一项功能如何设计\u003c/li\u003e\n\u003cli\u003e线上系统突然变得异常缓慢，你如何查找问题\u003c/li\u003e\n\u003cli\u003e什么样的项目不适合用框架\u003c/li\u003e\n\u003cli\u003e新浪微博是如何实现把微博推给订阅者\u003c/li\u003e\n\u003cli\u003e简要介绍下从浏览器输入 URL 开始到获取到请求界面之后 Java Web 应用中发生了什么\u003c/li\u003e\n\u003cli\u003e请你谈谈SSH整合\u003c/li\u003e\n\u003cli\u003e高并发下，如何做到安全的修改同一行数据\u003c/li\u003e\n\u003cli\u003e12306网站的订票系统如何实现，如何保证不会票不被超卖\u003c/li\u003e\n\u003cli\u003e网站性能优化如何优化的\u003c/li\u003e\n\u003cli\u003e聊了下曾经参与设计的服务器架构\u003c/li\u003e\n\u003cli\u003e请思考一个方案，实现分布式环境下的 countDownLatch\u003c/li\u003e\n\u003cli\u003e请思考一个方案，设计一个可以控制缓存总体大小的自动适应的本地缓存\u003c/li\u003e\n\u003cli\u003e在你的职业生涯中，算得上最困难的技术挑战是什么\u003c/li\u003e\n\u003cli\u003e如何写一篇设计文档，目录是什么\u003c/li\u003e\n\u003cli\u003e大写的O是什么？举几个例子\u003c/li\u003e\n\u003cli\u003e编程中自己都怎么考虑一些设计原则的，比如开闭原则，以及在工作中的应用\u003c/li\u003e\n\u003cli\u003e解释一下网络应用的模式及其特点\u003c/li\u003e\n\u003cli\u003e设计一个在线文档系统，文档可以被编辑，如何防止多人同时对同一份文档进行编辑更新\u003c/li\u003e\n\u003cli\u003e说出数据连接池的工作机制是什么\u003c/li\u003e\n\u003cli\u003e怎么获取一个文件中单词出现的最高频率\u003c/li\u003e\n\u003cli\u003e描述一下你最常用的编程风格\u003c/li\u003e\n\u003cli\u003e如果有机会重新设计你们的产品，你会怎么做\u003c/li\u003e\n\u003cli\u003e如何搭建一个高可用系统\u003c/li\u003e\n\u003cli\u003e如何启动时不需输入用户名与密码\u003c/li\u003e\n\u003cli\u003e如何在基于Java的Web项目中实现文件上传和下载\u003c/li\u003e\n\u003cli\u003e如何实现一个秒杀系统，保证只有几位用户能买到某件商品。\u003c/li\u003e\n\u003cli\u003e如何实现负载均衡，有哪些算法可以实现\u003c/li\u003e\n\u003cli\u003e如何设计一个购物车？想想淘宝的购物车如何实现的\u003c/li\u003e\n\u003cli\u003e如何设计一套高并发支付方案，架构如何设计\u003c/li\u003e\n\u003cli\u003e如何设计建立和保持 100w 的长连接\u003c/li\u003e\n\u003cli\u003e如何避免浏览器缓存。\u003c/li\u003e\n\u003cli\u003e如何防止缓存雪崩\u003c/li\u003e\n\u003cli\u003e如果AB两个系统互相依赖，如何解除依\u003c/li\u003e\n\u003cli\u003e如果有人恶意创建非法连接，怎么解决\u003c/li\u003e\n\u003cli\u003e如果有几十亿的白名单，每天白天需要高并发查询，晚上需要更新一次，如何设计这个功能\u003c/li\u003e\n\u003cli\u003e如果系统要使用超大整数（超过long长度范围），请你设计一个数据结构来存储这种超大型数字以及设计一种算法来实现超大整数加法运算）\u003c/li\u003e\n\u003cli\u003e如果要设计一个图形系统，请你设计基本的图形元件(Point,Line,Rectangle,Triangle)的简单实现\u003c/li\u003e\n\u003cli\u003e如果让你实现一个并发安全的链表，你会怎么做\u003c/li\u003e\n\u003cli\u003e应用服务器与WEB 服务器的区别？应用服务器怎么监控性能，各种方式的区别？你使用过的应用服务器优化技术有哪些\u003c/li\u003e\n\u003cli\u003e大型网站在架构上应当考虑哪些问题\u003c/li\u003e\n\u003cli\u003e有没有处理过线上问题？出现内存泄露，CPU利用率标高，应用无响应时如何处理的\u003c/li\u003e\n\u003cli\u003e最近看什么书，印象最深刻的是什么\u003c/li\u003e\n\u003cli\u003e描述下常用的重构技巧\u003c/li\u003e\n\u003cli\u003e你使用什么版本管理工具？分支（Branch）与标签（Tag）之间的区别在哪里\u003c/li\u003e\n\u003cli\u003e你有了解过存在哪些反模式（Anti-Patterns）吗\u003c/li\u003e\n\u003cli\u003e你用过的网站前端优化的技术有哪些\u003c/li\u003e\n\u003cli\u003e如何分析Thread dump\u003c/li\u003e\n\u003cli\u003e你如何理解AOP中的连接点（Joinpoint）、切点（Pointcut）、增强（Advice）、引介（Introduction）、织入（Weaving）、切面（Aspect）这些概念\u003c/li\u003e\n\u003cli\u003e你是如何处理内存泄露或者栈溢出问题的\u003c/li\u003e\n\u003cli\u003e你们线上应用的 JVM 参数有哪些\u003c/li\u003e\n\u003cli\u003e怎么提升系统的QPS和吞吐量\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"知识面\"\u003e知识面\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e解释什么是 MESI 协议(缓存一致性)\u003c/li\u003e\n\u003cli\u003e谈谈 reactor 模型\u003c/li\u003e\n\u003cli\u003eJava 9 带来了怎样的新功能\u003c/li\u003e\n\u003cli\u003eJava 与 C++ 对比，C++ 或 Java 中的异常处理机制的简单原理和应用\u003c/li\u003e\n\u003cli\u003e简单讲讲 Tomcat 结构，以及其类加载器流程\u003c/li\u003e\n\u003cli\u003e虚拟内存是什么\u003c/li\u003e\n\u003cli\u003e阐述下 SOLID 原则\u003c/li\u003e\n\u003cli\u003e请简要讲一下你对测试驱动开发（TDD）的认识\u003c/li\u003e\n\u003cli\u003eCDN实现原理\u003c/li\u003e\n\u003cli\u003eMaven 和 ANT 有什么区别\u003c/li\u003e\n\u003cli\u003eUML中有哪些常用的图\u003c/li\u003e\n\u003cli\u003eLinux\n\u003cul\u003e\n\u003cli\u003eLinux 下 IO 模型有几种，各自的含义是什么。\u003c/li\u003e\n\u003cli\u003eLinux 系统下你关注过哪些内核参数，说说你知道的\u003c/li\u003e\n\u003cli\u003eLinux 下用一行命令查看文件的最后五行\u003c/li\u003e\n\u003cli\u003e平时用到哪些 Linux 命令\u003c/li\u003e\n\u003cli\u003e用一行命令输出正在运行的 Java 进程\u003c/li\u003e\n\u003cli\u003e使用什么命令来确定是否有 Tomcat 实例运行在机器上\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e什么是 N+1 难题\u003c/li\u003e\n\u003cli\u003e什么是 paxos 算法\u003c/li\u003e\n\u003cli\u003e什么是 restful，讲讲你理解的 restful\u003c/li\u003e\n\u003cli\u003e什么是 zab 协议\u003c/li\u003e\n\u003cli\u003e什么是领域模型(domain model)？贫血模型(anaemic domain model) 和充血模型(rich domain model)有什么区别\u003c/li\u003e\n\u003cli\u003e什么是领域驱动开发（Domain Driven Development）\u003c/li\u003e\n\u003cli\u003e介绍一下了解的 Java 领域的 Web Service 框架\u003c/li\u003e\n\u003cli\u003eWeb Server、Web Container 与 Application Server 的区别是什么\u003c/li\u003e\n\u003cli\u003e微服务（MicroServices）与巨石型应用（Monolithic Applications）之间的区别在哪里\u003c/li\u003e\n\u003cli\u003e描述 Cookie 和 Session 的作用，区别和各自的应用范围，Session工作原理\u003c/li\u003e\n\u003cli\u003e你常用的持续集成（Continuous Integration）、静态代码分析（Static Code Analysis）工具有哪些\u003c/li\u003e\n\u003cli\u003e简述下数据库正则化（Normalizations）\u003c/li\u003e\n\u003cli\u003eKISS,DRY,YAGNI 等原则是什么含义\u003c/li\u003e\n\u003cli\u003e分布式事务的原理，优缺点，如何使用分布式事务？\u003c/li\u003e\n\u003cli\u003e布式集群下如何做到唯一序列号\u003c/li\u003e\n\u003cli\u003e网络\n\u003cul\u003e\n\u003cli\u003eHTTPS 的加密方式是什么，讲讲整个加密解密流程\u003c/li\u003e\n\u003cli\u003eHTTPS和HTTP的区别\u003c/li\u003e\n\u003cli\u003eHTTP连接池实现原理\u003c/li\u003e\n\u003cli\u003eHTTP集群方案\u003c/li\u003e\n\u003cli\u003eNginx、lighttpd、Apache三大主流 Web服务器的区别\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e是否看过框架的一些代码\u003c/li\u003e\n\u003cli\u003e持久层设计要考虑的问题有哪些？你用过的持久层框架有哪些\u003c/li\u003e\n\u003cli\u003e数值提升是什么\u003c/li\u003e\n\u003cli\u003e你能解释一下里氏替换原则吗\u003c/li\u003e\n\u003cli\u003e你是如何测试一个应用的？知道哪些测试框架\u003c/li\u003e\n\u003cli\u003e传输层常见编程协议有哪些？并说出各自的特点\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"编程题\"\u003e编程题\u003c/h2\u003e\n\u003ch3 id=\"计算加班费\"\u003e计算加班费\u003c/h3\u003e\n\u003cp\u003e加班10小时以下加班费是时薪的1.5倍。加班10小时或以上，按4元/时算。提示：（一个月工作26天，一天正常工作8小时）\u003c/p\u003e","title":"Java基础知识点"},{"content":"前言 框架用的多了，已经不会写野生的SQL语句了，于是决定系统地阅读一下MySQL的官方文档。\n常用类型比较 类型 范围 存储空间 备注 BIT(M) [1, 64]越界后默认值为1 (M+7)/8 bytes TINYINT(M) signed[-128, 127] unsigned[0, 255] 1bytes SMALLINT(M) signed[-32768, 32767] unsigned[0, 65535] 2bytes MEDIUMINTINT(M) signed[-8388608, 8388607] unsigned[0, 16777605] 3bytes INT(M) signed[-2147483648, 2147483647] unsigned[0, 4294967295] 4bytes BIGINT(M) signed[-9223372036854775808, 9223372036854775807] unsigned[0, 18446744073709551615] 8bytes DECIMAL[(M[,D])] [~ -1E+66, ~1E+66] 8bytes M数字的总数（精度），D是小数点后的数字（刻度）, M最大65，溢出后默认值为10，D最大30，溢出后默认值为0 DOUBLE[(M[,D])] [-1.7976931348623157E+308, 1.7976931348623157E+308] 8bytes FLOAT[(p)] [-3.402823466E+38,3.402823466E+38] 4bytes, 0 \u0026lt;= p \u0026lt;= 24;8bytes, 25 \u0026lt;= p \u0026lt;= 53 CHAR(M) 当0 \u0026lt;= M \u0026lt;= 255时为M × w bytes 其中w为指定字符集下每个字符的大小 VARCHAR(M) L + 1 bytes, L \u0026lt; =255;L + 2 bytes, L \u0026gt; 255 TEXT [0, 65535] L + 2 bytes MEDIUMTEXT [0, 167776150] L + 3 bytes LONGTEXT [0, 4294967295] L + 4 bytes YEAR [1901, 2155] 1bytes DATE [1000-01-01，9999-12-31] 3bytes TIME [-838:59:59, -838:59:59] 3bytes 5.6.4开始 5.6.4开始 3 bytes + fractional seconds storage DATETIME [1000-01-01 00:00:00, 9999-12-31 23:59:59] 8bytes 5.6.4开始 5 bytes + fractional seconds storage TIMESTAMP [1970-01-01 08:00:01, 2038-01-19 11:14:07] 4bytes 5.6.4开始 4 bytes + fractional seconds storage 备注：5.6.4开始，时间类型支持微秒(最大6位)，所占的存储空间原来基础上加上微秒部分\n","permalink":"http://bug1024.com/2017/10/29/mysql-data-type/","summary":"\u003ch2 id=\"前言\"\u003e前言\u003c/h2\u003e\n\u003cp\u003e框架用的多了，已经不会写野生的SQL语句了，于是决定系统地阅读一下MySQL的\u003ca href=\"https://dev.mysql.com/doc/refman/5.7/en/\"\u003e官方文档\u003c/a\u003e。\u003c/p\u003e\n\u003ch2 id=\"常用类型比较\"\u003e常用类型比较\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e类型\u003c/th\u003e\n          \u003cth\u003e范围\u003c/th\u003e\n          \u003cth\u003e存储空间\u003c/th\u003e\n          \u003cth\u003e备注\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eBIT(M)\u003c/td\u003e\n          \u003ctd\u003e[1, 64]越界后默认值为1\u003c/td\u003e\n          \u003ctd\u003e(M+7)/8 bytes\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eTINYINT(M)\u003c/td\u003e\n          \u003ctd\u003esigned[-128, 127] unsigned[0, 255]\u003c/td\u003e\n          \u003ctd\u003e1bytes\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eSMALLINT(M)\u003c/td\u003e\n          \u003ctd\u003esigned[-32768, 32767] unsigned[0, 65535]\u003c/td\u003e\n          \u003ctd\u003e2bytes\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eMEDIUMINTINT(M)\u003c/td\u003e\n          \u003ctd\u003esigned[-8388608, 8388607] unsigned[0, 16777605]\u003c/td\u003e\n          \u003ctd\u003e3bytes\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eINT(M)\u003c/td\u003e\n          \u003ctd\u003esigned[-2147483648, 2147483647] unsigned[0, 4294967295]\u003c/td\u003e\n          \u003ctd\u003e4bytes\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eBIGINT(M)\u003c/td\u003e\n          \u003ctd\u003esigned[-9223372036854775808, 9223372036854775807] unsigned[0, 18446744073709551615]\u003c/td\u003e\n          \u003ctd\u003e8bytes\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eDECIMAL[(M[,D])]\u003c/td\u003e\n          \u003ctd\u003e[~ -1E+66, ~1E+66]\u003c/td\u003e\n          \u003ctd\u003e8bytes\u003c/td\u003e\n          \u003ctd\u003eM数字的总数（精度），D是小数点后的数字（刻度）, M最大65，溢出后默认值为10，D最大30，溢出后默认值为0\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eDOUBLE[(M[,D])]\u003c/td\u003e\n          \u003ctd\u003e[-1.7976931348623157E+308, 1.7976931348623157E+308]\u003c/td\u003e\n          \u003ctd\u003e8bytes\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eFLOAT[(p)]\u003c/td\u003e\n          \u003ctd\u003e[-3.402823466E+38,3.402823466E+38]\u003c/td\u003e\n          \u003ctd\u003e4bytes, 0 \u0026lt;= p \u0026lt;= 24;8bytes, 25 \u0026lt;= p \u0026lt;= 53\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eCHAR(M)\u003c/td\u003e\n          \u003ctd\u003e当0 \u0026lt;= M \u0026lt;= 255时为M × w bytes 其中w为指定字符集下每个字符的大小\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eVARCHAR(M)\u003c/td\u003e\n          \u003ctd\u003eL + 1 bytes, L \u0026lt; =255;L + 2 bytes, L \u0026gt; 255\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eTEXT\u003c/td\u003e\n          \u003ctd\u003e[0, 65535]\u003c/td\u003e\n          \u003ctd\u003eL + 2 bytes\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eMEDIUMTEXT\u003c/td\u003e\n          \u003ctd\u003e[0, 167776150]\u003c/td\u003e\n          \u003ctd\u003eL + 3 bytes\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eLONGTEXT\u003c/td\u003e\n          \u003ctd\u003e[0, 4294967295]\u003c/td\u003e\n          \u003ctd\u003eL + 4 bytes\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eYEAR\u003c/td\u003e\n          \u003ctd\u003e[1901, 2155]\u003c/td\u003e\n          \u003ctd\u003e1bytes\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eDATE\u003c/td\u003e\n          \u003ctd\u003e[1000-01-01，9999-12-31]\u003c/td\u003e\n          \u003ctd\u003e3bytes\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eTIME\u003c/td\u003e\n          \u003ctd\u003e[-838:59:59,  -838:59:59]\u003c/td\u003e\n          \u003ctd\u003e3bytes\u003c/td\u003e\n          \u003ctd\u003e5.6.4开始 5.6.4开始 3 bytes + fractional seconds storage\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eDATETIME\u003c/td\u003e\n          \u003ctd\u003e[1000-01-01 00:00:00, 9999-12-31 23:59:59]\u003c/td\u003e\n          \u003ctd\u003e8bytes\u003c/td\u003e\n          \u003ctd\u003e5.6.4开始 5 bytes + fractional seconds storage\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eTIMESTAMP\u003c/td\u003e\n          \u003ctd\u003e[1970-01-01 08:00:01, 2038-01-19 11:14:07]\u003c/td\u003e\n          \u003ctd\u003e4bytes\u003c/td\u003e\n          \u003ctd\u003e5.6.4开始 4 bytes + fractional seconds storage\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e备注：5.6.4开始，时间类型支持微秒(最大6位)，所占的存储空间原来基础上加上微秒部分\u003c/p\u003e","title":"MySQL数据类型"},{"content":"毕业参加工作已有3年半时间了，活到现在一路过来都是波澜不惊。每当听到周围的人讲述那些不幸时，我总是发自肺腑地感觉到上天对我实在是太眷顾了。\n我还是很喜欢程序员这份工作的，因为需要不断地学习，而我本身也是一个喜爱学习的人，学习总是容易让人获得一种满足感。\n个体差异总是那么大，而需要做的就是承认这个差异，不与别人比，只和自己比，不要给自己徒增压力。\n自律的生活，需要强大的意志力。我一向喜欢规律的生活，尤其不喜欢生活节奏被打乱，但调整能力又十分强。\n过去大半年，有两件事没有做到，一个是早睡，另一个是学英语。有点想去国外体验一下，人应该适当跳出舒适区。\n总是梦见自己在逃亡，沿途的景都是满满的回忆。我实在是太过于怀旧了，时光真的是令人回味。\n","permalink":"http://bug1024.com/2017/10/24/thought/","summary":"\u003cp\u003e毕业参加工作已有3年半时间了，活到现在一路过来都是波澜不惊。每当听到周围的人讲述那些不幸时，我总是发自肺腑地感觉到上天对我实在是太眷顾了。\u003c/p\u003e\n\u003cp\u003e我还是很喜欢程序员这份工作的，因为需要不断地学习，而我本身也是一个喜爱学习的人，学习总是容易让人获得一种满足感。\u003c/p\u003e","title":"突然想到"},{"content":"监控指标 load 特定事时间间隔内运行队列中的平均线程数 user time CPU执行用户进程所占用的时间 system time CPU在内核所花费的时间 nice time 系统在调整进程优先级的时候所花费的时间 idle time 系统空闲等待进程运行的时间 waiting time CPU在等待IO操作所花费的时间 hard irq time 系统处理硬件中断所占用的时间 soft irq time 系统处理软件中断所占用的时间 steal time 被强制等待虚拟机CPU的时间，占比较高表示当前虚拟机与该宿主其他虚拟机争用CPU频繁 磁盘剩余空间 使用df和du命令查看 网络traffic 使用sar命令查看 sar -n DEV 1 1 磁盘IO 使用iostat命令查看 iostat -d -k 内存使用 使用free命令查看 swap IO 使用vmstat命令查看 CPU 使用top或uptime看过去1分钟、5分钟、15分钟机器的负载。按照经验，若数值小于 0.7 * CPU核数，则系统工作正常 通过vmstat查看CPU上下文切换次数， 上下文切换的场景： 时间片用完，CPU正常调度下一个任务 被其它优先级更高的任务抢占 执行任务碰到I/O阻塞，挂起当前任务，切换到下一个任务 户代码主动挂起当前任务让出CPU 多任务抢占资源，由于没有抢到被挂起 硬件中断 Memory 操作系统角度，内存关注应用进程是否足够，可以使用free –m查看内存的使用情况。 通过top查看进程使用的虚拟内存VIRT和物理内存RES，根据公式VIRT = SWAP + RES可以推算出具体应用使用的交换分区（Swap）情况 I/O I/O包括磁盘I/O和网络 I/O，一般情况下磁盘更容易出现I/O瓶颈。 通过iostat可查看磁盘的读写情况，通过CPU的I/O wait可以看出磁盘I/O是否正常。 System Call strace常用来跟踪进程执行时的系统调用和所接收的信，常见选项:\n-c 统计每一系统调用的所执行的时间,次数和出错的次数等 -d 输出strace关于标准错误的调试信息 -f 跟踪由fork调用所产生的子进程 -ff 如果提供-o filename,则所有进程的跟踪结果输出到相应的filename.pid中, pid是各进程的进程号 -F 尝试跟踪vfork调用.在-f时,vfork不被跟踪 -h 输出简要的帮助信息 -i 输出系统调用的入口指针 -q 禁止输出关于脱离的消息 -r 打印出相对时间关于,,每一个系统调用 -t 在输出中的每一行前加上时间信息 -tt 在输出中的每一行前加上时间信息,微秒级 -ttt 微秒级输出,以秒了表示时间 -T 显示每一调用所耗的时间 -v 输出所有的系统调用一些调用关于环境变量,状态,输入输出等调用由于使用频繁,默认不输出 -V 输出strace的版本信息 strace -tt -f -p {pid} Others # 抓包 tcpdump -i eth2 -w capture.cap tcp port 9501 and dst host 172.16.1.31 ","permalink":"http://bug1024.com/2017/10/05/linux-performance-tool/","summary":"\u003ch2 id=\"监控指标\"\u003e监控指标\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eload 特定事时间间隔内运行队列中的平均线程数\u003c/li\u003e\n\u003cli\u003euser time CPU执行用户进程所占用的时间\u003c/li\u003e\n\u003cli\u003esystem time CPU在内核所花费的时间\u003c/li\u003e\n\u003cli\u003enice time 系统在调整进程优先级的时候所花费的时间\u003c/li\u003e\n\u003cli\u003eidle time 系统空闲等待进程运行的时间\u003c/li\u003e\n\u003cli\u003ewaiting time CPU在等待IO操作所花费的时间\u003c/li\u003e\n\u003cli\u003ehard irq time 系统处理硬件中断所占用的时间\u003c/li\u003e\n\u003cli\u003esoft irq time 系统处理软件中断所占用的时间\u003c/li\u003e\n\u003cli\u003esteal time 被强制等待虚拟机CPU的时间，占比较高表示当前虚拟机与该宿主其他虚拟机争用CPU频繁\u003c/li\u003e\n\u003cli\u003e磁盘剩余空间 使用df和du命令查看\u003c/li\u003e\n\u003cli\u003e网络traffic 使用sar命令查看 sar -n DEV 1 1\u003c/li\u003e\n\u003cli\u003e磁盘IO 使用iostat命令查看 iostat -d -k\u003c/li\u003e\n\u003cli\u003e内存使用 使用free命令查看\u003c/li\u003e\n\u003cli\u003eswap IO 使用vmstat命令查看\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"cpu\"\u003eCPU\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e使用\u003ccode\u003etop\u003c/code\u003e或\u003ccode\u003euptime\u003c/code\u003e看过去1分钟、5分钟、15分钟机器的负载。按照经验，若数值小于 0.7 * CPU核数，则系统工作正常\u003c/li\u003e\n\u003cli\u003e通过\u003ccode\u003evmstat\u003c/code\u003e查看CPU上下文切换次数， 上下文切换的场景：\n\u003cul\u003e\n\u003cli\u003e时间片用完，CPU正常调度下一个任务\u003c/li\u003e\n\u003cli\u003e被其它优先级更高的任务抢占\u003c/li\u003e\n\u003cli\u003e执行任务碰到I/O阻塞，挂起当前任务，切换到下一个任务\u003c/li\u003e\n\u003cli\u003e户代码主动挂起当前任务让出CPU\u003c/li\u003e\n\u003cli\u003e多任务抢占资源，由于没有抢到被挂起\u003c/li\u003e\n\u003cli\u003e硬件中断\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"memory\"\u003eMemory\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e操作系统角度，内存关注应用进程是否足够，可以使用\u003ccode\u003efree –m\u003c/code\u003e查看内存的使用情况。\n\u003cimg alt=\"查看内存\" loading=\"lazy\" src=\"http://bug1024.com/img/free-m.jpeg\"\u003e\u003c/li\u003e\n\u003cli\u003e通过\u003ccode\u003etop\u003c/code\u003e查看进程使用的虚拟内存\u003ccode\u003eVIRT\u003c/code\u003e和物理内存\u003ccode\u003eRES\u003c/code\u003e，根据公式VIRT = SWAP + RES可以推算出具体应用使用的交换分区（Swap）情况\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"io\"\u003eI/O\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003eI/O\u003c/code\u003e包括\u003ccode\u003e磁盘I/O\u003c/code\u003e和\u003ccode\u003e网络 I/O\u003c/code\u003e，一般情况下磁盘更容易出现\u003ccode\u003eI/O瓶颈\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e通过\u003ccode\u003eiostat\u003c/code\u003e可查看磁盘的读写情况，通过CPU的\u003ccode\u003eI/O wait\u003c/code\u003e可以看出磁盘I/O是否正常。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"system-call\"\u003eSystem Call\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003estrace\u003c/code\u003e常用来跟踪进程执行时的系统调用和所接收的信，常见选项:\u003c/p\u003e","title":"Linux性能调优工具"},{"content":" 虚拟机把描述类的数据从Class文件加载到内存，并对数据进行校验、转换解析和初始化，最终形成可以被虚拟机直接使用的Java类型，这便是虚拟机的类加载机制。\n加载 Loading 通过一个类的全限定名来获取定义此类的二进制字节流 将字节流所代表静态存储结果转化为方法区运行时数据结构 在内存中生成一个代表这个类的java.lang.Class对象作为方法区这个类各种数据的访问入口 验证 Verification 文件格式验证 元数据验证 字节码验证 符号引用验证 准备 Preparation 正式为类变量（被static修饰的变量）分配内存并初始化变量值 解析 Resolution 类或接口的解析 字段解析 类方法解析 接口方法解析 初始化 Initialization 真正开始执行字节码 使用 Using 卸载 Unloading ","permalink":"http://bug1024.com/2017/10/03/java-class-load/","summary":"\u003cblockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e虚拟机把描述类的数据从Class文件加载到内存，并对数据进行校验、转换解析和初始化，最终形成可以被虚拟机直接使用的Java类型，这便是虚拟机的类加载机制。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"加载-loading\"\u003e加载 Loading\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e通过一个类的全限定名来获取定义此类的二进制字节流\u003c/li\u003e\n\u003cli\u003e将字节流所代表静态存储结果转化为方法区运行时数据结构\u003c/li\u003e\n\u003cli\u003e在内存中生成一个代表这个类的java.lang.Class对象作为方法区这个类各种数据的访问入口\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"验证-verification\"\u003e验证 Verification\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e文件格式验证\u003c/li\u003e\n\u003cli\u003e元数据验证\u003c/li\u003e\n\u003cli\u003e字节码验证\u003c/li\u003e\n\u003cli\u003e符号引用验证\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"准备-preparation\"\u003e准备 Preparation\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e正式为类变量（被static修饰的变量）分配内存并初始化变量值\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"解析-resolution\"\u003e解析 Resolution\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e类或接口的解析\u003c/li\u003e\n\u003cli\u003e字段解析\u003c/li\u003e\n\u003cli\u003e类方法解析\u003c/li\u003e\n\u003cli\u003e接口方法解析\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"初始化-initialization\"\u003e初始化 Initialization\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e真正开始执行字节码\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"使用-using\"\u003e使用 Using\u003c/h2\u003e\n\u003ch2 id=\"卸载-unloading\"\u003e卸载 Unloading\u003c/h2\u003e","title":"Java类加载"},{"content":"垃圾回收堆的行为统计 # 每隔2000ms输出pid为1234的gc情况，一共输出20次 jstat -gc 1234 2000 20 # 同-gc，不过还会输出Java堆各区域使用到的最大、最小空间 jstat -gccapacity 1234 # 同-gc，不过输出的是已使用空间占总空间的百分比 jstat -gcutil 1234 # 垃圾收集统计概述（同-gcutil），附加最近两次垃圾回收事件的原因 jstat -gccause 1234 # 统计新生代的行为 jstat -gcnew 1234 # 新生代与其相应的内存空间的统计 jstat -gcnewcapacity 1234 C即Capacity 总容量，U即Used 已使用的容量 S0C : survivor0区的总容量 S1C : survivor1区的总容量 S0U : survivor0区已使用的容量 S1U : survivor1区已使用的容量 EC : Eden区的总容量 EU : Eden区已使用的容量 OC : Old区的总容量 OU : Old区已使用的容量 PC 当前perm的容量 (KB) PU perm的使用 (KB) YGC : 新生代垃圾回收次数 YGCT : 新生代垃圾回收时间 FGC : 老年代垃圾回收次数 FGCT : 老年代垃圾回收时间 GCT : 垃圾回收总消耗时间 GC日志 [GC [\u0026lt;收集器\u0026gt;: \u0026lt;Young区在GC前占的内存\u0026gt; -\u0026gt; \u0026lt;Young区在GC后占用的内存\u0026gt;(总大小) \u0026lt;Young区局部收集时JVM暂停处理的时间\u0026gt; secs] \u0026lt;JVM Heap在GC前占的内存\u0026gt; -\u0026gt; \u0026lt;JVM Heap在GC后占用的内存\u0026gt;(), \u0026lt;GC过程中JVM暂停处理的总时间\u0026gt;]] 如果 Young区在GC后占用的内存 - Young区在GC后占用的内存 = JVM Heap在GC后占用的内存 - JVM Heap在GC前的内存，则表示GC对象完全被回收，没有对象进入Old区或者Perm区。如果等号前面的值大雨后面的值，那么差值就是这次回收对象进入Old或者Perm区的大小。如果随着时间延长，JVM Heap在GC后占用的内存一直增长，而且Full GC频繁，那么可能就是内存泄露了。\n其他 # 分析cpu使用率高的java线程 ps -mp PID -o THREAD,tid,time|sort -rn printf \u0026#34;%x\\n\u0026#34; TID jstack PID|grep TID -A 80|less # 查看某个进程占用CPU高的线程 top -Hp PID -d 1 -n 1 ","permalink":"http://bug1024.com/2017/09/30/jstat/","summary":"\u003ch2 id=\"垃圾回收堆的行为统计\"\u003e垃圾回收堆的行为统计\u003c/h2\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e    # 每隔2000ms输出pid为1234的gc情况，一共输出20次\n    jstat -gc 1234 2000 20\n    # 同-gc，不过还会输出Java堆各区域使用到的最大、最小空间\n    jstat -gccapacity 1234\n    # 同-gc，不过输出的是已使用空间占总空间的百分比\n    jstat -gcutil 1234\n    # 垃圾收集统计概述（同-gcutil），附加最近两次垃圾回收事件的原因\n    jstat -gccause 1234\n    # 统计新生代的行为\n    jstat -gcnew 1234\n    # 新生代与其相应的内存空间的统计\n    jstat -gcnewcapacity 1234\n\u003c/code\u003e\u003c/pre\u003e\u003cul\u003e\n\u003cli\u003eC即Capacity 总容量，U即Used 已使用的容量\u003c/li\u003e\n\u003cli\u003eS0C : survivor0区的总容量\u003c/li\u003e\n\u003cli\u003eS1C : survivor1区的总容量\u003c/li\u003e\n\u003cli\u003eS0U : survivor0区已使用的容量\u003c/li\u003e\n\u003cli\u003eS1U : survivor1区已使用的容量\u003c/li\u003e\n\u003cli\u003eEC : Eden区的总容量\u003c/li\u003e\n\u003cli\u003eEU : Eden区已使用的容量\u003c/li\u003e\n\u003cli\u003eOC : Old区的总容量\u003c/li\u003e\n\u003cli\u003eOU : Old区已使用的容量\u003c/li\u003e\n\u003cli\u003ePC 当前perm的容量 (KB)\u003c/li\u003e\n\u003cli\u003ePU perm的使用 (KB)\u003c/li\u003e\n\u003cli\u003eYGC : 新生代垃圾回收次数\u003c/li\u003e\n\u003cli\u003eYGCT : 新生代垃圾回收时间\u003c/li\u003e\n\u003cli\u003eFGC : 老年代垃圾回收次数\u003c/li\u003e\n\u003cli\u003eFGCT : 老年代垃圾回收时间\u003c/li\u003e\n\u003cli\u003eGCT : 垃圾回收总消耗时间\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"gc日志\"\u003eGC日志\u003c/h2\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e    [GC [\u0026lt;收集器\u0026gt;: \u0026lt;Young区在GC前占的内存\u0026gt; -\u0026gt; \u0026lt;Young区在GC后占用的内存\u0026gt;(总大小) \u0026lt;Young区局部收集时JVM暂停处理的时间\u0026gt; secs] \u0026lt;JVM Heap在GC前占的内存\u0026gt; -\u0026gt; \u0026lt;JVM Heap在GC后占用的内存\u0026gt;(), \u0026lt;GC过程中JVM暂停处理的总时间\u0026gt;]]\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e如果 Young区在GC后占用的内存 - Young区在GC后占用的内存 =  JVM Heap在GC后占用的内存 - JVM Heap在GC前的内存，则表示GC对象完全被回收，没有对象进入Old区或者Perm区。如果等号前面的值大雨后面的值，那么差值就是这次回收对象进入Old或者Perm区的大小。如果随着时间延长，JVM Heap在GC后占用的内存一直增长，而且Full GC频繁，那么可能就是内存泄露了。\u003c/p\u003e","title":"jstat"},{"content":"Java 线程池关键属性 corePoolSize 到 maximumPoolSize 之间的线程会被回收，当然 corePoolSize 的线程也可以通过设置而得到回收（allowCoreThreadTimeOut(true)）。 workQueue 用于存放任务，添加任务的时候，如果当前线程数超过了 corePoolSize，那么往该队列中插入任务，线程池中的线程会负责到队列中拉取任务。 keepAliveTime 用于设置空闲时间，如果线程数超出了 corePoolSize，并且有些线程的空闲时间超过了这个值，会执行关闭这些线程的操作 rejectedExecutionHandler 用于处理当线程池不能执行此任务时的情况，默认有抛出 RejectedExecutionException 异常、忽略任务、使用提交任务的线程来执行此任务和将队列中等待最久的任务删除，然后提交此任务这四种策略，默认为抛出异常。 Java 线程池中的线程创建时机 如果当前线程数少于 corePoolSize，那么提交任务的时候创建一个新的线程，并由这个线程执行这个任务； 如果当前线程数已经达到 corePoolSize，那么将提交的任务添加到队列中，等待线程池中的线程去队列中取任务； 如果队列已满，那么创建新的线程来执行任务，需要保证池中的线程数不会超过 maximumPoolSize，如果此时线程数超过了 maximumPoolSize，那么执行拒绝策略。\nJava 任务执行过程中发生异常怎么处理 如果某个任务执行出现异常，那么执行任务的线程会被关闭，而不是继续接收其他任务。然后会启动一个新的线程来代替它。\n执行拒绝策略的场景 workers 的数量达到了 corePoolSize，任务入队成功，以此同时线程池被关闭了，而且关闭线程池并没有将这个任务出队，那么执行拒绝策略。这里说的是非常边界的问题，入队和关闭线程池并发执行，读者仔细看看 execute 方法是怎么进到第一个 reject(command) 里面的。 workers 的数量大于等于 corePoolSize，准备入队，可是队列满了，任务入队失败，那么准备开启新的线程，可是线程数已经达到 maximumPoolSize，那么执行拒绝策略。 ThreadPoolExecutor 的内部工作原理 整个思路总结起来就是5句话：\n如果当前池大小 poolSize 小于 corePoolSize ，则创建新线程执行任务。 如果当前池大小 poolSize 大于 corePoolSize ，且等待队列未满，则进入等待队列。 如果当前池大小 poolSize 大于 corePoolSize 且小于 maximumPoolSize ，且等待队列已满，则创建新线程执行任务。 如果当前池大小 poolSize 大于 corePoolSize 且大于 maximumPoolSize ，且等待队列已满，则调用拒绝策略来处理该任务。 线程池里的每个线程执行完任务后不会立刻退出，而是会去检查下等待队列里是否还有线程任务需要执行，如果在 keepAliveTime 里等不到新的任务了，那么线程就会退出。 ","permalink":"http://bug1024.com/2017/09/06/java-thread-pool/","summary":"\u003ch2 id=\"java-线程池关键属性\"\u003eJava 线程池关键属性\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003ecorePoolSize 到 maximumPoolSize 之间的线程会被回收，当然 corePoolSize 的线程也可以通过设置而得到回收（allowCoreThreadTimeOut(true)）。\u003c/li\u003e\n\u003cli\u003eworkQueue 用于存放任务，添加任务的时候，如果当前线程数超过了 corePoolSize，那么往该队列中插入任务，线程池中的线程会负责到队列中拉取任务。\u003c/li\u003e\n\u003cli\u003ekeepAliveTime 用于设置空闲时间，如果线程数超出了 corePoolSize，并且有些线程的空闲时间超过了这个值，会执行关闭这些线程的操作\u003c/li\u003e\n\u003cli\u003erejectedExecutionHandler 用于处理当线程池不能执行此任务时的情况，默认有抛出 RejectedExecutionException 异常、忽略任务、使用提交任务的线程来执行此任务和将队列中等待最久的任务删除，然后提交此任务这四种策略，默认为抛出异常。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"java-线程池中的线程创建时机\"\u003eJava 线程池中的线程创建时机\u003c/h2\u003e\n\u003cp\u003e如果当前线程数少于 corePoolSize，那么提交任务的时候创建一个新的线程，并由这个线程执行这个任务；\n如果当前线程数已经达到 corePoolSize，那么将提交的任务添加到队列中，等待线程池中的线程去队列中取任务；\n如果队列已满，那么创建新的线程来执行任务，需要保证池中的线程数不会超过 maximumPoolSize，如果此时线程数超过了 maximumPoolSize，那么执行拒绝策略。\u003c/p\u003e","title":"Java线程池"},{"content":"负载均衡分类 二层负载均衡 对外依然提供一个VIP，集群中不同的机器采用相同IP地址，但是机器的MAC地址不一样。当负载均衡服务器接受到请求之后，通过改写报文的目标MAC地址的方式将请求转发到目标机器实现负载均衡。\n三层负载均衡 对外提供一个VIP，但是集群中不同的机器采用不同的IP地址。当负载均衡服务器接受到请求之后，根据不同的负载均衡算法，通过IP将请求转发至不同的真实服务器。\n四层负载均衡 四层负载均衡工作在OSI模型的传输层，由于在传输层，只有TCP/UDP协议，这两种协议中除了包含源IP、目标IP以外，还包含源端口号及目的端口号。四层负载均衡服务器在接受到客户端请求后，以后通过修改数据包的地址信息（IP+端口号）将流量转发到应用服务器。\n七层负载均衡 七层负载均衡工作在OSI模型的应用层，应用层协议较多，常用http、radius、dns等。七层负载就可以基于这些协议来负载。这些应用层协议中会包含很多有意义的内容。比如同一个Web服务器的负载均衡，除了根据IP加端口进行负载外，还可根据七层的URL、浏览器类别、语言来决定是否要进行负载均衡。\n负载均衡工具 硬件负载均衡性能优越，功能全面，但是价格昂贵，因此软件负载均衡在互联网领域大量使用。常用的软件负载均衡软件有Nginx，Lvs，HaProxy等。\nNginx 七层负载均衡 LVS Linux Virtual Server，也就是Linux虚拟服务器，四层负载均衡 HaProxy C语言编写的自由及开放源代码软件，其提供高可用性、负载均衡，以及基于TCP和HTTP的应用程序代理，七层负载均衡 负载均衡算法 通常可以分成静态负载均衡算法和动态负载均衡算法\n静态负载均衡算法 轮询，比率，优先权 动态负载均衡算法 最少连接数，最快响应速度，观察方法，预测法，动态性能分配，动态服务器补充，服务质量，服务类型，规则模式 VIP技术 实现原理主要是靠TCP/IP的ARP协议。因为ip地址只是一个逻辑地址，在以太网中MAC地址才是真正用来进行数据传输的物理地址，每台主机中都有一个ARP高速缓存，存储同一个网络内的IP地址与MAC地址的对应关系，以太网中的主机发送数据时会先从这个缓存中查询目标IP对应的MAC地址，会向这个MAC地址发送数据。操作系统会自动维护这个缓存\n","permalink":"http://bug1024.com/2017/08/27/load-balance/","summary":"\u003ch1 id=\"负载均衡分类\"\u003e负载均衡分类\u003c/h1\u003e\n\u003ch2 id=\"二层负载均衡\"\u003e二层负载均衡\u003c/h2\u003e\n\u003cp\u003e对外依然提供一个VIP，集群中不同的机器采用相同IP地址，但是机器的MAC地址不一样。当负载均衡服务器接受到请求之后，通过改写报文的目标MAC地址的方式将请求转发到目标机器实现负载均衡。\u003c/p\u003e","title":"负载均衡"},{"content":"文件I/O常用函数 open 打开或创建一个文件 create 创建一个新文件 read 从打开文件中读取数据 write 向打开文件中写入数据 lseek 显示设置文件的偏移量 close 关闭一个文件 文件描述符 对于内核而言，所有打开的文件都通过文件描述符引用，它是一个非负数，打开或新建文件时内核向进程返回一个文件描述符，当读写一个文件时，使用oepn或create返回文件描述符标识文件，并将其作为参数传给read或write。\nI/O的效率 缓冲区超过磁盘块长度后对效率基本没有影响，文件系统通常采用预读（read ahead）来改善性能。\n文件共享 内核使用3种数据结构表示打开文件\n每个进程在进程表中都有一个记录项，记录项中包含一张打开文件描述符表，包括文件描述符标志和指向一个文件表项的指针 内核为所有打开文件维持一张文件表，包括文件状态标志，当前文件偏移量，指向该文件v节点表项的指针 每个打开的文件都有一个v节点（v-node），包含文件类型和次文件进程各种操作函数指针，对于大多数文件而言v-node还包含了i节点（i-node，索引节点）。 原子操作 任何一个多于一个函数调用的操作都不是原子操作，因为两个函数调用之间，内核可能会临时挂起进程。\n标准I/O 对于标准I/O库，它们的操作围绕的是流（stream）进行的，它提供缓冲以尽可能减少使用read和write的调用次数，通常提供以下3种缓冲类型：\n全缓冲 填满标准I/O缓冲区才进行实际的I/O，在一个流上执行第一次I/O操作时通常使用malloc获得使用的缓冲区 行缓冲 输入和输出遇到换行符或者填满了一个缓冲区时进行I/O操作 不带缓冲 标准I/O不对字符进行缓冲存储，标准错误流stderr通常也是不带缓冲的，因为需要尽快显示出来 ","permalink":"http://bug1024.com/2017/08/12/io/","summary":"\u003ch1 id=\"文件io常用函数\"\u003e文件I/O常用函数\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003eopen 打开或创建一个文件\u003c/li\u003e\n\u003cli\u003ecreate 创建一个新文件\u003c/li\u003e\n\u003cli\u003eread 从打开文件中读取数据\u003c/li\u003e\n\u003cli\u003ewrite 向打开文件中写入数据\u003c/li\u003e\n\u003cli\u003elseek 显示设置文件的偏移量\u003c/li\u003e\n\u003cli\u003eclose 关闭一个文件\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1 id=\"文件描述符\"\u003e文件描述符\u003c/h1\u003e\n\u003cp\u003e对于内核而言，所有打开的文件都通过文件描述符引用，它是一个非负数，打开或新建文件时内核向进程返回一个文件描述符，当读写一个文件时，使用oepn或create返回文件描述符标识文件，并将其作为参数传给read或write。\u003c/p\u003e","title":"IO"},{"content":"MySQL实例 在Unix上，启动一个MySQL实例通常会产生两个进程，mysqld 就是真正的数据库服务守护进程，而mysqld_safe是一个用于检查和设置mysqld启动的控制程序，它负责监控于重启。\n数据存储 在InnoDB存储引擎中，所有的数据都被逻辑地存放在表空间中，表空间（tablespace）是存储引擎中最高的存储逻辑单位，在表空间的下面又包括段（segment）、区（extent）、页（page)\n存储表 MySQL使用InnoDB存储表时，会将表的定义和数据索引等信息分开存储，其中前者存储在.frm 文件中，后者存储在.ibd 文件中\n存储记录 与现有的大多数存储引擎一样，InnoDB 使用页作为磁盘管理的最小单位；数据在 InnoDB 存储引擎中都是按行存储的，每个 16KB 大小的页中可以存放 2-200 行的记录。\n聚集索引 InnoDB 存储引擎中的表都是使用索引组织的，也就是按照键的顺序存放；聚集索引就是按照表中主键的顺序构建一颗 B+ 树，并在叶节点中存放表中的行记录数据。\n辅助索引 数据库将所有的非聚集索引都划分为辅助索引，辅助索引也是通过B+树实现的，但是它的叶节点并不包含行记录的全部数据，仅包含索引中的所有键和一个用于查找对应行记录的『书签』，在InnoDB中这个书签就是当前记录的主键。\n并发控制机制 乐观锁是一种思想，它其实并不是一种真正的『锁』，它会先尝试对资源进行修改，在写回时判断资源是否进行了改变，如果没有发生改变就会写回，否则就会进行重试，在整个的执行过程中其实都没有对数据库进行加锁 悲观锁就是一种真正的锁了，它会在获取资源前对资源进行加锁，确保同一时刻只有有限的线程能够访问该资源，其他想要尝试获取资源的操作都会进入等待状态，直到该线程完成了对资源的操作并且释放了锁后，其他线程才能重新操作资源 冲突频率和重试成本较高时更推荐使用悲观锁，而需要非常高的响应速度并且并发量非常大的时候使用乐观锁就能较好的解决问题，在这时使用悲观锁就可能出现严重的性能问题；在选择并发控制机制时，需要综合考虑上面的四个方面（冲突频率、重试成本、响应速度和并发量）进行选择 锁 共享锁（读锁）：允许事务对一条行数据进行读取； 互斥锁（写锁）：允许事务对一条行数据进行删除或更新； 为什么MyISAM读更快“快” INNODB在做SELECT的时候，要维护的东西比MYISAM引擎多很多:\n数据块，InnoDB要缓存，MyISAM只缓存索引块， 这中间还有换进换出的减少 InnoDB寻址要映射到块，再到行，MYISAM记录的直接是文件的OFFSET，定位比INNODB要快 InnoDB还需要维护MVCC (Multi-Version Concurrency Control)多版本并发控制，虽然你的场景没有，但他还是需要去检查和维护 常见误区 count(column) 和 count(*) 一样 count(column) 是表示结果集中有多少个column字段不为空的记录 count(*) 是表示整个结果集有多少条记录 select a,b from 比 select a,b,c from … 可以让数据库访问更少的数据量 实际上，大多数关系型数据库都是按照行（row）的方式存储，而数据存取操作都是以一个固定大小的IO单元（被称作 block 或者 page）为单位，一般为4KB，8KB… 大多数时候，每个IO单元中存储了多行，每行都是存储了该行的所有字段（lob等特殊类型字段除外）。 所以，我们是取一个字段还是多个字段，实际上数据库在表中需要访问的数据量其实是一样的。 当然，也有例外情况，那就是我们的这个查询在索引中就可以完成，也就是说当只取 a,b两个字段的时候，不需要回表，而c这个字段不在使用的索引中，需要回表取得其数据。在这样的情况下，二者的IO量会有较大差异。\norder by 一定需要排序操作 引数据实际上是有序的，如果我们的需要的数据和某个索引的顺序一致，而且我们的查询又通过这个索引来执行，那么数据库一般会省略排序操作，而直接将数据返回，因为数据库知道数据已经满足我们的排序需求了\n","permalink":"http://bug1024.com/2017/08/08/mysql-innodb/","summary":"\u003ch2 id=\"mysql实例\"\u003eMySQL实例\u003c/h2\u003e\n\u003cp\u003e在Unix上，启动一个MySQL实例通常会产生两个进程，mysqld 就是真正的数据库服务守护进程，而mysqld_safe是一个用于检查和设置mysqld启动的控制程序，它负责监控于重启。\u003c/p\u003e","title":"MySQL InnoDB"},{"content":"简介 Dubbo 是一个分布式服务框架，致力于提供高性能和透明化的RPC远程服务调用方案，以及SOA服务治理方案。 其核心部分包含:\n远程通讯: 提供对多种基于长连接的NIO框架抽象封装，包括多种线程模型，序列化，以及“请求-响应”模式的信息交换方式。 集群容错: 提供基于接口方法的透明远程过程调用，包括多协议支持，以及软负载均衡，失败容错，地址路由，动态配置等集群支持 自动发现: 基于注册中心目录服务，使服务消费方能动态的查找服务提供方，使地址透明，使服务提供方可以平滑增加或减少机器。 调用关系 服务容器负责启动，加载，运行服务提供者。 服务提供者在启动时，向注册中心注册自己提供的服务。 服务消费者在启动时，向注册中心订阅自己所需的服务。 注册中心返回服务提供者地址列表给消费者，如果有变更，注册中心将基于长连接推送变更数据给消费者。 服务消费者，从提供者地址列表中，基于软负载均衡算法，选一台提供者进行调用，如果调用失败，再选另一台调用。 服务消费者和提供者，在内存中累计调用次数和调用时间，定时每分钟发送一次统计数据到监控中心 负载均衡 Random LoadBalance 随机，按权重设置随机概率。 在一个截面上碰撞的概率高，但调用量越大分布越均匀，而且按概率使用权重后也比较均匀，有利于动态调整提供者权重。 RoundRobin LoadBalance 轮循，按公约后的权重设置轮循比率。 存在慢的提供者累积请求的问题，比如：第二台机器很慢，但没挂，当请求调到第二台时就卡在那，久而久之，所有请求都卡在调到第二台上。 LeastActive LoadBalance 最少活跃调用数，相同活跃数的随机，活跃数指调用前后计数差。 使慢的提供者收到更少请求，因为越慢的提供者的调用前后计数差会越大。 ConsistentHash LoadBalance 一致性Hash，相同参数的请求总是发到同一提供者。 当某一台提供者挂时，原本发往该提供者的请求，基于虚拟节点，平摊到其它提供者，不会引起剧烈变动。 ","permalink":"http://bug1024.com/2017/08/03/dubbo/","summary":"\u003ch1 id=\"简介\"\u003e简介\u003c/h1\u003e\n\u003cp\u003eDubbo 是一个分布式服务框架，致力于提供高性能和透明化的RPC远程服务调用方案，以及SOA服务治理方案。 其核心部分包含:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e远程通讯: 提供对多种基于长连接的NIO框架抽象封装，包括多种线程模型，序列化，以及“请求-响应”模式的信息交换方式。\u003c/li\u003e\n\u003cli\u003e集群容错: 提供基于接口方法的透明远程过程调用，包括多协议支持，以及软负载均衡，失败容错，地址路由，动态配置等集群支持\u003c/li\u003e\n\u003cli\u003e自动发现: 基于注册中心目录服务，使服务消费方能动态的查找服务提供方，使地址透明，使服务提供方可以平滑增加或减少机器。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1 id=\"调用关系\"\u003e调用关系\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e服务容器负责启动，加载，运行服务提供者。\u003c/li\u003e\n\u003cli\u003e服务提供者在启动时，向注册中心注册自己提供的服务。\u003c/li\u003e\n\u003cli\u003e服务消费者在启动时，向注册中心订阅自己所需的服务。\u003c/li\u003e\n\u003cli\u003e注册中心返回服务提供者地址列表给消费者，如果有变更，注册中心将基于长连接推送变更数据给消费者。\u003c/li\u003e\n\u003cli\u003e服务消费者，从提供者地址列表中，基于软负载均衡算法，选一台提供者进行调用，如果调用失败，再选另一台调用。\u003c/li\u003e\n\u003cli\u003e服务消费者和提供者，在内存中累计调用次数和调用时间，定时每分钟发送一次统计数据到监控中心\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1 id=\"负载均衡\"\u003e负载均衡\u003c/h1\u003e\n\u003ch2 id=\"random-loadbalance\"\u003eRandom LoadBalance\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e随机，按权重设置随机概率。\u003c/li\u003e\n\u003cli\u003e在一个截面上碰撞的概率高，但调用量越大分布越均匀，而且按概率使用权重后也比较均匀，有利于动态调整提供者权重。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"roundrobin-loadbalance\"\u003eRoundRobin LoadBalance\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e轮循，按公约后的权重设置轮循比率。\u003c/li\u003e\n\u003cli\u003e存在慢的提供者累积请求的问题，比如：第二台机器很慢，但没挂，当请求调到第二台时就卡在那，久而久之，所有请求都卡在调到第二台上。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"leastactive-loadbalance\"\u003eLeastActive LoadBalance\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e最少活跃调用数，相同活跃数的随机，活跃数指调用前后计数差。\u003c/li\u003e\n\u003cli\u003e使慢的提供者收到更少请求，因为越慢的提供者的调用前后计数差会越大。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"consistenthash-loadbalance\"\u003eConsistentHash LoadBalance\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e一致性Hash，相同参数的请求总是发到同一提供者。\u003c/li\u003e\n\u003cli\u003e当某一台提供者挂时，原本发往该提供者的请求，基于虚拟节点，平摊到其它提供者，不会引起剧烈变动。\u003c/li\u003e\n\u003c/ul\u003e","title":"Dubbo"},{"content":"时间规划 工作中要注意做好时间规划，也要做好任务记录，遇到临时任务，先记录下来形成TodoList，并确定deadline，并非所有任务都要立刻跟进，以免打扰手工正在进行的工作，造成频繁切换任务，影响效率。每天早上来，花5分钟思考整理当天的工作计划。\n事件优先级 通常一天中的黄金时间是早上，集中精力把最重要的工作，比如编码/bug修复花在早上10-12点和下午2-4点，这是编码的黄金时间，剩下的下午时间用来处理：\nTodoList上面的临时任务，并按优先级选择 统一回复邮件 回复消息 开会，沟通需求 沟通效率 沟通效率优先级：当面沟通 \u0026gt; 电话 \u0026gt; IM \u0026gt; 邮件 在大群不要过度讨论问题，而是说一句收到/跟进，然后私下讨论 在IM里面也尽量少讨论，少PK问题，甚至争论问题，对形成结论并没有帮助，还会造成误会。 邮件用来发结论，不要在邮件里面讨论问题，来来往往多封邮件，极其低效。 ","permalink":"http://bug1024.com/2017/07/05/time-manage/","summary":"\u003ch2 id=\"时间规划\"\u003e时间规划\u003c/h2\u003e\n\u003cp\u003e工作中要注意做好时间规划，也要做好任务记录，遇到临时任务，先记录下来形成TodoList，并确定deadline，并非所有任务都要立刻跟进，以免打扰手工正在进行的工作，造成频繁切换任务，影响效率。每天早上来，花5分钟思考整理当天的工作计划。\u003c/p\u003e","title":"时间管理"},{"content":"转眼半年就结束了，比想象中的要快很多。\n编程 我向来是不喜欢Java的，万万没想到现在用的却是它。Java在我看来实在是太笨重了，一点都不是我像我的风格，我自认为骨子里是个放荡不羁的人。 不过学习Java拓宽了对编程语言的视野，对面向对象编程的理解更为深入，同时写代码的思路也更为严谨。 但是对Java底层原理的认识仍不够深入，排查定位问题的技巧仍有待提升。 在操作系统上花的时间仍旧不是很多，对于一些问题的排查仍然只是停留在表层，下半年得加强这一块。 Github连击已有半年了，似乎对我的编程水平的提升并没有什么帮助，下半年应该做一下有技术含量的项目，或者练习一下算法也可以。 希望接下去可以更深入地学习底层，提升自己运维方面的水平。\n运动 基本还是保持每天运动的习惯，体重控制的很好，不过力量训练有待加强。 不知从何时起，发现膝盖不如以前，弹跳骤减，难道是因为跑步过多导致的？ 运动是保持激情的一种方式，就算下班很迟了，我也会坚持去锻炼。 希望运动的习惯可以一直保持下去，我不想体能下降，肉体一定要强壮，这样才能配的上精神的强大。\n朋友 我向来不爱交际，认识的朋友多是打球结识的，所以过去半年并未结交太多的朋友。 曾经的那些好友们也逐渐有了自己的家庭，联系也变少了，幸好我是一个极其善于独处的人，并不会因此感到不悦。 或许自己才是自己最好的朋友，毕竟和自己相处的时间是最长久的，所以珍惜自己吧！ 希望曾经陪伴过自己的那些朋友们一切顺利。\n写在最后 来北漂算是圆了自己的一个心愿，发现其实北漂和原来的生活相比也没有什么太大的区别，兴许是因为我太过于独立，适应性很强的原因的吧。 我突然想去买辆车，这样就可以去更远的地方了，不过北京这种地方买车似乎挺麻烦的。 生活还是得找点乐趣的，希望可以有一天我可以遇到有趣的事，有趣的人。 北漂的路才刚开始，千万要坚持下去！\n","permalink":"http://bug1024.com/2017/06/28/2017-middle-summary/","summary":"\u003cp\u003e转眼半年就结束了，比想象中的要快很多。\u003c/p\u003e\n\u003ch2 id=\"编程\"\u003e编程\u003c/h2\u003e\n\u003cp\u003e我向来是不喜欢Java的，万万没想到现在用的却是它。Java在我看来实在是太笨重了，一点都不是我像我的风格，我自认为骨子里是个放荡不羁的人。\n不过学习Java拓宽了对编程语言的视野，对面向对象编程的理解更为深入，同时写代码的思路也更为严谨。\n但是对Java底层原理的认识仍不够深入，排查定位问题的技巧仍有待提升。\n在操作系统上花的时间仍旧不是很多，对于一些问题的排查仍然只是停留在表层，下半年得加强这一块。\nGithub连击已有半年了，似乎对我的编程水平的提升并没有什么帮助，下半年应该做一下有技术含量的项目，或者练习一下算法也可以。\n希望接下去可以更深入地学习底层，提升自己运维方面的水平。\u003c/p\u003e","title":"2017上半年总结"},{"content":"前言 Git是一个快速、可扩展的分布式版本控制系统（Svn是集中式） 分布式版本控制的优点 没有“中央服务器”，每个人的电脑上都是一个完整的版本库 工作的时候不需要联网，因为版本库就在本地，因此可以轻松进行版本管理，而svn服务器挂了或断网时就无法commit 存储内容 svn使用的是增量文件系统（Delta Storage systems）存储每次提交(commit)之间的差异 Git会记录每次提交的文件的全部内容（snapshot） 基础 常用命令 git clone git checkcout git pull git push git merge 可参考 Git远程操作详解 工作区\u0026amp;暂存区\u0026amp;版本库 工作区 用户本地coding的目录 暂存区 英文叫stage, 或index 一般存放在 \u0026ldquo;.git目录下\u0026rdquo; 下的index文件（.git/index）中 版本库 工作区有一个隐藏目录.git，这就是Git的版本库 origin的概念 git为你默认创建的指向这个远程仓库的标签 可使用 git remote -v 查看origin具体指向的远程仓库 开发流程 克隆仓库 默认克隆maser分支 git clone git@github.com:bug1024/jeet-vim.git 克隆指定的分支 git clone -b bug_fix git@github.com:bug1024/jeet-vim.git git clone 支持多种协议，除了HTTP(s)以外，还支持SSH、Git、本地文件协议等 检出分支 基于当前本地分支创建并切换到develop分支 git checkout -b develop 基于远程分支创建并切换到develop分支 git checkout -b develop origin/develop 修改代码 查看文件状态 git status 查看具体的改动 git diff 将改动的文件添加到暂存区 添加指定的文件 git add 文件1 文件2 添加所有改动文件 `git add .`` 将暂存区的文件纳入版本库 一次commit就是一个版本 git commit 将当前分支同步到远程仓库 git push git push 的默认行为和gitconfig配置文件中push.default选项相关，参考 push失败 通常是由于远程分支有了新的版本提交 直接拉取，会产生额外的merge git pull 拉取远程分支，以此为基础，不会产生额外的merge（推荐）git pull --rebase，更多戳我 使用git push -f 可强制推送（慎用） 解决冲突 查看冲突文件 git status 解决冲突，保存文件 git add \u0026amp; git commit \u0026amp; git push 参考 解决冲突 最佳实践 保持本地分支和远程分支名一致 保持本地分支和master分支同步，即时常git merge master 或者 git rebase master，两种方式的区别 完善git配置，可参考git配置，这是我的配置文件 配置加强的终端，比如oh-my-zsh，可方便的在终端上显示git分支名称，改动状态等 使用额外工具，比如tig，MacOS下安装直接brew install tig commit时尽量最小粒度提交，不要将所有改动做一次提交，注释信息中避免只写update，fix bug等，通常提交类型包括 feature (feature) fix (bug fix) docs (documentation) style (formatting, missing semi colons, …) refactor test (when adding missing tests) chore (maintain) 代码回滚 清理工作区中没有被track的文件 git clean -f 移除所有没有被追踪的文件或目录 git clean -dfx 撤销改动过但未add的文件 git checkout -- 文件1 撤销add过但未commit的文件 git reset 文件1 回滚某个文件到指定版本 git reset 版本号 文件1 回滚版本库到指定版本（不会保留本地改动, soft会保留本地改动） git reset --hard 版本号 git log找不回commit时可以使用git reflog 合并前3个commitgit rebase -i HEAD~4 其他命令 checkout指定文件，git checkout origin/remote_branch_name -- file_path 追加最近一次的commit，git commit --amend 删除远程分支, git push origin :remote_branch_name 切换到上一次分支 git checkout - 参考 廖雪峰的Git教程 ","permalink":"http://bug1024.com/2017/06/13/git/","summary":"\u003ch2 id=\"前言\"\u003e前言\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eGit是一个快速、可扩展的分布式版本控制系统（Svn是集中式）\u003c/li\u003e\n\u003cli\u003e分布式版本控制的优点\n\u003cul\u003e\n\u003cli\u003e没有“中央服务器”，每个人的电脑上都是一个完整的版本库\u003c/li\u003e\n\u003cli\u003e工作的时候不需要联网，因为版本库就在本地，因此可以轻松进行版本管理，而svn服务器挂了或断网时就无法commit\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e存储内容\n\u003cul\u003e\n\u003cli\u003esvn使用的是增量文件系统（Delta Storage systems）存储每次提交(commit)之间的差异\u003c/li\u003e\n\u003cli\u003eGit会记录每次提交的文件的全部内容（snapshot）\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"基础\"\u003e基础\u003c/h2\u003e\n\u003ch3 id=\"常用命令\"\u003e常用命令\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003egit clone\u003c/code\u003e \u003ccode\u003egit checkcout\u003c/code\u003e \u003ccode\u003egit pull\u003c/code\u003e \u003ccode\u003egit push\u003c/code\u003e \u003ccode\u003egit merge\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e可参考 \u003ca href=\"http://www.ruanyifeng.com/blog/2014/06/git_remote.html\"\u003eGit远程操作详解\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"工作区暂存区版本库\"\u003e工作区\u0026amp;暂存区\u0026amp;版本库\u003c/h3\u003e\n\u003cp\u003e\u003cimg alt=\"关系图\" loading=\"lazy\" src=\"http://bug1024.com/img/git-working-stage-repo.jpg\"\u003e\u003c/p\u003e","title":"Git入门"},{"content":"简述 全局变量为各线程共享，不同的线程引用同一地址空间，如果一个线程修改了全局变量就会影响所有的线程，所以线程安全是指多线程环境下如何安全的获取公共资源。\nPHP的SAPI多数是单线程环境，比如cli、fpm、cgi，每个进程只启动一个主线程，这种模式下是不存在线程安全问题的，但是也有多线程的环境，比如Apache，或用户自己嵌入PHP实现的环境，这种情况下就需要考虑线程安全的问题了，因为PHP中有很多全局变量，比如最常见的：EG、CG，如果多个线程共享同一个变量将会冲突，所以PHP为多线程的应用模型提供了一个安全机制：Zend线程安全(Zend Thread Safe, ZTS)\n线程安全管理器 PHP中专门为解决线程安全的问题抽象出了一个线程安全资源管理器(Thread Safe Resource Mananger, TSRM)，实现原理比较简单：既然共用资源这么困难那么就干脆不共用，各线程不再共享同一份全局变量，而是各复制一份，使用数据时各线程各取自己的副本，互不干扰。\n基本实现 TSRM核心思想就是为不同的线程分配独立的内存空间，如果一个资源会被多线程使用，那么首先需要预先向TSRM注册资源，然后TSRM为这个资源分配一个唯一的编号，并把这种资源的大小、初始化函数等保存到一个tsrm_resource_type结构中，各线程只能通过TSRM分配的那个编号访问这个资源；然后当线程拿着这个编号获取资源时TSRM如果发现是第一次请求，则会根据注册时的资源大小分配一块内存，然后调用初始化函数进行初始化，并把这块资源保存下来供这个线程后续使用。\n","permalink":"http://bug1024.com/2017/06/07/php-thread-safe/","summary":"\u003ch2 id=\"简述\"\u003e简述\u003c/h2\u003e\n\u003cp\u003e全局变量为各线程共享，不同的线程引用同一地址空间，如果一个线程修改了全局变量就会影响所有的线程，所以线程安全是指多线程环境下如何安全的获取公共资源。\u003c/p\u003e\n\u003cp\u003ePHP的SAPI多数是单线程环境，比如cli、fpm、cgi，每个进程只启动一个主线程，这种模式下是不存在线程安全问题的，但是也有多线程的环境，比如Apache，或用户自己嵌入PHP实现的环境，这种情况下就需要考虑线程安全的问题了，因为PHP中有很多全局变量，比如最常见的：EG、CG，如果多个线程共享同一个变量将会冲突，所以PHP为多线程的应用模型提供了一个安全机制：Zend线程安全(Zend Thread Safe, ZTS)\u003c/p\u003e","title":"PHP线程安全"},{"content":"自旋锁 自旋锁在JDK1.6之后就默认开启了。基于之前的观察，共享数据的锁定状态只会持续很短的时间，为了这一小段时间而去挂起和恢复线程有点浪费，所以这里就做了一个处理，让后面请求锁的那个线程在稍等一会，但是不放弃处理器的执行时间，看看持有锁的线程能否快速释放。为了让线程等待，所以需要让线程执行一个忙循环也就是自旋操作。 在jdk6之后，引入了自适应的自旋锁，也就是等待的时间不再固定了，而是由上一次在同一个锁上的自旋时间及锁的拥有者状态来决定。\n偏向锁 在JDK1.之后引入的一项锁优化，目的是消除数据在无竞争情况下的同步原语。进一步提升程序的运行性能。 偏向锁就是偏心的偏，意思是这个锁会偏向第一个获得他的线程，如果接下来的执行过程中，改锁没有被其他线程获取，则持有偏向锁的线程将永远不需要再进行同步。偏向锁可以提高带有同步但无竞争的程序性能，也就是说他并不一定总是对程序运行有利，如果程序中大多数的锁都是被多个不同的线程访问，那偏向模式就是多余的，在具体问题具体分析的前提下，可以考虑是否使用偏向锁。\n轻量级锁 为了减少获得锁和释放锁所带来的性能消耗，引入了“偏向锁”和“轻量级锁”，所以在Java SE1.6里锁一共有四种状态，无锁状态，偏向锁状态，轻量级锁状态和重量级锁状态，它会随着竞争情况逐渐升级。锁可以升级但不能降级，意味着偏向锁升级成轻量级锁后不能降级成偏向锁。这种锁升级却不能降级的策略，目的是为了提高获得锁和释放锁的效率，下文会详细分析。\nSynchronized和Lock的区别 Synchronized 与Lock都是可重入锁，同一个线程再次进入同步代码的时候.可以使用自己已经获取到的锁。 Synchronized是悲观锁机制，独占锁。而Locks.ReentrantLock是，每次不加锁而是假设没有冲突而去完成某项操作，如果因为冲突失败就重试，直到成功为止。 ReentrantLock适用场景:\n某个线程在等待一个锁的控制权的这段时间需要中断 需要分开处理一些wait-notify，ReentrantLock里面的Condition应用，能够控制notify哪个线程，锁可以绑定多个条件。 具有公平锁功能，每个到来的线程都将排队等候。 ","permalink":"http://bug1024.com/2017/06/05/java-lock/","summary":"\u003ch3 id=\"自旋锁\"\u003e自旋锁\u003c/h3\u003e\n\u003cp\u003e自旋锁在JDK1.6之后就默认开启了。基于之前的观察，共享数据的锁定状态只会持续很短的时间，为了这一小段时间而去挂起和恢复线程有点浪费，所以这里就做了一个处理，让后面请求锁的那个线程在稍等一会，但是不放弃处理器的执行时间，看看持有锁的线程能否快速释放。为了让线程等待，所以需要让线程执行一个忙循环也就是自旋操作。\n在jdk6之后，引入了自适应的自旋锁，也就是等待的时间不再固定了，而是由上一次在同一个锁上的自旋时间及锁的拥有者状态来决定。\u003c/p\u003e","title":"Java 中的锁"},{"content":" FPM(FastCGI Process Manager)是PHP FastCGI运行模式的一个进程管理器，从它的定义可以看出，FPM的核心功能是进程管理。FastCGI是Web服务器(如：Nginx、Apache)和处理程序之间的一种通信协议，它是与Http类似的一种应用层通信协议，注意：它只是一种协议！\n概述 CGI，通用网关接口，用于WEB服务器和应用程序间的交互，定义输入输出规范，用户的请求通过WEB服务器转发给FastCGI进程，FastCGI进程再调用应用程序进行处理，如php解析器，应用程序的处理结果如html返回给FastCGI，FastCGI返回给Nginx 进行输出。假设这里WEB服务器是Nginx，应用程序是 PHP，而 php-fpm 是管理 FastCGI 的，这也就是 php-fpm，FastCGI，和 Nginx 之间的关系。 FastCGI 用来提高 cgi 程序性能，启动一个master，再启动多个 worker，不需要每次解析 php.ini. 而 php-fpm 实现了 FastCGI 协议，是 FastCGI 的进程管理器，支持平滑重启，可以启动的时候预先生成多个进程。 PHP实现了FastCGI协议的解析，但是并没有具体实现网络处理，一般的处理模型：多进程、多线程，多进程模型通常是主进程只负责管理子进程，而基本的网络事件由各个子进程处理，nginx、fpm就是这种模式；另一种多线程模型与多进程类似，只是它是线程粒度，通常会由主线程监听、接收请求，然后交由子线程处理，memcached就是这种模式，有的也是采用多进程那种模式：主线程只负责管理子线程不处理网络事件，各个子线程监听、接收、处理请求，memcached使用udp协议时采用的是这种模式。\n实现 fpm的实现就是创建一个master进程，在master进程中创建并监听socket，然后fork出多个子进程，这些子进程各自accept请求，子进程的处理非常简单，它在启动后阻塞在accept上，有请求到达后开始读取请求数据，读取完成后开始处理然后再返回，在这期间是不会接收其它请求的，也就是说fpm的子进程同时只能响应一个请求，只有把这个请求处理完成后才会accept下一个请求，这一点与nginx的事件驱动有很大的区别，nginx的子进程通过epoll管理套接字，如果一个请求数据还未发送完成则会处理下一个请求，即一个进程会同时连接多个请求，它是非阻塞的 模型，只处理活跃的套接字。\nfpm的master进程与worker进程之间不会直接进行通信，master通过共享内存获取worker进程的信息，比如worker进程当前状态、已处理请求数等，当master进程要杀掉一个worker进程时则通过发送信号的方式通知worker进程。\nfpm可以同时监听多个端口，每个端口对应一个worker pool，而每个pool下对应多个worker进程，类似nginx中server概念。\n管理worker进程 static: 这种方式比较简单，在启动时master按照pm.max_children配置fork出相应数量的worker进程，即worker进程数是固定不变的 dynamic: 动态进程管理，首先在fpm启动时按照pm.start_servers初始化一定数量的worker，运行期间如果master发现空闲worker数低于pm.min_spare_servers配置数(表示请求比较多，worker处理不过来了)则会fork worker进程，但总的worker数不能超过pm.max_children，如果master发现空闲worker数超过了pm.max_spare_servers(表示闲着的worker太多了)则会杀掉一些worker，避免占用过多资源，master通过这4个值来控制worker数 ondemand: 这种方式一般很少用，在启动时不分配worker进程，等到有请求了后再通知master进程fork worker进程，总的worker数不超过pm.max_children，处理完成后worker进程不会立即退出，当空闲时间超过pm.process_idle_timeout后再退出 守护进程 守护进程是脱离于终端并且在后台运行的进程。守护进程脱离于终端是为了避免进程在执行过程中的信息在任何终端上显示并且进程也不会被任何终端所产生的终端信息所打断。\n","permalink":"http://bug1024.com/2017/06/04/php-fpm/","summary":"\u003cblockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003eFPM(FastCGI Process Manager)是PHP FastCGI运行模式的一个进程管理器，从它的定义可以看出，FPM的核心功能是进程管理。FastCGI是Web服务器(如：Nginx、Apache)和处理程序之间的一种通信协议，它是与Http类似的一种应用层通信协议，注意：它只是一种协议！\u003c/p\u003e","title":"FPM"},{"content":"PHP生命周期 模块初始化阶段 注册常量 注册核心php.ini 注册GET、POST等全局变量 注册内部核心扩展 根据php.ini注册加载其他扩展 调用扩展的PHP_MINIT() 请求初始化阶段 初始化编译器 初始化EG、全局符号表、include file数组、词法分析器 初始化SG 调用扩展的PHP_RINIT() 脚本执行阶段 编译opcode 执行zvm 请求关闭阶段 调用register_shutdown_fucntion() 清理EG 销毁全局变量PG 调用扩展的PHP_RSHUTDOWN() 关闭编译器、执行器、内存管理器 模块关闭阶段 调用扩展的PHP_MSHUTDOWN() 清理ini HashTable元素 关闭output 释放PG 内核基础-变量 变量存储结构\ntypedef struct _zval_struct zval; ... struct _zval_struct { // 变量值 zvalue_value value; // 引用计数 zend_uint refcount__gc; // 变量类型 zend_uchar type; // 是否引用 zend_uchar is_ref__gc; }; 变量值存储结构\n// 使用联合体提升空间利用率 typedef union _zvalue_value { long lval; double dval; // 存储字符串时多了一个字符串长度的字段 struct { char *val; int len; } str; // 数组Array基于此实现，通常使用拉链法来避免值冲突 HashTable *ht; // 对象Object，PHP的对象只有在运行时才会被创建 zend_object_value obj; } zvalue_value; __FILE__等常量其实相当于一个常量模板，或者说是一个占位符，在词法解析时这些模板或占位符就被替换成实际的值\nGET、POST这些变量是存储在一个集中的地方：EG(symbol_table)\n内核基础-函数和类 PHP函数\nPHP_FUNCTION(count) { zval *array; long mode = COUNT_NORMAL; // 参数个数 + 宏 + 参数类型 + 接收参数的指针 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, \u0026#34;z|l\u0026#34;, \u0026amp;array, \u0026amp;mode) == FAILURE) { return; } ... //省略 // 返回值，其余的有RETURN_DOUBLE、RETURN_STRING、RETURN_BOOL、RETURN_NULL、RETURN_EMPTY_STRING、RETURN_REAOURCE RETURN_LONG } PHP类实现\nstruct _zend_class_entry { // 类型：ZEND_INTERNAL_CLASS / ZEND_USER_CLASS char type; // 类名称 char *name; // 即sizeof(name) - 1 zend_uint name_length; // 继承的父类 struct　_zend_class_entry *parent; // 引用数 int refcount; zend_bool constants_updated; zend_uint ce_flags; // ZEND_ACC_IMPLICIT_ABSTRACT_CLASS: 类存在abstract方法 // ZEND_ACC_EXPLICIT_ABSTRACT_CLASS: 在类名称前加了abstract关键字 // ZEND_ACC_FINAL_CLASS // ZEND_ACC_INTERFACE HashTable function_table; // 方法 HashTable default_properties; // 默认属性 HashTable properties_info; // 属性信息 HashTable default_static_members;// 类本身所具有的静态变量 HashTable *static_members; // type == ZEND_USER_CLASS时，取\u0026amp;default_static_members; // type == ZEND_INTERAL_CLASS时，设为NULL HashTable constants_table; // 常量 struct _zend_function_entry *builtin_functions;// 方法定义入口 union _zend_function *constructor; union _zend_function *destructor; union _zend_function *clone; // 魔术方法 union _zend_function *__get; union _zend_function *__set; union _zend_function *__unset; union _zend_function *__isset; union _zend_function *__call; union _zend_function *__tostring; union _zend_function *serialize_func; union _zend_function *unserialize_func; // 迭代 zend_class_iterator_funcs iterator_funcs; // 类句柄 zend_object_value (*create_object)(zend_class_entry *class_type TSRMLS_DC); zend_object_iterator *(*get_iterator)(zend_class_entry *ce, zval *object, intby_ref TSRMLS_DC); // 类声明的接口 int(*interface_gets_implemented)(zend_class_entry *iface, zend_class_entry *class_type TSRMLS_DC); // 序列化回调函数指针 int(*serialize)(zval *object， unsignedchar**buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC); int(*unserialize)(zval **object, zend_class_entry *ce, constunsignedchar*buf, zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC); // 类实现的接口 zend_class_entry **interfaces; // 类实现的接口数 zend_uint num_interfaces; // 类的存放文件地址 绝对地址 char *filename; // 类定义的开始行 zend_uint line_start; // 类定义的结束行 zend_uint line_end; char *doc_comment; zend_uint doc_comment_len; // 类所在的模块入口：EG(current_module) struct _zend_module_entry *module; }; 函数和方法的异同 函数和方法都是在编译阶段注册到compiler_globals变量中的，二者都使用相同的内核处理函数zend_do_begin_function_declaration() 和zend_do_end_function_declaration()来完成这一过程，不同的的地方在于定义（注册）的实现和调用的实现\n编写扩展的基本步骤 下载php-src源码 通过ext目录下ext_skel脚本生成扩展的基本框架：./ext_skel \u0026ndash;extname=your_extname； 修改config.m4配置：设置编译配置参数、设置扩展的源文件、依赖库/函数检查等等； 编写扩展要实现的功能：按照PHP扩展的格式以及PHP提供的API编写功能； 生成configure：扩展编写完成后执行phpize脚本生成configure及其它配置文件； 编译\u0026amp;安装：./configure、make、make install，然后将扩展的.so路径添加到php.ini中。 扩展中参数的解析 使用zend_parse_parameters方法进行解析，PHP7中推荐使用 Fast Parameter Parsing API\nPHP_FUNCTION(array_slice) { // 省略... #ifndef FAST_ZPP if (zend_parse_parameters(ZEND_NUM_ARGS(), \u0026#34;al|zb\u0026#34;, \u0026amp;input, \u0026amp;offset, \u0026amp;z_length, \u0026amp;preserve_keys) == FAILURE) { return; } #else ZEND_PARSE_PARAMETERS_START(2, 4) // 最少参数数和最多参数数 Z_PARAM_ARRAY(input) Z_PARAM_LONG(offset) Z_PARAM_OPTIONAL Z_PARAM_ZVAL(z_length) Z_PARAM_BOOL(preserve_keys) ZEND_PARSE_PARAMETERS_END(); #endif // 省略... } PHP进程通信 pcntl扩展：主要的进程扩展，完成进程的创建，子进程的创建，也是当前使用比较广的多进程 posix扩展：完成posix兼容机通用api,如获取进程id,杀死进程等。主要依赖 IEEE 1003.1 (POSIX.1) ，兼容posi sysvmsg扩展：实现system v方式的进程间通信之消息队列 sysvsem扩展：实现system v方式的信号量 sysvshm扩展：实现system v方式的共享内存 sockets扩展：实现socket通信，跨机器，跨平台 php也有一些封装好的异步进程处理框架：例如swoole,workman等 Zend内存池 zend针对内存的操作封装了一层，用于替换直接的内存操作：malloc、free等，实现了更高效率的内存利用，其实现主要参考了tcmalloc的设计。 内存池是内核中最底层的内存操作，定义了三种粒度的内存块：chunk、page、slot，每个chunk的大小为2M，page大小为4KB，一个chunk被切割为512个page，而一个或若干个page被切割为多个slot，所以申请内存时按照不同的申请大小决定具体的分配策略：\nHuge(chunk): 申请内存大于2M，直接调用系统分配，分配若干个chunk Large(page): 申请内存大于3092B(3/4 page_size)，小于2044KB(511 page_size)，分配若干个page Small(slot): 申请内存小于等于3092B(3/4 page_size)，内存池提前定义好了30种同等大小的内存(8,16,24,32，\u0026hellip;3072)，他们分配在不同的page上(不同大小的内存可能会分配在多个连续的page)，申请内存时直接在对应page上查找可用位置 未完待续。。。\n","permalink":"http://bug1024.com/2017/05/27/php-extension/","summary":"\u003ch2 id=\"php生命周期\"\u003ePHP生命周期\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e模块初始化阶段\n\u003cul\u003e\n\u003cli\u003e注册常量\u003c/li\u003e\n\u003cli\u003e注册核心php.ini\u003c/li\u003e\n\u003cli\u003e注册GET、POST等全局变量\u003c/li\u003e\n\u003cli\u003e注册内部核心扩展\u003c/li\u003e\n\u003cli\u003e根据php.ini注册加载其他扩展\u003c/li\u003e\n\u003cli\u003e调用扩展的PHP_MINIT()\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e请求初始化阶段\n\u003cul\u003e\n\u003cli\u003e初始化编译器\u003c/li\u003e\n\u003cli\u003e初始化EG、全局符号表、include file数组、词法分析器\u003c/li\u003e\n\u003cli\u003e初始化SG\u003c/li\u003e\n\u003cli\u003e调用扩展的PHP_RINIT()\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e脚本执行阶段\n\u003cul\u003e\n\u003cli\u003e编译opcode\u003c/li\u003e\n\u003cli\u003e执行zvm\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e请求关闭阶段\n\u003cul\u003e\n\u003cli\u003e调用register_shutdown_fucntion()\u003c/li\u003e\n\u003cli\u003e清理EG\u003c/li\u003e\n\u003cli\u003e销毁全局变量PG\u003c/li\u003e\n\u003cli\u003e调用扩展的PHP_RSHUTDOWN()\u003c/li\u003e\n\u003cli\u003e关闭编译器、执行器、内存管理器\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e模块关闭阶段\n\u003cul\u003e\n\u003cli\u003e调用扩展的PHP_MSHUTDOWN()\u003c/li\u003e\n\u003cli\u003e清理ini HashTable元素\u003c/li\u003e\n\u003cli\u003e关闭output\u003c/li\u003e\n\u003cli\u003e释放PG\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"内核基础-变量\"\u003e内核基础-变量\u003c/h2\u003e\n\u003cp\u003e变量存储结构\u003c/p\u003e","title":"PHP扩展开发"},{"content":"IntelliJ IDEA For Mac 快捷键 根据官方pdf翻译：https://www.jetbrains.com/idea/docs/IntelliJIDEA_ReferenceCard_Mac.pdf 在 IntelliJ IDEA 中有两个 Mac 版本的快捷键，一个叫做：Mac OS X，一个叫做：Mac OS X 10.5+ 目前都是用：Mac OS X 10.5+ 有两套的原因：https://intellij-support.jetbrains.com/hc/en-us/community/posts/206159109-Updated-Mac-OS-X-keymap-Feedback-needed 建议将 Mac 系统中与 IntelliJ IDEA 冲突的快捷键取消或更改，不建议改 IntelliJ IDEA 的默认快捷键。\nMac键盘符号和修饰键说明 ⌘ Command ⇧ Shift ⌥ Option ⌃ Control ↩︎ Return/Enter ⌫ Delete ⌦ 向前删除键（Fn+Delete） ↑ 上箭头 ↓ 下箭头 ← 左箭头 → 右箭头 ⇞ Page Up（Fn+↑） ⇟ Page Down（Fn+↓） Home Fn + ← End Fn + → ⇥ 右制表符（Tab键） ⇤ 左制表符（Shift+Tab） ⎋ Escape (Esc) 一、Editing（编辑） Control + Space 基本的代码补全（补全任何类、方法、变量） Control + Shift + Space 智能代码补全（过滤器方法列表和变量的预期类型） Command + Shift + Enter 自动结束代码，行末自动添加分号 Command + P 显示方法的参数信息 Control + J 快速查看文档 Shift + F1 查看外部文档（在某些代码上会触发打开浏览器显示相关文档） Command + 鼠标放在代码上 显示代码简要信息 Command + F1 在错误或警告处显示具体描述信息 Command + N, Control + Enter, Control + N 生成代码（getter、setter、构造函数、hashCode/equals,toString） Control + O 覆盖方法（重写父类方法） Control + I 实现方法（实现接口中的方法） Command + Option + T 包围代码（使用if..else, try..catch, for, synchronized等包围选中的代码） Command + / 注释/取消注释与行注释 Command + Option + / 注释/取消注释与块注释 Option + 方向键上 连续选中代码块 Option + 方向键下 减少当前选中的代码块 Control + Shift + Q 显示上下文信息 Option + Enter 显示意向动作和快速修复代码 Command + Option + L 格式化代码 Control + Option + O 优化import Control + Option + I 自动缩进线 Tab / Shift + Tab 缩进代码 / 反缩进代码 Command + X 剪切当前行或选定的块到剪贴板 Command + C 复制当前行或选定的块到剪贴板 Command + V 从剪贴板粘贴 Command + Shift + V 从最近的缓冲区粘贴 Command + D 复制当前行或选定的块 Command + Delete 删除当前行或选定的块的行 Control + Shift + J 智能的将代码拼接成一行 Command + Enter 智能的拆分拼接的行 Shift + Enter 开始新的一行 Command + Shift + U 大小写切换 Command + Shift + ] / Command + Shift + [ 选择直到代码块结束/开始 Option + Fn + Delete 删除到单词的末尾 Option + Delete 删除到单词的开头 Command + 加号 / Command + 减号 展开 / 折叠代码块 Command + Shift + 加号 展开所以代码块 Command + Shift + 减号 折叠所有代码块 Command + W 关闭活动的编辑器选项卡 二、Search/Replace（查询/替换） Double Shift 查询任何东西 Command + F 文件内查找 Command + G 查找模式下，向下查找 Command + Shift + G 查找模式下，向上查找 Command + R 文件内替换 Command + Shift + F 全局查找（根据路径） Command + Shift + R 全局替换（根据路径） Command + Shift + S 查询结构（Ultimate Edition 版专用，需要在Keymap中设置） Command + Shift + M 替换结构（Ultimate Edition 版专用，需要在Keymap中设置） 三、Usage Search（使用查询） Option + F7 / Command + F7 在文件中查找用法 / 在类中查找用法 Command + Shift + F7 在文件中突出显示的用法 Command + Option + F7 显示用法 四、Compile and Run（编译和运行） Command + F9 编译Project Command + Shift + F9 编译选择的文件、包或模块 Control + Option + R 弹出 Run 的可选择菜单 Control + Option + D 弹出 Debug 的可选择菜单 Control + R 运行 Control + D 调试 Control + Shift + R, Control + Shift + D 从编辑器运行上下文环境配置 五、Debugging（调试） F8 进入下一步，如果当前行断点是一个方法，则不进入当前方法体内 F7 进入下一步，如果当前行断点是一个方法，则进入当前方法体内，如果该方法体还有方法，则不会进入该内嵌的方法中 Shift + F7 智能步入，断点所在行上有多个方法调用，会弹出进入哪个方法 Shift + F8 跳出 Option + F9 运行到光标处，如果光标前有其他断点会进入到该断点 Option + F8 计算表达式（可以更改变量值使其生效） Command + Option + R 恢复程序运行，如果该断点下面代码还有断点则停在下一个断点上 Command + F8 切换断点（若光标当前行有断点则取消断点，没有则加上断点） Command + Shift + F8 查看断点信息 六、Navigation（导航） Command + O 查找类文件 Command + Shift + O 查找所有类型文件、打开文件、打开目录，打开目录需要在输入的内容前面或后面加一个反斜杠/ Command + Option + O 前往指定的变量 / 方法 Control + 方向键左 / Control + 方向键右 左右切换打开的编辑tab页 F12 返回到前一个工具窗口 Esc 从工具窗口进入代码文件窗口 Shift + Esc 隐藏当前或最后一个活动的窗口，且光标进入代码文件窗口 Command + Shift + F4 关闭活动run/messages/find/\u0026hellip; tab Command + L 在当前文件跳转到某一行的指定处 Command + E 显示最近打开的文件记录列表 Option + 方向键左 / Option + 方向键右 光标跳转到当前单词 / 中文句的左 / 右侧开头位置 Command + Option + 方向键左 / Command + Option + 方向键右 退回 / 前进到上一个操作的地方 Command + Shift + Delete 跳转到最后一个编辑的地方 Option + F1 显示当前文件选择目标弹出层，弹出层中有很多目标可以进行选择(如在代码编辑窗口可以选择显示该文件的Finder) Command + B / Command + 鼠标点击 进入光标所在的方法/变量的接口或是定义处 Command + Option + B 跳转到实现处，在某个调用的方法名上使用会跳到具体的实现处，可以跳过接口 Option + Space, Command + Y 快速打开光标所在方法、类的定义 Control + Shift + B 跳转到类型声明处 Command + U 前往当前光标所在方法的父类的方法 / 接口定义 Control + 方向键下 / Control + 方向键上 当前光标跳转到当前文件的前一个/后一个方法名位置 Command + ] / Command + [ 移动光标到当前所在代码的花括号开始/结束位置 Command + F12 弹出当前文件结构层，可以在弹出的层上直接输入进行筛选（可用于搜索类中的方法） Control + H 显示当前类的层次结构 Command + Shift + H 显示方法层次结构 Control + Option + H 显示调用层次结构 F2 / Shift + F2 跳转到下一个/上一个突出错误或警告的位置 F4 / Command + 方向键下 编辑/查看代码源 Option + Home 显示到当前文件的导航条 F3选中文件/文件夹/代码行，添加/取消书签 Option + F3 选中文件/文件夹/代码行，使用助记符添加/取消书签 Control + 0...Control + 9 定位到对应数值的书签位置 Command + F3 显示所有书签 七、Refactoring（重构） F5 复制文件到指定目录 F6 移动文件到指定目录 Command + Delete 在文件上为安全删除文件，弹出确认框 Shift + F6 重命名文件 Command + F6 更改签名 Command + Option + N 一致性 Command + Option + M 将选中的代码提取为方法 Command + Option + V 提取变量 Command + Option + F 提取字段 Command + Option + C 提取常量 Command + Option + P 提取参数 八、VCS/Local History（版本控制/本地历史记录） Command + K 提交代码到版本控制器 Command + T 从版本控制器更新代码 Option + Shift + C 查看最近的变更记录 Control + C 快速弹出版本控制器操作面板 九、Live Templates（动态代码模板） Command + Option + J 弹出模板选择窗口，将选定的代码使用动态模板包住 Command + J 插入自定义动态代码模板 十、General（通用） Command + 1...Command + 9 打开相应编号的工具窗口 Command + S 保存所有 Command + Option + Y 同步、刷新 Control + Command + F 切换全屏模式 Command + Shift + F12 切换最大化编辑器 Option + Shift + F 添加到收藏夹 Option + Shift + I 检查当前文件与当前的配置文件 Control + ` 快速切换当前的scheme（切换主题、代码样式等） Command + , 打开IDEA系统设置 Command + ; 打开项目结构对话框 Shift + Command + A 查找动作（可设置相关选项） Control + Shift + Tab 编辑窗口标签和工具窗口之间切换（如果在切换的过程加按上delete，则是关闭对应选中的窗口） 十一、Other（一些官方文档上没有体现的快捷键） Command + Shift +8 竖编辑模式 十二、Tips 运行单个文件 File-Project Structure-Modules中把你代码所在文件夹选为Sources然后确定 ","permalink":"http://bug1024.com/2017/05/21/intelllij-idea-keymap/","summary":"\u003ch1 id=\"intellij-idea-for-mac-快捷键\"\u003eIntelliJ IDEA For Mac 快捷键\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e根据官方pdf翻译：\u003ca href=\"https://www.jetbrains.com/idea/docs/IntelliJIDEA_ReferenceCard_Mac.pdf\"\u003ehttps://www.jetbrains.com/idea/docs/IntelliJIDEA_ReferenceCard_Mac.pdf\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e在 IntelliJ IDEA 中有两个 Mac 版本的快捷键，一个叫做：Mac OS X，一个叫做：Mac OS X 10.5+\u003c/li\u003e\n\u003cli\u003e目前都是用：Mac OS X 10.5+\u003c/li\u003e\n\u003cli\u003e有两套的原因：\u003ca href=\"https://intellij-support.jetbrains.com/hc/en-us/community/posts/206159109-Updated-Mac-OS-X-keymap-Feedback-needed\"\u003ehttps://intellij-support.jetbrains.com/hc/en-us/community/posts/206159109-Updated-Mac-OS-X-keymap-Feedback-needed\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cblockquote\u003e\n\u003cp\u003e建议将 Mac 系统中与 IntelliJ IDEA 冲突的快捷键取消或更改，不建议改 IntelliJ IDEA 的默认快捷键。\u003c/p\u003e","title":"IntelliJ IDEA 快捷键"},{"content":"特点 1、处理响应请求很快 在正常的情况下，单次请求会得到更快的响应。 2、高并发连接 理论上，Nginx 支持的并发连接上限取决于你的内存，10 万远未封顶。 3、低的内存消耗 在一般的情况下，10000 个非活跃的 HTTP Keep-Alive 连接在 Nginx 中仅消耗 2.5MB 的内存。 4、具有很高的可靠性 Nginx 是一个高可靠性的 Web 服务器，高可靠性来自其核心框架代码的优秀设计、模块设计的简单性，并且这些模块都非常的稳定。 5、高扩展性 Nginx 的设计极具扩展性，它完全是由多个不同功能、不同层次、不同类型且耦合度极低的模块组成。这种设计造就了 Nginx 庞大的第三方模块。 6、热部署 master 管理进程与 worker 工作进程的分离设计，使得 Nginx 具有热部署的功能，可以在 7 × 24 小时不间断服务的前提下，升级 Nginx 的可执行文件。也可以在不停止服务的情况下修改配置文件，更换日志文件等功能。 7、自由的 BSD 许可协议 BSD 许可协议不只是允许用户免费使用 Nginx，也允许用户修改 Nginx 源码，还允许用户用于商业用途。 基础配置 worker_process # 表示工作进程的数量，一般设置为cpu的核数 worker_connections # 表示每个工作进程的最大连接数 server{} # 块定义了虚拟主机 listen # 监听端口 server_name # 监听域名 location {} # 是用来为匹配的 URI 进行配置，URI 即语法中的“/uri/” location /{} # 匹配任何查询，因为所有请求都以 / 开头 root # 指定对应uri的资源查找路径，这里html为相对路径，完整路径为 index # 指定首页index文件的名称，可以配置多个，以空格分开。如有多个，按配置顺序查找。 location 匹配规则 模式 含义 location = /uri = 表示精确匹配，只有完全匹配上才能生效 location ^~ /uri ^~ 开头对URL路径进行前缀匹配，并且在正则之前。 location ~ pattern 开头表示区分大小写的正则匹配 location ~* pattern 开头表示不区分大小写的正则匹配* location /uri 不带任何修饰符，也表示前缀匹配，但是在正则匹配之后 location / 通用匹配，任何未匹配到其它location的请求都会匹配到，相当于switch中的default 负载均衡 轮询（默认）：每个请求按时间顺序逐一分配到不同的后端服务器，如果后端某台服务器宕机，故障系统被自动剔除，使用户访问不受影响。Weight 指定轮询权值，Weight 值越大，分配到的访问机率越高，主要用于后端每个服务器性能不均的情况下。 ip_hash：每个请求按访问 IP 的 hash 结果分配，这样来自同一个 IP 的访客固定访问一个后端服务器，有效解决了动态网页存在的 session 共享问题。 fair：这是比上面两个更加智能的负载均衡算法。此种算法可以依据页面大小和加载时间长短智能地进行负载均衡，也就是根据后端服务器的响应时间来分配请求，响应时间短的优先分配。Nginx 本身是不支持 fair 的，如果需要使用这种调度算法，必须下载 Nginx 的 upstream_fair 模块。 url_hash：此方法按访问 url 的 hash 结果来分配请求，使每个 url 定向到同一个后端服务器，可以进一步提高后端缓存服务器的效率。Nginx 本身是不支持 url_hash 的，如果需要使用这种调度算法，必须安装 Nginx 的 hash 软件包。 least_conn：最少连接负载均衡算法，简单来说就是每次选择的后端都是当前最少连接的一个 server(这个最少连接不是共享的，是每个 worker 都有自己的一个数组进行记录后端 server 的连接数)。 hash：这个 hash 模块又支持两种模式 hash, 一种是普通的 hash, 另一种是一致性 hash(consistent)。 ","permalink":"http://bug1024.com/2017/05/14/nginx/","summary":"\u003ch2 id=\"特点\"\u003e特点\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e1、处理响应请求很快 在正常的情况下，单次请求会得到更快的响应。\u003c/li\u003e\n\u003cli\u003e2、高并发连接 理论上，Nginx 支持的并发连接上限取决于你的内存，10 万远未封顶。\u003c/li\u003e\n\u003cli\u003e3、低的内存消耗 在一般的情况下，10000 个非活跃的 HTTP Keep-Alive 连接在 Nginx 中仅消耗 2.5MB 的内存。\u003c/li\u003e\n\u003cli\u003e4、具有很高的可靠性 Nginx 是一个高可靠性的 Web 服务器，高可靠性来自其核心框架代码的优秀设计、模块设计的简单性，并且这些模块都非常的稳定。\u003c/li\u003e\n\u003cli\u003e5、高扩展性 Nginx 的设计极具扩展性，它完全是由多个不同功能、不同层次、不同类型且耦合度极低的模块组成。这种设计造就了 Nginx 庞大的第三方模块。\u003c/li\u003e\n\u003cli\u003e6、热部署 master 管理进程与 worker 工作进程的分离设计，使得 Nginx 具有热部署的功能，可以在 7 × 24 小时不间断服务的前提下，升级 Nginx 的可执行文件。也可以在不停止服务的情况下修改配置文件，更换日志文件等功能。\u003c/li\u003e\n\u003cli\u003e7、自由的 BSD 许可协议 BSD 许可协议不只是允许用户免费使用 Nginx，也允许用户修改 Nginx 源码，还允许用户用于商业用途。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"基础配置\"\u003e基础配置\u003c/h2\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e    worker_process      # 表示工作进程的数量，一般设置为cpu的核数\n\n    worker_connections  # 表示每个工作进程的最大连接数\n\n    server{}            # 块定义了虚拟主机\n\n    listen          # 监听端口\n\n    server_name     # 监听域名\n\n    location {}     # 是用来为匹配的 URI 进行配置，URI 即语法中的“/uri/”\n\n    location /{}    # 匹配任何查询，因为所有请求都以 / 开头\n\n    root        # 指定对应uri的资源查找路径，这里html为相对路径，完整路径为\n\n    index       # 指定首页index文件的名称，可以配置多个，以空格分开。如有多个，按配置顺序查找。\n\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"location-匹配规则\"\u003elocation 匹配规则\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e模式\u003c/th\u003e\n          \u003cth\u003e含义\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003elocation = /uri\u003c/td\u003e\n          \u003ctd\u003e= 表示精确匹配，只有完全匹配上才能生效\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003elocation ^~ /uri\u003c/td\u003e\n          \u003ctd\u003e^~ 开头对URL路径进行前缀匹配，并且在正则之前。\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003elocation ~ pattern\u003c/td\u003e\n          \u003ctd\u003e开头表示区分大小写的正则匹配\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003elocation ~* pattern\u003c/td\u003e\n          \u003ctd\u003e开头表示不区分大小写的正则匹配*\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003elocation /uri\u003c/td\u003e\n          \u003ctd\u003e不带任何修饰符，也表示前缀匹配，但是在正则匹配之后\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003elocation /\u003c/td\u003e\n          \u003ctd\u003e通用匹配，任何未匹配到其它location的请求都会匹配到，相当于switch中的default\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch1 id=\"负载均衡\"\u003e负载均衡\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e轮询（默认）：每个请求按时间顺序逐一分配到不同的后端服务器，如果后端某台服务器宕机，故障系统被自动剔除，使用户访问不受影响。Weight 指定轮询权值，Weight 值越大，分配到的访问机率越高，主要用于后端每个服务器性能不均的情况下。\u003c/li\u003e\n\u003cli\u003eip_hash：每个请求按访问 IP 的 hash 结果分配，这样来自同一个 IP 的访客固定访问一个后端服务器，有效解决了动态网页存在的 session 共享问题。\u003c/li\u003e\n\u003cli\u003efair：这是比上面两个更加智能的负载均衡算法。此种算法可以依据页面大小和加载时间长短智能地进行负载均衡，也就是根据后端服务器的响应时间来分配请求，响应时间短的优先分配。Nginx 本身是不支持 fair 的，如果需要使用这种调度算法，必须下载 Nginx 的 upstream_fair 模块。\u003c/li\u003e\n\u003cli\u003eurl_hash：此方法按访问 url 的 hash 结果来分配请求，使每个 url 定向到同一个后端服务器，可以进一步提高后端缓存服务器的效率。Nginx 本身是不支持 url_hash 的，如果需要使用这种调度算法，必须安装 Nginx 的 hash 软件包。\u003c/li\u003e\n\u003cli\u003eleast_conn：最少连接负载均衡算法，简单来说就是每次选择的后端都是当前最少连接的一个 server(这个最少连接不是共享的，是每个 worker 都有自己的一个数组进行记录后端 server 的连接数)。\u003c/li\u003e\n\u003cli\u003ehash：这个 hash 模块又支持两种模式 hash, 一种是普通的 hash, 另一种是一致性 hash(consistent)。\u003c/li\u003e\n\u003c/ul\u003e","title":"Nginx入门"},{"content":"select 模型 下面是 select 函数接口：\nint select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); select 函数监视的文件描述符分 3 类，分别是 writefds、readfds 和 exceptfds。调用后 select 函数会阻塞，直到有描述符就绪（有数据 可读、可写、或者有 except），或者超时（timeout 指定等待时间，如果立即返回设为 null 即可）。当 select 函数返回后，通过遍历 fd_set，来找到就绪的描述符。 select 目前几乎在所有的平台上支持，其良好跨平台支持是它的一大优点。select 的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制，在 Linux 上一般为 1024，可以通过修改宏定义甚至重新编译内核的方式提升这一限制，但是这样也会造成效率的降低。 poll 模型 int poll (struct pollfd *fds, unsigned int nfds, int timeout); 不同与 select 使用三个位图来表示三个 fdset 的方式，poll 使用一个 pollfd 的指针实现。\nstruct pollfd { int fd; /* file descriptor */ short events; /* requested events to watch */ short revents; /* returned events witnessed */ }; pollfd 结构包含了要监视的 event 和发生的 event，不再使用 select “参数-值”传递的方式。同时，pollfd 并没有最大数量限制（但是数量过大后性能也是会下降）。和 select 函数一样，poll 返回后，需要轮询 pollfd 来获取就绪的描述符。 从上面看，select 和 poll 都需要在返回后，通过遍历文件描述符来获取已经就绪的 socket。事实上，同时连接的大量客户端在一时刻可能只有很少的处于就绪状态，因此随着监视的描述符数量的增长，其效率也会线性下降。 epoll 模型 epoll 的接口如下：\nint epoll_create(int size)； int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)； typedef union epoll_data { void *ptr; int fd; __uint32_t u32; __uint64_t u64; } epoll_data_t; struct epoll_event { __uint32_t events; /* Epoll events */ epoll_data_t data; /* User data variable */ }; int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout); 主要是 epoll_create，epoll_ctl 和 epoll_wait 三个函数。epoll_create 函数创建 epoll 文件描述符，参数 size 并不是限制了 epoll 所能监听的描述符最大个数，只是对内核初始分配内部数据结构的一个建议。epoll_ctl 完成对指定描述符 fd 执行 op 操作控制，event 是与 fd 关联的监听事件。op 操作有三种：添加 EPOLL_CTL_ADD，删除 EPOLL_CTL_DEL，修改 EPOLL_CTL_MOD。分别添加、删除和修改对 fd 的监听事件。epoll_wait 等待 epfd 上的 IO 事件，最多返回 maxevents 个事件。 在 select/poll 中，进程只有在调用一定的方法后，内核才对所有监视的文件描述符进行扫描，而 epoll 事先通过 epoll_ctl() 来注册一个文件描述符，一旦基于某个文件描述符就绪时，内核会采用类似 callback 的回调机制，迅速激活这个文件描述符，当进程调用 epoll_wait 时便得到通知。 epoll 优点 监视的描述符数量不受限制，它所支持的 fd 上限是最大可以打开文件的数目，这个数字一般远大于 2048, 举个例子, 在 1GB 内存的机器上大约是 10 万左右，具体数目可以 cat /proc/sys/fs/file-max 察看, 一般来说这个数目和系统内存关系很大。select 的最大缺点就是进程打开的 fd 是有数量限制的。这对于连接数量比较大的服务器来说根本不能满足。虽然也可以选择多进程的解决方案( Apache 就是这样实现的)，不过虽然 linux 上面创建进程的代价比较小，但仍旧是不可忽视的，加上进程间数据同步远比不上线程间同步的高效，所以也不是一种完美的方案。 IO 的效率不会随着监视 fd 的数量的增长而下降。epoll 不同于 select 和 poll 轮询的方式，而是通过每个 fd 定义的回调函数来实现的。只有就绪的 fd 才会执行回调函数。 支持水平触发和边沿触发两种模式： 水平触发模式，文件描述符状态发生变化后，如果没有采取行动，它将后面反复通知，这种情况下编程相对简单，libevent 等开源库很多都是使用的这种模式。 边沿触发模式，只告诉进程哪些文件描述符刚刚变为就绪状态，只说一遍，如果没有采取行动，那么它将不会再次告知。理论上边缘触发的性能要更高一些，但是代码实现相当复杂（Nginx 使用的边缘触发）。 mmap 加速内核与用户空间的信息传递。epoll 是通过内核与用户空间 mmap 同一块内存，避免了无谓的内存拷贝。 ","permalink":"http://bug1024.com/2017/05/10/io/","summary":"\u003ch2 id=\"select-模型\"\u003eselect 模型\u003c/h2\u003e\n\u003cp\u003e下面是 select 函数接口：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eselect\u003c/span\u003e (\u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e n, fd_set \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003ereadfds, fd_set \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003ewritefds, fd_set \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003eexceptfds, \u003cspan style=\"color:#66d9ef\"\u003estruct\u003c/span\u003e timeval \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003etimeout);\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003eselect 函数监视的文件描述符分 3 类，分别是 writefds、readfds 和 exceptfds。调用后 select 函数会阻塞，直到有描述符就绪（有数据 可读、可写、或者有 except），或者超时（timeout 指定等待时间，如果立即返回设为 null 即可）。当 select 函数返回后，通过遍历 fd_set，来找到就绪的描述符。\u003c/li\u003e\n\u003cli\u003eselect 目前几乎在所有的平台上支持，其良好跨平台支持是它的一大优点。select 的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制，在 Linux 上一般为 1024，可以通过修改宏定义甚至重新编译内核的方式提升这一限制，但是这样也会造成效率的降低。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"poll-模型\"\u003epoll 模型\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003epoll\u003c/span\u003e (\u003cspan style=\"color:#66d9ef\"\u003estruct\u003c/span\u003e pollfd \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003efds, \u003cspan style=\"color:#66d9ef\"\u003eunsigned\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e nfds, \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e timeout);\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e不同与 select 使用三个位图来表示三个 fdset 的方式，poll 使用一个 pollfd 的指针实现。\u003c/p\u003e","title":"IO复用"},{"content":"关系 Collection |-List │ |-LinkedList │ |-ArrayList │ |-Vector │ |-Stack | |-Set Map |-Hashtable |-HashMap |-WeakHashMap 介绍 Collection Collection是最基本的集合接口，一个Collection代表一组Object。所有实现Collection接口的类都必须提供两个标准的构造函数：无参数的构造函数用于创建一个空的Collection，有一个 Collection参数的构造函数用于创建一个新的Collection，这个新的Collection与传入的Collection有相同的元素。后一个构造函数允许用户复制一个Collection。 LinkedList LinkedList实现了List接口，允许null元素。此外LinkedList提供额外的get，remove，insert方法在 LinkedList的首部或尾部。 ArrayList ArrayList实现了可变大小的数组。它允许所有元素，包括null。ArrayList没有同步。 size，isEmpty，get，set方法运行时间为常数。但是add方法开销为分摊的常数，添加n个元素需要O(n)的时间。其他的方法运行时间为线性。 Vector Vector非常类似ArrayList，但是Vector是同步的。 Stack Stack继承自Vector，实现一个后进先出的堆栈。 Set Set是一种不包含重复的元素的Collection，即任意的两个元素e1和e2都有e1.equals(e2)=false，Set最多有一个null元素。 Map 请注意，Map没有继承Collection接口，Map提供key到value的映射。一个Map中不能包含相同的key，每个key只能映射一个 value。Map接口提供3种集合的视图，Map的内容可以被当作一组key集合，一组value集合，或者一组key-value映射。 Hashtable Hashtable继承Map接口，实现一个key-value映射的哈希表。任何非空（non-null）的对象都可作为key或者value。 HashMap HashMap和Hashtable类似，不同之处在于HashMap是非同步的，并且允许null，即null value和null key。　WeakHashMap WeakHashMap是一种改进的HashMap，它对key实行“弱引用”，如果一个key不再被外部所引用，那么该key可以被GC回收。 Map HashMap：基于散列表实现，是无序的； TreeMap：基于红黑树实现，按Key排序； LinkedHashMap：保存了插入顺序； Hashtable：是同步的，与HashMap类似； LinkedHashMap 底层使用哈希表与双向链表来实现迭代有序，非同步的HashMap 新增双向链表维护所有元素的有序性(因此非遍历操作性能可能低于HashMap) 包含两种排序方式：访问顺序和插入顺序(默认) 访问顺序有利于实现LRU(最近最少访问) 遍历速度只与元素总量(size)有关，与容量(capacity)无关 总结 如果涉及到堆栈，队列等操作，应该考虑用List，对于需要快速插入，删除元素，应该使用LinkedList，如果需要快速随机访问元素，应该使用ArrayList。 如果程序在单线程环境中，或者访问仅仅在一个线程中进行，考虑非同步的类，其效率较高，如果多个线程可能同时操作一个类，应该使用同步的类。 要特别注意对哈希表的操作，作为key的对象要正确复写equals和hashCode方法。 ","permalink":"http://bug1024.com/2017/05/09/java-collection-map/","summary":"\u003ch2 id=\"关系\"\u003e关系\u003c/h2\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e    Collection\n    |-List\n    │ |-LinkedList\n    │ |-ArrayList\n    │ |-Vector\n    │   |-Stack\n    |\n    |-Set\n\n    Map\n    |-Hashtable\n    |-HashMap\n    |-WeakHashMap\n\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"介绍\"\u003e介绍\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eCollection Collection是最基本的集合接口，一个Collection代表一组Object。所有实现Collection接口的类都必须提供两个标准的构造函数：无参数的构造函数用于创建一个空的Collection，有一个 Collection参数的构造函数用于创建一个新的Collection，这个新的Collection与传入的Collection有相同的元素。后一个构造函数允许用户复制一个Collection。\u003c/li\u003e\n\u003cli\u003eLinkedList LinkedList实现了List接口，允许null元素。此外LinkedList提供额外的get，remove，insert方法在 LinkedList的首部或尾部。\u003c/li\u003e\n\u003cli\u003eArrayList ArrayList实现了可变大小的数组。它允许所有元素，包括null。ArrayList没有同步。 size，isEmpty，get，set方法运行时间为常数。但是add方法开销为分摊的常数，添加n个元素需要O(n)的时间。其他的方法运行时间为线性。\u003c/li\u003e\n\u003cli\u003eVector Vector非常类似ArrayList，但是Vector是同步的。\u003c/li\u003e\n\u003cli\u003eStack Stack继承自Vector，实现一个后进先出的堆栈。\u003c/li\u003e\n\u003cli\u003eSet Set是一种不包含重复的元素的Collection，即任意的两个元素e1和e2都有e1.equals(e2)=false，Set最多有一个null元素。\u003c/li\u003e\n\u003cli\u003eMap 请注意，Map没有继承Collection接口，Map提供key到value的映射。一个Map中不能包含相同的key，每个key只能映射一个 value。Map接口提供3种集合的视图，Map的内容可以被当作一组key集合，一组value集合，或者一组key-value映射。\u003c/li\u003e\n\u003cli\u003eHashtable Hashtable继承Map接口，实现一个key-value映射的哈希表。任何非空（non-null）的对象都可作为key或者value。\u003c/li\u003e\n\u003cli\u003eHashMap HashMap和Hashtable类似，不同之处在于HashMap是非同步的，并且允许null，即null value和null key。　\u003c/li\u003e\n\u003cli\u003eWeakHashMap WeakHashMap是一种改进的HashMap，它对key实行“弱引用”，如果一个key不再被外部所引用，那么该key可以被GC回收。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"map\"\u003eMap\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eHashMap：基于散列表实现，是无序的；\u003c/li\u003e\n\u003cli\u003eTreeMap：基于红黑树实现，按Key排序；\u003c/li\u003e\n\u003cli\u003eLinkedHashMap：保存了插入顺序；\u003c/li\u003e\n\u003cli\u003eHashtable：是同步的，与HashMap类似；\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"linkedhashmap\"\u003eLinkedHashMap\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e底层使用哈希表与双向链表来实现迭代有序，非同步的HashMap\u003c/li\u003e\n\u003cli\u003e新增双向链表维护所有元素的有序性(因此非遍历操作性能可能低于HashMap)\u003c/li\u003e\n\u003cli\u003e包含两种排序方式：访问顺序和插入顺序(默认)\u003c/li\u003e\n\u003cli\u003e访问顺序有利于实现LRU(最近最少访问)\u003c/li\u003e\n\u003cli\u003e遍历速度只与元素总量(size)有关，与容量(capacity)无关\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"总结\"\u003e总结\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e如果涉及到堆栈，队列等操作，应该考虑用List，对于需要快速插入，删除元素，应该使用LinkedList，如果需要快速随机访问元素，应该使用ArrayList。\u003c/li\u003e\n\u003cli\u003e如果程序在单线程环境中，或者访问仅仅在一个线程中进行，考虑非同步的类，其效率较高，如果多个线程可能同时操作一个类，应该使用同步的类。\u003c/li\u003e\n\u003cli\u003e要特别注意对哈希表的操作，作为key的对象要正确复写equals和hashCode方法。\u003c/li\u003e\n\u003c/ul\u003e","title":"Java的List，Map，Set"},{"content":" C 语言是一种通用的、面向过程式的计算机程序设计语言。1972 年，为了移植与开发 UNIX 操作系统，丹尼斯·里奇在贝尔电话实验室设计开发了 C 语言。\n// 单行注释以//开始。（仅适用于C99或更新的版本。） /* 多行注释是这个样子的。（C89也适用。） */ // 常数： #define 关键词 define表示创建变量或分配存储单元，而declaration指的是说明变量的性质并不分配存储单元 #define DAYS_IN_YEAR 365 // 以枚举的方式定义常数 enum days {SUN = 1, MON, TUE, WED, THU, FRI, SAT}; // MON自动被定义为2，TUE被定义为3，以此类推。 // 用#include来导入头文件 #include \u0026lt;stdlib.h\u0026gt; #include \u0026lt;stdio.h\u0026gt; #include \u0026lt;string.h\u0026gt; // \u0026lt;尖括号\u0026gt;间的文件名是C标准库的头文件。 // 标准库以外的头文件，使用双引号代替尖括号。 #include \u0026#34;my_header.h\u0026#34; // 函数的签名可以事先在.h文件中定义， // 也可以直接在.c文件的头部定义。 void function_1(char c); void function_2(void); // 如果函数出现在main()之后，那么必须在main()之前 // 先声明一个函数原型 int add_two_ints(int x1, int x2); // 函数原型 // 你的程序的入口是一个返回值为整型的main函数 int main() { // 用printf打印到标准输出，可以设定格式， // %d 代表整数, \\n 代表换行 printf(\u0026#34;%d\\n\u0026#34;, 0); // =\u0026gt; 打印 0 // 所有的语句都要以分号结束 /////////////////////////////////////// // 类型 /////////////////////////////////////// // 在使用变量之前我们必须先声明它们。 // 变量在声明时需要指明其类型，而类型能够告诉系统这个变量所占用的空间 // int型（整型）变量一般占用4个字节 int x_int = 0; // short型（短整型）变量一般占用2个字节 short x_short = 0; // char型（字符型）变量会占用1个字节 char x_char = 0; char y_char = \u0026#39;y\u0026#39;; // 字符变量的字面值需要用单引号包住 // long型（长整型）一般需要4个字节到8个字节; 而long long型则至少需要8个字节（64位） long x_long = 0; long long x_long_long = 0; // float一般是用32位表示的浮点数字 float x_float = 0.0; // double一般是用64位表示的浮点数字 double x_double = 0.0; // 整数类型也可以有无符号的类型表示。这样这些变量就无法表示负数 // 但是无符号整数所能表示的范围就可以比原来的整数大一些 unsigned short ux_short; unsigned int ux_int; unsigned long long ux_long_long; // 单引号内的字符是机器的字符集中的整数。 \u0026#39;0\u0026#39; // =\u0026gt; 在ASCII字符集中是48 \u0026#39;A\u0026#39; // =\u0026gt; 在ASCII字符集中是65 // char类型一定会占用1个字节，但是其他的类型却会因具体机器的不同而各异 // sizeof(T) 可以返回T类型在运行的机器上占用多少个字节 // 这样你的代码就可以在各处正确运行了 // sizeof(obj)返回表达式（变量、字面量等）的尺寸 printf(\u0026#34;%zu\\n\u0026#34;, sizeof(int)); // =\u0026gt; 4 (大多数的机器字长为4) // 如果`sizeof`的参数是一个表达式，那么这个参数不会被演算（VLA例外，见下） // 它产生的值是编译期的常数 int a = 1; // size_t是一个无符号整型，表示对象的尺寸，至少2个字节 size_t size = sizeof(a++); // a++ 不会被演算 printf(\u0026#34;sizeof(a++) = %zu where a = %d\\n\u0026#34;, size, a); // 打印 \u0026#34;sizeof(a++) = 4 where a = 1\u0026#34; （在32位架构上） // 数组必须要被初始化为具体的长度 char my_char_array[20]; // 这个数组占据 1 * 20 = 20 个字节 int my_int_array[20]; // 这个数组占据 4 * 20 = 80 个字节 // (这里我们假设字长为4) // 可以用下面的方法把数组初始化为0: char my_array[20] = {0}; // 索引数组和其他语言类似 -- 好吧，其实是其他的语言像C my_array[0]; // =\u0026gt; 0 // 数组是可变的，其实就是内存的映射！ my_array[1] = 2; printf(\u0026#34;%d\\n\u0026#34;, my_array[1]); // =\u0026gt; 2 // 在C99 （C11中是可选特性），变长数组（VLA）也可以声明长度。 // 其长度不用是编译期常量。 printf(\u0026#34;Enter the array size: \u0026#34;); // 询问用户数组长度 char buf[0x100]; fgets(buf, sizeof buf, stdin); // stroul 将字符串解析为无符号整数 size_t size = strtoul(buf, NULL, 10); int var_length_array[size]; // 声明VLA printf(\u0026#34;sizeof array = %zu\\n\u0026#34;, sizeof var_length_array); // 上述程序可能的输出为： // \u0026gt; Enter the array size: 10 // \u0026gt; sizeof array = 40 // 字符串就是以 NUL (0x00) 这个字符结尾的字符数组, // NUL可以用\u0026#39;\\0\u0026#39;来表示. // (在字符串字面量中我们不必输入这个字符，编译器会自动添加的) char a_string[20] = \u0026#34;This is a string\u0026#34;; printf(\u0026#34;%s\\n\u0026#34;, a_string); // %s 可以对字符串进行格式化 /* 也许你会注意到 a_string 实际上只有16个字节长. 第17个字节是一个空字符(NUL) 而第18, 19 和 20 个字符的值是未定义。 */ printf(\u0026#34;%d\\n\u0026#34;, a_string[16]); // =\u0026gt; 0 // byte #17值为0（18，19，20同样为0） // 单引号间的字符是字符字面量 // 它的类型是`int`，而 *不是* `char` // （由于历史原因） int cha = \u0026#39;a\u0026#39;; // 合法 char chb = \u0026#39;a\u0026#39;; // 同样合法 (隐式类型转换 // 多维数组 int multi_array[2][5] = { {1, 2, 3, 4, 5}, {6, 7, 8, 9, 0} } // 获取元素 int array_int = multi_array[0][2]; // =\u0026gt; 3 /////////////////////////////////////// // 操作符 /////////////////////////////////////// // 多个变量声明的简写 int i1 = 1, i2 = 2; float f1 = 1.0, f2 = 2.0; int a, b, c; a = b = c = 0; // 算数运算直截了当 i1 + i2; // =\u0026gt; 3 i2 - i1; // =\u0026gt; 1 i2 * i1; // =\u0026gt; 2 i1 / i2; // =\u0026gt; 0 (0.5，但会被化整为 0) f1 / f2; // =\u0026gt; 0.5, 也许会有很小的误差 // 浮点数和浮点数运算都是近似值 // 取余运算 11 % 3; // =\u0026gt; 2 // 你多半会觉得比较操作符很熟悉, 不过C中没有布尔类型 // 而是用整形替代 // (C99中有_Bool或bool。) // 0为假, 其他均为真. (比较操作符的返回值总是返回0或1) 3 == 2; // =\u0026gt; 0 (false) 3 != 2; // =\u0026gt; 1 (true) 3 \u0026gt; 2; // =\u0026gt; 1 3 \u0026lt; 2; // =\u0026gt; 0 2 \u0026lt;= 2; // =\u0026gt; 1 2 \u0026gt;= 2; // =\u0026gt; 1 // C不是Python —— 连续比较不合法 int a = 1; // 错误 int between_0_and_2 = 0 \u0026lt; a \u0026lt; 2; // 正确 int between_0_and_2 = 0 \u0026lt; a \u0026amp;\u0026amp; a \u0026lt; 2; // 逻辑运算符适用于整数 !3; // =\u0026gt; 0 (非) !0; // =\u0026gt; 1 1 \u0026amp;\u0026amp; 1; // =\u0026gt; 1 (且) 0 \u0026amp;\u0026amp; 1; // =\u0026gt; 0 0 || 1; // =\u0026gt; 1 (或) 0 || 0; // =\u0026gt; 0 // 条件表达式 （ ? : ） int a = 5; int b = 10; int z; z = (a \u0026gt; b) ? a : b; // 10 “若a \u0026gt; b返回a，否则返回b。” // 增、减 char *s = \u0026#34;iLoveC\u0026#34; int j = 0; s[j++]; // \u0026#34;i\u0026#34; 返回s的第j项，然后增加j的值。 j = 0; s[++j]; // =\u0026gt; \u0026#34;L\u0026#34; 增加j的值，然后返回s的第j项。 // j-- 和 --j 同理 // 位运算 ~0x0F; // =\u0026gt; 0xF0 (取反) 0x0F \u0026amp; 0xF0; // =\u0026gt; 0x00 (和) 0x0F | 0xF0; // =\u0026gt; 0xFF (或) 0x04 ^ 0x0F; // =\u0026gt; 0x0B (异或) 0x01 \u0026lt;\u0026lt; 1; // =\u0026gt; 0x02 (左移1位) 0x02 \u0026gt;\u0026gt; 1; // =\u0026gt; 0x01 (右移1位) // 对有符号整数进行移位操作要小心 —— 以下未定义： // 有符号整数位移至符号位 int a = 1 \u0026lt;\u0026lt; 32 // 左移位一个负数 int a = -1 \u0026lt;\u0026lt; 2 // 移位超过或等于该类型数值的长度 // int a = 1 \u0026lt;\u0026lt; 32; // 假定int32位 /////////////////////////////////////// // 控制结构 /////////////////////////////////////// if (0) { printf(\u0026#34;I am never run\\n\u0026#34;); } else if (0) { printf(\u0026#34;I am also never run\\n\u0026#34;); } else { printf(\u0026#34;I print\\n\u0026#34;); } // While循环 int ii = 0; while (ii \u0026lt; 10) { // 任何非0的值均为真 printf(\u0026#34;%d, \u0026#34;, ii++); // ii++ 在取值过后自增 } // =\u0026gt; 打印 \u0026#34;0, 1, 2, 3, 4, 5, 6, 7, 8, 9, \u0026#34; printf(\u0026#34;\\n\u0026#34;); int kk = 0; do { printf(\u0026#34;%d, \u0026#34;, kk); } while (++kk \u0026lt; 10); // ++kk 先自增，再被取值 // =\u0026gt; 打印 \u0026#34;0, 1, 2, 3, 4, 5, 6, 7, 8, 9, \u0026#34; printf(\u0026#34;\\n\u0026#34;); // For 循环 int jj; for (jj=0; jj \u0026lt; 10; jj++) { printf(\u0026#34;%d, \u0026#34;, jj); } // =\u0026gt; 打印 \u0026#34;0, 1, 2, 3, 4, 5, 6, 7, 8, 9, \u0026#34; printf(\u0026#34;\\n\u0026#34;); // *****注意*****: // 循环和函数必须有主体部分，如果不需要主体部分： int i; for (i = 0; i \u0026lt;= 5; i++) { ; // 使用分号表达主体（null语句） } // 多重分支：switch() switch (some_integral_expression) { case 0: // 标签必须是整数常量表达式 do_stuff(); break; // 如果不使用break，控制结构会继续执行下面的标签 case 1: do_something_else(); break; default: // 假设 `some_integral_expression` 不匹配任何标签 fputs(\u0026#34;error!\\n\u0026#34;, stderr); exit(-1); break; } /////////////////////////////////////// // 类型转换 /////////////////////////////////////// // 在C中每个变量都有类型，你可以将变量的类型进行转换 // (有一定限制) int x_hex = 0x01; // 可以用16进制字面量赋值 // 在类型转换时，数字本身的值会被保留下来 printf(\u0026#34;%d\\n\u0026#34;, x_hex); // =\u0026gt; 打印 1 printf(\u0026#34;%d\\n\u0026#34;, (short) x_hex); // =\u0026gt; 打印 1 printf(\u0026#34;%d\\n\u0026#34;, (char) x_hex); // =\u0026gt; 打印 1 // 类型转换时可能会造成溢出，而且不会抛出警告 printf(\u0026#34;%d\\n\u0026#34;, (char) 257); // =\u0026gt; 1 (char的最大值为255，假定char为8位长) // 使用\u0026lt;limits.h\u0026gt;提供的CHAR_MAX、SCHAR_MAX和UCHAR_MAX宏可以确定`char`、`signed_char`和`unisigned char`的最大值。 // 整数型和浮点型可以互相转换 printf(\u0026#34;%f\\n\u0026#34;, (float)100); // %f 格式化单精度浮点 printf(\u0026#34;%lf\\n\u0026#34;, (double)100); // %lf 格式化双精度浮点 printf(\u0026#34;%d\\n\u0026#34;, (char)100.0); /////////////////////////////////////// // 指针 /////////////////////////////////////// // 指针变量是用来储存内存地址的变量 // 指针变量的声明也会告诉它所指向的数据的类型 // 你可以使用得到你的变量的地址，并把它们搞乱，;-) int x = 0; printf(\u0026#34;%p\\n\u0026#34;, \u0026amp;x); // 用 \u0026amp; 来获取变量的地址 // (%p 格式化一个类型为 void *的指针) // =\u0026gt; 打印某个内存地址 // 指针类型在声明中以*开头 int* px, not_a_pointer; // px是一个指向int型的指针 px = \u0026amp;x; // 把x的地址保存到px中 printf(\u0026#34;%p\\n\u0026#34;, (void *)px); // =\u0026gt; 输出内存中的某个地址 printf(\u0026#34;%zu, %zu\\n\u0026#34;, sizeof(px), sizeof(not_a_pointer)); // =\u0026gt; 在64位系统上打印“8， 4”。 // 要得到某个指针指向的内容的值，可以在指针前加一个*来取得（取消引用） // 注意： 是的，这可能让人困惑，\u0026#39;*\u0026#39;在用来声明一个指针的同时取消引用它。 printf(\u0026#34;%d\\n\u0026#34;, *px); // =\u0026gt; 输出 0, 即x的值 // 你也可以改变指针所指向的值 // 此时你需要取消引用上添加括号，因为++比*的优先级更高 (*px)++; // 把px所指向的值增加1 printf(\u0026#34;%d\\n\u0026#34;, *px); // =\u0026gt; 输出 1 printf(\u0026#34;%d\\n\u0026#34;, x); // =\u0026gt; 输出 1 // 数组是分配一系列连续空间的常用方式 int x_array[20]; int xx; for (xx=0; xx\u0026lt;20; xx++) { x_array[xx] = 20 - xx; } // 初始化 x_array 为 20, 19, 18,... 2, 1 // 声明一个整型的指针，并初始化为指向x_array int* x_ptr = x_array; // x_ptr现在指向了数组的第一个元素(即整数20). // 这是因为数组通常衰减为指向它们的第一个元素的指针。 // 例如，当一个数组被传递给一个函数或者绑定到一个指针时， //它衰减为(隐式转化为）一个指针。 // 例外： 当数组是`\u0026amp;`操作符的参数： int arr[10]; int (*ptr_to_arr)[10] = \u0026amp;arr; // \u0026amp;arr的类型不是`int *`！ // 它的类型是指向数组的指针（数组由10个int组成） // 或者当数组是字符串字面量（初始化字符数组） char arr[] = \u0026#34;foobarbazquirk\u0026#34;; // 或者当它是`sizeof`或`alignof`操作符的参数时： int arr[10]; int *ptr = arr; // 等价于 int *ptr = \u0026amp;arr[0]; printf(\u0026#34;%zu, %zu\\n\u0026#34;, sizeof arr, sizeof ptr); // 应该会输出\u0026#34;40, 4\u0026#34;或\u0026#34;40, 8\u0026#34; // 指针的增减多少是依据它本身的类型而定的 // （这被称为指针算术） printf(\u0026#34;%d\\n\u0026#34;, *(x_ptr + 1)); // =\u0026gt; 打印 19 printf(\u0026#34;%d\\n\u0026#34;, x_array[1]); // =\u0026gt; 打印 19 // 你也可以通过标准库函数malloc来实现动态分配 // 这个函数接受一个代表容量的参数，参数类型为`size_t` // 系统一般会从堆区分配指定容量字节大小的空间 // （在一些系统，例如嵌入式系统中这点不一定成立 // C标准对此未置一词。） // malloc并不是从一个在编译时就确定的固定大小的数组中分配存储空间，而是在需要的时候向操作系统申请空间 // 程序中可能不通过malloc调用申请空间，因此malloc管理的空间不一定是连续的 int *my_ptr = malloc(sizeof(*my_ptr) * 20); for (xx=0; xx\u0026lt;20; xx++) { *(my_ptr + xx) = 20 - xx; // my_ptr[xx] = 20-xx } // 初始化内存为 20, 19, 18, 17... 2, 1 (类型为int） // 对未分配的内存进行取消引用会产生未定义的结果 printf(\u0026#34;%d\\n\u0026#34;, *(my_ptr + 21)); // =\u0026gt; 谁知道会输出什么 // malloc分配的区域需要手动释放 // 否则没人能够再次使用这块内存，直到程序结束为止 free(my_ptr); // 字符串通常是字符数组，但是经常用字符指针表示 // (它是指向数组的第一个元素的指针) // 一个优良的实践是使用`const char *`来引用一个字符串字面量， // 因为字符串字面量不应当被修改（即\u0026#34;foo\u0026#34;[0] = \u0026#39;a\u0026#39;犯了大忌） const char* my_str = \u0026#34;This is my very own string\u0026#34;; printf(\u0026#34;%c\\n\u0026#34;, *my_str); // =\u0026gt; \u0026#39;T\u0026#39; // 如果字符串是数组，（多半是用字符串字面量初始化的） // 情况就不一样了，字符串位于可写的内存中 char foo[] = \u0026#34;foo\u0026#34;; foo[0] = \u0026#39;a\u0026#39;; // 这是合法的，foo现在包含\u0026#34;aoo\u0026#34; function_1(); } // main函数结束 /////////////////////////////////////// // 函数 /////////////////////////////////////// // 函数声明语法: // \u0026lt;返回值类型\u0026gt; \u0026lt;函数名称\u0026gt;(\u0026lt;参数\u0026gt;) int add_two_ints(int x1, int x2){ return x1 + x2; // 用return来返回一个值 } /* 函数是按值传递的。当调用一个函数的时候，传递给函数的参数 是原有值的拷贝（数组除外）。你在函数内对参数所进行的操作 不会改变该参数原有的值。 但是你可以通过指针来传递引用，这样函数就可以更改值 例子：字符串本身翻转 */ // 类型为void的函数没有返回值 void str_reverse(char *str_in){ char tmp; int ii = 0; size_t len = strlen(str_in); // `strlen()`` 是C标准库函数 for (ii = 0; ii \u0026lt; len / 2; ii++) { tmp = str_in[ii]; str_in[ii] = str_in[len - ii - 1]; // 从倒数第ii个开始 str_in[len - ii - 1] = tmp; } } /* char c[] = \u0026#34;This is a test.\u0026#34;; str_reverse(c); printf(\u0026#34;%s\\n\u0026#34;, c); // =\u0026gt; \u0026#34;.tset a si sihT\u0026#34; */ // 如果引用函数之外的变量，必须使用extern关键字 int i = 0; void testFunc() { extern int i; // 使用外部变量 i } // 使用static确保external变量为源文件私有 static int i = 0; // 其他使用 testFunc()的文件无法访问变量i void testFunc() { extern int i; } //**你同样可以声明函数为static** /////////////////////////////////////// // 用户自定义类型和结构 /////////////////////////////////////// // Typedefs可以创建类型别名 typedef int my_type; my_type my_type_var = 0; // struct是数据的集合，成员依序分配，按照 // 编写的顺序 struct rectangle { int width; int height; }; // 一般而言，以下断言不成立： // sizeof(struct rectangle) == sizeof(int) + sizeof(int) //这是因为structure成员之间可能存在潜在的间隙（为了对齐）[1] void function_1(){ struct rectangle my_rec; // 通过 . 来访问结构中的数据 my_rec.width = 10; my_rec.height = 20; // 你也可以声明指向结构体的指针 struct rectangle *my_rec_ptr = \u0026amp;my_rec; // 通过取消引用来改变结构体的成员... (*my_rec_ptr).width = 30; // ... 或者用 -\u0026gt; 操作符作为简写提高可读性 my_rec_ptr-\u0026gt;height = 10; // Same as (*my_rec_ptr).height = 10; } // 你也可以用typedef来给一个结构体起一个别名 typedef struct rectangle rect; int area(rect r) { return r.width * r.height; } // 如果struct较大，你可以通过指针传递，避免 // 复制整个struct。 int area(const rect *r) { return r-\u0026gt;width * r-\u0026gt;height; } /////////////////////////////////////// // 函数指针 /////////////////////////////////////// /* 在运行时，函数本身也被存放到某块内存区域当中 函数指针就像其他指针一样（不过是存储一个内存地址） 但却可以被用来直接调用函数, 并且可以四处传递回调函数 但是，定义的语法初看令人有些迷惑 例子：通过指针调用str_reverse */ void str_reverse_through_pointer(char *str_in) { // 定义一个函数指针 f. void (*f)(char *); // 签名一定要与目标函数相同 f = \u0026amp;str_reverse; // 将函数的地址在运行时赋给指针 (*f)(str_in); // 通过指针调用函数 // f(str_in); // 等价于这种调用方式 } /* 只要函数签名是正确的，任何时候都能将任何函数赋给某个函数指针 为了可读性和简洁性，函数指针经常和typedef搭配使用： */ typedef void (*my_fnp_type)(char *); // 实际声明函数指针会这么用: // ... // my_fnp_type f; // 特殊字符 \u0026#39;\\a\u0026#39; // bell \u0026#39;\\n\u0026#39; // 换行 \u0026#39;\\t\u0026#39; // tab \u0026#39;\\v\u0026#39; // vertical tab \u0026#39;\\f\u0026#39; // formfeed \u0026#39;\\r\u0026#39; // 回车 \u0026#39;\\b\u0026#39; // 退格 \u0026#39;\\0\u0026#39; // null，通常置于字符串的最后。 // hello\\n\\0. 按照惯例，\\0用于标记字符串的末尾。 \u0026#39;\\\\\u0026#39; // 反斜杠 \u0026#39;\\?\u0026#39; // 问号 \u0026#39;\\\u0026#39;\u0026#39; // 单引号 \u0026#39;\\\u0026#34;\u0026#39; // 双引号 \u0026#39;\\xhh\u0026#39; // 十六进制数字. 例子: \u0026#39;\\xb\u0026#39; = vertical tab \u0026#39;\\ooo\u0026#39; // 八进制数字. 例子: \u0026#39;\\013\u0026#39; = vertical tab // 打印格式： \u0026#34;%d\u0026#34; // 整数 \u0026#34;%3d\u0026#34; // 3位以上整数 （右对齐文本） \u0026#34;%s\u0026#34; // 字符串 \u0026#34;%f\u0026#34; // float \u0026#34;%ld\u0026#34; // long \u0026#34;%3.2f\u0026#34; // 左3位以上、右2位以上十进制浮 \u0026#34;%7.4s\u0026#34; // (字符串同样适用) \u0026#34;%c\u0026#34; // 字母 \u0026#34;%p\u0026#34; // 指针 \u0026#34;%x\u0026#34; // 十六进制 \u0026#34;%o\u0026#34; // 八进制 \u0026#34;%%\u0026#34; // 打印 % /////////////////////////////////////// // 演算优先级 /////////////////////////////////////// //---------------------------------------------------// // 操作符 | 组合 // //---------------------------------------------------// // () [] -\u0026gt; . | 从左到右 // // ! ~ ++ -- + = *(type)sizeof | 从右到左 // // * / % | 从左到右 // // + - | 从左到右 // // \u0026lt;\u0026lt; \u0026gt;\u0026gt; | 从左到右 // // \u0026lt; \u0026lt;= \u0026gt; \u0026gt;= | 从左到右 // // == != | 从左到右 // // \u0026amp; | 从左到右 // // ^ | 从左到右 // // | | 从左到右 // // \u0026amp;\u0026amp; | 从左到右 // // || | 从左到右 // // ?: | 从右到左 // // = += -= *= /= %= \u0026amp;= ^= |= \u0026lt;\u0026lt;= \u0026gt;\u0026gt;= | 从右到左 // // , | 从左到右 // //---------------------------------------------------// ","permalink":"http://bug1024.com/2017/05/08/c/","summary":"\u003cblockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003eC 语言是一种通用的、面向过程式的计算机程序设计语言。1972 年，为了移植与开发 UNIX 操作系统，丹尼斯·里奇在贝尔电话实验室设计开发了 C 语言。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003c/blockquote\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 单行注释以//开始。（仅适用于C99或更新的版本。）\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e/*\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e    多行注释是这个样子的。（C89也适用。）\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e    */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 常数： #define 关键词 define表示创建变量或分配存储单元，而declaration指的是说明变量的性质并不分配存储单元\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e#define DAYS_IN_YEAR 365\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 以枚举的方式定义常数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eenum\u003c/span\u003e days {SUN \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, MON, TUE, WED, THU, FRI, SAT};\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// MON自动被定义为2，TUE被定义为3，以此类推。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 用#include来导入头文件\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e#include\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e\u0026lt;stdlib.h\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e#include\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e\u0026lt;stdio.h\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e#include\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e\u0026lt;string.h\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// \u0026lt;尖括号\u0026gt;间的文件名是C标准库的头文件。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 标准库以外的头文件，使用双引号代替尖括号。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e#include\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e\u0026#34;my_header.h\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 函数的签名可以事先在.h文件中定义，\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 也可以直接在.c文件的头部定义。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003evoid\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003efunction_1\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e c);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003evoid\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003efunction_2\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003evoid\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 如果函数出现在main()之后，那么必须在main()之前\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 先声明一个函数原型\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eadd_two_ints\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e x1, \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e x2); \u003cspan style=\"color:#75715e\"\u003e// 函数原型\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 你的程序的入口是一个返回值为整型的main函数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emain\u003c/span\u003e() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 用printf打印到标准输出，可以设定格式，\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// %d 代表整数, \\n 代表换行\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%d\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e); \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 打印 0\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 所有的语句都要以分号结束\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e///////////////////////////////////////\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 类型\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e///////////////////////////////////////\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 在使用变量之前我们必须先声明它们。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 变量在声明时需要指明其类型，而类型能够告诉系统这个变量所占用的空间\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// int型（整型）变量一般占用4个字节\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e x_int \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// short型（短整型）变量一般占用2个字节\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eshort\u003c/span\u003e x_short \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// char型（字符型）变量会占用1个字节\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e x_char \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e y_char \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;y\u0026#39;\u003c/span\u003e; \u003cspan style=\"color:#75715e\"\u003e// 字符变量的字面值需要用单引号包住\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// long型（长整型）一般需要4个字节到8个字节; 而long long型则至少需要8个字节（64位）\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003elong\u003c/span\u003e x_long \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003elong\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003elong\u003c/span\u003e x_long_long \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// float一般是用32位表示的浮点数字\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efloat\u003c/span\u003e x_float \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0.0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// double一般是用64位表示的浮点数字\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edouble\u003c/span\u003e x_double \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0.0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 整数类型也可以有无符号的类型表示。这样这些变量就无法表示负数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 但是无符号整数所能表示的范围就可以比原来的整数大一些\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eunsigned\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eshort\u003c/span\u003e ux_short;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eunsigned\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e ux_int;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eunsigned\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003elong\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003elong\u003c/span\u003e ux_long_long;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 单引号内的字符是机器的字符集中的整数。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;0\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 在ASCII字符集中是48\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;A\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 在ASCII字符集中是65\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// char类型一定会占用1个字节，但是其他的类型却会因具体机器的不同而各异\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// sizeof(T) 可以返回T类型在运行的机器上占用多少个字节\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 这样你的代码就可以在各处正确运行了\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// sizeof(obj)返回表达式（变量、字面量等）的尺寸\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%zu\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#66d9ef\"\u003esizeof\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e)); \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 4 (大多数的机器字长为4)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 如果`sizeof`的参数是一个表达式，那么这个参数不会被演算（VLA例外，见下）\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 它产生的值是编译期的常数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e a \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// size_t是一个无符号整型，表示对象的尺寸，至少2个字节\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003esize_t\u003c/span\u003e size \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003esizeof\u003c/span\u003e(a\u003cspan style=\"color:#f92672\"\u003e++\u003c/span\u003e); \u003cspan style=\"color:#75715e\"\u003e// a++ 不会被演算\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;sizeof(a++) = %zu where a = %d\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, size, a);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 打印 \u0026#34;sizeof(a++) = 4 where a = 1\u0026#34; （在32位架构上）\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 数组必须要被初始化为具体的长度\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e my_char_array[\u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e]; \u003cspan style=\"color:#75715e\"\u003e// 这个数组占据 1 * 20 = 20 个字节\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e my_int_array[\u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e]; \u003cspan style=\"color:#75715e\"\u003e// 这个数组占据 4 * 20 = 80 个字节\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                          \u003cspan style=\"color:#75715e\"\u003e// (这里我们假设字长为4)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 可以用下面的方法把数组初始化为0:\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e my_array[\u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e};\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 索引数组和其他语言类似 -- 好吧，其实是其他的语言像C\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    my_array[\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e]; \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 0\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 数组是可变的，其实就是内存的映射！\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    my_array[\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%d\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, my_array[\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e]); \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 2\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 在C99 （C11中是可选特性），变长数组（VLA）也可以声明长度。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 其长度不用是编译期常量。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Enter the array size: \u0026#34;\u003c/span\u003e); \u003cspan style=\"color:#75715e\"\u003e// 询问用户数组长度\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e buf[\u003cspan style=\"color:#ae81ff\"\u003e0x100\u003c/span\u003e];\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003efgets\u003c/span\u003e(buf, \u003cspan style=\"color:#66d9ef\"\u003esizeof\u003c/span\u003e buf, stdin);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// stroul 将字符串解析为无符号整数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003esize_t\u003c/span\u003e size \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estrtoul\u003c/span\u003e(buf, NULL, \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e var_length_array[size]; \u003cspan style=\"color:#75715e\"\u003e// 声明VLA\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;sizeof array = %zu\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#66d9ef\"\u003esizeof\u003c/span\u003e var_length_array);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 上述程序可能的输出为：\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// \u0026gt; Enter the array size: 10\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// \u0026gt; sizeof array = 40\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 字符串就是以 NUL (0x00) 这个字符结尾的字符数组,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// NUL可以用\u0026#39;\\0\u0026#39;来表示.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// (在字符串字面量中我们不必输入这个字符，编译器会自动添加的)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e a_string[\u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;This is a string\u0026#34;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%s\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, a_string); \u003cspan style=\"color:#75715e\"\u003e// %s 可以对字符串进行格式化\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e/*\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e    也许你会注意到 a_string 实际上只有16个字节长.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e    第17个字节是一个空字符(NUL)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e    而第18, 19 和 20 个字符的值是未定义。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e    */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%d\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, a_string[\u003cspan style=\"color:#ae81ff\"\u003e16\u003c/span\u003e]); \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 0\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e//  byte #17值为0（18，19，20同样为0）\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 单引号间的字符是字符字面量\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 它的类型是`int`，而 *不是* `char`\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// （由于历史原因）\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e cha \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;a\u0026#39;\u003c/span\u003e; \u003cspan style=\"color:#75715e\"\u003e// 合法\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e chb \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;a\u0026#39;\u003c/span\u003e; \u003cspan style=\"color:#75715e\"\u003e// 同样合法 (隐式类型转换\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 多维数组\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e multi_array[\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e][\u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            {\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e},\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            {\u003cspan style=\"color:#ae81ff\"\u003e6\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e7\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e8\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e9\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 获取元素\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e array_int \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e multi_array[\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e][\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e]; \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 3\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e///////////////////////////////////////\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 操作符\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e///////////////////////////////////////\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 多个变量声明的简写\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e i1 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, i2 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efloat\u003c/span\u003e f1 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1.0\u003c/span\u003e, f2 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2.0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e a, b, c;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    a \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e b \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e c \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 算数运算直截了当\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    i1 \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e i2; \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 3\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    i2 \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e i1; \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 1\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    i2 \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e i1; \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 2\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    i1 \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003e i2; \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 0 (0.5，但会被化整为 0)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    f1 \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003e f2; \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 0.5, 也许会有很小的误差\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 浮点数和浮点数运算都是近似值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 取余运算\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ae81ff\"\u003e11\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e%\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e; \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 2\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 你多半会觉得比较操作符很熟悉, 不过C中没有布尔类型\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 而是用整形替代\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// (C99中有_Bool或bool。)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 0为假, 其他均为真. (比较操作符的返回值总是返回0或1)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e; \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 0 (false)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e!=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e; \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 1 (true)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e; \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 1\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e; \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 0\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e; \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 1\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e; \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 1\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// C不是Python —— 连续比较不合法\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e a \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 错误\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e between_0_and_2 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e a \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 正确\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e between_0_and_2 \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e a \u003cspan style=\"color:#f92672\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e a \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 逻辑运算符适用于整数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003e!\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e; \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 0 (非)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003e!\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e; \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 1\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e; \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 1 (且)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e; \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 0\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e||\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e; \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 1 (或)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e||\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e; \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 0\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 条件表达式 （ ? : ）\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e a \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e b \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e z;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    z \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e (a \u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e b) \u003cspan style=\"color:#f92672\"\u003e?\u003c/span\u003e a : b; \u003cspan style=\"color:#75715e\"\u003e//  10 “若a \u0026gt; b返回a，否则返回b。”\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 增、减\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003es \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;iLoveC\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e j \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    s[j\u003cspan style=\"color:#f92672\"\u003e++\u003c/span\u003e]; \u003cspan style=\"color:#75715e\"\u003e// \u0026#34;i\u0026#34; 返回s的第j项，然后增加j的值。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    j \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    s[\u003cspan style=\"color:#f92672\"\u003e++\u003c/span\u003ej]; \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; \u0026#34;L\u0026#34;  增加j的值，然后返回s的第j项。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// j-- 和 --j 同理\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 位运算\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003e~\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e0x0F\u003c/span\u003e; \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 0xF0 (取反)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ae81ff\"\u003e0x0F\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e\u0026amp;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0xF0\u003c/span\u003e; \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 0x00 (和)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ae81ff\"\u003e0x0F\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e|\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0xF0\u003c/span\u003e; \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 0xFF (或)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ae81ff\"\u003e0x04\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e^\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0x0F\u003c/span\u003e; \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 0x0B (异或)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ae81ff\"\u003e0x01\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e; \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 0x02 (左移1位)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ae81ff\"\u003e0x02\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e; \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 0x01 (右移1位)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 对有符号整数进行移位操作要小心 —— 以下未定义：\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 有符号整数位移至符号位 int a = 1 \u0026lt;\u0026lt; 32\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 左移位一个负数 int a = -1 \u0026lt;\u0026lt; 2\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 移位超过或等于该类型数值的长度\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// int a = 1 \u0026lt;\u0026lt; 32; // 假定int32位\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e///////////////////////////////////////\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 控制结构\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e///////////////////////////////////////\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e (\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;I am never run\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    } \u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e (\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;I am also never run\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    } \u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;I print\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// While循环\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e ii \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ewhile\u003c/span\u003e (ii \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e) { \u003cspan style=\"color:#75715e\"\u003e// 任何非0的值均为真\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%d, \u0026#34;\u003c/span\u003e, ii\u003cspan style=\"color:#f92672\"\u003e++\u003c/span\u003e); \u003cspan style=\"color:#75715e\"\u003e// ii++ 在取值过后自增\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    } \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt;  打印 \u0026#34;0, 1, 2, 3, 4, 5, 6, 7, 8, 9, \u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e kk \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edo\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%d, \u0026#34;\u003c/span\u003e, kk);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    } \u003cspan style=\"color:#66d9ef\"\u003ewhile\u003c/span\u003e (\u003cspan style=\"color:#f92672\"\u003e++\u003c/span\u003ekk \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e); \u003cspan style=\"color:#75715e\"\u003e// ++kk 先自增，再被取值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 打印 \u0026#34;0, 1, 2, 3, 4, 5, 6, 7, 8, 9, \u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// For 循环\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e jj;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e (jj\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e; jj \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e; jj\u003cspan style=\"color:#f92672\"\u003e++\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%d, \u0026#34;\u003c/span\u003e, jj);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    } \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 打印 \u0026#34;0, 1, 2, 3, 4, 5, 6, 7, 8, 9, \u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// *****注意*****:\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 循环和函数必须有主体部分，如果不需要主体部分：\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e i;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e (i \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e; i \u003cspan style=\"color:#f92672\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e; i\u003cspan style=\"color:#f92672\"\u003e++\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        ; \u003cspan style=\"color:#75715e\"\u003e// 使用分号表达主体（null语句）\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 多重分支：switch()\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eswitch\u003c/span\u003e (some_integral_expression) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ecase\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e// 标签必须是整数常量表达式\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#a6e22e\"\u003edo_stuff\u003c/span\u003e();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ebreak\u003c/span\u003e; \u003cspan style=\"color:#75715e\"\u003e// 如果不使用break，控制结构会继续执行下面的标签\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ecase\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#a6e22e\"\u003edo_something_else\u003c/span\u003e();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ebreak\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edefault\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e// 假设 `some_integral_expression` 不匹配任何标签\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#a6e22e\"\u003efputs\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;error!\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, stderr);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#a6e22e\"\u003eexit\u003c/span\u003e(\u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ebreak\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e///////////////////////////////////////\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 类型转换\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e///////////////////////////////////////\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 在C中每个变量都有类型，你可以将变量的类型进行转换\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// (有一定限制)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e x_hex \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0x01\u003c/span\u003e; \u003cspan style=\"color:#75715e\"\u003e// 可以用16进制字面量赋值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 在类型转换时，数字本身的值会被保留下来\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%d\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, x_hex); \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 打印 1\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%d\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, (\u003cspan style=\"color:#66d9ef\"\u003eshort\u003c/span\u003e) x_hex); \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 打印 1\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%d\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, (\u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e) x_hex); \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 打印 1\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 类型转换时可能会造成溢出，而且不会抛出警告\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%d\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, (\u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e) \u003cspan style=\"color:#ae81ff\"\u003e257\u003c/span\u003e); \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 1 (char的最大值为255，假定char为8位长)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 使用\u0026lt;limits.h\u0026gt;提供的CHAR_MAX、SCHAR_MAX和UCHAR_MAX宏可以确定`char`、`signed_char`和`unisigned char`的最大值。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 整数型和浮点型可以互相转换\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%f\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, (\u003cspan style=\"color:#66d9ef\"\u003efloat\u003c/span\u003e)\u003cspan style=\"color:#ae81ff\"\u003e100\u003c/span\u003e); \u003cspan style=\"color:#75715e\"\u003e// %f 格式化单精度浮点\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%lf\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, (\u003cspan style=\"color:#66d9ef\"\u003edouble\u003c/span\u003e)\u003cspan style=\"color:#ae81ff\"\u003e100\u003c/span\u003e); \u003cspan style=\"color:#75715e\"\u003e// %lf 格式化双精度浮点\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%d\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, (\u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e)\u003cspan style=\"color:#ae81ff\"\u003e100.0\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e///////////////////////////////////////\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 指针\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e///////////////////////////////////////\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 指针变量是用来储存内存地址的变量\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 指针变量的声明也会告诉它所指向的数据的类型\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 你可以使用得到你的变量的地址，并把它们搞乱，;-)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e x \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%p\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#f92672\"\u003e\u0026amp;\u003c/span\u003ex); \u003cspan style=\"color:#75715e\"\u003e// 用 \u0026amp; 来获取变量的地址\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// (%p 格式化一个类型为 void *的指针)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 打印某个内存地址\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 指针类型在声明中以*开头\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e px, not_a_pointer; \u003cspan style=\"color:#75715e\"\u003e// px是一个指向int型的指针\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    px \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e\u0026amp;\u003c/span\u003ex; \u003cspan style=\"color:#75715e\"\u003e// 把x的地址保存到px中\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%p\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, (\u003cspan style=\"color:#66d9ef\"\u003evoid\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e)px); \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 输出内存中的某个地址\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%zu, %zu\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#66d9ef\"\u003esizeof\u003c/span\u003e(px), \u003cspan style=\"color:#66d9ef\"\u003esizeof\u003c/span\u003e(not_a_pointer));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 在64位系统上打印“8， 4”。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 要得到某个指针指向的内容的值，可以在指针前加一个*来取得（取消引用）\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 注意： 是的，这可能让人困惑，\u0026#39;*\u0026#39;在用来声明一个指针的同时取消引用它。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%d\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003epx); \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 输出 0, 即x的值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 你也可以改变指针所指向的值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 此时你需要取消引用上添加括号，因为++比*的优先级更高\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    (\u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003epx)\u003cspan style=\"color:#f92672\"\u003e++\u003c/span\u003e; \u003cspan style=\"color:#75715e\"\u003e// 把px所指向的值增加1\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%d\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003epx); \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 输出 1\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%d\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, x); \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 输出 1\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 数组是分配一系列连续空间的常用方式\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e x_array[\u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e];\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e xx;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e (xx\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e; xx\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e; xx\u003cspan style=\"color:#f92672\"\u003e++\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        x_array[xx] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e xx;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    } \u003cspan style=\"color:#75715e\"\u003e// 初始化 x_array 为 20, 19, 18,... 2, 1\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 声明一个整型的指针，并初始化为指向x_array\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e x_ptr \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e x_array;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// x_ptr现在指向了数组的第一个元素(即整数20).\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 这是因为数组通常衰减为指向它们的第一个元素的指针。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 例如，当一个数组被传递给一个函数或者绑定到一个指针时，\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e//它衰减为(隐式转化为）一个指针。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 例外： 当数组是`\u0026amp;`操作符的参数：\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e arr[\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e];\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e (\u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003eptr_to_arr)[\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e\u0026amp;\u003c/span\u003earr; \u003cspan style=\"color:#75715e\"\u003e// \u0026amp;arr的类型不是`int *`！\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                                  \u003cspan style=\"color:#75715e\"\u003e// 它的类型是指向数组的指针（数组由10个int组成）\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 或者当数组是字符串字面量（初始化字符数组）\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e arr[] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;foobarbazquirk\u0026#34;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 或者当它是`sizeof`或`alignof`操作符的参数时：\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e arr[\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e];\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003eptr \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e arr; \u003cspan style=\"color:#75715e\"\u003e// 等价于 int *ptr = \u0026amp;arr[0];\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%zu, %zu\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#66d9ef\"\u003esizeof\u003c/span\u003e arr, \u003cspan style=\"color:#66d9ef\"\u003esizeof\u003c/span\u003e ptr); \u003cspan style=\"color:#75715e\"\u003e// 应该会输出\u0026#34;40, 4\u0026#34;或\u0026#34;40, 8\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 指针的增减多少是依据它本身的类型而定的\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// （这被称为指针算术）\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%d\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e(x_ptr \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e)); \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 打印 19\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%d\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, x_array[\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e]); \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 打印 19\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 你也可以通过标准库函数malloc来实现动态分配\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 这个函数接受一个代表容量的参数，参数类型为`size_t`\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 系统一般会从堆区分配指定容量字节大小的空间\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// （在一些系统，例如嵌入式系统中这点不一定成立\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// C标准对此未置一词。）\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// malloc并不是从一个在编译时就确定的固定大小的数组中分配存储空间，而是在需要的时候向操作系统申请空间\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 程序中可能不通过malloc调用申请空间，因此malloc管理的空间不一定是连续的\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003emy_ptr \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emalloc\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003esizeof\u003c/span\u003e(\u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003emy_ptr) \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e (xx\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e; xx\u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e; xx\u003cspan style=\"color:#f92672\"\u003e++\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e(my_ptr \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e xx) \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e xx; \u003cspan style=\"color:#75715e\"\u003e// my_ptr[xx] = 20-xx\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    } \u003cspan style=\"color:#75715e\"\u003e// 初始化内存为 20, 19, 18, 17... 2, 1 (类型为int）\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 对未分配的内存进行取消引用会产生未定义的结果\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%d\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e(my_ptr \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e21\u003c/span\u003e)); \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; 谁知道会输出什么\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// malloc分配的区域需要手动释放\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 否则没人能够再次使用这块内存，直到程序结束为止\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003efree\u003c/span\u003e(my_ptr);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 字符串通常是字符数组，但是经常用字符指针表示\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// (它是指向数组的第一个元素的指针)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 一个优良的实践是使用`const char *`来引用一个字符串字面量，\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 因为字符串字面量不应当被修改（即\u0026#34;foo\u0026#34;[0] = \u0026#39;a\u0026#39;犯了大忌）\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003econst\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e my_str \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;This is my very own string\u0026#34;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%c\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003emy_str); \u003cspan style=\"color:#75715e\"\u003e// =\u0026gt; \u0026#39;T\u0026#39;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 如果字符串是数组，（多半是用字符串字面量初始化的）\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 情况就不一样了，字符串位于可写的内存中\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e foo[] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;foo\u0026#34;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    foo[\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;a\u0026#39;\u003c/span\u003e; \u003cspan style=\"color:#75715e\"\u003e// 这是合法的，foo现在包含\u0026#34;aoo\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#a6e22e\"\u003efunction_1\u003c/span\u003e();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    } \u003cspan style=\"color:#75715e\"\u003e// main函数结束\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e///////////////////////////////////////\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 函数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e///////////////////////////////////////\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 函数声明语法:\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// \u0026lt;返回值类型\u0026gt; \u0026lt;函数名称\u0026gt;(\u0026lt;参数\u0026gt;)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eadd_two_ints\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e x1, \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e x2){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e x1 \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e x2; \u003cspan style=\"color:#75715e\"\u003e// 用return来返回一个值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e/*\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e    函数是按值传递的。当调用一个函数的时候，传递给函数的参数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e    是原有值的拷贝（数组除外）。你在函数内对参数所进行的操作\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e    不会改变该参数原有的值。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e    但是你可以通过指针来传递引用，这样函数就可以更改值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e    例子：字符串本身翻转\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e    */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 类型为void的函数没有返回值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003evoid\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estr_reverse\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003estr_in){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e tmp;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e ii \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003esize_t\u003c/span\u003e len \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estrlen\u003c/span\u003e(str_in); \u003cspan style=\"color:#75715e\"\u003e// `strlen()`` 是C标准库函数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e (ii \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e; ii \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e len \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e; ii\u003cspan style=\"color:#f92672\"\u003e++\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            tmp \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e str_in[ii];\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            str_in[ii] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e str_in[len \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e ii \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e]; \u003cspan style=\"color:#75715e\"\u003e// 从倒数第ii个开始\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            str_in[len \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e ii \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e tmp;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e/*\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e    char c[] = \u0026#34;This is a test.\u0026#34;;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e    str_reverse(c);\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e    printf(\u0026#34;%s\\n\u0026#34;, c); // =\u0026gt; \u0026#34;.tset a si sihT\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e    */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 如果引用函数之外的变量，必须使用extern关键字\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e i \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003evoid\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003etestFunc\u003c/span\u003e() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eextern\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e i; \u003cspan style=\"color:#75715e\"\u003e// 使用外部变量 i\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 使用static确保external变量为源文件私有\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003estatic\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e i \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e; \u003cspan style=\"color:#75715e\"\u003e// 其他使用 testFunc()的文件无法访问变量i\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003evoid\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003etestFunc\u003c/span\u003e() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eextern\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e i;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e//**你同样可以声明函数为static**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e///////////////////////////////////////\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 用户自定义类型和结构\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e///////////////////////////////////////\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// Typedefs可以创建类型别名\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etypedef\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e my_type;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    my_type my_type_var \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// struct是数据的集合，成员依序分配，按照\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 编写的顺序\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003estruct\u003c/span\u003e rectangle {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e width;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e height;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    };\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 一般而言，以下断言不成立：\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// sizeof(struct rectangle) == sizeof(int) + sizeof(int)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e//这是因为structure成员之间可能存在潜在的间隙（为了对齐）[1]\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003evoid\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003efunction_1\u003c/span\u003e(){\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003estruct\u003c/span\u003e rectangle my_rec;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e// 通过 . 来访问结构中的数据\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        my_rec.width \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        my_rec.height \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e// 你也可以声明指向结构体的指针\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003estruct\u003c/span\u003e rectangle \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003emy_rec_ptr \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e\u0026amp;\u003c/span\u003emy_rec;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e// 通过取消引用来改变结构体的成员...\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        (\u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003emy_rec_ptr).width \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e30\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e// ... 或者用 -\u0026gt; 操作符作为简写提高可读性\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        my_rec_ptr\u003cspan style=\"color:#f92672\"\u003e-\u0026gt;\u003c/span\u003eheight \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e; \u003cspan style=\"color:#75715e\"\u003e// Same as (*my_rec_ptr).height = 10;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 你也可以用typedef来给一个结构体起一个别名\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etypedef\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003estruct\u003c/span\u003e rectangle rect;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003earea\u003c/span\u003e(rect r) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e r.width \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e r.height;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 如果struct较大，你可以通过指针传递，避免\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 复制整个struct。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003earea\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003econst\u003c/span\u003e rect \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003er)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e r\u003cspan style=\"color:#f92672\"\u003e-\u0026gt;\u003c/span\u003ewidth \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e r\u003cspan style=\"color:#f92672\"\u003e-\u0026gt;\u003c/span\u003eheight;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e///////////////////////////////////////\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 函数指针\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e///////////////////////////////////////\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e/*\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e    在运行时，函数本身也被存放到某块内存区域当中\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e    函数指针就像其他指针一样（不过是存储一个内存地址） 但却可以被用来直接调用函数,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e    并且可以四处传递回调函数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e    但是，定义的语法初看令人有些迷惑\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e    例子：通过指针调用str_reverse\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e    */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003evoid\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estr_reverse_through_pointer\u003c/span\u003e(\u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003estr_in) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e// 定义一个函数指针 f.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003evoid\u003c/span\u003e (\u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003ef)(\u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e); \u003cspan style=\"color:#75715e\"\u003e// 签名一定要与目标函数相同\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        f \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e\u0026amp;\u003c/span\u003estr_reverse; \u003cspan style=\"color:#75715e\"\u003e// 将函数的地址在运行时赋给指针\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        (\u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003ef)(str_in); \u003cspan style=\"color:#75715e\"\u003e// 通过指针调用函数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e// f(str_in); // 等价于这种调用方式\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e/*\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e    只要函数签名是正确的，任何时候都能将任何函数赋给某个函数指针\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e    为了可读性和简洁性，函数指针经常和typedef搭配使用：\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e    */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etypedef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evoid\u003c/span\u003e (\u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003emy_fnp_type)(\u003cspan style=\"color:#66d9ef\"\u003echar\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 实际声明函数指针会这么用:\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// ...\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// my_fnp_type f;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 特殊字符\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\a\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e// bell\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\n\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e// 换行\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\t\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e// tab\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\v\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e// vertical tab\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\f\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e// formfeed\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\r\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e// 回车\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\b\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e// 退格\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\0\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e// null，通常置于字符串的最后。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e         \u003cspan style=\"color:#75715e\"\u003e//   hello\\n\\0. 按照惯例，\\0用于标记字符串的末尾。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\\\\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e// 反斜杠\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\?\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e// 问号\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\\u0026#39;\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e// 单引号\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\\u0026#34;\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e// 双引号\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\u0026#39;\\\u003c/span\u003exhh\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e// 十六进制数字. 例子: \u0026#39;\\xb\u0026#39; = vertical tab\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\u0026#39;\\\u003c/span\u003eooo\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e// 八进制数字. 例子: \u0026#39;\\013\u0026#39; = vertical tab\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 打印格式：\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%d\u0026#34;\u003c/span\u003e    \u003cspan style=\"color:#75715e\"\u003e// 整数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%3d\u0026#34;\u003c/span\u003e   \u003cspan style=\"color:#75715e\"\u003e// 3位以上整数 （右对齐文本）\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%s\u0026#34;\u003c/span\u003e    \u003cspan style=\"color:#75715e\"\u003e// 字符串\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%f\u0026#34;\u003c/span\u003e    \u003cspan style=\"color:#75715e\"\u003e// float\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%ld\u0026#34;\u003c/span\u003e   \u003cspan style=\"color:#75715e\"\u003e// long\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%3.2f\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e// 左3位以上、右2位以上十进制浮\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%7.4s\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e// (字符串同样适用)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%c\u0026#34;\u003c/span\u003e    \u003cspan style=\"color:#75715e\"\u003e// 字母\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%p\u0026#34;\u003c/span\u003e    \u003cspan style=\"color:#75715e\"\u003e// 指针\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%x\u0026#34;\u003c/span\u003e    \u003cspan style=\"color:#75715e\"\u003e// 十六进制\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%o\u0026#34;\u003c/span\u003e    \u003cspan style=\"color:#75715e\"\u003e// 八进制\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%%\u0026#34;\u003c/span\u003e    \u003cspan style=\"color:#75715e\"\u003e// 打印 %\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e///////////////////////////////////////\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 演算优先级\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e///////////////////////////////////////\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e//---------------------------------------------------//\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e//        操作符                     | 组合          //\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e//---------------------------------------------------//\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// () [] -\u0026gt; .                        | 从左到右      //\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// ! ~ ++ -- + = *(type)sizeof       | 从右到左      //\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// * / %                             | 从左到右      //\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// + -                               | 从左到右      //\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// \u0026lt;\u0026lt; \u0026gt;\u0026gt;                             | 从左到右      //\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// \u0026lt; \u0026lt;= \u0026gt; \u0026gt;=                         | 从左到右      //\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// == !=                             | 从左到右      //\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// \u0026amp;                                 | 从左到右      //\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// ^                                 | 从左到右      //\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// |                                 | 从左到右      //\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// \u0026amp;\u0026amp;                                | 从左到右      //\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// ||                                | 从左到右      //\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// ?:                                | 从右到左      //\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// = += -= *= /= %= \u0026amp;= ^= |= \u0026lt;\u0026lt;= \u0026gt;\u0026gt;= | 从右到左      //\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// ,                                 | 从左到右      //\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e//---------------------------------------------------//\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"C语法"},{"content":" bash 是一个为GNU计划编写的Unix shell。它的名字是一系列缩写：Bourne-Again SHell — 这是关于Bourne shell（sh）的一个双关语（Bourne again / born again）。 Bourne shell是一个早期的重要shell，由史蒂夫·伯恩在1978年前后编写，并同Version 7 Unix一起发布。bash则在1987年由布莱恩·福克斯创造。在1990年，Chet Ramey成为了主要的维护者。\n#!/bin/bash # 脚本的第一行叫 shebang，用来告知系统如何执行该脚本: # 参见： http://en.wikipedia.org/wiki/Shebang_(Unix) # 如你所见，注释以 # 开头，shebang 也是注释。 # 推荐使用 #!/usr/bin/env bash # 获取脚本路径 script_dir=$(cd $(dirname $0) \u0026amp;\u0026amp; pwd) script_dir=$(dirname $(readlink -f $0 )) # 显示 “Hello world!” echo Hello world! # 每一句指令以换行或分号隔开： echo \u0026#39;This is the first line\u0026#39;; echo \u0026#39;This is the second line\u0026#39; # 声明一个变量： Variable=\u0026#34;Some string\u0026#34; # 下面是错误的做法： Variable = \u0026#34;Some string\u0026#34; # Bash 会把 Variable 当做一个指令，由于找不到该指令，因此这里会报错。 # 也不可以这样： Variable= \u0026#39;Some string\u0026#39; # Bash 会认为 \u0026#39;Some string\u0026#39; 是一条指令，由于找不到该指令，这里再次报错。 # （这个例子中 \u0026#39;Variable=\u0026#39; 这部分会被当作仅对 \u0026#39;Some string\u0026#39; 起作用的赋值。） # 使用变量： echo $Variable echo \u0026#34;$Variable\u0026#34; echo \u0026#39;$Variable\u0026#39; # 当你赋值 (assign) 、导出 (export)，或者以其他方式使用变量时，变量名前不加 $。 # 如果要使用变量的值， 则要加 $。 # 注意： \u0026#39; (单引号) 不会展开变量（即会屏蔽掉变量）。 # 在变量内部进行字符串代换 echo ${Variable/Some/A} # 会把 Variable 中首次出现的 \u0026#34;some\u0026#34; 替换成 “A”。 # 变量的截取 Length=7 echo ${Variable:0:Length} # 这样会仅返回变量值的前7个字符 # 变量的默认值 echo ${Foo:-\u0026#34;DefaultValueIfFooIsMissingOrEmpty\u0026#34;} # 对 null (Foo=) 和空串 (Foo=\u0026#34;\u0026#34;) 起作用； 零（Foo=0）时返回0 # 注意这仅返回默认值而不是改变变量的值 # 内置变量： # 下面的内置变量很有用 echo \u0026#34;Last program return value: $?\u0026#34; echo \u0026#34;Script\u0026#39;s PID: $$\u0026#34; echo \u0026#34;Number of arguments: $#\u0026#34; echo \u0026#34;Scripts arguments: $@\u0026#34; echo \u0026#34;Scripts arguments separated in different variables: $1 $2...\u0026#34; # 读取输入： echo \u0026#34;What\u0026#39;s your name?\u0026#34; read Name # 这里不需要声明新变量 echo Hello, $Name! # 通常的 if 结构看起来像这样： # \u0026#39;man test\u0026#39; 可查看更多的信息 if [ $Name -ne $USER ] then echo \u0026#34;Your name isn\u0026#39;t your username\u0026#34; else echo \u0026#34;Your name is your username\u0026#34; fi # 根据上一个指令执行结果决定是否执行下一个指令 echo \u0026#34;Always executed\u0026#34; || echo \u0026#34;Only executed if first command fails\u0026#34; echo \u0026#34;Always executed\u0026#34; \u0026amp;\u0026amp; echo \u0026#34;Only executed if first command does NOT fail\u0026#34; # 在 if 语句中使用 \u0026amp;\u0026amp; 和 || 需要多对方括号 if [ $Name == \u0026#34;Steve\u0026#34; ] \u0026amp;\u0026amp; [ $Age -eq 15 ] then echo \u0026#34;This will run if $Name is Steve AND $Age is 15.\u0026#34; fi if [ $Name == \u0026#34;Daniya\u0026#34; ] || [ $Name == \u0026#34;Zach\u0026#34; ] then echo \u0026#34;This will run if $Name is Daniya OR Zach.\u0026#34; fi # 表达式的格式如下: echo $(( 10 + 5 )) # 与其他编程语言不同的是，bash 运行时依赖上下文。比如，使用 ls 时，列出当前目录。 ls # 指令可以带有选项： ls -l # 列出文件和目录的详细信息 # 前一个指令的输出可以当作后一个指令的输入。grep 用来匹配字符串。 # 用下面的指令列出当前目录下所有的 txt 文件： ls -l | grep \u0026#34;\\.txt\u0026#34; # 重定向输入和输出（标准输入，标准输出，标准错误）。 # 以 ^EOF$ 作为结束标记从标准输入读取数据并覆盖 hello.py : cat \u0026gt; hello.py \u0026lt;\u0026lt; EOF #!/usr/bin/env python from __future__ import print_function import sys print(\u0026#34;#stdout\u0026#34;, file=sys.stdout) print(\u0026#34;#stderr\u0026#34;, file=sys.stderr) for line in sys.stdin: print(line, file=sys.stdout) EOF # 重定向可以到输出，输入和错误输出。 python hello.py \u0026lt; \u0026#34;input.in\u0026#34; python hello.py \u0026gt; \u0026#34;output.out\u0026#34; python hello.py 2\u0026gt; \u0026#34;error.err\u0026#34; python hello.py \u0026gt; \u0026#34;output-and-error.log\u0026#34; 2\u0026gt;\u0026amp;1 python hello.py \u0026gt; /dev/null 2\u0026gt;\u0026amp;1 # \u0026gt; 会覆盖已存在的文件， \u0026gt;\u0026gt; 会以累加的方式输出文件中。 python hello.py \u0026gt;\u0026gt; \u0026#34;output.out\u0026#34; 2\u0026gt;\u0026gt; \u0026#34;error.err\u0026#34; # 覆盖 output.out , 追加 error.err 并统计行数 info bash \u0026#39;Basic Shell Features\u0026#39; \u0026#39;Redirections\u0026#39; \u0026gt; output.out 2\u0026gt;\u0026gt; error.err wc -l output.out error.err # 运行指令并打印文件描述符 （比如 /dev/fd/123） # 具体可查看： man fd echo \u0026lt;(echo \u0026#34;#helloworld\u0026#34;) # 以 \u0026#34;#helloworld\u0026#34; 覆盖 output.out: cat \u0026gt; output.out \u0026lt;(echo \u0026#34;#helloworld\u0026#34;) echo \u0026#34;#helloworld\u0026#34; \u0026gt; output.out echo \u0026#34;#helloworld\u0026#34; | cat \u0026gt; output.out echo \u0026#34;#helloworld\u0026#34; | tee output.out \u0026gt;/dev/null # 清理临时文件并显示详情（增加 \u0026#39;-i\u0026#39; 选项启用交互模式） rm -v output.out error.err output-and-error.log # 一个指令可用 $( ) 嵌套在另一个指令内部： # 以下的指令会打印当前目录下的目录和文件总数 echo \u0026#34;There are $(ls | wc -l) items here.\u0026#34; # 反引号 `` 起相同作用，但不允许嵌套 # 优先使用 $( ). echo \u0026#34;There are `ls | wc -l` items here.\u0026#34; # Bash 的 case 语句与 Java 和 C++ 中的 switch 语句类似: case \u0026#34;$Variable\u0026#34; in # 列出需要匹配的字符串 0) echo \u0026#34;There is a zero.\u0026#34;;; 1) echo \u0026#34;There is a one.\u0026#34;;; *) echo \u0026#34;It is not null.\u0026#34;;; esac # 循环遍历给定的参数序列: # 变量$Variable 的值会被打印 3 次。 for Variable in {1..3} do echo \u0026#34;$Variable\u0026#34; done # 或传统的 “for循环” ： for ((a=1; a \u0026lt;= 3; a++)) do echo $a done # 也可以用于文件 # 用 cat 输出 file1 和 file2 内容 for Variable in file1 file2 do cat \u0026#34;$Variable\u0026#34; done # 或作用于其他命令的输出 # 对 ls 输出的文件执行 cat 指令。 for Output in $(ls) do cat \u0026#34;$Output\u0026#34; done # while 循环： while [ true ] do echo \u0026#34;loop body here...\u0026#34; break done # 你也可以使用函数 # 定义函数： function foo () { echo \u0026#34;Arguments work just like script arguments: $@\u0026#34; echo \u0026#34;And: $1 $2...\u0026#34; echo \u0026#34;This is a function\u0026#34; return 0 } # 更简单的方法 bar () { echo \u0026#34;Another way to declare functions!\u0026#34; return 0 } # 调用函数 foo \u0026#34;My name is\u0026#34; $Name # 有很多有用的指令需要学习: # 打印 file.txt 的最后 10 行 tail -n 10 file.txt # 打印 file.txt 的前 10 行 head -n 10 file.txt # 将 file.txt 按行排序 sort file.txt # 报告或忽略重复的行，用选项 -d 打印重复的行 uniq -d file.txt # 打印每行中 \u0026#39;,\u0026#39; 之前内容 cut -d \u0026#39;,\u0026#39; -f 1 file.txt # 将 file.txt 文件所有 \u0026#39;okay\u0026#39; 替换为 \u0026#39;great\u0026#39;, （兼容正则表达式） sed -i \u0026#39;s/okay/great/g\u0026#39; file.txt # 将 file.txt 中匹配正则的行打印到标准输出 # 这里打印以 \u0026#34;foo\u0026#34; 开头, \u0026#34;bar\u0026#34; 结尾的行 grep \u0026#34;^foo.*bar$\u0026#34; file.txt # 使用选项 \u0026#34;-c\u0026#34; 统计行数 grep -c \u0026#34;^foo.*bar$\u0026#34; file.txt # 如果只是要按字面形式搜索字符串而不是按正则表达式，使用 fgrep (或 grep -F) fgrep \u0026#34;^foo.*bar$\u0026#34; file.txt # 以 bash 内建的 \u0026#39;help\u0026#39; 指令阅读 Bash 自带文档： help help help help for help return help source help . # 用 man 指令阅读相关的 Bash 手册 apropos bash man 1 bash man bash # 用 info 指令查阅命令的 info 文档 （info 中按 ? 显示帮助信息） apropos info | grep \u0026#39;^info.*(\u0026#39; man info info info info 5 info # 阅读 Bash 的 info 文档： info bash info bash \u0026#39;Bash Features\u0026#39; info bash 6 info --apropos bash ","permalink":"http://bug1024.com/2017/05/07/bash/","summary":"\u003cblockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003ebash 是一个为GNU计划编写的Unix shell。它的名字是一系列缩写：Bourne-Again SHell — 这是关于Bourne shell（sh）的一个双关语（Bourne again / born again）。\nBourne shell是一个早期的重要shell，由史蒂夫·伯恩在1978年前后编写，并同Version 7 Unix一起发布。bash则在1987年由布莱恩·福克斯创造。在1990年，Chet Ramey成为了主要的维护者。\u003c/p\u003e","title":"Bash语法"},{"content":" Lua 是一个小巧的脚本语言。作者是巴西人。该语言的设计目的是为了嵌入应用程序中，从而为应用程序提供灵活的扩展和定制功能。 Lua脚本可以很容易的被C/C++代码调用，也可以反过来调用C/C++的函数，这使得Lua在应用程序中可以被广泛应用。不仅仅作为扩展脚本，也可以作为普通的配置文件，代替XML,Ini等文件格式，并且更容易理解和维护。 Lua由标准C编写而成，代码简洁优美，几乎在所有操作系统和平台上都可以编译，运行。 一个完整的Lua解释器不过200k，在目前所有脚本引擎中，Lua的速度是最快的。这一切都决定了Lua是作为嵌入式脚本的最佳选择。\n-- 单行注释 --[[ 多行注视 --]] ---------------------------------------------------- -- 1. 参数和控制语句 ---------------------------------------------------- num = 42 -- 所有的数值都是double类型 -- Don\u0026#39;t freak out, 64-bit doubles have 52 bits for -- storing exact int values; machine precision is -- not a problem for ints that need \u0026lt; 52 bits. s = \u0026#39;walternate\u0026#39; -- 不可改变的字符串，单引号双引号都可以 t = \u0026#34;double-quotes are also fine\u0026#34; u = [[ Double brackets start and end multi-line strings.]] t = nil -- Undefines t; Lua has garbage collection. -- Blocks are denoted with keywords like do/end: while num \u0026lt; 50 do num = num + 1 -- No ++ or += type operators. end -- If clauses: if num \u0026gt; 40 then print(\u0026#39;over 40\u0026#39;) elseif s ~= \u0026#39;walternate\u0026#39; then -- ~= is not equals. -- Equality check is == like Python; ok for strs. io.write(\u0026#39;not over 40\\n\u0026#39;) -- Defaults to stdout. else -- 参数默认是全局的 thisIsGlobal = 5 -- Camel case is common. -- 声明非全局变量 local line = io.read() -- Reads next stdin line. -- 使用..进行字符连接 print(\u0026#39;Winter is coming, \u0026#39; .. line) end -- 为定义的变量的值都是nil -- This is not an error: foo = anUnknownVariable -- Now foo = nil. aBoolValue = false -- 只有nil和false的值是false，0和\u0026#39;\u0026#39;都是true的 if not aBoolValue then print(\u0026#39;twas false\u0026#39;) end -- \u0026#39;or\u0026#39; and \u0026#39;and\u0026#39; are short-circuited. -- This is similar to the a?b:c operator in C/js: ans = aBoolValue and \u0026#39;yes\u0026#39; or \u0026#39;no\u0026#39; --\u0026gt; \u0026#39;no\u0026#39; karlSum = 0 for i = 1, 100 do -- The range includes both ends. karlSum = karlSum + i end -- Use \u0026#34;100, 1, -1\u0026#34; as the range to count down: fredSum = 0 for j = 100, 1, -1 do fredSum = fredSum + j end -- In general, the range is begin, end[, step]. -- Another loop construct: repeat print(\u0026#39;the way of the future\u0026#39;) num = num - 1 until num == 0 ---------------------------------------------------- -- 2. 函数 ---------------------------------------------------- function fib(n) if n \u0026lt; 2 then return 1 end return fib(n - 2) + fib(n - 1) end -- 闭包和匿名函数 function adder(x) -- The returned function is created when adder is -- called, and remembers the value of x: return function (y) return x + y end end a1 = adder(9) a2 = adder(36) print(a1(16)) --\u0026gt; 25 print(a2(64)) --\u0026gt; 100 -- Returns, func calls, and assignments all work -- with lists that may be mismatched in length. -- Unmatched receivers are nil; -- unmatched senders are discarded. x, y, z = 1, 2, 3, 4 -- Now x = 1, y = 2, z = 3, and 4 is thrown away. function bar(a, b, c) print(a, b, c) return 4, 8, 15, 16, 23, 42 end x, y = bar(\u0026#39;zaphod\u0026#39;) --\u0026gt; prints \u0026#34;zaphod nil nil\u0026#34; -- Now x = 4, y = 8, values 15..42 are discarded. -- Functions are first-class, may be local/global. -- These are the same: function f(x) return x * x end f = function (x) return x * x end -- And so are these: local function g(x) return math.sin(x) end local g; g = function (x) return math.sin(x) end -- the \u0026#39;local g\u0026#39; decl makes g-self-references ok. -- Trig funcs work in radians, by the way. -- Calls with one string param don\u0026#39;t need parens: print \u0026#39;hello\u0026#39; -- Works fine. ---------------------------------------------------- -- 3. 映射表 ---------------------------------------------------- -- Tables = Lua\u0026#39;s only compound data structure; -- they are associative arrays. -- Similar to php arrays or js objects, they are -- hash-lookup dicts that can also be used as lists. -- Using tables as dictionaries / maps: -- Dict literals have string keys by default: t = {key1 = \u0026#39;value1\u0026#39;, key2 = false} -- String keys can use js-like dot notation: print(t.key1) -- Prints \u0026#39;value1\u0026#39;. t.newKey = {} -- Adds a new key/value pair. t.key2 = nil -- Removes key2 from the table. -- Literal notation for any (non-nil) value as key: u = {[\u0026#39;@!#\u0026#39;] = \u0026#39;qbert\u0026#39;, [{}] = 1729, [6.28] = \u0026#39;tau\u0026#39;} print(u[6.28]) -- prints \u0026#34;tau\u0026#34; -- Key matching is basically by value for numbers -- and strings, but by identity for tables. a = u[\u0026#39;@!#\u0026#39;] -- Now a = \u0026#39;qbert\u0026#39;. b = u[{}] -- We might expect 1729, but it\u0026#39;s nil: -- b = nil since the lookup fails. It fails -- because the key we used is not the same object -- as the one used to store the original value. So -- strings \u0026amp; numbers are more portable keys. -- A one-table-param function call needs no parens: function h(x) print(x.key1) end h{key1 = \u0026#39;Sonmi~451\u0026#39;} -- Prints \u0026#39;Sonmi~451\u0026#39;. for key, val in pairs(u) do -- Table iteration. print(key, val) end -- _G is a special table of all globals. print(_G[\u0026#39;_G\u0026#39;] == _G) -- Prints \u0026#39;true\u0026#39;. -- Using tables as lists / arrays: -- List literals implicitly set up int keys: v = {\u0026#39;value1\u0026#39;, \u0026#39;value2\u0026#39;, 1.21, \u0026#39;gigawatts\u0026#39;} for i = 1, #v do -- #v is the size of v for lists. print(v[i]) -- Indices start at 1 !! SO CRAZY! end -- A \u0026#39;list\u0026#39; is not a real type. v is just a table -- with consecutive integer keys, treated as a list. ---------------------------------------------------- -- 3.1 Metatables and metamethods. ---------------------------------------------------- -- A table can have a metatable that gives the table -- operator-overloadish behavior. Later we\u0026#39;ll see -- how metatables support js-prototypey behavior. f1 = {a = 1, b = 2} -- Represents the fraction a/b. f2 = {a = 2, b = 3} -- This would fail: -- s = f1 + f2 metafraction = {} function metafraction.__add(f1, f2) sum = {} sum.b = f1.b * f2.b sum.a = f1.a * f2.b + f2.a * f1.b return sum end setmetatable(f1, metafraction) setmetatable(f2, metafraction) s = f1 + f2 -- call __add(f1, f2) on f1\u0026#39;s metatable -- f1, f2 have no key for their metatable, unlike -- prototypes in js, so you must retrieve it as in -- getmetatable(f1). The metatable is a normal table -- with keys that Lua knows about, like __add. -- But the next line fails since s has no metatable: -- t = s + s -- Class-like patterns given below would fix this. -- An __index on a metatable overloads dot lookups: defaultFavs = {animal = \u0026#39;gru\u0026#39;, food = \u0026#39;donuts\u0026#39;} myFavs = {food = \u0026#39;pizza\u0026#39;} setmetatable(myFavs, {__index = defaultFavs}) eatenBy = myFavs.animal -- works! thanks, metatable -- Direct table lookups that fail will retry using -- the metatable\u0026#39;s __index value, and this recurses. -- An __index value can also be a function(tbl, key) -- for more customized lookups. -- Values of __index,add, .. are called metamethods. -- Full list. Here a is a table with the metamethod. -- __add(a, b) for a + b -- __sub(a, b) for a - b -- __mul(a, b) for a * b -- __div(a, b) for a / b -- __mod(a, b) for a % b -- __pow(a, b) for a ^ b -- __unm(a) for -a -- __concat(a, b) for a .. b -- __len(a) for #a -- __eq(a, b) for a == b -- __lt(a, b) for a \u0026lt; b -- __le(a, b) for a \u0026lt;= b -- __index(a, b) \u0026lt;fn or a table\u0026gt; for a.b -- __newindex(a, b, c) for a.b = c -- __call(a, ...) for a(...) ---------------------------------------------------- -- 3.2 类与继承 ---------------------------------------------------- -- Classes aren\u0026#39;t built in; there are different ways -- to make them using tables and metatables. -- Explanation for this example is below it. Dog = {} -- 1. function Dog:new() -- 2. newObj = {sound = \u0026#39;woof\u0026#39;} -- 3. self.__index = self -- 4. return setmetatable(newObj, self) -- 5. end function Dog:makeSound() -- 6. print(\u0026#39;I say \u0026#39; .. self.sound) end mrDog = Dog:new() -- 7. mrDog:makeSound() -- \u0026#39;I say woof\u0026#39; -- 8. -- 1. Dog acts like a class; it\u0026#39;s really a table. -- 2. function tablename:fn(...) is the same as -- function tablename.fn(self, ...) -- The : just adds a first arg called self. -- Read 7 \u0026amp; 8 below for how self gets its value. -- 3. newObj will be an instance of class Dog. -- 4. self = the class being instantiated. Often -- self = Dog, but inheritance can change it. -- newObj gets self\u0026#39;s functions when we set both -- newObj\u0026#39;s metatable and self\u0026#39;s __index to self. -- 5. Reminder: setmetatable returns its first arg. -- 6. The : works as in 2, but this time we expect -- self to be an instance instead of a class. -- 7. Same as Dog.new(Dog), so self = Dog in new(). -- 8. Same as mrDog.makeSound(mrDog); self = mrDog. ---------------------------------------------------- -- Inheritance example: LoudDog = Dog:new() -- 1. function LoudDog:makeSound() s = self.sound .. \u0026#39; \u0026#39; -- 2. print(s .. s .. s) end seymour = LoudDog:new() -- 3. seymour:makeSound() -- \u0026#39;woof woof woof\u0026#39; -- 4. -- 1. LoudDog gets Dog\u0026#39;s methods and variables. -- 2. self has a \u0026#39;sound\u0026#39; key from new(), see 3. -- 3. Same as LoudDog.new(LoudDog), and converted to -- Dog.new(LoudDog) as LoudDog has no \u0026#39;new\u0026#39; key, -- but does have __index = Dog on its metatable. -- Result: seymour\u0026#39;s metatable is LoudDog, and -- LoudDog.__index = LoudDog. So seymour.key will -- = seymour.key, LoudDog.key, Dog.key, whichever -- table is the first with the given key. -- 4. The \u0026#39;makeSound\u0026#39; key is found in LoudDog; this -- is the same as LoudDog.makeSound(seymour). -- If needed, a subclass\u0026#39;s new() is like the base\u0026#39;s: function LoudDog:new() newObj = {} -- set up newObj self.__index = self return setmetatable(newObj, self) end ---------------------------------------------------- -- 4. 模块封装 ---------------------------------------------------- --[[ I\u0026#39;m commenting out this section so the rest of -- this script remains runnable. -- Suppose the file mod.lua looks like this: local M = {} local function sayMyName() print(\u0026#39;Hrunkner\u0026#39;) end function M.sayHello() print(\u0026#39;Why hello there\u0026#39;) sayMyName() end return M -- Another file can use mod.lua\u0026#39;s functionality: local mod = require(\u0026#39;mod\u0026#39;) -- Run the file mod.lua. -- require is the standard way to include modules. -- require acts like: (if not cached; see below) local mod = (function () \u0026lt;contents of mod.lua\u0026gt; end)() -- It\u0026#39;s like mod.lua is a function body, so that -- locals inside mod.lua are invisible outside it. -- This works because mod here = M in mod.lua: mod.sayHello() -- Says hello to Hrunkner. -- This is wrong; sayMyName only exists in mod.lua: mod.sayMyName() -- error -- require\u0026#39;s return values are cached so a file is -- run at most once, even when require\u0026#39;d many times. -- Suppose mod2.lua contains \u0026#34;print(\u0026#39;Hi!\u0026#39;)\u0026#34;. local a = require(\u0026#39;mod2\u0026#39;) -- Prints Hi! local b = require(\u0026#39;mod2\u0026#39;) -- Doesn\u0026#39;t print; a=b. -- dofile is like require without caching: dofile(\u0026#39;mod2.lua\u0026#39;) --\u0026gt; Hi! dofile(\u0026#39;mod2.lua\u0026#39;) --\u0026gt; Hi! (runs it again) -- loadfile loads a lua file but doesn\u0026#39;t run it yet. f = loadfile(\u0026#39;mod2.lua\u0026#39;) -- Call f() to run it. -- loadstring is loadfile for strings. g = loadstring(\u0026#39;print(343)\u0026#39;) -- Returns a function. g() -- Prints out 343; nothing printed before now. -- 推荐写法 -- square.lua 长方形模块 local _M = {} -- 局部的变量 _M._VERSION = \u0026#39;1.0\u0026#39; -- 模块版本 local mt = { __index = _M } function _M.new(self, width, height) return setmetatable({ width=width, height=height }, mt) end function _M.get_square(self) return self.width * self.height end function _M.get_circumference(self) return (self.width + self.height) * 2 end return _M -- 引用示例代码： local square = require \u0026#34;square\u0026#34; local s1 = square:new(1, 2) print(s1:get_square()) --output: 2 print(s1:get_circumference()) --output: 6 --]] ---------------------------------------------------- -- 5. 参考 ---------------------------------------------------- --[[ http://tylerneylon.com/a/learn-lua/ Have fun with Lua! --]] ","permalink":"http://bug1024.com/2017/04/30/lua/","summary":"\u003cblockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003eLua 是一个小巧的脚本语言。作者是巴西人。该语言的设计目的是为了嵌入应用程序中，从而为应用程序提供灵活的扩展和定制功能。\nLua脚本可以很容易的被C/C++代码调用，也可以反过来调用C/C++的函数，这使得Lua在应用程序中可以被广泛应用。不仅仅作为扩展脚本，也可以作为普通的配置文件，代替XML,Ini等文件格式，并且更容易理解和维护。\nLua由标准C编写而成，代码简洁优美，几乎在所有操作系统和平台上都可以编译，运行。\n一个完整的Lua解释器不过200k，在目前所有脚本引擎中，Lua的速度是最快的。这一切都决定了Lua是作为嵌入式脚本的最佳选择。\u003c/p\u003e","title":"Lua语法"},{"content":"进程和CPU信息 参数 含义 load average: 0.06, 0.60, 0.48 系统负载，即任务队列的平均长度，1分钟、5分钟、15分钟前到现在的平均值, 按照经验小于0.7 x cpu核数则正常 Tasks: 29 total 进程总数 1 running 正在运行的进程数 28 sleeping 睡眠的进程数 0 stopped 停止的进程数 0 zombie 僵尸进程数 Cpu(s): 0.3% us 用户空间占用CPU百分比 1.0% sy 内核空间占用CPU百分比 0.0% ni 用户进程空间内改变过优先级的进程占用CPU百分比 98.7% id 空闲CPU百分比 0.0% wa 等待输入输出的CPU时间百分比 0.0% hi CPU服务于硬中断所耗费的时间总额 0.0% si、0.0%st CPU服务于软中断所耗费的时间总额、Steal Time 内存信息 参数 含义 Mem: 191272k total 物理内存总量 173656k used 使用的物理内存总量 17616k free 空闲内存总量 22052k buffers 用作内核缓存的内存量 Swap: 192772k total 交换区总量 0k used 使用的交换区总量 192772k free 空闲交换区总量 123988k cached 缓冲的交换区总量，内存中的内容被换出到交换区,而后又被换入到内存,但使用过的交换区尚未被覆盖, 该数值即为这些内容已存在于内存中的交换区的大小，相应的内存再次被换出时可不必再对交换区写入 进程统计信息 参数 含义 PID 进程id PPID 父进程id RUSER Real user name UID 进程所有者的用户id USER 进程所有者的用户名 GROUP 进程所有者的组名 TTY 启动进程的终端名.不是从终端启动的进程则显示为 ? PR 优先级 NI nice值.负值表示高优先级，正值表示低优先级 P 最后使用的CPU,仅在多CPU环境下有意义 %CPU 上次更新到现在的CPU时间占用百分比 TIME 进程使用的CPU时间总计,单位秒 TIME+ 进程使用的CPU时间总计,单位1/100秒 %MEM 进程使用的物理内存百分比 VIRT 进程使用的虚拟内存总量,单位kb,VIRT=SWAP+RES SWAP 进程使用的虚拟内存中,被换出的大小,单位kb. RES 进程使用的、未被换出的物理内存大小,单位kb,RES=CODE+DATA CODE 可执行代码占用的物理内存大小,单位kb DATA 可执行代码以外的部分(数据段+栈)占用的物理内存大小,单位kb SHR 共享内存大小,单位kb nFLT 页面错误次数 nDRT 最后一次写入到现在,被修改过的页面数. S 进程状态: D=不可中断的睡眠状态 R=运行 S=睡眠 T=跟踪/停止 Z=僵尸进程 COMMAND 命令名/命令行 WCHAN 若该进程在睡眠,则显示睡眠中的系统函数名 Flags 任务标志,参考 sched.h ","permalink":"http://bug1024.com/2017/04/29/top/","summary":"\u003ch2 id=\"进程和cpu信息\"\u003e进程和CPU信息\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e参数\u003c/th\u003e\n          \u003cth\u003e含义\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eload average: 0.06, 0.60, 0.48\u003c/td\u003e\n          \u003ctd\u003e系统负载，即任务队列的平均长度，1分钟、5分钟、15分钟前到现在的平均值, 按照经验小于0.7 x cpu核数则正常\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eTasks: 29 total\u003c/td\u003e\n          \u003ctd\u003e进程总数\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e1 running\u003c/td\u003e\n          \u003ctd\u003e正在运行的进程数\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e28 sleeping\u003c/td\u003e\n          \u003ctd\u003e睡眠的进程数\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e0 stopped\u003c/td\u003e\n          \u003ctd\u003e停止的进程数\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e0 zombie\u003c/td\u003e\n          \u003ctd\u003e僵尸进程数\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eCpu(s): 0.3% us\u003c/td\u003e\n          \u003ctd\u003e用户空间占用CPU百分比\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e1.0% sy\u003c/td\u003e\n          \u003ctd\u003e内核空间占用CPU百分比\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e0.0% ni\u003c/td\u003e\n          \u003ctd\u003e用户进程空间内改变过优先级的进程占用CPU百分比\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e98.7% id\u003c/td\u003e\n          \u003ctd\u003e空闲CPU百分比\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e0.0% wa\u003c/td\u003e\n          \u003ctd\u003e等待输入输出的CPU时间百分比\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e0.0% hi\u003c/td\u003e\n          \u003ctd\u003eCPU服务于硬中断所耗费的时间总额\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e0.0% si、0.0%st\u003c/td\u003e\n          \u003ctd\u003eCPU服务于软中断所耗费的时间总额、Steal Time\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"内存信息\"\u003e内存信息\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e参数\u003c/th\u003e\n          \u003cth\u003e含义\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eMem: 191272k total\u003c/td\u003e\n          \u003ctd\u003e物理内存总量\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e173656k used\u003c/td\u003e\n          \u003ctd\u003e使用的物理内存总量\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e17616k free\u003c/td\u003e\n          \u003ctd\u003e空闲内存总量\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e22052k buffers\u003c/td\u003e\n          \u003ctd\u003e用作内核缓存的内存量\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eSwap: 192772k total\u003c/td\u003e\n          \u003ctd\u003e交换区总量\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e0k used\u003c/td\u003e\n          \u003ctd\u003e使用的交换区总量\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e192772k free\u003c/td\u003e\n          \u003ctd\u003e空闲交换区总量\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e123988k cached\u003c/td\u003e\n          \u003ctd\u003e缓冲的交换区总量，内存中的内容被换出到交换区,而后又被换入到内存,但使用过的交换区尚未被覆盖, 该数值即为这些内容已存在于内存中的交换区的大小，相应的内存再次被换出时可不必再对交换区写入\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"进程统计信息\"\u003e进程统计信息\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e参数\u003c/th\u003e\n          \u003cth\u003e含义\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003ePID\u003c/td\u003e\n          \u003ctd\u003e进程id\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003ePPID\u003c/td\u003e\n          \u003ctd\u003e父进程id\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eRUSER\u003c/td\u003e\n          \u003ctd\u003eReal user name\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eUID\u003c/td\u003e\n          \u003ctd\u003e进程所有者的用户id\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eUSER\u003c/td\u003e\n          \u003ctd\u003e进程所有者的用户名\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eGROUP\u003c/td\u003e\n          \u003ctd\u003e进程所有者的组名\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eTTY\u003c/td\u003e\n          \u003ctd\u003e启动进程的终端名.不是从终端启动的进程则显示为 ?\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003ePR\u003c/td\u003e\n          \u003ctd\u003e优先级\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eNI\u003c/td\u003e\n          \u003ctd\u003enice值.负值表示高优先级，正值表示低优先级\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eP\u003c/td\u003e\n          \u003ctd\u003e最后使用的CPU,仅在多CPU环境下有意义\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e%CPU\u003c/td\u003e\n          \u003ctd\u003e上次更新到现在的CPU时间占用百分比\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eTIME\u003c/td\u003e\n          \u003ctd\u003e进程使用的CPU时间总计,单位秒\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eTIME+\u003c/td\u003e\n          \u003ctd\u003e进程使用的CPU时间总计,单位1/100秒\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e%MEM\u003c/td\u003e\n          \u003ctd\u003e进程使用的物理内存百分比\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eVIRT\u003c/td\u003e\n          \u003ctd\u003e进程使用的虚拟内存总量,单位kb,VIRT=SWAP+RES\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eSWAP\u003c/td\u003e\n          \u003ctd\u003e进程使用的虚拟内存中,被换出的大小,单位kb.\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eRES\u003c/td\u003e\n          \u003ctd\u003e进程使用的、未被换出的物理内存大小,单位kb,RES=CODE+DATA\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eCODE\u003c/td\u003e\n          \u003ctd\u003e可执行代码占用的物理内存大小,单位kb\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eDATA\u003c/td\u003e\n          \u003ctd\u003e可执行代码以外的部分(数据段+栈)占用的物理内存大小,单位kb\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eSHR\u003c/td\u003e\n          \u003ctd\u003e共享内存大小,单位kb\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003enFLT\u003c/td\u003e\n          \u003ctd\u003e页面错误次数\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003enDRT\u003c/td\u003e\n          \u003ctd\u003e最后一次写入到现在,被修改过的页面数.\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eS\u003c/td\u003e\n          \u003ctd\u003e进程状态: D=不可中断的睡眠状态 R=运行 S=睡眠 T=跟踪/停止 Z=僵尸进程\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eCOMMAND\u003c/td\u003e\n          \u003ctd\u003e命令名/命令行\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eWCHAN\u003c/td\u003e\n          \u003ctd\u003e若该进程在睡眠,则显示睡眠中的系统函数名\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eFlags\u003c/td\u003e\n          \u003ctd\u003e任务标志,参考 sched.h\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e","title":"性能监控之top"},{"content":"内置变量 $0 脚本名称 $n 传给脚本/函数的第n个参数 $$ 脚本的PID $! 上一个被执行的命令的PID(后台运行的进程) $? 上一个命令的退出状态(管道命令使用${PIPESTATUS}) $# 传递给脚本/函数的参数个数 $@ 传递给脚本/函数的所有参数(识别每个参数) $* 传递给脚本/函数的所有参数(把所有参数当成一个字符串) 调试 # 抓包 tcpdump -i eth2 -w capture.cap tcp port 9501 and dst host 172.16.1.31 # 跟踪系统调用 strace -o strace.log -tt -f -e {call} -p {pid} # 开启coredump Mac下的cordump文件不在当前运行目录下，而是在系统指定目录，通常是/cores ulimit -c unlimited # 查看MTU cat /sys/class/net/eth0/mtu # -s 包的大小，Specifies the number of data bytes to be sent. ping -c 3 -s 2900 -M do 172.168.0.2 用户 # 新增用户 useradd user1 # 设置密码 passwd user1 # 新建用户组 groupadd group1 # 用户组新增用户 gpasswd -a user1 group1 # 修改目录所有者 chown -R user1:group1 dir1 文本处理 # 遍历查找当前目录下同时包含xxx和yyy的行 grep -r \u0026#34;xxx\u0026#34; . | grep \u0026#34;yyy\u0026#34; # 遍历查找当前目录下包含xxx或者yyy的行 grep -r . -e \u0026#34;xxx\u0026#34; -e \u0026#34;yyy\u0026#34; # 遍历查找当前目录下包含xxx但不包含yyy的行 grep -r \u0026#34;xxx\u0026#34; . | grep -v \u0026#34;yyy\u0026#34; # 查处字符串出现次数 grep -o \u0026#34;xxx\u0026#34;|wc -l # 显示file文件中匹配foo字串那行以及上下5行 grep -C 5 foo file # 显示foo及前5行 grep -B 5 foo file # 显示foo及后5行 grep -A 5 foo file # 匹配行带文件名，以下命令会返回类似结果结果：file1:hello file2:hhhhello grep -H hello file* # 查找7天内没访问过的文件 find path -atime +7 # 查找7天内访问过的文件 find path -atime -7 # 表示在当前目录及其子目录下查找普通文件中包含abc字符串的文件行，经常用于搜索代码 find . -type f|xargs grep \u0026#39;abc\u0026#39; # 清理文件 find 路径 -name \u0026#34;*.log.*\u0026#34; -mtime +1 -delete # 从备份中的日志查询数据 bzcat xx.log.bz2 | grep \u0026#34;xxxx\u0026#34; bzgrep \u0026#34;xxxx\u0026#34; xx.log.bz2 # 消除重复行 sort unsort.txt | uniq # 统计各行在文件中出现的次数 sort unsort.txt | uniq -c # 找出重复行 sort unsort.txt | uniq -d # 统计行数，单词数，字符数 wc -[l][w][c] file # 清空文件，文件空间会立刻释放 echo \u0026#34;\u0026#34; \u0026gt; a.log # awk 转义需要两个反斜杆 awk -F\u0026#39;url\\\\[\u0026#39; \u0026#39;{print $2}\u0026#39; 磁盘管理 # 查看当前目录所占空间大小 du -sh # 查看当前目录下所有子文件夹排序后的大小: du -sh `ls` | sort # 查看当前正在写磁盘的进程id信息 iotop -o 进程管理 # 查看8080端口 lsof -i:8080 # 查看占用8080端口的进程 netstat -pan|grep 8080 # 查看用户username的进程所打开的文件 lsof -u username # 查询nginx进程当前打开的文件 lsof -c nginx # 查询指定的进程ID(23295)打开的文件： lsof -p 23295 # 查看打开文件数最多的10个进程 lsof +c 10 | awk \u0026#39;{print $1}\u0026#39; | sort | uniq -c | sort -rn | head 性能监控 # 查看页面交换发生状况 页面发生交换时，服务器的吞吐量会大幅下降，通常是内存不足导致，每秒采样1次，共采样3次 # sar不可用时，可以使用以下工具替代：linux下有 vmstat、Unix系统有prstat sar -W 1 3 # Linux上的ss命令可以用于替换netstat，ss直接读取解析/proc/net下的统计信息，相比netstat遍历/proc下的每个PID目录，速度快很多 ss -t -a 显示所有的TCP Sockets ss -u -a 显示所有的UDP Sockets ss -x src /tmp/a.sock 显示连接到/tmp/a.sock的进程 ss -o state [state TCP-STATE] 如ss -o state established显示所有建立的连接 系统信息 # 总核数 = 物理CPU个数 X 每颗物理CPU的核数 # 总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU的核数 X 超线程数 # 查看物理CPU个数 cat /proc/cpuinfo| grep \u0026#34;physical id\u0026#34;| sort| uniq| wc -l # 查看每个物理CPU中core的个数(即核数) cat /proc/cpuinfo| grep \u0026#34;cpu cores\u0026#34;| uniq # 查看逻辑CPU的个数 cat /proc/cpuinfo| grep \u0026#34;processor\u0026#34;| wc -l 定时任务 格式：分钟[0-59] 小时[1-23] 日期[1-31] 月份[1-12] 星期[0-6]\n# 实例1：每1分钟执行一次myCommand * * * * * myCommand # 实例2：每小时的第3和第15分钟执行 3,15 * * * * myCommand # 实例3：在上午8点到11点的第3和第15分钟执行 3,15 8-11 * * * myCommand # 实例4：每隔两天的上午8点到11点的第3和第15分钟执行 3,15 8-11 */2 * * myCommand # 实例5：每周一上午8点到11点的第3和第15分钟执行 3,15 8-11 * * 1 myCommand # 实例6：每晚的21:30重启smb 30 21 * * * /etc/init.d/smb restart # 实例7：每月1、10、22日的4 : 45重启smb 45 4 1,10,22 * * /etc/init.d/smb restart # 实例8：每周六、周日的1 : 10重启smb 10 1 * * 6,0 /etc/init.d/smb restart # 实例9：每天18 : 00至23 : 00之间每隔30分钟重启smb 0,30 18-23 * * * /etc/init.d/smb restart # 实例10：每星期六的晚上11 : 00 pm重启smb 0 23 * * 6 /etc/init.d/smb restart # 实例11：每一小时重启smb * */1 * * * /etc/init.d/smb restart # 实例12：晚上11点到早上7点之间，每隔一小时重启smb 0 23-7 * * * /etc/init.d/smb restart 运行 # 标准输出和错误都被重定向到info.log中, 2\u0026gt;\u0026amp;1表示标准错误拷贝了标准输出的行为 your_command \u0026gt;info.log 2\u0026gt;\u0026amp;1 # 挂起后台运行，并忽略所有输出 nohup your_command \u0026gt;/dev/null 2\u0026gt;\u0026amp;1 \u0026amp; Git # 不clone历史commit，可加快clone速度 git clone --depth=1 git_repo_url # 切换到远程分支 git checkout -b branch_name origin/branch_name # 撤销add过但未commit的文件 git reset file # checkout远程某个文件 git checkout origin/branch_name -- file1 file2 # 追加最近一次的commit git commit --amend # push到远程分支, 通常local和remote的分支名是一样的 git push origin local_branch_name:remote_branch_name # 删除远程分支 git push origin :remote_branch_name # 强推 git push -f # 更新远程分支 git remote update -p # checkout指定文件 git checkout origin/remote_branch_name -- file_path 压测 ab -n100 -c5 http://www.baidu.com/ # Request per sencond 每秒处理的请求数量 # Time per request 第一个值为每次并发消耗的平均时间，第二个为每次请求所消耗的平均时间 # Complete requests 完成的请求数量 # Failed requests 失败的请求数量 #wrk 使用的是 HTTP/1.1，缺省开启的是长连接，而 ab 使用的是 HTTP/1.0，缺省开启的是短链接 #采用多线程 + 异步事件驱动的框架，其中事件机制使用了redis的ae事件框架，协议解析使用了nginx的相关代码 wrk -c 100 -d 10 http://www.baidu.com/ 其他 # TCP ESTABLISHED数量 netstat -n|grep ^tcp|awk \u0026#39;{print $NF}\u0026#39;|sort -nr|uniq -c #之所以能用到xargs这个命令，关键是由于很多命令不支持|管道来传递参数，而日常工作中有有这个必要，所以就有了xargs命令，例如： find /sbin -perm +700 |ls -l 这个命令是错误的 find /sbin -perm +700 |xargs ls -l 这样才是正确的 #Mac home目录下创建目录 用命令 sudo vim /etc/auto_master 打开文件，把里面的home开始的行删掉或用#注释掉 然后用命令 sudo automount 使设置立刻生效 # 判断端口是否通 nc -z 10.1.1.1 8081 #查看网卡大小 ethtool 网卡名称 参考 awk ","permalink":"http://bug1024.com/2017/04/12/shell-sheet/","summary":"\u003ch2 id=\"内置变量\"\u003e内置变量\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    $0 脚本名称\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    $n 传给脚本/函数的第n个参数\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    $$ 脚本的PID\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    $! 上一个被执行的命令的PID\u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003e后台运行的进程\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    $? 上一个命令的退出状态\u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003e管道命令使用\u003cspan style=\"color:#e6db74\"\u003e${\u003c/span\u003ePIPESTATUS\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    $# 传递给脚本/函数的参数个数\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    $@ 传递给脚本/函数的所有参数\u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003e识别每个参数\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    $* 传递给脚本/函数的所有参数\u003cspan style=\"color:#f92672\"\u003e(\u003c/span\u003e把所有参数当成一个字符串\u003cspan style=\"color:#f92672\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"调试\"\u003e调试\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 抓包\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    tcpdump -i eth2 -w capture.cap tcp port \u003cspan style=\"color:#ae81ff\"\u003e9501\u003c/span\u003e and dst host 172.16.1.31\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 跟踪系统调用\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    strace -o strace.log -tt -f -e \u003cspan style=\"color:#f92672\"\u003e{\u003c/span\u003ecall\u003cspan style=\"color:#f92672\"\u003e}\u003c/span\u003e -p \u003cspan style=\"color:#f92672\"\u003e{\u003c/span\u003epid\u003cspan style=\"color:#f92672\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 开启coredump  Mac下的cordump文件不在当前运行目录下，而是在系统指定目录，通常是/cores\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ulimit -c unlimited\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 查看MTU\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    cat /sys/class/net/eth0/mtu\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# -s 包的大小，Specifies the number of data bytes to be sent.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ping -c \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e -s \u003cspan style=\"color:#ae81ff\"\u003e2900\u003c/span\u003e -M \u003cspan style=\"color:#66d9ef\"\u003edo\u003c/span\u003e 172.168.0.2\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"用户\"\u003e用户\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 新增用户\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    useradd user1\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 设置密码\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    passwd user1\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 新建用户组\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    groupadd group1\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 用户组新增用户\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    gpasswd -a user1 group1\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 修改目录所有者\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    chown -R user1:group1 dir1\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"文本处理\"\u003e文本处理\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 遍历查找当前目录下同时包含xxx和yyy的行\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    grep -r \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;xxx\u0026#34;\u003c/span\u003e . | grep \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;yyy\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 遍历查找当前目录下包含xxx或者yyy的行\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    grep -r . -e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;xxx\u0026#34;\u003c/span\u003e -e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;yyy\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 遍历查找当前目录下包含xxx但不包含yyy的行\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    grep -r \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;xxx\u0026#34;\u003c/span\u003e . | grep -v \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;yyy\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 查处字符串出现次数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    grep -o \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;xxx\u0026#34;\u003c/span\u003e|wc -l\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 显示file文件中匹配foo字串那行以及上下5行\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    grep -C \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e foo file\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 显示foo及前5行\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    grep -B \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e foo file\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 显示foo及后5行\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    grep -A \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e foo file\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 匹配行带文件名，以下命令会返回类似结果结果：file1:hello file2:hhhhello\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    grep -H hello file*\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 查找7天内没访问过的文件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    find path -atime +7\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 查找7天内访问过的文件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    find path -atime -7\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 表示在当前目录及其子目录下查找普通文件中包含abc字符串的文件行，经常用于搜索代码\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    find . -type f|xargs grep \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;abc\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 清理文件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    find 路径 -name \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;*.log.*\u0026#34;\u003c/span\u003e -mtime +1 -delete\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 从备份中的日志查询数据\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    bzcat xx.log.bz2 | grep \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;xxxx\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    bzgrep \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;xxxx\u0026#34;\u003c/span\u003e xx.log.bz2\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 消除重复行\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    sort unsort.txt | uniq\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 统计各行在文件中出现的次数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    sort unsort.txt | uniq -c\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 找出重复行\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    sort unsort.txt | uniq -d\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 统计行数，单词数，字符数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    wc -\u003cspan style=\"color:#f92672\"\u003e[\u003c/span\u003el\u003cspan style=\"color:#f92672\"\u003e][\u003c/span\u003ew\u003cspan style=\"color:#f92672\"\u003e][\u003c/span\u003ec\u003cspan style=\"color:#f92672\"\u003e]\u003c/span\u003e file\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 清空文件，文件空间会立刻释放\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    echo \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e \u0026gt; a.log\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# awk 转义需要两个反斜杆\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    awk -F\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;url\\\\[\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;{print $2}\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"磁盘管理\"\u003e磁盘管理\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   \u003cspan style=\"color:#75715e\"\u003e# 查看当前目录所占空间大小\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   du -sh\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   \u003cspan style=\"color:#75715e\"\u003e# 查看当前目录下所有子文件夹排序后的大小:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   du -sh \u003cspan style=\"color:#e6db74\"\u003e`\u003c/span\u003els\u003cspan style=\"color:#e6db74\"\u003e`\u003c/span\u003e | sort\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   \u003cspan style=\"color:#75715e\"\u003e# 查看当前正在写磁盘的进程id信息\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e   iotop -o\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"进程管理\"\u003e进程管理\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 查看8080端口\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    lsof -i:8080\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 查看占用8080端口的进程\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    netstat -pan|grep \u003cspan style=\"color:#ae81ff\"\u003e8080\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 查看用户username的进程所打开的文件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    lsof -u username\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 查询nginx进程当前打开的文件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    lsof -c nginx\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 查询指定的进程ID(23295)打开的文件：\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    lsof -p \u003cspan style=\"color:#ae81ff\"\u003e23295\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 查看打开文件数最多的10个进程\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    lsof +c \u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e | awk \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;{print $1}\u0026#39;\u003c/span\u003e | sort | uniq -c | sort -rn | head\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"性能监控\"\u003e性能监控\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 查看页面交换发生状况 页面发生交换时，服务器的吞吐量会大幅下降，通常是内存不足导致，每秒采样1次，共采样3次\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# sar不可用时，可以使用以下工具替代：linux下有 vmstat、Unix系统有prstat\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    sar -W \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# Linux上的ss命令可以用于替换netstat，ss直接读取解析/proc/net下的统计信息，相比netstat遍历/proc下的每个PID目录，速度快很多\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ss -t -a 显示所有的TCP Sockets\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ss -u -a 显示所有的UDP Sockets\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ss -x src /tmp/a.sock 显示连接到/tmp/a.sock的进程\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ss -o state \u003cspan style=\"color:#f92672\"\u003e[\u003c/span\u003estate TCP-STATE\u003cspan style=\"color:#f92672\"\u003e]\u003c/span\u003e 如ss -o state established显示所有建立的连接\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"系统信息\"\u003e系统信息\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 总核数 = 物理CPU个数 X 每颗物理CPU的核数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU的核数 X 超线程数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 查看物理CPU个数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    cat /proc/cpuinfo| grep \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;physical id\u0026#34;\u003c/span\u003e| sort| uniq| wc -l\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 查看每个物理CPU中core的个数(即核数)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    cat /proc/cpuinfo| grep \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;cpu cores\u0026#34;\u003c/span\u003e| uniq\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# 查看逻辑CPU的个数\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    cat /proc/cpuinfo| grep \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;processor\u0026#34;\u003c/span\u003e| wc -l\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"定时任务\"\u003e定时任务\u003c/h2\u003e\n\u003cp\u003e格式：分钟[0-59] 小时[1-23] 日期[1-31] 月份[1-12] 星期[0-6]\u003c/p\u003e","title":"常用shell"},{"content":"简介 由国人开发的, 用C语言实现的，开源的分布式文件系统，对文件进行管理，功能包括：文件存储、文件同步、文件访问（文件上传、文件下载）等，解决了大容量存储和负载均衡的问题, 特别适合以文件为载体的在线服务\n设计 FastDFS中只有两个角色：Tracker和Storage。 Tracker作为中心结点，其主要作用是维护Storage信息，负载均衡和调度等。 Tracker会在内存和临时文件中记录Storage分组和Storage的状态等信息，不记录文件索引信息，占用的内存量很少。 而重要的文件索引信息将附属在Storage生成的文件ID中，这无疑去掉文件索引这一步，也提高了文件检索的性能。 存储 FastDFS采用了分组存储方式来保存文件的多个备份。 存储集群由一个或多个逻辑组构成，集群存储总容量为集群中所有组的存储容量(一个存储组的容量由该组中容量最小的Storage决定)之和。 一个组由一台或多台Storage组成，同组内的多台Storage之间是互备关系，同组内的存储服务器上的文件是完全一致的。 文件上传、下载、删除等操作可以在组内任意一台Storage上进行。 架构 Client和Storage主动连接Tracker。Storage主动向Tracker报告其状态信息，包括磁盘剩余空间、文件同步状况、文件上传下载次数等统计信息。Storage会启动一个单独的线程来完成对一台Tracker的连接和定时报告。一个组包含的Storage不是通过配置文件设定的，而是通过Tracker获取到的。 文件操作。Storage采用binlog文件记录文件上传、删除等更新操作。binlog中只记录时间戳，操作类型，文件路径。 文件同步。不同组的Storage相互独立，同组内的Storage之间会相互连接进行文件同步，采用push的方式。 安装 安装FastDFS依赖的公共库\ngit clone git@github.com:happyfish100/libfastcommon.git cd libfastcommon ./make.sh ./make.sh install 安装FastDFS\ngit clone git@github.com:happyfish100/fastdfs.git cd fastdfs ./make.sh ./make.sh install 常用命令\n# 启动/关闭/重启 Tracker fdfs_trackerd tracker.conf [start|stop|restart] # 启动/关闭/重启 Storage fdfs_storaged storage.conf [start|stop|restart] # 监控 fdfs_monitor client.conf # 上传测试 fdfs_test client.conf upload xxx.jpeg # 下载测试 fdfs_test client.conf download group1 M00/yyy.jpeg ","permalink":"http://bug1024.com/2017/04/09/fastdfs/","summary":"\u003ch2 id=\"简介\"\u003e简介\u003c/h2\u003e\n\u003cp\u003e由国人开发的, 用C语言实现的，\u003ca href=\"https://github.com/happyfish100/fastdfs\"\u003e开源\u003c/a\u003e的分布式文件系统，对文件进行管理，功能包括：文件存储、文件同步、文件访问（文件上传、文件下载）等，解决了大容量存储和负载均衡的问题, 特别适合以文件为载体的在线服务\u003c/p\u003e\n\u003ch2 id=\"设计\"\u003e设计\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eFastDFS中只有两个角色：Tracker和Storage。\u003c/li\u003e\n\u003cli\u003eTracker作为中心结点，其主要作用是维护Storage信息，负载均衡和调度等。\u003c/li\u003e\n\u003cli\u003eTracker会在内存和临时文件中记录Storage分组和Storage的状态等信息，不记录文件索引信息，占用的内存量很少。\u003c/li\u003e\n\u003cli\u003e而重要的文件索引信息将附属在Storage生成的文件ID中，这无疑去掉文件索引这一步，也提高了文件检索的性能。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"存储\"\u003e存储\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eFastDFS采用了分组存储方式来保存文件的多个备份。\u003c/li\u003e\n\u003cli\u003e存储集群由一个或多个逻辑组构成，集群存储总容量为集群中所有组的存储容量(一个存储组的容量由该组中容量最小的Storage决定)之和。\u003c/li\u003e\n\u003cli\u003e一个组由一台或多台Storage组成，同组内的多台Storage之间是互备关系，同组内的存储服务器上的文件是完全一致的。\u003c/li\u003e\n\u003cli\u003e文件上传、下载、删除等操作可以在组内任意一台Storage上进行。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"架构\"\u003e架构\u003c/h2\u003e\n\u003cp\u003e\u003cimg alt=\"架构\" loading=\"lazy\" src=\"http://bug1024.com/img/fastdfs-arch.png\"\u003e\u003c/p\u003e","title":"FastDFS"},{"content":"Cgroup 计算资源 内存资源 IO资源 网络资源 进程 具有独立功能的程序，关于某个数据集合的一次运行过程 进程 = 程序 + 数据+ PCB 3个基本状态：ready(就绪等cpu)/running(运行)/waiting(等待事件的发生) PCB：进程存在的唯一标志 调度：状态转换时发生调度，IO密集型/CPU密集型，进程树，overhead(系统消耗) IPC：管道/共享内存(生产者/消费者)/消息传递(send/recv)/信号量/套接字，busy waiting CPU调度 FCFS(First-Come First-Served) SJF(Shortest-Job-First)，preemptive(抢占式) Priority Scheduling Round Robin Multilevel Queue Scheduling Multilevel Feedback Queues 进程同步 entry section, critical section, exit section, remainder section 临界区使用原则：互斥(忙则等待)，空闲让进，有限等待，让权等待 semaphore: wait()用于申请资源, signal()用于释放资源 生产者消费者问题，读者写者问题，哲学家进餐问题 管程 进程间通信 管道 文件和文件锁 共享内存 信号量 消息队列 死锁 两个或两个以上的进程由于竞争资源导致系统无法推进 产生必要条件：互斥，占有必等待，非抢占，循环等待 银行家算法(allocation,max,available) 内存管理 swapping, paging, segmentation 单CPU需要两个寄存器（基础+界限） 逻辑地址 物理地址 重定位寄存器 连续分配：固定分区，可变分区 离散分配：分页(页=\u0026gt;页框)，分段，段页 虚拟存储 demand paging page replacement allocation of frames thrashing(抖动) 监控指标 load 特定事时间间隔内运行队列中的平均线程数 user time CPU执行用户进程所占用的时间 system time CPU在内核所花费的时间 nice time 系统在调整进程优先级的时候所花费的时间 idle time 系统空闲等待进程运行的时间 waiting time CPU在等待IO操作所花费的时间 hard irq time 系统处理硬件中断所占用的时间 soft irq time 系统处理软件中断所占用的时间 steal time 被强制等待虚拟机CPU的时间，占比较高表示当前虚拟机与该宿主其他虚拟机争用CPU频繁 磁盘剩余空间 使用df和du命令查看 网络traffic 使用sar命令查看 sar -n DEV 1 1 磁盘IO 使用iostat命令查看 iostat -d -k 内存使用 使用free命令查看 swap IO 使用vmstat命令查看 同步异步阻塞非阻塞 同步与异步关注的是消息通信机制 (synchronous communication/ asynchronous communication) 阻塞与非阻塞关注的是程序在等待调用结果（消息，返回值）时的状态，主要是从CPU消耗上来说的 同步阻塞 最常用，IO性能较差，CPU大部分处于空闲 同步非阻塞 在网络IO是长链接且传输数据较小时可以有效提升性能 异步阻塞 在分布式数据库中常用，写一份记录通常会有一个是同步阻塞，而其他几份会采用异步阻塞方式写入其他机器 异步非阻塞 比较复杂，通常在集群间同步消息使用，例如cassandra，适合同时要传多份相同数据到不同机器，数据量不大但是异常频繁 僵尸进程与孤儿进程 在unix/linux中，正常情况下，子进程是通过父进程创建的，子进程再创建新的进程。子进程的结束和父进程的运行是一个异步过程，即父进程永远无法预测子进程到底什么时候结束。 当一个进程完成它的工作终止之后，它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态。\n僵尸进程：一个进程使用fork创建子进程，如果子进程退出，而父进程并没有调用wait或waitpid获取子进程的状态信息，那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。 孤儿进程：一个父进程退出，而它的一个或多个子进程还在运行，那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养，并由init进程对它们完成状态收集工作。 不管进程如何终止，最后都会执行内核中的同一段代码，它为相应进程关闭所有描述符，释放使用的存储器。一个由init进程收养的进程终止时是不会变成僵死进程的，因为init被编写成无论何时只要有一个子进程终止就会调用wait函数取得其终止状态。 ","permalink":"http://bug1024.com/2017/03/28/linux/","summary":"\u003ch2 id=\"cgroup\"\u003eCgroup\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e计算资源\u003c/li\u003e\n\u003cli\u003e内存资源\u003c/li\u003e\n\u003cli\u003eIO资源\u003c/li\u003e\n\u003cli\u003e网络资源\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"进程\"\u003e进程\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e具有独立功能的程序，关于某个数据集合的一次运行过程\u003c/li\u003e\n\u003cli\u003e进程 = 程序 + 数据+ PCB\u003c/li\u003e\n\u003cli\u003e3个基本状态：ready(就绪等cpu)/running(运行)/waiting(等待事件的发生)\u003c/li\u003e\n\u003cli\u003ePCB：进程存在的唯一标志\u003c/li\u003e\n\u003cli\u003e调度：状态转换时发生调度，IO密集型/CPU密集型，进程树，overhead(系统消耗)\u003c/li\u003e\n\u003cli\u003eIPC：管道/共享内存(生产者/消费者)/消息传递(send/recv)/信号量/套接字，busy waiting\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"cpu调度\"\u003eCPU调度\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eFCFS(First-Come First-Served)\u003c/li\u003e\n\u003cli\u003eSJF(Shortest-Job-First)，preemptive(抢占式)\u003c/li\u003e\n\u003cli\u003ePriority Scheduling\u003c/li\u003e\n\u003cli\u003eRound Robin\u003c/li\u003e\n\u003cli\u003eMultilevel  Queue Scheduling\u003c/li\u003e\n\u003cli\u003eMultilevel Feedback Queues\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"进程同步\"\u003e进程同步\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eentry section, critical section, exit section, remainder section\u003c/li\u003e\n\u003cli\u003e临界区使用原则：互斥(忙则等待)，空闲让进，有限等待，让权等待\u003c/li\u003e\n\u003cli\u003esemaphore: wait()用于申请资源, signal()用于释放资源\u003c/li\u003e\n\u003cli\u003e生产者消费者问题，读者写者问题，哲学家进餐问题\u003c/li\u003e\n\u003cli\u003e管程\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"进程间通信\"\u003e进程间通信\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e管道\u003c/li\u003e\n\u003cli\u003e文件和文件锁\u003c/li\u003e\n\u003cli\u003e共享内存\u003c/li\u003e\n\u003cli\u003e信号量\u003c/li\u003e\n\u003cli\u003e消息队列\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"死锁\"\u003e死锁\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e两个或两个以上的进程由于竞争资源导致系统无法推进\u003c/li\u003e\n\u003cli\u003e产生必要条件：互斥，占有必等待，非抢占，循环等待\u003c/li\u003e\n\u003cli\u003e银行家算法(allocation,max,available)\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"内存管理\"\u003e内存管理\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eswapping, paging, segmentation\u003c/li\u003e\n\u003cli\u003e单CPU需要两个寄存器（基础+界限）\u003c/li\u003e\n\u003cli\u003e逻辑地址 物理地址 重定位寄存器\u003c/li\u003e\n\u003cli\u003e连续分配：固定分区，可变分区\u003c/li\u003e\n\u003cli\u003e离散分配：分页(页=\u0026gt;页框)，分段，段页\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"虚拟存储\"\u003e虚拟存储\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003edemand paging\u003c/li\u003e\n\u003cli\u003epage replacement\u003c/li\u003e\n\u003cli\u003eallocation of frames\u003c/li\u003e\n\u003cli\u003ethrashing(抖动)\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"监控指标\"\u003e监控指标\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eload 特定事时间间隔内运行队列中的平均线程数\u003c/li\u003e\n\u003cli\u003euser time CPU执行用户进程所占用的时间\u003c/li\u003e\n\u003cli\u003esystem time CPU在内核所花费的时间\u003c/li\u003e\n\u003cli\u003enice time 系统在调整进程优先级的时候所花费的时间\u003c/li\u003e\n\u003cli\u003eidle time 系统空闲等待进程运行的时间\u003c/li\u003e\n\u003cli\u003ewaiting time CPU在等待IO操作所花费的时间\u003c/li\u003e\n\u003cli\u003ehard irq time 系统处理硬件中断所占用的时间\u003c/li\u003e\n\u003cli\u003esoft irq time 系统处理软件中断所占用的时间\u003c/li\u003e\n\u003cli\u003esteal time 被强制等待虚拟机CPU的时间，占比较高表示当前虚拟机与该宿主其他虚拟机争用CPU频繁\u003c/li\u003e\n\u003cli\u003e磁盘剩余空间 使用df和du命令查看\u003c/li\u003e\n\u003cli\u003e网络traffic 使用sar命令查看 sar -n DEV 1 1\u003c/li\u003e\n\u003cli\u003e磁盘IO 使用iostat命令查看 iostat -d -k\u003c/li\u003e\n\u003cli\u003e内存使用 使用free命令查看\u003c/li\u003e\n\u003cli\u003eswap IO 使用vmstat命令查看\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"同步异步阻塞非阻塞\"\u003e同步异步阻塞非阻塞\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e同步与异步关注的是消息通信机制 (synchronous communication/ asynchronous communication)\u003c/li\u003e\n\u003cli\u003e阻塞与非阻塞关注的是程序在等待调用结果（消息，返回值）时的状态，主要是从CPU消耗上来说的\u003c/li\u003e\n\u003cli\u003e同步阻塞 最常用，IO性能较差，CPU大部分处于空闲\u003c/li\u003e\n\u003cli\u003e同步非阻塞 在网络IO是长链接且传输数据较小时可以有效提升性能\u003c/li\u003e\n\u003cli\u003e异步阻塞 在分布式数据库中常用，写一份记录通常会有一个是同步阻塞，而其他几份会采用异步阻塞方式写入其他机器\u003c/li\u003e\n\u003cli\u003e异步非阻塞 比较复杂，通常在集群间同步消息使用，例如cassandra，适合同时要传多份相同数据到不同机器，数据量不大但是异常频繁\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"僵尸进程与孤儿进程\"\u003e僵尸进程与孤儿进程\u003c/h2\u003e\n\u003cp\u003e在unix/linux中，正常情况下，子进程是通过父进程创建的，子进程再创建新的进程。子进程的结束和父进程的运行是一个异步过程，即父进程永远无法预测子进程到底什么时候结束。 当一个进程完成它的工作终止之后，它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态。\u003c/p\u003e","title":"Linux"},{"content":"多个字段实现状态 以商品为例，通常一个商品拥有多种状态标志，是否是打折商品，是否是推荐商品，是否是秒杀商品，对应表结构：\nid is_on_sale is_recommend is_seckill 1 1 0 1 2 0 0 1 3 1 1 1 这种方案不利于扩展，后期有新的标志需要再添加新的字段\n利用位运算实现多种状态 Linux系统中的权限，通常我们所知权限分为r 读, w 写, x 执行，它们的权值分别为4，2，1，所以如果用户要想拥有这三个权限就必须chomd 7, 即7=4+2+1，表明这个用户具有rwx权限，如果只想这个用户具有r,x权限 那么就chomd 5即可。 商品的状态也可以参考类似的设计，我们可以分别设置is_on_sale，is_recommend，is_seckill的权值为4，2，1\nid is_on_sale is_recommend is_seckill flag 1 1 0 1 5 2 0 0 1 1 3 1 1 1 7 如果新增了第4种状态，那么则可以设置其权值为8，第5种则为16\n相关SQL -- 设置打折商品(或操作) update demo set flag = flag | 4; -- 取消打折商品(异或操作) update demo set flag = flag ^ 4; -- 获取打折商品(与操作) select * from demo where flag \u0026amp; 4; 缺点 搜索的时候无法利用索引 bigint最最大数值为2^126，因此flag最多只能支持126个 ","permalink":"http://bug1024.com/2017/03/22/flag/","summary":"\u003ch2 id=\"多个字段实现状态\"\u003e多个字段实现状态\u003c/h2\u003e\n\u003cp\u003e以商品为例，通常一个商品拥有多种状态标志，是否是打折商品，是否是推荐商品，是否是秒杀商品，对应表结构：\u003c/p\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003eid\u003c/th\u003e\n          \u003cth\u003eis_on_sale\u003c/th\u003e\n          \u003cth\u003eis_recommend\u003c/th\u003e\n          \u003cth\u003eis_seckill\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e1\u003c/td\u003e\n          \u003ctd\u003e1\u003c/td\u003e\n          \u003ctd\u003e0\u003c/td\u003e\n          \u003ctd\u003e1\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e2\u003c/td\u003e\n          \u003ctd\u003e0\u003c/td\u003e\n          \u003ctd\u003e0\u003c/td\u003e\n          \u003ctd\u003e1\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e3\u003c/td\u003e\n          \u003ctd\u003e1\u003c/td\u003e\n          \u003ctd\u003e1\u003c/td\u003e\n          \u003ctd\u003e1\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e这种方案不利于扩展，后期有新的标志需要再添加新的字段\u003c/p\u003e","title":"flag字段设计"},{"content":"类图常见关系 泛化 Generalization 实现 Realization 关联 Association 聚合 Aggregation 组合 Composition 依赖 Dependency 泛化 继承关系，表示一般与特殊的关系 带三角箭头的实线，箭头指向父类 实现 类与接口的关系，表示类是接口所有特征和行为的实现 带三角箭头的虚线，箭头指向接口 关联 拥有的关系，它使一个类知道另一个类的属性和方法，双向的，代码体现为成员变量 带普通箭头的实心线，指向被拥有者 聚合 整体与部分的关系，且部分可以离开整体而单独存在，代码体现为成员变量 聚合关系是关联关系的一种，是强的关联关系，关联和聚合在语法上无法区分，必须考察具体的逻辑关系 带空心菱形的实心线，菱形指向整体 组合 整体与部分的关系，但部分不能离开整体而单独存在，代码体现为成员变量 带实心菱形的实线，菱形指向整体 依赖 使用的关系，即一个类的实现需要另一个类的协助，所以要尽量不使用双向的互相依赖，代码表现为局部变量、方法的参数或者对静态方法的调用 带箭头的虚线，指向被使用者 ","permalink":"http://bug1024.com/2017/03/21/uml/","summary":"\u003ch2 id=\"类图常见关系\"\u003e类图常见关系\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e泛化 Generalization\u003c/li\u003e\n\u003cli\u003e实现 Realization\u003c/li\u003e\n\u003cli\u003e关联 Association\u003c/li\u003e\n\u003cli\u003e聚合 Aggregation\u003c/li\u003e\n\u003cli\u003e组合 Composition\u003c/li\u003e\n\u003cli\u003e依赖 Dependency\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"泛化\"\u003e泛化\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e继承关系，表示一般与特殊的关系\u003c/li\u003e\n\u003cli\u003e带三角箭头的实线，箭头指向父类\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"实现\"\u003e实现\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e类与接口的关系，表示类是接口所有特征和行为的实现\u003c/li\u003e\n\u003cli\u003e带三角箭头的虚线，箭头指向接口\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"关联\"\u003e关联\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e拥有的关系，它使一个类知道另一个类的属性和方法，双向的，代码体现为成员变量\u003c/li\u003e\n\u003cli\u003e带普通箭头的实心线，指向被拥有者\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"聚合\"\u003e聚合\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e整体与部分的关系，且部分可以离开整体而单独存在，代码体现为成员变量\u003c/li\u003e\n\u003cli\u003e聚合关系是关联关系的一种，是强的关联关系，关联和聚合在语法上无法区分，必须考察具体的逻辑关系\u003c/li\u003e\n\u003cli\u003e带空心菱形的实心线，菱形指向整体\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"组合\"\u003e组合\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e整体与部分的关系，但部分不能离开整体而单独存在，代码体现为成员变量\u003c/li\u003e\n\u003cli\u003e带实心菱形的实线，菱形指向整体\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"依赖\"\u003e依赖\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e使用的关系，即一个类的实现需要另一个类的协助，所以要尽量不使用双向的互相依赖，代码表现为局部变量、方法的参数或者对静态方法的调用\u003c/li\u003e\n\u003cli\u003e带箭头的虚线，指向被使用者\u003c/li\u003e\n\u003c/ul\u003e","title":"UML系列"},{"content":" 为规范前端开发代码，提高代码质量，特制定此文档，其中声明，安全和分号这三节是必须执行的，组件类必须遵循注释规范。\n声明 变量声明必须加var关键字，严格控制作用域； 建议使用驼峰式命名变量和函数，如：functionNamesLikeThis, variableNamesLikeThis, ClassNamesLikeThis,namespaceNamesLikeThis； 私有成员变量和方法命名以下划线开头，如：var _this； 常量定义单词全部大写，以下划线连接，但不要用const关键字来声明，如：SOME_CONSTANTS； 函数参数大于3个时，应以对象形式作为参数集传递； 禁止在代码块中声明函数，错误的范例：if (true) {function foo() {}}； 禁止用new来实例化基本类型，错误的范例：var x = new Boolean(false)； 直接定义数组或对象，而不使用new关键字声明，错误的范例：var a = new Array();var o = new Object()； 使用单引号来定义字符串； 文件名必须全部用小写，文件名分隔符用中划线连接，版本连接符用实心点，合并文件的文件名连接符用下划线，如：passport-core.min.js和reset-1.0_utils-1.0.css； 安全 审查用户输入，如：从URL获取参数，使用跳转页面的referer，用于eval或DOM操作的用户数据； 禁止通过在iframe使用script进行跨域回调； 警惕jquery xss，禁止这样的写法：$(window.location.hash)； 禁止引用站外资源； 分号 语句结束一定要加分号\n// bad var myMethod = function() { return 42; } (function() { // 一个匿名函数，在这里会被错误解析当作参数调用导致报错 })(); // good var myMethod = function() { return 42; }; (function() { // 一个匿名函数，在这里会被错误解析当作参数调用导致报错 })(); 异常 由于无法完美的控制都不出现异常，所以尽量在可能但不确定出现异常的地方（大量运算，AJAX请求，数组操作或DOM操作等）用try-catch(e)来抛出异常，这样有利于规模较大的项目中排查错误。使用自定义异常抛出错误信息，更有利于错误信息阅读，且更加通用，因为不同浏览器抛出的信息不一样，有时候可能很难定位到问题所在位置，特别是IE下可能遇到的如下报错信息：\nStack overflow at line: 0 或： 未知的运行时错误 标准化代码编写 为获取最大化的可移植性和兼容性，代码中应使用标准中支持的方式来书写代码，虽然浏览器支持某些语法但不在规范中，你无法保证你将来不会遇到兼容其他浏览器的情况，如果这个浏览器完全或部分特性只按规范实现。\n//错误的范例 var char = 'hello world'[3]; var myForm = document.myForm; //正确的写法 var char = 'hello world'.charAt(3) var myForm = document.forms[0];或者var myForm = document.getElementsByTagName('form')[0]; 面向对象编程 类中的成员变量使用构造函数来初始化； 除非是必须移除类的成员，否则析构函数中对成员的销毁应通过将其设置为null，而不是用delete，因为重新赋值方式性能比用delete好； 避免通过prototype方式污染内置对象原型链； 作用域相关 不使用with关键字，容易造成作用域混乱；\nthis仅用于类成员函数或对象中；\n通用全局函数，特别是通用组件代码应将业务逻辑放入闭包中，并通过“命名空间”将其引入；\n若函数中使用到全局变量，则访问全局变量时应使用window来引入，如：\nvar somevar = 10； function getvar(){ var num = window.somevar + 1; //... return num; } 空白 将tab设为4个空格\n// bad function() { ∙∙var name; } // bad function() { ∙var name; } // good function() { ∙∙∙∙var name; } 大括号前放一个空格\n// bad function test(){ console.log(\u0026#39;test\u0026#39;); } // good function test() { console.log(\u0026#39;test\u0026#39;); } // bad dog.set(\u0026#39;attr\u0026#39;,{ age: \u0026#39;1 year\u0026#39;, breed: \u0026#39;Bernese Mountain Dog\u0026#39; }); // good dog.set(\u0026#39;attr\u0026#39;, { age: \u0026#39;1 year\u0026#39;, breed: \u0026#39;Bernese Mountain Dog\u0026#39; }); 在做长方法链时使用缩进.\n// bad $(\u0026#39;#items\u0026#39;).find(\u0026#39;.selected\u0026#39;).highlight().end().find(\u0026#39;.open\u0026#39;).updateCount(); // good $(\u0026#39;#items\u0026#39;) .find(\u0026#39;.selected\u0026#39;) .highlight() .end() .find(\u0026#39;.open\u0026#39;) .updateCount(); 逗号 不要将逗号放前面\n// bad var once , upon , aTime; // good var once, upon, aTime; // bad var hero = { firstName: \u0026#39;Bob\u0026#39; , lastName: \u0026#39;Parr\u0026#39; , heroName: \u0026#39;Mr. Incredible\u0026#39; , superPower: \u0026#39;strength\u0026#39; }; // good var hero = { firstName: \u0026#39;Bob\u0026#39;, lastName: \u0026#39;Parr\u0026#39;, heroName: \u0026#39;Mr. Incredible\u0026#39;, superPower: \u0026#39;strength\u0026#39; }; 不要加多余的逗号，这可能会在IE下引起错误，同时如果多一个逗号某些ES3的实现会计算多数组的长度。\n// bad var hero = { firstName: \u0026#39;Kevin\u0026#39;, lastName: \u0026#39;Flynn\u0026#39;, }; var heroes = [ \u0026#39;Batman\u0026#39;, \u0026#39;Superman\u0026#39;, ]; // good var hero = { firstName: \u0026#39;Kevin\u0026#39;, lastName: \u0026#39;Flynn\u0026#39; }; var heroes = [ \u0026#39;Batman\u0026#39;, \u0026#39;Superman\u0026#39; ]; 类型 原始值: 相当于传值\nstring number boolean null undefined var foo = 1, bar = foo; bar = 9; console.log(foo, bar); // =\u0026gt; 1, 9 复杂类型: 相当于传引用\nobject array function var foo = [1, 2], bar = foo; bar[0] = 9; console.log(foo[0], bar[0]); // =\u0026gt; 9, 9 对象 使用字面值创建对象\n// bad var item = new Object(); // good var item = {}; 不要使用保留字 reserved words 作为键\n// bad var superman = { class: \u0026#39;superhero\u0026#39;, default: { clark: \u0026#39;kent\u0026#39; }, private: true }; // good var superman = { klass: \u0026#39;superhero\u0026#39;, defaults: { clark: \u0026#39;kent\u0026#39; }, hidden: true }; 数组 使用字面值创建数组\n// bad var items = new Array(); // good var items = []; 如果你不知道数组的长度，使用push\nvar someStack = []; // bad someStack[someStack.length] = \u0026#39;abracadabra\u0026#39;; // good someStack.push(\u0026#39;abracadabra\u0026#39;); 当你需要拷贝数组时使用slice. jsPerf\nvar len = items.length, itemsCopy = [], i; // bad for (i = 0; i \u0026lt; len; i++) { itemsCopy[i] = items[i]; } // good itemsCopy = items.slice(); 使用slice将类数组的对象转成数组.\nfunction trigger() { var args = Array.prototype.slice.call(arguments); ... } 字符串 对字符串使用单引号 ''\n// bad var name = \u0026#34;Bob Parr\u0026#34;; // good var name = \u0026#39;Bob Parr\u0026#39;; // bad var fullName = \u0026#34;Bob \u0026#34; + this.lastName; // good var fullName = \u0026#39;Bob \u0026#39; + this.lastName; 超过80个字符的字符串应该使用字符串连接换行\n注: 如果过度使用，长字符串连接可能会对性能有影响. jsPerf \u0026amp; Discussion\n// bad var errorMessage = \u0026#39;This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.\u0026#39;; // bad var errorMessage = \u0026#39;This is a super long error that \\ was thrown because of Batman. \\ When you stop to think about \\ how Batman had anything to do \\ with this, you would get nowhere \\ fast.\u0026#39;; // good var errorMessage = \u0026#39;This is a super long error that \u0026#39; + \u0026#39;was thrown because of Batman.\u0026#39; + \u0026#39;When you stop to think about \u0026#39; + \u0026#39;how Batman had anything to do \u0026#39; + \u0026#39;with this, you would get nowhere \u0026#39; + \u0026#39;fast.\u0026#39;; 编程时使用join而不是字符串连接来构建字符串，特别是IE: jsPerf.\nvar items, messages, length, i; messages = [{ state: \u0026#39;success\u0026#39;, message: \u0026#39;This one worked.\u0026#39; },{ state: \u0026#39;success\u0026#39;, message: \u0026#39;This one worked as well.\u0026#39; },{ state: \u0026#39;error\u0026#39;, message: \u0026#39;This one did not work.\u0026#39; }]; length = messages.length; // bad function inbox(messages) { items = \u0026#39;\u0026lt;ul\u0026gt;\u0026#39;; for (i = 0; i \u0026lt; length; i++) { items += \u0026#39;\u0026lt;li\u0026gt;\u0026#39; + messages[i].message + \u0026#39;\u0026lt;/li\u0026gt;\u0026#39;; } return items + \u0026#39;\u0026lt;/ul\u0026gt;\u0026#39;; } // good function inbox(messages) { items = []; for (i = 0; i \u0026lt; length; i++) { items[i] = messages[i].message; } return \u0026#39;\u0026lt;ul\u0026gt;\u0026lt;li\u0026gt;\u0026#39; + items.join(\u0026#39;\u0026lt;/li\u0026gt;\u0026lt;li\u0026gt;\u0026#39;) + \u0026#39;\u0026lt;/li\u0026gt;\u0026lt;/ul\u0026gt;\u0026#39;; } 函数 函数表达式:\n// 匿名函数表达式 var anonymous = function() { return true; }; // 有名函数表达式 var named = function named() { return true; }; // 立即调用函数表达式 (function() { console.log(\u0026#39;Welcome to the Internet. Please follow me.\u0026#39;); })(); 绝对不要在一个非函数块里声明一个函数，把那个函数赋给一个变量。浏览器允许你这么做，但是它们解析不同。\n注: ECMA-262定义把块定义为一组语句，函数声明不是一个语句。阅读ECMA-262对这个问题的说明.\n// bad if (currentUser) { function test() { console.log(\u0026#39;Nope.\u0026#39;); } } // good if (currentUser) { var test = function test() { console.log(\u0026#39;Yup.\u0026#39;); }; } 绝对不要把参数命名为 arguments, 这将会逾越函数作用域内传过来的 arguments 对象.\n// bad function nope(name, options, arguments) { // ...stuff... } // good function yup(name, options, args) { // ...stuff... } 属性 当使用变量访问属性时使用中括号.\nvar luke = { jedi: true, age: 28 }; function getProp(prop) { return luke[prop]; } var isJedi = getProp(\u0026#39;jedi\u0026#39;); 条件表达式和等号 适当使用 === 和 !== 以及 == 和 !=. -以下表达式结果为false\n```javascript null undefined '' // 空字符串 0 // 数字 ``` -以下表达式结果全为true\n```javascript '0' // 字符串 [] // 空数组 {} // 空对象 Boolean('0') == true '0' != true 0 != null 0 == [] 0 == false Boolean(null) == false null != true null != false Boolean(undefined) == false undefined != true undefined != false Boolean([]) == true [] != true [] == false Boolean({}) == true {} != true {} != false ``` 条件表达式的强制类型转换遵循以下规则：\n对象 被计算为 true Undefined 被计算为 false Null 被计算为 false 布尔值 被计算为 布尔的值 数字 如果是 +0, -0, or NaN 被计算为 false , 否则为 true 字符串 如果是空字符串 '' 则被计算为 false, 否则为 true if ([0]) { // true // An array is an object, objects evaluate to true } 使用快捷方式.\n// bad if (name !== \u0026#39;\u0026#39;) { // ...stuff... } // good if (name) { // ...stuff... } // bad if (collection.length \u0026gt; 0) { // ...stuff... } // good if (collection.length) { // ...stuff... } 阅读 Truth Equality and JavaScript 了解更多\n块 给所有多行的块使用大括号\n// bad if (test) return false; // good if (test) return false; // good if (test) { return false; } // bad function() {return false;} // good function() { return false; } 注释 使用 /** ... */ 进行多行注释，包括描述，指定类型以及参数值和返回值\n// bad // make() returns a new element // based on the passed in tag name // // @param \u0026lt;String\u0026gt; tag // @return \u0026lt;Element\u0026gt; element function make(tag) { // ...stuff... return element; } // good /** * make() returns a new element * based on the passed in tag name * * @param \u0026lt;String\u0026gt; tag * @return \u0026lt;Element\u0026gt; element */ function make(tag) { // ...stuff... return element; } 使用 // 进行单行注释，在评论对象的上面进行单行注释，注释前放一个空行.\n// bad var active = true; // is current tab // good // is current tab var active = true; // bad function getType() { console.log(\u0026#39;fetching type...\u0026#39;); // set the default type to \u0026#39;no type\u0026#39; var type = this._type || \u0026#39;no type\u0026#39;; return type; } // good function getType() { console.log(\u0026#39;fetching type...\u0026#39;); // set the default type to \u0026#39;no type\u0026#39; var type = this._type || \u0026#39;no type\u0026#39;; return type; } 如果你有一个问题需要重新来看一下或如果你建议一个需要被实现的解决方法的话需要在你的注释前面加上 FIXME 或 TODO 帮助其他人迅速理解\nfunction Calculator() { // FIXME: shouldn\u0026#39;t use a global here total = 0; return this; } function Calculator() { // TODO: total should be configurable by an options param this.total = 0; return this; } ## 类型转换 ## - 在语句的开始执行类型转换. - 字符串: ```javascript // =\u0026gt; this.reviewScore = 9; // bad var totalScore = this.reviewScore + \u0026#39;\u0026#39;; // good var totalScore = \u0026#39;\u0026#39; + this.reviewScore; // bad var totalScore = \u0026#39;\u0026#39; + this.reviewScore + \u0026#39; total score\u0026#39;; // good var totalScore = this.reviewScore + \u0026#39; total score\u0026#39;; ``` - 对数字使用 `parseInt` 并且总是带上类型转换的基数. ```javascript var inputValue = \u0026#39;4\u0026#39;; // bad var val = new Number(inputValue); // bad var val = +inputValue; // bad var val = inputValue \u0026gt;\u0026gt; 0; // bad var val = parseInt(inputValue); // good var val = Number(inputValue); // good var val = parseInt(inputValue, 10); // good /** * parseInt was the reason my code was slow. * Bitshifting the String to coerce it to a * Number made it a lot faster. */ var val = inputValue \u0026gt;\u0026gt; 0; ``` - 布尔值: ```javascript var age = 0; // bad var hasAge = new Boolean(age); // good var hasAge = Boolean(age); // good var hasAge = !!age; ``` ## 命名约定 ## - 避免单个字符名，让你的变量名有描述意义。 ```javascript // bad function q() { // ...stuff... } // good function query() { // ..stuff.. } ``` - 当命名对象、函数和实例时使用驼峰命名规则 ```javascript // bad var OBJEcttsssss = {}; var this_is_my_object = {}; var this-is-my-object = {}; function c() {}; var u = new user({ name: \u0026#39;Bob Parr\u0026#39; }); // good var thisIsMyObject = {}; function thisIsMyFunction() {}; var user = new User({ name: \u0026#39;Bob Parr\u0026#39; }); ``` - 当命名构造函数或类时使用驼峰式大写 ```javascript // bad function user(options) { this.name = options.name; } var bad = new user({ name: \u0026#39;nope\u0026#39; }); // good function User(options) { this.name = options.name; } var good = new User({ name: \u0026#39;yup\u0026#39; }); ``` - 命名私有属性时前面加个下划线 `_` ```javascript // bad this.__firstName__ = \u0026#39;Panda\u0026#39;; this.firstName_ = \u0026#39;Panda\u0026#39;; // good this._firstName = \u0026#39;Panda\u0026#39;; ``` - 当保存对 `this` 的引用时使用 `_this`. ```javascript // bad function() { var self = this; return function() { console.log(self); }; } // bad function() { var that = this; return function() { console.log(that); }; } // good function() { var _this = this; return function() { console.log(_this); }; } ``` ## 存取器 ## - 属性的存取器函数不是必需的 - 如果你确实有存取器函数的话使用getVal() 和 setVal(\u0026#39;hello\u0026#39;) ```javascript // bad dragon.age(); // good dragon.getAge(); // bad dragon.age(25); // good dragon.setAge(25); ``` - 如果属性是布尔值，使用isVal() 或 hasVal() ```javascript // bad if (!dragon.age()) { return false; } // good if (!dragon.hasAge()) { return false; } ``` - 可以创建get()和set()函数，但是要保持一致 ```javascript function Jedi(options) { options || (options = {}); var lightsaber = options.lightsaber || \u0026#39;blue\u0026#39;; this.set(\u0026#39;lightsaber\u0026#39;, lightsaber); } Jedi.prototype.set = function(key, val) { this[key] = val; }; Jedi.prototype.get = function(key) { return this[key]; }; ``` ## 构造器 ## - 给对象原型分配方法，而不是用一个新的对象覆盖原型，覆盖原型会使继承出现问题。 ```javascript function Jedi() { console.log(\u0026#39;new jedi\u0026#39;); } // bad Jedi.prototype = { fight: function fight() { console.log(\u0026#39;fighting\u0026#39;); }, block: function block() { console.log(\u0026#39;blocking\u0026#39;); } }; // good Jedi.prototype.fight = function fight() { console.log(\u0026#39;fighting\u0026#39;); }; Jedi.prototype.block = function block() { console.log(\u0026#39;blocking\u0026#39;); }; ``` - 方法可以返回 `this` 帮助方法可链。 ```javascript // bad Jedi.prototype.jump = function() { this.jumping = true; return true; }; Jedi.prototype.setHeight = function(height) { this.height = height; }; var luke = new Jedi(); luke.jump(); // =\u0026gt; true luke.setHeight(20) // =\u0026gt; undefined // good Jedi.prototype.jump = function() { this.jumping = true; return this; }; Jedi.prototype.setHeight = function(height) { this.height = height; return this; }; var luke = new Jedi(); luke.jump() .setHeight(20); ``` - 可以写一个自定义的toString()方法，但是确保它工作正常并且不会有副作用。 ```javascript function Jedi(options) { options || (options = {}); this.name = options.name || \u0026#39;no name\u0026#39;; } Jedi.prototype.getName = function getName() { return this.name; }; Jedi.prototype.toString = function toString() { return \u0026#39;Jedi - \u0026#39; + this.getName(); }; ``` ## 事件 ## - 当给事件附加数据时，传入一个哈希而不是原始值，这可以让后面的贡献者加入更多数据到事件数据里而不用找出并更新那个事件的事件处理器 ```js // bad $(this).trigger(\u0026#39;listingUpdated\u0026#39;, listing.id); ... $(this).on(\u0026#39;listingUpdated\u0026#39;, function(e, listingId) { // do something with listingId }); ``` 更好: ```js // good $(this).trigger(\u0026#39;listingUpdated\u0026#39;, {listingId: listing.id}); ... $(this).on(\u0026#39;listingUpdated\u0026#39;, function(e, data) { // do something with data.listingId }); ``` ## jQuery ## - 缓存jQuery查询 ```javascript // bad function setSidebar() { $(\u0026#39;.sidebar\u0026#39;).hide(); // ...stuff... $(\u0026#39;.sidebar\u0026#39;).css({ \u0026#39;background-color\u0026#39;: \u0026#39;pink\u0026#39; }); } // good function setSidebar() { var $sidebar = $(\u0026#39;.sidebar\u0026#39;); $sidebar.hide(); // ...stuff... $sidebar.css({ \u0026#39;background-color\u0026#39;: \u0026#39;pink\u0026#39; }); } ``` - 对DOM查询使用级联的 `$(\u0026#39;.sidebar ul\u0026#39;)` 或 `$(\u0026#39;.sidebar ul\u0026#39;)`，[jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16) - 对有作用域的jQuery对象查询使用 `find` ```javascript // bad $(\u0026#39;.sidebar\u0026#39;, \u0026#39;ul\u0026#39;).hide(); // bad $(\u0026#39;.sidebar\u0026#39;).find(\u0026#39;ul\u0026#39;).hide(); // good $(\u0026#39;.sidebar ul\u0026#39;).hide(); // good $(\u0026#39;.sidebar \u0026gt; ul\u0026#39;).hide(); // good (slower) $sidebar.find(\u0026#39;ul\u0026#39;); // good (faster) $($sidebar[0]).find(\u0026#39;ul\u0026#39;); ``` ## 杂项 ## - 尽量使用优雅的模版写法，避免多行字符串用\\加换行的方式或使用+运算连接字符串这种难维护的编码方式； ## 常用词命名统一 ## 规则： 1. *可读性强，见名知义。* 1. 尽量不与 jQuery 社区已有的习惯冲突。 1. 尽量写全。不用缩写，除非是下面列表中约定的。 大家一起来，逐步完善。 - options 表示配置，与 jQuery 社区保持一致，不要用 config, opts 等 - active 表示当前，不要用 current 等 - active 表示当前，不要用 current 等 - index 表示索引，不要用 idx 等 - trigger 触点元素 - triggerType 触发类型、方式 - context 表示传入的 this 对象 - object 推荐写全，不推荐简写为 o, obj 等 - element 推荐写全，不推荐简写为 el, elem 等 - length 不要写成 len, l - prev previous 的缩写 - constructor 不能写成 ctor - easing 表示动画平滑函数 - min minimize 的缩写 - max maximize 的缩写 - DOM 不要写成 dom, Dom - .tpl 使用 tpl 后缀表示模版 - btn button 的缩写 ## JSHint配置 ## 待定 ## ECMAScript 5兼容性 ## - 参考[Kangax](https://twitter.com/kangax/)的 ES5 [compatibility table](http://kangax.github.com/es5-compat-table/) ## 性能 ## - [On Layout \u0026amp; Web Performance](http://kellegous.com/j/2013/01/26/layout-performance/) - [String vs Array Concat](http://jsperf.com/string-vs-array-concat/2) - [Try/Catch Cost In a Loop](http://jsperf.com/try-catch-in-loop-cost) - [Bang Function](http://jsperf.com/bang-function) - [jQuery Find vs Context, Selector](http://jsperf.com/jquery-find-vs-context-sel/13) - [innerHTML vs textContent for script text](http://jsperf.com/innerhtml-vs-textcontent-for-script-text) - [Long String Concatenation](http://jsperf.com/ya-string-concat) - Loading... ","permalink":"http://bug1024.com/2017/03/17/javascript-referrence/","summary":"\u003cblockquote\u003e\n\u003cp\u003e为规范前端开发代码，提高代码质量，特制定此文档，其中\u003cstrong\u003e声明\u003c/strong\u003e，\u003cstrong\u003e安全\u003c/strong\u003e和\u003cstrong\u003e分号\u003c/strong\u003e这三节是必须执行的，组件类必须遵循\u003cstrong\u003e注释规范\u003c/strong\u003e。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"声明\"\u003e声明\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e变量声明必须加var关键字，严格控制作用域；\u003c/li\u003e\n\u003cli\u003e建议使用驼峰式命名变量和函数，如：functionNamesLikeThis, variableNamesLikeThis, ClassNamesLikeThis,namespaceNamesLikeThis；\u003c/li\u003e\n\u003cli\u003e私有成员变量和方法命名以下划线开头，如：var _this；\u003c/li\u003e\n\u003cli\u003e常量定义单词全部大写，以下划线连接，但不要用const关键字来声明，如：SOME_CONSTANTS；\u003c/li\u003e\n\u003cli\u003e函数参数大于3个时，应以对象形式作为参数集传递；\u003c/li\u003e\n\u003cli\u003e禁止在代码块中声明函数，错误的范例：if (true) {function foo() {}}；\u003c/li\u003e\n\u003cli\u003e禁止用new来实例化\u003cstrong\u003e基本类型\u003c/strong\u003e，错误的范例：var x = new Boolean(false)；\u003c/li\u003e\n\u003cli\u003e直接定义数组或对象，而不使用new关键字声明，错误的范例：var a = new Array();var o = new Object()；\u003c/li\u003e\n\u003cli\u003e使用单引号来定义字符串；\u003c/li\u003e\n\u003cli\u003e文件名必须全部用小写，文件名分隔符用\u003cstrong\u003e中划线\u003c/strong\u003e连接，版本连接符用\u003cstrong\u003e实心点\u003c/strong\u003e，合并文件的文件名连接符用\u003cstrong\u003e下划线\u003c/strong\u003e，如：passport-core.min.js和reset-1.0_utils-1.0.css；\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"安全\"\u003e安全\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e审查用户输入，如：从URL获取参数，使用跳转页面的referer，用于eval或DOM操作的用户数据；\u003c/li\u003e\n\u003cli\u003e禁止通过在iframe使用script进行跨域回调；\u003c/li\u003e\n\u003cli\u003e警惕jquery xss，禁止这样的写法：$(window.location.hash)；\u003c/li\u003e\n\u003cli\u003e禁止引用站外资源；\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"分号\"\u003e分号\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e语句结束一定要加分号\u003c/p\u003e","title":"JavaScript规范"},{"content":"判断一个字符串是否是合法的json串通常有以下两种方式\n// 不推荐使用 function isValidJson($json) { return is_null(json_decode($json)); } // 推荐使用 function isValidJson($json) { json_decode($json); return json_last_error() === JSON_ERROR_NONE; } 但是无意中发现直接json_decode一个数字123或者一个字符串\u0026quot;abc\u0026quot;也是可以的\n$a = json_decode(123); // $a值为123 $b = json_last_error() === JSON_ERROR_NONE; // $b值为true JSON JSON 是文本格式，能用于在不同编程语言中交换结构化数据 早期的 RFC 4627 中，JSON 文本（即 JSON 的根值）只允许对象和数组类型，直至 ECMA-404 和 RFC 7159 才放松了规定，容许 7 种类型都能为 JSON 文本 所有 JSON 都是合法的 JS 脚本（反之非必然），但在 JS 中为了安全考虑通常是使用 JSON.parse() 来解析成 JS 对象 JSON 的值通常有三种类型：简单值(字符串, 数字, 布尔, NULL), 对象，数组，其中NULL解码后仍是NULL，这也是不推荐使用方法1的原因\n","permalink":"http://bug1024.com/2017/03/15/php-json-decode/","summary":"\u003cp\u003e判断一个字符串是否是合法的json串通常有以下两种方式\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-php\" data-lang=\"php\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 不推荐使用\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efunction\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eisValidJson\u003c/span\u003e($json) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eis_null\u003c/span\u003e(\u003cspan style=\"color:#a6e22e\"\u003ejson_decode\u003c/span\u003e($json));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 推荐使用\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efunction\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eisValidJson\u003c/span\u003e($json) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#a6e22e\"\u003ejson_decode\u003c/span\u003e($json);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ejson_last_error\u003c/span\u003e() \u003cspan style=\"color:#f92672\"\u003e===\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eJSON_ERROR_NONE\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e但是无意中发现直接json_decode一个数字123或者一个字符串\u0026quot;abc\u0026quot;也是可以的\u003c/p\u003e","title":"PHP中的json_decode"},{"content":" Redis 从2.6版本起开始支持 Lua 脚本\n非脚本方式实现的访问限速 private boolean accessLimit(String ip, int limit, int time, Jedis jedis) { boolean result = true; String key = \u0026#34;rate.limit:\u0026#34; + ip; if (jedis.exists(key)) { long afterValue = jedis.incr(key); if (afterValue \u0026gt; limit) { result = false; } } else { Transaction transaction = jedis.multi(); transaction.incr(key); transaction.expire(key, time); transaction.exec(); } return result; } 使用Lua脚本实现的访问限速 Lua\nlocal key = \u0026#34;rate.limit:\u0026#34; .. KEYS[1] local limit = tonumber(ARGV[1]) local expire_time = ARGV[2] local is_exists = redis.call(\u0026#34;EXISTS\u0026#34;, key) if is_exists == 1 then if redis.call(\u0026#34;INCR\u0026#34;, key) \u0026gt; limit then return 0 else return 1 end else redis.call(\u0026#34;SET\u0026#34;, key, 1) redis.call(\u0026#34;EXPIRE\u0026#34;, key, expire_time) return 1 end Java\nprivate boolean accessLimit(String ip, int limit, int timeout, Jedis connection) throws IOException { List\u0026lt;String\u0026gt; keys = Collections.singletonList(ip); List\u0026lt;String\u0026gt; argv = Arrays.asList(String.valueOf(limit), String.valueOf(timeout)); return 1 == (long) connection.eval(loadScriptString(\u0026#34;script.lua\u0026#34;), keys, argv); } // 加载Lua代码 private String loadScriptString(String fileName) throws IOException { Reader reader = new InputStreamReader(Client.class.getClassLoader().getResourceAsStream(fileName)); return CharStreams.toString(reader); } Lua脚本方式优势 减少网络开销: 不使用 Lua 的代码需要向 Redis 发送多次请求, 而脚本只需一次即可, 减少网络传输 原子操作: Redis 将整个脚本作为一个原子执行, 无需担心并发, 也就无需事务 复用: 脚本会永久保存 Redis 中, 其他客户端可继续使用 ","permalink":"http://bug1024.com/2017/03/14/lua-redis/","summary":"\u003cblockquote\u003e\n\u003cp\u003eRedis 从2.6版本起开始支持 Lua 脚本\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"非脚本方式实现的访问限速\"\u003e非脚本方式实现的访问限速\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eprivate\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eboolean\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eaccessLimit\u003c/span\u003e(String ip, \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e limit, \u003cspan style=\"color:#66d9ef\"\u003eint\u003c/span\u003e time, Jedis jedis) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eboolean\u003c/span\u003e result \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003etrue\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        String key \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;rate.limit:\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e ip;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e (jedis.\u003cspan style=\"color:#a6e22e\"\u003eexists\u003c/span\u003e(key)) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003elong\u003c/span\u003e afterValue \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e jedis.\u003cspan style=\"color:#a6e22e\"\u003eincr\u003c/span\u003e(key);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e (afterValue \u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e limit) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                result \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003efalse\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        } \u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            Transaction transaction \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e jedis.\u003cspan style=\"color:#a6e22e\"\u003emulti\u003c/span\u003e();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            transaction.\u003cspan style=\"color:#a6e22e\"\u003eincr\u003c/span\u003e(key);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            transaction.\u003cspan style=\"color:#a6e22e\"\u003eexpire\u003c/span\u003e(key, time);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            transaction.\u003cspan style=\"color:#a6e22e\"\u003eexec\u003c/span\u003e();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e result;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"使用lua脚本实现的访问限速\"\u003e使用Lua脚本实现的访问限速\u003c/h2\u003e\n\u003cp\u003eLua\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-lua\" data-lang=\"lua\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003elocal\u003c/span\u003e key \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;rate.limit:\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e..\u003c/span\u003e KEYS[\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003elocal\u003c/span\u003e limit \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e tonumber(ARGV[\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e])\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003elocal\u003c/span\u003e expire_time \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e ARGV[\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003elocal\u003c/span\u003e is_exists \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e redis.call(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;EXISTS\u0026#34;\u003c/span\u003e, key)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e is_exists \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003ethen\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e redis.call(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;INCR\u0026#34;\u003c/span\u003e, key) \u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e limit \u003cspan style=\"color:#66d9ef\"\u003ethen\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eend\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        redis.call(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;SET\u0026#34;\u003c/span\u003e, key, \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        redis.call(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;EXPIRE\u0026#34;\u003c/span\u003e, key, expire_time)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eend\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eJava\u003c/p\u003e","title":"Lua调用Redis"},{"content":"Spring简介 最基本的功能就是创建对象及管理这些对象之间的依赖关系，实现高内聚低耦合 方便集成第三方框架与组件 Spring启动 启动过程其实就是其IoC容器的启动过程，即建立上下文的过程\nimport org.springframework.context.support.ClassPathXmlApplicationContext; // 初始化Spring应用 public class SpringStart { public static void main(String[] args) { // 加载指定的Spring配置文件 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(\u0026#34;classpath:/META-INF/spring/applicationContext.xml\u0026#34;); context.start(); // 保证服务一直开着，利用输入流的阻塞来模拟 System.in.read(); } } Spring配置文件 配置文件通常命名为applicationContext.xml，一般会包含自动扫描包路径、jdbc、dataSource、mybatis等配置\n\u0026lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;UTF-8\u0026#34;?\u0026gt; \u0026lt;beans xmlns=\u0026#34;http://www.springframework.org/schema/beans\u0026#34; xmlns:context=\u0026#34;http://www.springframework.org/schema/context\u0026#34; xmlns:xsi=\u0026#34;http://www.w3.org/2001/XMLSchema-instance\u0026#34; xmlns:aop=\u0026#34;http://www.springframework.org/schema/aop\u0026#34; xmlns:tx=\u0026#34;http://www.springframework.org/schema/tx\u0026#34; xmlns:p=\u0026#34;http://www.springframework.org/schema/p\u0026#34; xmlns:util=\u0026#34;http://www.springframework.org/schema/util\u0026#34; xmlns:jdbc=\u0026#34;http://www.springframework.org/schema/jdbc\u0026#34; xmlns:cache=\u0026#34;http://www.springframework.org/schema/cache\u0026#34; xsi:schemaLocation=\u0026#34; http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd\u0026#34;\u0026gt; \u0026lt;!-- 自动扫描web包 ,将带有注解的类 纳入spring容器管理 --\u0026gt; \u0026lt;context:component-scan base-package=\u0026#34;com.eduoinfo.finances.bank.web\u0026#34;\u0026gt;\u0026lt;/context:component-scan\u0026gt; \u0026lt;!-- 引入jdbc配置文件 --\u0026gt; \u0026lt;bean id=\u0026#34;propertyConfigurer\u0026#34; class=\u0026#34;org.springframework.beans.factory.config.PropertyPlaceholderConfigurer\u0026#34;\u0026gt; \u0026lt;property name=\u0026#34;locations\u0026#34;\u0026gt; \u0026lt;list\u0026gt; \u0026lt;value\u0026gt;classpath*:jdbc.properties\u0026lt;/value\u0026gt; \u0026lt;/list\u0026gt; \u0026lt;/property\u0026gt; \u0026lt;/bean\u0026gt; \u0026lt;!-- dataSource 配置 --\u0026gt; \u0026lt;bean id=\u0026#34;dataSource\u0026#34; class=\u0026#34;com.alibaba.druid.pool.DruidDataSource\u0026#34; init-method=\u0026#34;init\u0026#34; destroy-method=\u0026#34;close\u0026#34;\u0026gt; \u0026lt;!-- 基本属性 url、user、password --\u0026gt; \u0026lt;property name=\u0026#34;url\u0026#34; value=\u0026#34;${jdbc.url}\u0026#34; /\u0026gt; \u0026lt;property name=\u0026#34;username\u0026#34; value=\u0026#34;${jdbc.username}\u0026#34; /\u0026gt; \u0026lt;property name=\u0026#34;password\u0026#34; value=\u0026#34;${jdbc.password}\u0026#34; /\u0026gt; \u0026lt;!-- 配置初始化大小、最小、最大 --\u0026gt; \u0026lt;property name=\u0026#34;initialSize\u0026#34; value=\u0026#34;1\u0026#34; /\u0026gt; \u0026lt;property name=\u0026#34;minIdle\u0026#34; value=\u0026#34;1\u0026#34; /\u0026gt; \u0026lt;property name=\u0026#34;maxActive\u0026#34; value=\u0026#34;20\u0026#34; /\u0026gt; \u0026lt;!-- 配置获取连接等待超时的时间 --\u0026gt; \u0026lt;property name=\u0026#34;maxWait\u0026#34; value=\u0026#34;60000\u0026#34; /\u0026gt; \u0026lt;!-- 配置间隔多久才进行一次检测，检测需要关闭的空闲连接，单位是毫秒 --\u0026gt; \u0026lt;property name=\u0026#34;timeBetweenEvictionRunsMillis\u0026#34; value=\u0026#34;60000\u0026#34; /\u0026gt; \u0026lt;!-- 配置一个连接在池中最小生存的时间，单位是毫秒 --\u0026gt; \u0026lt;property name=\u0026#34;minEvictableIdleTimeMillis\u0026#34; value=\u0026#34;300000\u0026#34; /\u0026gt; \u0026lt;property name=\u0026#34;validationQuery\u0026#34; value=\u0026#34;SELECT \u0026#39;x\u0026#39;\u0026#34; /\u0026gt; \u0026lt;property name=\u0026#34;testWhileIdle\u0026#34; value=\u0026#34;true\u0026#34; /\u0026gt; \u0026lt;property name=\u0026#34;testOnBorrow\u0026#34; value=\u0026#34;false\u0026#34; /\u0026gt; \u0026lt;property name=\u0026#34;testOnReturn\u0026#34; value=\u0026#34;false\u0026#34; /\u0026gt; \u0026lt;!-- 打开PSCache，并且指定每个连接上PSCache的大小 --\u0026gt; \u0026lt;property name=\u0026#34;poolPreparedStatements\u0026#34; value=\u0026#34;false\u0026#34; /\u0026gt; \u0026lt;property name=\u0026#34;maxPoolPreparedStatementPerConnectionSize\u0026#34; value=\u0026#34;20\u0026#34; /\u0026gt; \u0026lt;!-- 配置监控统计拦截的filters --\u0026gt; \u0026lt;property name=\u0026#34;filters\u0026#34; value=\u0026#34;stat\u0026#34; /\u0026gt; \u0026lt;/bean\u0026gt; \u0026lt;!-- mybatis文件配置，扫描所有mapper文件 --\u0026gt; \u0026lt;bean id=\u0026#34;sqlSessionFactory\u0026#34; class=\u0026#34;org.mybatis.spring.SqlSessionFactoryBean\u0026#34; p:dataSource-ref=\u0026#34;dataSource\u0026#34; p:configLocation=\u0026#34;classpath:mybatis-config.xml\u0026#34; p:mapperLocations=\u0026#34;classpath:com/eduoinfo/finances/bank/web/dao/*.xml\u0026#34; /\u0026gt; \u0026lt;!-- spring与mybatis整合配置，扫描所有dao --\u0026gt; \u0026lt;bean class=\u0026#34;org.mybatis.spring.mapper.MapperScannerConfigurer\u0026#34; p:basePackage=\u0026#34;com.eduoinfo.finances.bank.web.dao\u0026#34; p:sqlSessionFactoryBeanName=\u0026#34;sqlSessionFactory\u0026#34; /\u0026gt; \u0026lt;!-- 对dataSource 数据源进行事务管理 --\u0026gt; \u0026lt;bean id=\u0026#34;transactionManager\u0026#34; class=\u0026#34;org.springframework.jdbc.datasource.DataSourceTransactionManager\u0026#34; p:dataSource-ref=\u0026#34;dataSource\u0026#34; /\u0026gt; \u0026lt;!-- 配置使Spring采用CGLIB代理 --\u0026gt; \u0026lt;aop:aspectj-autoproxy proxy-target-class=\u0026#34;true\u0026#34; /\u0026gt; \u0026lt;!-- 启用对事务注解的支持 --\u0026gt; \u0026lt;tx:annotation-driven transaction-manager=\u0026#34;transactionManager\u0026#34; /\u0026gt; \u0026lt;!-- Cache配置 --\u0026gt; \u0026lt;cache:annotation-driven cache-manager=\u0026#34;cacheManager\u0026#34; /\u0026gt; \u0026lt;bean id=\u0026#34;ehCacheManagerFactory\u0026#34; class=\u0026#34;org.springframework.cache.ehcache.EhCacheManagerFactoryBean\u0026#34; p:configLocation=\u0026#34;classpath:ehcache.xml\u0026#34; /\u0026gt; \u0026lt;bean id=\u0026#34;cacheManager\u0026#34; class=\u0026#34;org.springframework.cache.ehcache.EhCacheCacheManager\u0026#34; p:cacheManager-ref=\u0026#34;ehCacheManagerFactory\u0026#34; /\u0026gt; \u0026lt;/beans\u0026gt; IoC \u0026amp; DI \u0026amp; AOP \u0026amp; Bean IoC Inversion of Controller 它就是一个创建工厂，你要什么对象，它就给你什么对象 IoC控制反转说的是创建对象实例的控制权从代码控制剥离到IOC容器控制，实际就是你在xml文件控制，侧重于原理 有了IoC容器，依赖关系就变了，原先的依赖关系就没了，它们都依赖IoC容器了，通过IoC容器来建立它们之间的关系 DI Dependency Injection DI依赖注入说的是创建对象实例时，为这个对象注入属性值或其它对象实例，侧重于实现 AOP Aspect Oriented Programming AOP是动态代理的应用，将具体业务和相应的其它方面（比如日志，权限之类的）划分开来 业务不会知道还有没有其它的功能来辅助，需要的话我就给他加上一个配置就可以，而不用去修改业务代码 Bean 一种编程规范 所有属性为private 提供默认构造方法 提供getter和setter 实现serializable接口 引入注解的原因 大的项目中通常会有上百个组件，如果这些组件都采用xml的bean定义来配置，显然会增加配置文件的体积，维护成本太高 Spring2.5引入了组件自动扫描机制，它可以在类路径底下寻找标注了@Component，@Service，@Controller，@Repository注解的类，并把这些类纳入进spring容器中管理 注解的作用和在xml文件中使用bean节点配置组件是一样的 实现类的bean声明 @Service 服务层组件，用于标注业务层组件，表示定义一个bean，自动根据bean的类名实例化一个首写字母为小写的bean，例如Chinese实例化为chinese，如果需要自己改名字则@Service(\u0026ldquo;your-bean-name\u0026rdquo;) @Controller 用于标注控制层组件(如struts中的action) @Repository 持久层组件，用于标注数据访问组件，即DAO组件 @Component 泛指组件，当组件不好归类的时候，可使用这个注解进行标注 实现属性的自动装配 @Autowired : 按类的类型进行装配 @Resource (推荐) 不用写setter方法，该注解是属于J2EE的，减少与spring的耦合 如果同时指定了name和type，则从spring上下文中找到唯一匹配的bean进行装配，找不到则抛出异常 如果指定了name，则从上下文中查找名称（id）匹配的bean进行装配，找不到则抛出异常 如果指定了type，则从上下文中找到类型匹配的唯一bean进行装配，找不到或者找到多个，都会抛出异常 如果既没有指定name，又没有指定type，则自动按照byName方式进行装配；如果没有匹配，则回退为一个原始类型进行匹配，如果匹配则自动装配； 语法技巧 // 将sourceObj的属性拷贝给targetObj BeanUtils.copyProperties(sourceObj, targetObj); 注解关系图 ","permalink":"http://bug1024.com/2017/03/13/spring-annotation/","summary":"\u003ch2 id=\"spring简介\"\u003eSpring简介\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e最基本的功能就是创建对象及管理这些对象之间的依赖关系，实现高内聚低耦合\u003c/li\u003e\n\u003cli\u003e方便集成第三方框架与组件\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"spring启动\"\u003eSpring启动\u003c/h2\u003e\n\u003cp\u003e启动过程其实就是其IoC容器的启动过程，即建立上下文的过程\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e org.springframework.context.support.ClassPathXmlApplicationContext;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e// 初始化Spring应用\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eSpringStart\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003estatic\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003evoid\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emain\u003c/span\u003e(String\u003cspan style=\"color:#f92672\"\u003e[]\u003c/span\u003e args) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e// 加载指定的Spring配置文件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            ClassPathXmlApplicationContext context \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003enew\u003c/span\u003e ClassPathXmlApplicationContext(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;classpath:/META-INF/spring/applicationContext.xml\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            context.\u003cspan style=\"color:#a6e22e\"\u003estart\u003c/span\u003e();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e// 保证服务一直开着，利用输入流的阻塞来模拟\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            System.\u003cspan style=\"color:#a6e22e\"\u003ein\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003eread\u003c/span\u003e();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"spring配置文件\"\u003eSpring配置文件\u003c/h2\u003e\n\u003cp\u003e配置文件通常命名为applicationContext.xml，一般会包含自动扫描包路径、jdbc、dataSource、mybatis等配置\u003c/p\u003e","title":"Spring框架不完全指南"},{"content":"多个事务并发执行带来的问题 丢失更新：两个事务同时更新一行数据，最后一个事务的更新会覆盖掉第一个事务的更新，从而导致第一个事务更新的数据丢失，这是由于没有加锁造成的； 脏读：一个事务看到了另一个事务未提交的更新数据； 不可重复读：在同一事务中，多次读取同一数据却返回不同的结果，也就是有其他事务更改了这些数据； 幻读：一个事务在执行过程中读取到了另一个事务已提交的插入数据，即在第一个事务开始时读取到一批数据，但此后另一个事务又插入了新数据并提交，此时第一个事务又读取这批数据但发现多了一条，即好像发生幻觉一样。 不可重复读的重点是修改，同样的条件, 你读取过的数据, 再次读取出来发现值不一样了；幻读的重点是新增和删除，同样的条件, 第1次和第2次读出来的记录数不一样\n通过数据库隔离级别来解决这些并发问题 未提交读（Read Uncommitted）：最低隔离级别，一个事务能读取到别的事务未提交的更新数据，很不安全，可能出现丢失更新、脏读、不可重复读、幻读； 提交读（Read Committed）：一个事务能读取到别的事务提交的更新数据，不能看到未提交的更新数据，不可能出现丢失更新、脏读，但可能出现不可重复读、幻读； 可重复读（Repeatable Read）：保证同一事务中先后执行的多次查询将返回同一结果，不受其他事务影响，不可能出现丢失更新、脏读、不可重复读，但可能出现幻读； 序列化（Serializable）：最高隔离级别，不允许事务并发执行，而必须串行化执行，最安全，不可能出现更新、脏读、不可重复读、幻读。 隔离级别越高，数据库事务并发执行性能越差，能处理的操作越少。实际项目开发中一般使用提交读隔离级别，它能避免丢失更新和脏读，尽管不可重复读和幻读不能避免，但可以在可能出现的场合使用悲观锁或乐观锁来解决这些问题。\n","permalink":"http://bug1024.com/2017/03/13/mysql-transaction/","summary":"\u003ch2 id=\"多个事务并发执行带来的问题\"\u003e多个事务并发执行带来的问题\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e丢失更新：两个事务同时更新一行数据，最后一个事务的更新会覆盖掉第一个事务的更新，从而导致第一个事务更新的数据丢失，这是由于没有加锁造成的；\u003c/li\u003e\n\u003cli\u003e脏读：一个事务看到了另一个事务未提交的更新数据；\u003c/li\u003e\n\u003cli\u003e不可重复读：在同一事务中，多次读取同一数据却返回不同的结果，也就是有其他事务更改了这些数据；\u003c/li\u003e\n\u003cli\u003e幻读：一个事务在执行过程中读取到了另一个事务已提交的插入数据，即在第一个事务开始时读取到一批数据，但此后另一个事务又插入了新数据并提交，此时第一个事务又读取这批数据但发现多了一条，即好像发生幻觉一样。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e不可重复读的重点是修改，同样的条件, 你读取过的数据, 再次读取出来发现值不一样了；幻读的重点是新增和删除，同样的条件, 第1次和第2次读出来的记录数不一样\u003c/p\u003e","title":"事务"},{"content":"文件结构 src ├── main │ ├── java │ │ └── com │ │ └── demo │ │ ├── dao │ │ │ └── UserDao.java │ │ └── entity │ │ └── UserEntity.java │ └── resources │ ├── jdbc.properties │ ├── mapper │ │ └── User.xml │ ├── mybatis-config.xml │ └── spring │ └── spring-dao.xml pom.xml中引入依赖 \u0026lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;UTF-8\u0026#34;?\u0026gt; \u0026lt;project xmlns=\u0026#34;http://maven.apache.org/POM/4.0.0\u0026#34; xmlns:xsi=\u0026#34;http://www.w3.org/2001/XMLSchema-instance\u0026#34; xsi:schemaLocation=\u0026#34;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\u0026#34;\u0026gt; \u0026lt;modelVersion\u0026gt;4.0.0\u0026lt;/modelVersion\u0026gt; \u0026lt;groupId\u0026gt;my-java-demo\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;mybatis\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;1.0-SNAPSHOT\u0026lt;/version\u0026gt; \u0026lt;dependencies\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;!--3.0的junit是使用编程的方式来进行测试，而junit4是使用注解的方式来运行junit--\u0026gt; \u0026lt;groupId\u0026gt;junit\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;junit\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;4.11\u0026lt;/version\u0026gt; \u0026lt;scope\u0026gt;test\u0026lt;/scope\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;!--1.数据库相关依赖--\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;mysql\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;mysql-connector-java\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;5.1.35\u0026lt;/version\u0026gt; \u0026lt;scope\u0026gt;runtime\u0026lt;/scope\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;c3p0\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;c3p0\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;0.9.1.1\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;!--2.dao框架:MyBatis依赖--\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.mybatis\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;mybatis\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;3.3.0\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;!--mybatis自身实现的spring整合依赖--\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.mybatis\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;mybatis-spring\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;1.2.3\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;!--4:spring依赖--\u0026gt; \u0026lt;!--1)spring核心依赖--\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-core\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;4.1.7.RELEASE\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-beans\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;4.1.7.RELEASE\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-context\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;4.1.7.RELEASE\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;!--2)spring dao层依赖--\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-jdbc\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;4.1.7.RELEASE\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-tx\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;4.1.7.RELEASE\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;!--3)springweb相关依赖--\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-web\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;4.1.7.RELEASE\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-webmvc\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;4.1.7.RELEASE\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;!--4)spring test相关依赖--\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.springframework\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;spring-test\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;4.1.7.RELEASE\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;/dependencies\u0026gt; \u0026lt;/project\u0026gt; 配置mybatis-config.xml \u0026lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;UTF-8\u0026#34;?\u0026gt; \u0026lt;!DOCTYPE configuration PUBLIC \u0026#34;-//mybatis.org//DTD Config 3.0//EN\u0026#34; \u0026#34;http://mybatis.org/dtd/mybatis-3-config.dtd\u0026#34;\u0026gt; \u0026lt;configuration\u0026gt; \u0026lt;settings\u0026gt; \u0026lt;setting name=\u0026#34;cacheEnabled\u0026#34; value=\u0026#34;false\u0026#34; /\u0026gt; \u0026lt;setting name=\u0026#34;localCacheScope\u0026#34; value=\u0026#34;STATEMENT\u0026#34; /\u0026gt; \u0026lt;setting name=\u0026#34;mapUnderscoreToCamelCase\u0026#34; value=\u0026#34;true\u0026#34; /\u0026gt; \u0026lt;setting name=\u0026#34;useGeneratedKeys\u0026#34; value=\u0026#34;true\u0026#34; /\u0026gt; \u0026lt;setting name=\u0026#34;defaultStatementTimeout\u0026#34; value=\u0026#34;1\u0026#34; /\u0026gt; \u0026lt;/settings\u0026gt; \u0026lt;/configuration\u0026gt; 配置jdbc.properties driver=com.mysql.jdbc.Driver url=jdbc:mysql://127.0.0.1:3306/develop?setUnicode=true\u0026amp;characterEncoding=utf8 username=root password= 编写dao接口和entity类 dao接口可不用实现 entity类中只需要添加属性以及getter和setter即可 添加mapper 在resource中添加dao对应的mapper，mapper中写sql语句 添加spirng-dao.xml 将spring和mybatis整合起来需要一个配置文件 \u0026lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;UTF-8\u0026#34;?\u0026gt; \u0026lt;beans xmlns=\u0026#34;http://www.springframework.org/schema/beans\u0026#34; xmlns:xsi=\u0026#34;http://www.w3.org/2001/XMLSchema-instance\u0026#34; xmlns:context=\u0026#34;http://www.springframework.org/schema/context\u0026#34; xsi:schemaLocation=\u0026#34;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd\u0026#34;\u0026gt; \u0026lt;!--配置整合mybatis过程 1.配置数据库相关参数--\u0026gt; \u0026lt;context:property-placeholder location=\u0026#34;classpath:jdbc.properties\u0026#34;/\u0026gt; \u0026lt;!--2.数据库连接池--\u0026gt; \u0026lt;bean id=\u0026#34;dataSource\u0026#34; class=\u0026#34;com.mchange.v2.c3p0.ComboPooledDataSource\u0026#34;\u0026gt; \u0026lt;!--配置连接池属性--\u0026gt; \u0026lt;property name=\u0026#34;driverClass\u0026#34; value=\u0026#34;${driver}\u0026#34; /\u0026gt; \u0026lt;!-- 基本属性 url、user、password --\u0026gt; \u0026lt;property name=\u0026#34;jdbcUrl\u0026#34; value=\u0026#34;${url}\u0026#34; /\u0026gt; \u0026lt;property name=\u0026#34;user\u0026#34; value=\u0026#34;${username}\u0026#34; /\u0026gt; \u0026lt;property name=\u0026#34;password\u0026#34; value=\u0026#34;${password}\u0026#34; /\u0026gt; \u0026lt;!--c3p0私有属性--\u0026gt; \u0026lt;property name=\u0026#34;maxPoolSize\u0026#34; value=\u0026#34;30\u0026#34;/\u0026gt; \u0026lt;property name=\u0026#34;minPoolSize\u0026#34; value=\u0026#34;10\u0026#34;/\u0026gt; \u0026lt;!--关闭连接后不自动commit--\u0026gt; \u0026lt;property name=\u0026#34;autoCommitOnClose\u0026#34; value=\u0026#34;false\u0026#34;/\u0026gt; \u0026lt;!--获取连接超时时间--\u0026gt; \u0026lt;property name=\u0026#34;checkoutTimeout\u0026#34; value=\u0026#34;1000\u0026#34;/\u0026gt; \u0026lt;!--当获取连接失败重试次数--\u0026gt; \u0026lt;property name=\u0026#34;acquireRetryAttempts\u0026#34; value=\u0026#34;2\u0026#34;/\u0026gt; \u0026lt;/bean\u0026gt; \u0026lt;!--约定大于配置--\u0026gt; \u0026lt;!--３.配置SqlSessionFactory对象--\u0026gt; \u0026lt;bean id=\u0026#34;sqlSessionFactory\u0026#34; class=\u0026#34;org.mybatis.spring.SqlSessionFactoryBean\u0026#34;\u0026gt; \u0026lt;!--往下才是mybatis和spring真正整合的配置--\u0026gt; \u0026lt;!--注入数据库连接池--\u0026gt; \u0026lt;property name=\u0026#34;dataSource\u0026#34; ref=\u0026#34;dataSource\u0026#34;/\u0026gt; \u0026lt;!--配置mybatis全局配置文件:mybatis-config.xml--\u0026gt; \u0026lt;property name=\u0026#34;configLocation\u0026#34; value=\u0026#34;classpath:mybatis-config.xml\u0026#34;/\u0026gt; \u0026lt;!--扫描entity包,使用别名,多个用;隔开--\u0026gt; \u0026lt;property name=\u0026#34;typeAliasesPackage\u0026#34; value=\u0026#34;com.demo.entity\u0026#34;/\u0026gt; \u0026lt;!--扫描sql配置文件:mapper需要的xml文件--\u0026gt; \u0026lt;property name=\u0026#34;mapperLocations\u0026#34; value=\u0026#34;classpath:mapper/*.xml\u0026#34;/\u0026gt; \u0026lt;/bean\u0026gt; \u0026lt;!--４:配置扫描Dao接口包,动态实现DAO接口,注入到spring容器--\u0026gt; \u0026lt;bean class=\u0026#34;org.mybatis.spring.mapper.MapperScannerConfigurer\u0026#34;\u0026gt; \u0026lt;!--注入SqlSessionFactory--\u0026gt; \u0026lt;property name=\u0026#34;sqlSessionFactoryBeanName\u0026#34; value=\u0026#34;sqlSessionFactory\u0026#34;/\u0026gt; \u0026lt;!-- 给出需要扫描的Dao接口--\u0026gt; \u0026lt;property name=\u0026#34;basePackage\u0026#34; value=\u0026#34;com.demo.dao\u0026#34;/\u0026gt; \u0026lt;/bean\u0026gt; \u0026lt;/beans\u0026gt; 批量插入返回自增id 版本3.3.1之后才支持, 入参的集合名称必须叫collection、list、array\nint batchInsert(List\u0026lt;Area\u0026gt; list); mapper.xml\n\u0026lt;insert id=\u0026#34;batchInsert\u0026#34; useGeneratedKeys=\u0026#34;true\u0026#34; keyProperty=\u0026#34;id\u0026#34;\u0026gt; INSERT INTO account (province, city) VALUES \u0026lt;foreach collection=\u0026#34;list\u0026#34; item=\u0026#34;area\u0026#34; separator=\u0026#34;,\u0026#34;\u0026gt; (#{area.province},#{area.city}) \u0026lt;/foreach\u0026gt; \u0026lt;/insert\u0026gt; ","permalink":"http://bug1024.com/2017/03/12/mybatis-demo/","summary":"\u003ch2 id=\"文件结构\"\u003e文件结构\u003c/h2\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e    src\n    ├── main\n    │   ├── java\n    │   │   └── com\n    │   │       └── demo\n    │   │           ├── dao\n    │   │           │   └── UserDao.java\n    │   │           └── entity\n    │   │               └── UserEntity.java\n    │   └── resources\n    │       ├── jdbc.properties\n    │       ├── mapper\n    │       │   └── User.xml\n    │       ├── mybatis-config.xml\n    │       └── spring\n    │           └── spring-dao.xml\n\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"pomxml中引入依赖\"\u003epom.xml中引入依赖\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-xml\" data-lang=\"xml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e\u0026lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;UTF-8\u0026#34;?\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003e\u0026lt;project\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003exmlns=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;http://maven.apache.org/POM/4.0.0\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e             \u003cspan style=\"color:#a6e22e\"\u003exmlns:xsi=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;http://www.w3.org/2001/XMLSchema-instance\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e             \u003cspan style=\"color:#a6e22e\"\u003exsi:schemaLocation=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026lt;modelVersion\u0026gt;\u003c/span\u003e4.0.0\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/modelVersion\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026lt;groupId\u0026gt;\u003c/span\u003emy-java-demo\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/groupId\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026lt;artifactId\u0026gt;\u003c/span\u003emybatis\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/artifactId\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026lt;version\u0026gt;\u003c/span\u003e1.0-SNAPSHOT\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/version\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026lt;dependencies\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;dependency\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#75715e\"\u003e\u0026lt;!--3.0的junit是使用编程的方式来进行测试，而junit4是使用注解的方式来运行junit--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;groupId\u0026gt;\u003c/span\u003ejunit\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/groupId\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;artifactId\u0026gt;\u003c/span\u003ejunit\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/artifactId\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;version\u0026gt;\u003c/span\u003e4.11\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/version\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;scope\u0026gt;\u003c/span\u003etest\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/scope\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;/dependency\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e\u0026lt;!--1.数据库相关依赖--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;dependency\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;groupId\u0026gt;\u003c/span\u003emysql\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/groupId\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;artifactId\u0026gt;\u003c/span\u003emysql-connector-java\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/artifactId\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;version\u0026gt;\u003c/span\u003e5.1.35\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/version\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;scope\u0026gt;\u003c/span\u003eruntime\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/scope\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;/dependency\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;dependency\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;groupId\u0026gt;\u003c/span\u003ec3p0\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/groupId\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;artifactId\u0026gt;\u003c/span\u003ec3p0\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/artifactId\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;version\u0026gt;\u003c/span\u003e0.9.1.1\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/version\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;/dependency\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e\u0026lt;!--2.dao框架:MyBatis依赖--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;dependency\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;groupId\u0026gt;\u003c/span\u003eorg.mybatis\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/groupId\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;artifactId\u0026gt;\u003c/span\u003emybatis\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/artifactId\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;version\u0026gt;\u003c/span\u003e3.3.0\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/version\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;/dependency\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e\u0026lt;!--mybatis自身实现的spring整合依赖--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;dependency\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;groupId\u0026gt;\u003c/span\u003eorg.mybatis\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/groupId\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;artifactId\u0026gt;\u003c/span\u003emybatis-spring\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/artifactId\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;version\u0026gt;\u003c/span\u003e1.2.3\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/version\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;/dependency\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e\u0026lt;!--4:spring依赖--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e\u0026lt;!--1)spring核心依赖--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;dependency\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;groupId\u0026gt;\u003c/span\u003eorg.springframework\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/groupId\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;artifactId\u0026gt;\u003c/span\u003espring-core\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/artifactId\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;version\u0026gt;\u003c/span\u003e4.1.7.RELEASE\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/version\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;/dependency\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;dependency\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;groupId\u0026gt;\u003c/span\u003eorg.springframework\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/groupId\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;artifactId\u0026gt;\u003c/span\u003espring-beans\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/artifactId\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;version\u0026gt;\u003c/span\u003e4.1.7.RELEASE\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/version\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;/dependency\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;dependency\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;groupId\u0026gt;\u003c/span\u003eorg.springframework\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/groupId\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;artifactId\u0026gt;\u003c/span\u003espring-context\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/artifactId\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;version\u0026gt;\u003c/span\u003e4.1.7.RELEASE\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/version\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;/dependency\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e\u0026lt;!--2)spring dao层依赖--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;dependency\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;groupId\u0026gt;\u003c/span\u003eorg.springframework\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/groupId\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;artifactId\u0026gt;\u003c/span\u003espring-jdbc\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/artifactId\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;version\u0026gt;\u003c/span\u003e4.1.7.RELEASE\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/version\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;/dependency\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;dependency\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;groupId\u0026gt;\u003c/span\u003eorg.springframework\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/groupId\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;artifactId\u0026gt;\u003c/span\u003espring-tx\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/artifactId\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;version\u0026gt;\u003c/span\u003e4.1.7.RELEASE\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/version\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;/dependency\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e\u0026lt;!--3)springweb相关依赖--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;dependency\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;groupId\u0026gt;\u003c/span\u003eorg.springframework\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/groupId\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;artifactId\u0026gt;\u003c/span\u003espring-web\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/artifactId\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;version\u0026gt;\u003c/span\u003e4.1.7.RELEASE\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/version\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;/dependency\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;dependency\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;groupId\u0026gt;\u003c/span\u003eorg.springframework\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/groupId\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;artifactId\u0026gt;\u003c/span\u003espring-webmvc\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/artifactId\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;version\u0026gt;\u003c/span\u003e4.1.7.RELEASE\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/version\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;/dependency\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e\u0026lt;!--4)spring test相关依赖--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;dependency\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;groupId\u0026gt;\u003c/span\u003eorg.springframework\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/groupId\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;artifactId\u0026gt;\u003c/span\u003espring-test\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/artifactId\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#f92672\"\u003e\u0026lt;version\u0026gt;\u003c/span\u003e4.1.7.RELEASE\u003cspan style=\"color:#f92672\"\u003e\u0026lt;/version\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;/dependency\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026lt;/dependencies\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003e\u0026lt;/project\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"配置mybatis-configxml\"\u003e配置mybatis-config.xml\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-xml\" data-lang=\"xml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e\u0026lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;UTF-8\u0026#34;?\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e\u0026lt;!DOCTYPE configuration\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e            PUBLIC \u0026#34;-//mybatis.org//DTD Config 3.0//EN\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e            \u0026#34;http://mybatis.org/dtd/mybatis-3-config.dtd\u0026#34;\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003e\u0026lt;configuration\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026lt;settings\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;setting\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ename=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;cacheEnabled\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evalue=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;false\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;setting\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ename=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;localCacheScope\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evalue=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;STATEMENT\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;setting\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ename=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;mapUnderscoreToCamelCase\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evalue=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;true\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;setting\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ename=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;useGeneratedKeys\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evalue=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;true\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;setting\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ename=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;defaultStatementTimeout\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evalue=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;1\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026lt;/settings\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003e\u0026lt;/configuration\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"配置jdbcproperties\"\u003e配置jdbc.properties\u003c/h2\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e    driver=com.mysql.jdbc.Driver\n    url=jdbc:mysql://127.0.0.1:3306/develop?setUnicode=true\u0026amp;characterEncoding=utf8\n    username=root\n    password=\n\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"编写dao接口和entity类\"\u003e编写dao接口和entity类\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003edao接口可不用实现\u003c/li\u003e\n\u003cli\u003eentity类中只需要添加属性以及getter和setter即可\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"添加mapper\"\u003e添加mapper\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e在resource中添加dao对应的mapper，mapper中写sql语句\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"添加spirng-daoxml\"\u003e添加spirng-dao.xml\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e将spring和mybatis整合起来需要一个配置文件\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-xml\" data-lang=\"xml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e\u0026lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;UTF-8\u0026#34;?\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003e\u0026lt;beans\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003exmlns=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;http://www.springframework.org/schema/beans\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           \u003cspan style=\"color:#a6e22e\"\u003exmlns:xsi=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;http://www.w3.org/2001/XMLSchema-instance\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           \u003cspan style=\"color:#a6e22e\"\u003exmlns:context=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;http://www.springframework.org/schema/context\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e           \u003cspan style=\"color:#a6e22e\"\u003exsi:schemaLocation=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;http://www.springframework.org/schema/beans\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e            http://www.springframework.org/schema/beans/spring-beans.xsd\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e\u0026lt;!--配置整合mybatis过程\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e        1.配置数据库相关参数--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026lt;context:property-placeholder\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003elocation=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;classpath:jdbc.properties\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e\u0026lt;!--2.数据库连接池--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026lt;bean\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eid=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;dataSource\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eclass=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;com.mchange.v2.c3p0.ComboPooledDataSource\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e\u0026lt;!--配置连接池属性--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;property\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ename=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;driverClass\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evalue=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;${driver}\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e\u0026lt;!-- 基本属性 url、user、password --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;property\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ename=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;jdbcUrl\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evalue=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;${url}\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;property\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ename=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;user\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evalue=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;${username}\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;property\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ename=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;password\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evalue=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;${password}\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e\u0026lt;!--c3p0私有属性--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;property\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ename=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;maxPoolSize\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evalue=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;30\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;property\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ename=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;minPoolSize\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evalue=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;10\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e\u0026lt;!--关闭连接后不自动commit--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;property\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ename=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;autoCommitOnClose\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evalue=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;false\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e\u0026lt;!--获取连接超时时间--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;property\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ename=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;checkoutTimeout\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evalue=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;1000\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e\u0026lt;!--当获取连接失败重试次数--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;property\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ename=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;acquireRetryAttempts\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evalue=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;2\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026lt;/bean\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e\u0026lt;!--约定大于配置--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e\u0026lt;!--３.配置SqlSessionFactory对象--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026lt;bean\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eid=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;sqlSessionFactory\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eclass=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;org.mybatis.spring.SqlSessionFactoryBean\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e\u0026lt;!--往下才是mybatis和spring真正整合的配置--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e\u0026lt;!--注入数据库连接池--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;property\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ename=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;dataSource\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eref=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;dataSource\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e\u0026lt;!--配置mybatis全局配置文件:mybatis-config.xml--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;property\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ename=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;configLocation\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evalue=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;classpath:mybatis-config.xml\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e\u0026lt;!--扫描entity包,使用别名,多个用;隔开--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;property\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ename=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;typeAliasesPackage\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evalue=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;com.demo.entity\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e\u0026lt;!--扫描sql配置文件:mapper需要的xml文件--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;property\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ename=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;mapperLocations\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evalue=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;classpath:mapper/*.xml\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026lt;/bean\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e\u0026lt;!--４:配置扫描Dao接口包,动态实现DAO接口,注入到spring容器--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026lt;bean\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eclass=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;org.mybatis.spring.mapper.MapperScannerConfigurer\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e\u0026lt;!--注入SqlSessionFactory--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;property\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ename=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;sqlSessionFactoryBeanName\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evalue=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;sqlSessionFactory\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#75715e\"\u003e\u0026lt;!-- 给出需要扫描的Dao接口--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#f92672\"\u003e\u0026lt;property\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ename=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;basePackage\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003evalue=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;com.demo.dao\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003e\u0026lt;/bean\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003e\u0026lt;/beans\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"批量插入返回自增id\"\u003e批量插入返回自增id\u003c/h2\u003e\n\u003cp\u003e版本3.3.1之后才支持, 入参的集合名称必须叫collection、list、array\u003c/p\u003e","title":"Mybatis"},{"content":" PHP果然是最好的语言\nmaven Apache Maven is a software project management and comprehension tool. Based on the concept of a project object model (POM), Maven can manage a project\u0026rsquo;s build, reporting and documentation from a central piece of information.\nLifecycle validate： 用于验证项目的有效性和其项目所需要的内容是否具备 initialize：初始化操作，比如创建一些构建所需要的目录等。 generate-sources：用于生成一些源代码，这些源代码在compile phase中需要使用到 process-sources：对源代码进行一些操作，例如过滤一些源代码 generate-resources：生成资源文件（这些文件将被包含在最后的输入文件中） process-resources：对资源文件进行处理 compile：对源代码进行编译 process-classes：对编译生成的文件进行处理 generate-test-sources：生成测试用的源代码 process-test-sources：对生成的测试源代码进行处理 generate-test-resources：生成测试用的资源文件 process-test-resources：对测试用的资源文件进行处理 test-compile：对测试用的源代码进行编译 process-test-classes：对测试源代码编译后的文件进行处理 test：进行单元测试 prepare-package：打包前置操作 package：打包 pre-integration-test：集成测试前置操作 integration-test：集成测试 post-integration-test：集成测试后置操作 install：将打包产物安装到本地maven仓库 deploy：将打包产物安装到远程仓库 在maven中，你执行任何一个phase时，maven会将其之前的phase都执行。例如 mvn install，那么maven会将deploy之外的所有phase按照他们出现的顺序一次执行。\n打包发布 jar包发布 JavaTM Archive (JAR) file 即java存档文件 开发时要引用通用类，打成包便于存放管理 安全，快速下载，压缩，猎取包，版本化包，可携 JAR文件的格式是ZIP格式的, 因此它可以用各种能够处理ZIP文件的工具来进行操作 war包发布 做好一个web应用后，通常是网站，打成包部署到容器中 在tomcat中我们就不能再用jar这种格式，而改war格式，它是专门用于web应用的 装箱和拆箱 自动装箱就是将原始类型自动的转换为对应的对象，而拆箱就是将对象类型转换为基本类型\n垃圾回收机制 在Java中，不需要显示的去释放一个对象的内存的，而是由虚拟机自行执行。在JVM中，有一个垃圾回收线程，它是低优先级的，在正常情况下是不会执行的，只有在虚拟机空闲或者当前堆内存不足时，才会触发执行，扫面那些没有被任何引用的对象，并将它们添加到要回收的集合中，进行回收。 垃圾回收算法\n引用计数算法 标记-清扫算法 复制算法 标记-整理算法 分代收集算法 什么样的对象会被回收 不被任何线程或者静态变量引用的对象将被回收，主要分为以下四种情况： 对象被明确设置成null； 对象在区域内创建，并且工作线程已经离开这个区域； 对象的容器对象被设置成null，比如objectRoot引用了一堆object，那么当objectRoot被设置为null的时候，所有被它引用的对象也将被回收； 只被weakhashmap应用的对象； Young GC 新对象创建好了之后，就会被分配在新生代中。一般等到Eden区满了之后会触发YGC。YGC做了以下的事情\n将Eden区的需要回收的对象回收了； 将Eden区内的没有被回收的对象移动到空的Survivor中； 将有数据的Survivor区中的对象回收了； 将有数据的Survivor区中的复合条件的对象移动到空的Survivor中； 将有数据的Survivor区中的复合条件的对象移动到老年代中。 Full GC 一般是老年区满了才会触发FullGC，使用的是Mark-Sweep-Compact的算法：\nMark：对有用的引用进行标记； Sweep：对垃圾进行清理； Compact：对活着的对象进行迁移，挪到一块来，解决内存碎片问题。 HashMap原理 HashMap内部是通过一个数组实现的，只是这个数组比较特殊，数组里存储的元素是一个Entry实体(jdk 8为Node)，这个Entry实体主要包含key、value以及一个指向自身的next指针。HashMap是基于hashing实现的，当我们进行put操作时，根据传递的key值得到它的hashcode，然后再用这个hashcode与数组的长度进行模运算，得到一个int值，就是Entry要存储在数组的位置（下标）；当通过get方法获取指定key的值时，会根据这个key算出它的hash值（数组下标），根据这个hash值获取数组下标对应的Entry，然后判断Entry里的key，hash值或者通过equals()比较是 否与要查找的相同，如果相同，返回value，否则的话，遍历该链表（有可能就只有一个Entry，此时直接返回null），直到找到为止，否则返回null。 HashMap之所以在每个数组元素存储的是一个链表，是为了解决hash冲突问题，当两个对象的hash值相等时，那么一个位置肯定是放不下两个值的，于是hashmap采用链表来解决这种冲突，hash值相等的两个元素会形成一个链表。\n日志级别 TRACE – The TRACE Level designates finer-grained informational events than the DEBUG DEBUG – The DEBUG Level designates fine-grained informational events that are most useful to debug an application. INFO – The INFO level designates informational messages that highlight the progress of the application at coarse-grained level. WARN – The WARN level designates potentially harmful situations. ERROR – The ERROR level designates error events that might still allow the application to continue running. FATAL – The FATAL level designates very severe error events that will presumably lead the application to abort. Nginx/Tomcat 严格的来说，/Nginx 应该叫做HTTP Server，而 Tomcat 则是一个Application Server，或者更准确的来说，是一个Servlet/JSP应用的容器 HTTP Server 关心的是 HTTP 协议层面的传输和访问控制，所以在 Nginx 上你可以看到代理、负载均衡等功能。 客户端通过 HTTP Server 访问服务器上存储的资源（HTML 文件、图片文件等等），通过 CGI 技术，也可以将处理过的内容通过 HTTP Server 分发，但是一个 HTTP Server 始终 只是把服务器上的文件如实的通过 HTTP 协议传输给客户端。 而应用服务器，则是一个应用执行的容器，它首先需要支持开发语言的 Runtime（对于 Tomcat 来说，就是 Java），保证应用能够在应用服务器上正常运行。 其次，需要支持应用相关的规范，例如类库、安全方面的特性。对于 Tomcat 来说，就是需要提供 JSP/Sevlet 运行需要的标准类库、Interface 等。 为了方便，应用服务器往往也会集成 HTTP Server 的功能，但是不如专业的 HTTP Server 那么强大，所以应用服务器往往是运行在 HTTP Server 的背后，执行应用，将动态的内容转化为静态的内容 之后，通过 HTTP Server 分发到客户端。\n什么情况下回出现Full GC，什么情况下会出现Young GC 对象优先在新生代Eden区中分配，如果Eden区没有足够的空间时，就会触发一次young gc Full gc的触发条件有多个，FULL GC的时候会STOP THE WORD。 在执行Young gc之前，JVM会进行空间分配担保——如果老年代的连续空间小于新生代对象的总大小（或历次晋升的平均大小），则触发一次full gc。 显式调用System.gc()方法时； 大对象直接进入老年代，从年轻代晋升上来的老对象，尝试在老年代分配内存时，但是老年代内存空间不够； 关键字 synchronized 使用synchronized关键字会以加锁的方式解决不同步问题 volatile 使用volatile修饰的变量无需使用数据副本进行操作而是直接使用数据，因此不会造成不同步的现象 异常最佳实践 在Finally块中清理资源或者使用try-with-resource语句 指定具体的异常 对异常进行文档说明 抛出异常的时候包含描述信息 首先捕获最具体的异常 不要捕获Throwable 不要忽略异常 不要记录并抛出异常 包装异常时不要抛弃原始的异常 ","permalink":"http://bug1024.com/2017/03/09/php-java/","summary":"\u003cblockquote\u003e\n\u003cp\u003ePHP果然是最好的语言\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"maven\"\u003emaven\u003c/h2\u003e\n\u003cp\u003eApache Maven is a software project management and comprehension tool. Based on the concept of a project object model (POM), Maven can manage a project\u0026rsquo;s build, reporting and documentation from a central piece of information.\u003c/p\u003e\n\u003ch3 id=\"lifecycle\"\u003eLifecycle\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003evalidate： 用于验证项目的有效性和其项目所需要的内容是否具备\u003c/li\u003e\n\u003cli\u003einitialize：初始化操作，比如创建一些构建所需要的目录等。\u003c/li\u003e\n\u003cli\u003egenerate-sources：用于生成一些源代码，这些源代码在compile phase中需要使用到\u003c/li\u003e\n\u003cli\u003eprocess-sources：对源代码进行一些操作，例如过滤一些源代码\u003c/li\u003e\n\u003cli\u003egenerate-resources：生成资源文件（这些文件将被包含在最后的输入文件中）\u003c/li\u003e\n\u003cli\u003eprocess-resources：对资源文件进行处理\u003c/li\u003e\n\u003cli\u003ecompile：对源代码进行编译\u003c/li\u003e\n\u003cli\u003eprocess-classes：对编译生成的文件进行处理\u003c/li\u003e\n\u003cli\u003egenerate-test-sources：生成测试用的源代码\u003c/li\u003e\n\u003cli\u003eprocess-test-sources：对生成的测试源代码进行处理\u003c/li\u003e\n\u003cli\u003egenerate-test-resources：生成测试用的资源文件\u003c/li\u003e\n\u003cli\u003eprocess-test-resources：对测试用的资源文件进行处理\u003c/li\u003e\n\u003cli\u003etest-compile：对测试用的源代码进行编译\u003c/li\u003e\n\u003cli\u003eprocess-test-classes：对测试源代码编译后的文件进行处理\u003c/li\u003e\n\u003cli\u003etest：进行单元测试\u003c/li\u003e\n\u003cli\u003eprepare-package：打包前置操作\u003c/li\u003e\n\u003cli\u003epackage：打包\u003c/li\u003e\n\u003cli\u003epre-integration-test：集成测试前置操作\u003c/li\u003e\n\u003cli\u003eintegration-test：集成测试\u003c/li\u003e\n\u003cli\u003epost-integration-test：集成测试后置操作\u003c/li\u003e\n\u003cli\u003einstall：将打包产物安装到本地maven仓库\u003c/li\u003e\n\u003cli\u003edeploy：将打包产物安装到远程仓库\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e在maven中，你执行任何一个phase时，maven会将其之前的phase都执行。例如 mvn install，那么maven会将deploy之外的所有phase按照他们出现的顺序一次执行。\u003c/p\u003e","title":"Java学习"},{"content":"Apache Hadoop 的一个子项目，基于Java的分布式应用程序协调服务\n使用场景 数据发布与订阅（配置中心） 负载均衡 命名服务 分布式协调 集群管理与Master选举 分布式锁 Server角色 领导者（Leader) : 领导者不接受client的请求，负责进行投票的发起和决议，最终更新状态。 跟随者（Follower）: Follower用于接收客户请求并返回客户结果。参与Leader发起的投票。 观察者（observer）: Oberserver可以接收客户端连接，将写请求转发给leader节点。但是Observer不参加投票过程，只是同步leader的状态。Observer为系统扩展提供了一种方法。 原理 Master选举：针对Master选举的需求，通常情况下，我们可以选择常见的关系型数据库中的主键特性来实现：希望成为Master的机器都向数据库中插入一条相同主键ID的记录，数据库会帮我们进行主键冲突检查 zkClient 生成环境中经常遭遇session expire异常，zkClient解决watcher一次性注册问题，将znode的事件重新定于为子节点的变化，数据的变化，链接即状态的变化三类。\n","permalink":"http://bug1024.com/2017/03/08/zookeeper/","summary":"\u003cp\u003eApache Hadoop 的一个子项目，基于Java的分布式应用程序协调服务\u003c/p\u003e\n\u003ch2 id=\"使用场景\"\u003e使用场景\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e数据发布与订阅（配置中心）\u003c/li\u003e\n\u003cli\u003e负载均衡\u003c/li\u003e\n\u003cli\u003e命名服务\u003c/li\u003e\n\u003cli\u003e分布式协调\u003c/li\u003e\n\u003cli\u003e集群管理与Master选举\u003c/li\u003e\n\u003cli\u003e分布式锁\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"server角色\"\u003eServer角色\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e领导者（Leader) : 领导者不接受client的请求，负责进行投票的发起和决议，最终更新状态。\u003c/li\u003e\n\u003cli\u003e跟随者（Follower）: Follower用于接收客户请求并返回客户结果。参与Leader发起的投票。\u003c/li\u003e\n\u003cli\u003e观察者（observer）: Oberserver可以接收客户端连接，将写请求转发给leader节点。但是Observer不参加投票过程，只是同步leader的状态。Observer为系统扩展提供了一种方法。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"原理\"\u003e原理\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eMaster选举：针对Master选举的需求，通常情况下，我们可以选择常见的关系型数据库中的主键特性来实现：希望成为Master的机器都向数据库中插入一条相同主键ID的记录，数据库会帮我们进行主键冲突检查\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"zkclient\"\u003ezkClient\u003c/h2\u003e\n\u003cp\u003e生成环境中经常遭遇session expire异常，zkClient解决watcher一次性注册问题，将znode的事件重新定于为子节点的变化，数据的变化，链接即状态的变化三类。\u003c/p\u003e","title":"ZooKeeper"},{"content":"深入理解计算机系统、现代操作系统、C程序设计语言、C语言数据结构和算法、Unix环境高级编程、TCP/IP网络通信详解。 学习一下面向对象方面知识，PHP这方面的书不太多，建议看Java面向对象编程、Java编程思想、J2EE这些书。\n编程语言 学习PHP 深入理解PHP内核 完成简单的扩展开发 达到高级水平 学习Java IntelliJ IDEA 快捷键使用 maven pom.xml的使用 spring 注解的使用 mybatis mapper.xml的使用 dubbo rpc框架使用 tomcat原理了解 常用数据结构了解 达到中级水平 学习Go 学习beego框架 了解docker原理 系统学习 MySQL （重点） 索引与性能优化 InnoDB引擎 riplication原理 基础配置与调优 binlog格式了解 Redis （重点） 底层数据结构实现 持久化 集群配置 Nginx （重点） 网络模型 负载均衡 基础配置 Linux性能监控和常见问题排查命令(重点) 进程 线程 网络 (重点) RabbitMQ 组成 direct fanout topic headers场景 持久化 与kafka的比较 ElasticSearch 集群配置 与solr比较 Java客户端使用 HBase 使用场景 ZooKeeper 实现原理 选举算法 项目 检索系统 基于ElasticSearch实现的搜索 done 图片系统 实时切图和分布式存储 done 简易API网关 实现权限校验与限流 一个PHP扩展 done 个人博客 done 2018重点 主动学习很重要，官方文档很重要，实践很重要 巩固Java基础，尤其是线程，并发，jvm等，能熟练使用常用排查工具分析定位线上问题 了解tomcat应用服务器 了解dubbo框架 Linux性能排查，能根据CPU，IO，内存等指标排查问题 MySQL性能优化，巩固索引，连接数，缓冲池，死锁等基础知识 深入理解进程，线程，协程 提升文档能力 英语水平提升 Redis源码阅读 调整心态，明白个体差异，不制定过高的目标 学习Go语言 https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/preface.md 2018详细计划 1月份 学习Spring框架设计理念，以学习《深入分析Java Web技术内幕》中相关章节为主，做到能描绘组成结构图，熟练掌握几大核心组件的功能 学习Java多线程，主要通过网上学习，并实际编码验证，能阐明多线程编程的优缺点，几种创建线程方式的异同以及多线程编程的注意事项 2月份 重新学习常见数据结构与算法，并能熟练写出伪代码，排序算法，子串查找，最长回文子串查找等，主要通过leetcode巩固练习 学习TCP/IP协议，HTTP协议，了解网络传输的基本原理，数据报文格式，长链接与短链接的区别以及应用场景 了解常见序列化协议的优缺点与使用场景 3月份 新工作 了解SpringBoot，搭建项目 熟悉Shiro工作机制 4月份 熟悉netty，源码级了解，读《Netty权威指南》 5月份 熟悉JVM，读《深入理解Java虚拟机》 6月份 深入研究CAT监控系统 7月份 ZooKeeper 8月份 JPA Druid Kafka 9月份 Netty 10月份 Java并发编程 11月份 Tomcat架构 12月份 配置中心 Guava源码 ","permalink":"http://bug1024.com/2017/03/08/2017plan/","summary":"\u003cp\u003e深入理解计算机系统、现代操作系统、C程序设计语言、C语言数据结构和算法、Unix环境高级编程、TCP/IP网络通信详解。\n学习一下面向对象方面知识，PHP这方面的书不太多，建议看Java面向对象编程、Java编程思想、J2EE这些书。\u003c/p\u003e","title":"计划"},{"content":"创建表 CREATE TABLE `user_info` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT \u0026#39;自增id\u0026#39;, `username` int(11) unsigned NOT NULL DEFAULT 0 COMMENT \u0026#39;用户名\u0026#39;, `real_name` varchar(10) NOT NULL DEFAULT \u0026#39;\u0026#39; COMMENT \u0026#39;真实姓名\u0026#39;, `add_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT \u0026#39;创建时间\u0026#39;, `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT \u0026#39;更新时间\u0026#39;, PRIMARY KEY (`id`), UNIQUE KEY `uni_username` (`username`), KEY `idx_add_time` (`add_time`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; 修改表名 alter table user_info rename user; 增加字段 alter table user add column `status` tinyint(2) NOT NULL DEFAULT 0 COMMENT \u0026#39;状态\u0026#39;; 修改字段属性 alter table user modify column `real_name` varchar(50) NOT NULL DEFAULT \u0026#39;\u0026#39; COMMENT \u0026#39;真实姓名\u0026#39;; 修改字段名 alter table user change column add_time create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT \u0026#39;创建时间\u0026#39;; 修改索引 -- 增加索引 alter table user add index idx_update_time (update_time) ; -- 增加唯一索引 alter table user add unique (column_list) ; -- 增加主键 alter table user add primary key (column_list) ; -- 删除索引 alter table user drop index idx_update_time; -- 删除主键 alter table user drop primary key; 批量插入 insert into user (username, create_time, status) values(10000, \u0026#39;2017-03-01 12:12:12\u0026#39;, 1), (10001, \u0026#39;2017-03-01 12:13:14\u0026#39;, 1); 批量更新 UPDATE user SET username = CASE id WHEN 1 THEN 3 WHEN 2 THEN 4 WHEN 3 THEN 5 ELSE username END, status = CASE id WHEN 3 THEN 3 WHEN 4 THEN 4 ELSE status END WHERE id IN (1, 2, 3, 4); 批量插入若存在则更新 insert into user (username, create_time, status) values(10002, \u0026#39;2017-03-01 12:12:12\u0026#39;, 1), (10001, \u0026#39;2017-03-01 12:13:14\u0026#39;, 2) on duplicate key update status = values(status); 导入导出 -- 导出某个库 mysqldump -uroot -proot db_name \u0026gt; db_name.sql -- 导出某张表 mysqldump -uroot -proot db_name table_name \u0026gt; table_name.sql -- 导出数据库所有表结构 mysqldump -uroot -proot db_name -d --add-drop-table db_name \u0026gt; db.sql -- 导入 mysqldump -uroot -proot \u0026lt; import.sql -- 使用source方式导入，source import.sql 强制使用索引 select username from user force index(idx_update_time) where update_time \u0026gt; \u0026#39;2017-01-01 10:10:11\u0026#39; join语句 INNER JOIN（内连接或等值连接）：产生同时符合左表和右表的记录。 LEFT JOIN（左连接）：左连接从左表产生一套完整的记录，与匹配的记录(右表) ，如果没有匹配，右侧将包含null。 RIGHT JOIN（右连接）：与LEFT JOIN相反 mysql不支持Full join，不过可以通过UNION 关键字来合并 LEFT JOIN 与 RIGHT JOIN来模拟FULL join. 执行顺序 FORM: 对FROM的左边的表和右边的表计算笛卡尔积。产生虚表VT1 ON: 对虚表VT1进行ON筛选，只有那些符合的行才会被记录在虚表VT2中。 JOIN： 如果指定了OUTER JOIN（比如left join、 right join），那么保留表中未匹配的行就会作为外部行添加到虚拟表VT2中，产生虚拟表VT3, rug from子句中包含两个以上的表的话，那么就会对上一个join连接产生的结果VT3和下一个表重复执行步骤1~3这三个步骤，一直到处理完所有的表为止。 WHERE： 对虚拟表VT3进行WHERE条件过滤。只有符合的记录才会被插入到虚拟表VT4中。 GROUP BY: 根据group by子句中的列，对VT4中的记录进行分组操作，产生VT5. CUBE | ROLLUP: 对表VT5进行cube或者rollup操作，产生表VT6. HAVING： 对虚拟表VT6应用having过滤，只有符合的记录才会被 插入到虚拟表VT7中。 SELECT： 执行select操作，选择指定的列，插入到虚拟表VT8中。 DISTINCT： 对VT8中的记录进行去重。产生虚拟表VT9. ORDER BY: 将虚拟表VT9中的记录按照\u0026lt;order_by_list\u0026gt;进行排序操作，产生虚拟表VT10. LIMIT：取出指定行的记录，产生虚拟表VT11, 并将结果返回。 ","permalink":"http://bug1024.com/2017/03/07/mysql-cheat-sheet/","summary":"\u003ch2 id=\"创建表\"\u003e创建表\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eCREATE\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eTABLE\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e`\u003c/span\u003euser_info\u003cspan style=\"color:#f92672\"\u003e`\u003c/span\u003e (\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e`\u003c/span\u003eid\u003cspan style=\"color:#f92672\"\u003e`\u003c/span\u003e int(\u003cspan style=\"color:#ae81ff\"\u003e11\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eNOT\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNULL\u003c/span\u003e AUTO_INCREMENT \u003cspan style=\"color:#66d9ef\"\u003eCOMMENT\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;自增id\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e`\u003c/span\u003eusername\u003cspan style=\"color:#f92672\"\u003e`\u003c/span\u003e int(\u003cspan style=\"color:#ae81ff\"\u003e11\u003c/span\u003e) unsigned \u003cspan style=\"color:#66d9ef\"\u003eNOT\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNULL\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eDEFAULT\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eCOMMENT\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;用户名\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e`\u003c/span\u003ereal_name\u003cspan style=\"color:#f92672\"\u003e`\u003c/span\u003e varchar(\u003cspan style=\"color:#ae81ff\"\u003e10\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eNOT\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNULL\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eDEFAULT\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eCOMMENT\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;真实姓名\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e`\u003c/span\u003eadd_time\u003cspan style=\"color:#f92672\"\u003e`\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003etimestamp\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNOT\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNULL\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eDEFAULT\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eCURRENT_TIMESTAMP\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eCOMMENT\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;创建时间\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#f92672\"\u003e`\u003c/span\u003eupdate_time\u003cspan style=\"color:#f92672\"\u003e`\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003etimestamp\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNOT\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNULL\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eDEFAULT\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eCURRENT_TIMESTAMP\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eON\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eUPDATE\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eCURRENT_TIMESTAMP\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eCOMMENT\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;更新时间\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#66d9ef\"\u003ePRIMARY\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eKEY\u003c/span\u003e (\u003cspan style=\"color:#f92672\"\u003e`\u003c/span\u003eid\u003cspan style=\"color:#f92672\"\u003e`\u003c/span\u003e),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#66d9ef\"\u003eUNIQUE\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eKEY\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e`\u003c/span\u003euni_username\u003cspan style=\"color:#f92672\"\u003e`\u003c/span\u003e (\u003cspan style=\"color:#f92672\"\u003e`\u003c/span\u003eusername\u003cspan style=\"color:#f92672\"\u003e`\u003c/span\u003e),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#66d9ef\"\u003eKEY\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e`\u003c/span\u003eidx_add_time\u003cspan style=\"color:#f92672\"\u003e`\u003c/span\u003e (\u003cspan style=\"color:#f92672\"\u003e`\u003c/span\u003eadd_time\u003cspan style=\"color:#f92672\"\u003e`\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ) ENGINE\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003eInnoDB AUTO_INCREMENT\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eDEFAULT\u003c/span\u003e CHARSET\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003eutf8;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"修改表名\"\u003e修改表名\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ealter\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003etable\u003c/span\u003e user_info \u003cspan style=\"color:#66d9ef\"\u003erename\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003euser\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"增加字段\"\u003e增加字段\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ealter\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003etable\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003euser\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eadd\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003ecolumn\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e`\u003c/span\u003estatus\u003cspan style=\"color:#f92672\"\u003e`\u003c/span\u003e tinyint(\u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eNOT\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNULL\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eDEFAULT\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eCOMMENT\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;状态\u0026#39;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"修改字段属性\"\u003e修改字段属性\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ealter\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003etable\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003euser\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003emodify\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003ecolumn\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e`\u003c/span\u003ereal_name\u003cspan style=\"color:#f92672\"\u003e`\u003c/span\u003e varchar(\u003cspan style=\"color:#ae81ff\"\u003e50\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eNOT\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNULL\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eDEFAULT\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eCOMMENT\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;真实姓名\u0026#39;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"修改字段名\"\u003e修改字段名\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ealter\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003etable\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003euser\u003c/span\u003e change \u003cspan style=\"color:#66d9ef\"\u003ecolumn\u003c/span\u003e add_time create_time \u003cspan style=\"color:#66d9ef\"\u003etimestamp\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNOT\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNULL\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eDEFAULT\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eCURRENT_TIMESTAMP\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eCOMMENT\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;创建时间\u0026#39;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"修改索引\"\u003e修改索引\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e-- 增加索引\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ealter\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003etable\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003euser\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eadd\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eindex\u003c/span\u003e idx_update_time (update_time) ;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e-- 增加唯一索引\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ealter\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003etable\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003euser\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eadd\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eunique\u003c/span\u003e (column_list) ;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e-- 增加主键\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ealter\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003etable\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003euser\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eadd\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eprimary\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003ekey\u003c/span\u003e (column_list) ;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e-- 删除索引\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ealter\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003etable\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003euser\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003edrop\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eindex\u003c/span\u003e idx_update_time;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e-- 删除主键\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ealter\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003etable\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003euser\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003edrop\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eprimary\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003ekey\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"批量插入\"\u003e批量插入\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003einsert\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003einto\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003euser\u003c/span\u003e (username, create_time, status) \u003cspan style=\"color:#66d9ef\"\u003evalues\u003c/span\u003e(\u003cspan style=\"color:#ae81ff\"\u003e10000\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;2017-03-01 12:12:12\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e), (\u003cspan style=\"color:#ae81ff\"\u003e10001\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;2017-03-01 12:13:14\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"批量更新\"\u003e批量更新\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eUPDATE\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003euser\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eSET\u003c/span\u003e username \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eCASE\u003c/span\u003e id\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eWHEN\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eTHEN\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eWHEN\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eTHEN\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eWHEN\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eTHEN\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e5\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eELSE\u003c/span\u003e username\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eEND\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        status \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eCASE\u003c/span\u003e id\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eWHEN\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eTHEN\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eWHEN\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eTHEN\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eELSE\u003c/span\u003e status\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eEND\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eWHERE\u003c/span\u003e id \u003cspan style=\"color:#66d9ef\"\u003eIN\u003c/span\u003e (\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e4\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"批量插入若存在则更新\"\u003e批量插入若存在则更新\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003einsert\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003einto\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003euser\u003c/span\u003e (username, create_time, status) \u003cspan style=\"color:#66d9ef\"\u003evalues\u003c/span\u003e(\u003cspan style=\"color:#ae81ff\"\u003e10002\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;2017-03-01 12:12:12\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e), (\u003cspan style=\"color:#ae81ff\"\u003e10001\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;2017-03-01 12:13:14\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eon\u003c/span\u003e duplicate \u003cspan style=\"color:#66d9ef\"\u003ekey\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eupdate\u003c/span\u003e status \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003evalues\u003c/span\u003e(status);\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"导入导出\"\u003e导入导出\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e-- 导出某个库\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    mysqldump \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003euroot \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003eproot db_name \u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e db_name.\u003cspan style=\"color:#66d9ef\"\u003esql\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e-- 导出某张表\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    mysqldump \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003euroot \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003eproot db_name \u003cspan style=\"color:#66d9ef\"\u003etable_name\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003etable_name\u003c/span\u003e.\u003cspan style=\"color:#66d9ef\"\u003esql\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e-- 导出数据库所有表结构\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    mysqldump \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003euroot \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003eproot db_name  \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003ed \u003cspan style=\"color:#75715e\"\u003e--add-drop-table db_name \u0026gt; db.sql\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e-- 导入\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    mysqldump \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003euroot \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003eproot \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e import.\u003cspan style=\"color:#66d9ef\"\u003esql\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e-- 使用source方式导入，source import.sql\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"强制使用索引\"\u003e强制使用索引\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eselect\u003c/span\u003e username \u003cspan style=\"color:#66d9ef\"\u003efrom\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003euser\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eforce\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eindex\u003c/span\u003e(idx_update_time) \u003cspan style=\"color:#66d9ef\"\u003ewhere\u003c/span\u003e update_time \u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;2017-01-01 10:10:11\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"join语句\"\u003ejoin语句\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eINNER JOIN（内连接或等值连接）：产生同时符合左表和右表的记录。\u003c/li\u003e\n\u003cli\u003eLEFT JOIN（左连接）：左连接从左表产生一套完整的记录，与匹配的记录(右表) ，如果没有匹配，右侧将包含null。\u003c/li\u003e\n\u003cli\u003eRIGHT JOIN（右连接）：与LEFT JOIN相反\u003c/li\u003e\n\u003cli\u003emysql不支持Full join，不过可以通过UNION 关键字来合并 LEFT JOIN 与 RIGHT JOIN来模拟FULL join.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"执行顺序\"\u003e执行顺序\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eFORM: 对FROM的左边的表和右边的表计算笛卡尔积。产生虚表VT1\u003c/li\u003e\n\u003cli\u003eON: 对虚表VT1进行ON筛选，只有那些符合\u003c!-- raw HTML omitted --\u003e的行才会被记录在虚表VT2中。\u003c/li\u003e\n\u003cli\u003eJOIN： 如果指定了OUTER JOIN（比如left join、 right join），那么保留表中未匹配的行就会作为外部行添加到虚拟表VT2中，产生虚拟表VT3, rug from子句中包含两个以上的表的话，那么就会对上一个join连接产生的结果VT3和下一个表重复执行步骤1~3这三个步骤，一直到处理完所有的表为止。\u003c/li\u003e\n\u003cli\u003eWHERE： 对虚拟表VT3进行WHERE条件过滤。只有符合\u003c!-- raw HTML omitted --\u003e的记录才会被插入到虚拟表VT4中。\u003c/li\u003e\n\u003cli\u003eGROUP BY: 根据group by子句中的列，对VT4中的记录进行分组操作，产生VT5.\u003c/li\u003e\n\u003cli\u003eCUBE | ROLLUP: 对表VT5进行cube或者rollup操作，产生表VT6.\u003c/li\u003e\n\u003cli\u003eHAVING： 对虚拟表VT6应用having过滤，只有符合\u003c!-- raw HTML omitted --\u003e的记录才会被 插入到虚拟表VT7中。\u003c/li\u003e\n\u003cli\u003eSELECT： 执行select操作，选择指定的列，插入到虚拟表VT8中。\u003c/li\u003e\n\u003cli\u003eDISTINCT： 对VT8中的记录进行去重。产生虚拟表VT9.\u003c/li\u003e\n\u003cli\u003eORDER BY: 将虚拟表VT9中的记录按照\u0026lt;order_by_list\u0026gt;进行排序操作，产生虚拟表VT10.\u003c/li\u003e\n\u003cli\u003eLIMIT：取出指定行的记录，产生虚拟表VT11, 并将结果返回。\u003c/li\u003e\n\u003c/ul\u003e","title":"MySQL命令"},{"content":"LAMP ","permalink":"http://bug1024.com/2017/03/06/skill-tree/","summary":"\u003ch2 id=\"lamp\"\u003eLAMP\u003c/h2\u003e\n\u003cp\u003e\u003cimg alt=\"LAMP技能树\" loading=\"lazy\" src=\"http://bug1024.com/img/post-bg-skill-tree.jpg\"\u003e\u003c/p\u003e","title":"技能树"},{"content":"组成 Server(broker): 接受客户端连接，实现AMQP消息队列和路由功能的进程。 Virtual Host: 其实是一个虚拟概念，类似于权限控制组，一个Virtual Host里面可以有若干个Exchange和Queue，但是权限控制的最小粒度是Virtual Host Exchange: 接受生产者发送的消息，并根据Binding规则将消息路由给服务器中的队列。ExchangeType决定了Exchange路由消息的行为，例如，在RabbitMQ中，ExchangeType有direct、Fanout和Topic三种，不同类型的Exchange路由的行为是不一样的。 Message Queue：消息队列，用于存储还未被消费者消费的消息。 Message: 由Header和Body组成，Header是由生产者添加的各种属性的集合，包括Message是否被持久化、由哪个Message Queue接受、优先级是多少等。而Body是真正需要传输的APP数据。 Binding: Binding联系了Exchange与Message Queue。Exchange在与多个Message Queue发生Binding后会生成一张路由表，路由表中存储着Message Queue所需消息的限制条件即Binding Key。当Exchange收到Message时会解析其Header得到Routing Key，Exchange根据Routing Key与Exchange Type将Message路由到Message Queue。Binding Key由Consumer在Binding Exchange与Message Queue时指定，而Routing Key由Producer发送Message时指定，两者的匹配方式由Exchange Type决定。 Connection: 连接，对于RabbitMQ而言，其实就是一个位于客户端和Broker之间的TCP连接。 Channel: 信道，仅仅创建了客户端到Broker之间的连接后，客户端还是不能发送消息的。需要为每一个Connection创建Channel，AMQP协议规定只有通过Channel才能执行AMQP的命令。一个Connection可以包含多个Channel。之所以需要Channel，是因为TCP连接的建立和释放都是十分昂贵的，如果一个客户端每一个线程都需要与Broker交互，如果每一个线程都建立一个TCP连接，暂且不考虑TCP连接是否浪费，就算操作系统也无法承受每秒建立如此多的TCP连接。RabbitMQ建议客户端线程之间不要共用Channel，至少要保证共用Channel的线程发送消息必须是串行的，但是建议尽量共用Connection。 Command: AMQP的命令，客户端通过Command完成与AMQP服务器的交互来实现自身的逻辑。例如在RabbitMQ中，客户端可以通过publish命令发送消息，txSelect开启一个事务，txCommit提交一个事务。 原理 producer发布消息到exchnage，由exchange转发给quenue，consumer者再消费queue 场景 单发单收 单发多收 发布、订阅模式，发送端发送广播消息，多个接收端接收 Routing (按路线发送接收) Topics (按topic发送接收) exchange direct 如果routing_key匹配，消息就被投递到对应队列上 fanout 不处理routing_key，将消息广播到所有绑定的队列上，消息传播最快 topic 将路由键和某模式进行匹配，将不同源头的消息投递到同一个队列上 headers 允许匹配消息的header而非routing_key vhost 持久化 管理 使用rabbitmqctl进行管理 待续\u0026hellip;\n","permalink":"http://bug1024.com/2017/03/05/rabbitmq/","summary":"\u003ch2 id=\"组成\"\u003e组成\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eServer(broker): 接受客户端连接，实现AMQP消息队列和路由功能的进程。\u003c/li\u003e\n\u003cli\u003eVirtual Host: 其实是一个虚拟概念，类似于权限控制组，一个Virtual Host里面可以有若干个Exchange和Queue，但是权限控制的最小粒度是Virtual Host\u003c/li\u003e\n\u003cli\u003eExchange: 接受生产者发送的消息，并根据Binding规则将消息路由给服务器中的队列。ExchangeType决定了Exchange路由消息的行为，例如，在RabbitMQ中，ExchangeType有direct、Fanout和Topic三种，不同类型的Exchange路由的行为是不一样的。\u003c/li\u003e\n\u003cli\u003eMessage Queue：消息队列，用于存储还未被消费者消费的消息。\u003c/li\u003e\n\u003cli\u003eMessage: 由Header和Body组成，Header是由生产者添加的各种属性的集合，包括Message是否被持久化、由哪个Message Queue接受、优先级是多少等。而Body是真正需要传输的APP数据。\u003c/li\u003e\n\u003cli\u003eBinding: Binding联系了Exchange与Message Queue。Exchange在与多个Message Queue发生Binding后会生成一张路由表，路由表中存储着Message Queue所需消息的限制条件即Binding Key。当Exchange收到Message时会解析其Header得到Routing Key，Exchange根据Routing Key与Exchange Type将Message路由到Message Queue。Binding Key由Consumer在Binding Exchange与Message Queue时指定，而Routing Key由Producer发送Message时指定，两者的匹配方式由Exchange Type决定。\u003c/li\u003e\n\u003cli\u003eConnection: 连接，对于RabbitMQ而言，其实就是一个位于客户端和Broker之间的TCP连接。\u003c/li\u003e\n\u003cli\u003eChannel: 信道，仅仅创建了客户端到Broker之间的连接后，客户端还是不能发送消息的。需要为每一个Connection创建Channel，AMQP协议规定只有通过Channel才能执行AMQP的命令。一个Connection可以包含多个Channel。之所以需要Channel，是因为TCP连接的建立和释放都是十分昂贵的，如果一个客户端每一个线程都需要与Broker交互，如果每一个线程都建立一个TCP连接，暂且不考虑TCP连接是否浪费，就算操作系统也无法承受每秒建立如此多的TCP连接。RabbitMQ建议客户端线程之间不要共用Channel，至少要保证共用Channel的线程发送消息必须是串行的，但是建议尽量共用Connection。\u003c/li\u003e\n\u003cli\u003eCommand: AMQP的命令，客户端通过Command完成与AMQP服务器的交互来实现自身的逻辑。例如在RabbitMQ中，客户端可以通过publish命令发送消息，txSelect开启一个事务，txCommit提交一个事务。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"原理\"\u003e原理\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eproducer发布消息到exchnage，由exchange转发给quenue，consumer者再消费queue\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"场景\"\u003e场景\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e单发单收\u003c/li\u003e\n\u003cli\u003e单发多收\u003c/li\u003e\n\u003cli\u003e发布、订阅模式，发送端发送广播消息，多个接收端接收\u003c/li\u003e\n\u003cli\u003eRouting (按路线发送接收)\u003c/li\u003e\n\u003cli\u003eTopics (按topic发送接收)\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"exchange\"\u003eexchange\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003edirect 如果routing_key匹配，消息就被投递到对应队列上\u003c/li\u003e\n\u003cli\u003efanout 不处理routing_key，将消息广播到所有绑定的队列上，消息传播最快\u003c/li\u003e\n\u003cli\u003etopic 将路由键和某模式进行匹配，将不同源头的消息投递到同一个队列上\u003c/li\u003e\n\u003cli\u003eheaders 允许匹配消息的header而非routing_key\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"vhost\"\u003evhost\u003c/h2\u003e\n\u003ch2 id=\"持久化\"\u003e持久化\u003c/h2\u003e\n\u003ch2 id=\"管理\"\u003e管理\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e使用rabbitmqctl进行管理\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e待续\u0026hellip;\u003c/p\u003e","title":"RabbitMQ"},{"content":"连接建立过程 TCP 连接的建立采用客户服务器方式，主动发起连接建立的一方叫客户端（Client），被动等待连接建立的一方叫服务器（Server）。\n最初的时候，两端都处于 CLOSED 的状态，然后服务器打开了 TCP 服务，进入 LISTEN 状态，监听特定端口，等待客户端的 TCP 请求。\n第一次握手： 客户端主动打开连接，发送 TCP 报文，进行第一次握手，然后进入 SYN_SEND 状态，等待服务器发回确认报文。 这时首部的同步位 SYN = 1，同时初始化一个序号 Sequence Number = J。 TCP 规定，SYN 报文段不能携带数据，但会消耗一个序号。\n第二次握手： 服务器收到了 SYN 报文，如果同意建立连接，则向客户端发送一个确认报文，然后服务器进入 SYN_RCVD 状态。 这时首部的 SYN = 1，ACK = 1，而确认号 Acknowledgemt Number = J + 1，同时也为自己初始化一个序号 Sequence Number = K。 这个报文同样不携带数据。\n第三次握手： 客户端收到了服务器发过来的确认报文，还要向服务器给出确认，然后进入 ESTABLISHED 状态。 这时首部的 SYN 不再置为 1，而 ACK = 1，确认号 Acknowledgemt Number = K + 1，序号 Sequence Number = J + 1。 第三次握手，一般会携带真正需要传输的数据，当服务器收到该数据报文的时候，就会同样进入 ESTABLISHED 状态。 此时，TCP 连接已经建立。\n对于建立连接的三次握手，主要目的是初始化序号 Sequence Number，并且通信的双方都需要告知对方自己的初始化序号，所以这个过程也叫 SYN。 这个序号要作为以后的数据通信的序号，以保证应用层接收到的数据不会因为网络上的传输问题而乱序，因为TCP 会用这个序号来拼接数据。\nTCP 泛洪攻击 知道了 TCP 建立一个连接，需要进行三次握手。 但如果你开始思考「三次握手的必要性」的时候，就会知道，其实网络是很复杂的，一个信息在途中丢失的可能性是有的。 如果数据丢失了，那么，就需要重新发送，这时候就要知道数据是否真的送达了。 这就是三次握手的必要性。 但是再向深一层思考，你给我发信息，我收到了，我回复，因为我是君子。 如果是小人，你给我发信息，我就算收到了，我也不回复，你就一直等我着我的回复。 那么很多小人都这样做，你就要一直记住你在等待着小人1号、小人2号、小人3号\u0026hellip;\u0026hellip;直到你的脑容量爆棚，烧坏脑袋。 黑客就是利用这样的设计缺陷，实施 TCP Flood 攻击，属于 DDOS 攻击的一种。 想了解更多 SYN Flood 攻击请看：SYN flood - wiki\n四次挥手，释放连接 TCP 有一个特别的概念叫做半关闭，这个概念是说，TCP 的连接是全双工（可以同时发送和接收）的连接，因此在关闭连接的时候，必须关闭传送和接收两个方向上的连接。 客户端给服务器发送一个携带 FIN 的 TCP 结束报文段，然后服务器返回给客户端一个 确认报文段，同时发送一个 结束报文段，当客户端回复一个 确认报文段 之后，连接就结束了。\n释放连接过程 在结束之前，通信双方都是处于 ESTABLISHED 状态，然后其中一方主动断开连接。 下面假如客户端先主动断开连接。\n第一次挥手： 客户端向服务器发送结束报文段，然后进入 FIN_WAIT_1 状态。 此报文段 FIN = 1， Sequence Number = M。\n第二次挥手： 服务端收到客户端的结束报文段，然后发送确认报文段，进入 CLOSE_WAIT 状态。 此报文段 ACK = 1， Sequence Number = M + 1。\n客户端收到该报文，会进入 FIN_WAIT_2 状态。\n第三次挥手： 同时服务端向客户端发送结束报文段，然后进入 LAST_ACK 状态。 此报文段 FIN = 1，Sequence Number = N。\n第四次挥手： 客户端收到服务端的结束报文段，然后发送确认报文段，进入 TIME_WAIT 状态，经过 2MSL 之后，自动进入 CLOSED 状态。 此报文段 ACK = 1, Sequence Number = N + 1。\n服务端收到该报文之后，进入 CLOSED 状态。\n关于 TIME_WAIT 过渡到 CLOSED 状态说明： 从 TIME_WAIT 进入 CLOSED 需要经过 2MSL，其中 MSL 就叫做 最长报文段寿命（Maxinum Segment Lifetime），根据 RFC 793 建议该值这是为 2 分钟，也就是说需要经过 4 分钟，才进入 CLOSED 状态。\n为什么建立连接协议是三次握手，而关闭连接却是四次握手呢？ 这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的连接请求后，它可以把ACK和SYN(ACK起应答作用，而SYN起同步作用)放在一个报文里来发送。但关闭连接时，当收到对方的FIN报文通知时，它仅仅表示对方没有数据发送给你了；但未必你所有的数据都全部发送给对方了，所以你可能未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后，再发送FIN报文给对方来表示你同意现在可以关闭连接了，所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。\n","permalink":"http://bug1024.com/2017/02/01/tcp-handshake/","summary":"\u003ch3 id=\"连接建立过程\"\u003e连接建立过程\u003c/h3\u003e\n\u003cp\u003eTCP 连接的建立采用客户服务器方式，主动发起连接建立的一方叫\u003cstrong\u003e客户端（Client）\u003c/strong\u003e，被动等待连接建立的一方叫\u003cstrong\u003e服务器（Server）\u003c/strong\u003e。\u003c/p\u003e\n\u003cp\u003e最初的时候，两端都处于 \u003cstrong\u003eCLOSED\u003c/strong\u003e 的状态，然后服务器打开了 TCP 服务，进入 \u003cstrong\u003eLISTEN\u003c/strong\u003e 状态，监听特定端口，等待客户端的 TCP 请求。\u003c/p\u003e","title":"TCP握手"},{"content":"PHP 《PHP最佳实践》 《PHP开发者实践》 《PHP核心技术与最佳实践》 《PHP扩展开发及内核应用》 《深入理解PHP内核》 Java 《大型网站系统与Java中间件实践》 《Effective Java》 《深入分析Java Web技术内幕》 《深入理解Java虚拟机》 《Netty权威指南》 JS 《JavaScript高级程序设计（第3版）》 《JavaScript语言精粹》 《精通JavaScript开发》 《深入浅出Node.js》 DB 《MySQL技术内幕：SQL编程》 《MySQL技术内幕：InnoDB存储引擎》 Linux 《高级Bash脚本编程指南》 《Linux工具快速教程》 《UNIX环境高级编程》 Nginx \u0026amp; Lua 《Nginx开发从入门到精通》 《agentzh的Nginx教程》 《OpenResty最佳实践》 《Lua源码欣赏》 C 《C程序设计语言 第2版·新版》 《Learn C The Hard Way》 ElasticSearch 《Elasticsearch权威指南》 《ELK中文指南》 MQ 《RabbitMQ实战》 Tool 《Git教程》 《Wireshark用户手册》 Others 《卓有成效的程序员》 《安全技术大系:Web前端黑客技术揭秘》 《高效团队开发 工具与方法》 《API Design Principles》 《全栈增长工程师实战》 《代码整洁之道》 《大型分布式网站架构设计与实践》 《淘宝技术这十年》 《程序员的自我修养—链接、装载与库》 ","permalink":"http://bug1024.com/2017/01/11/books/","summary":"\u003ch2 id=\"php\"\u003ePHP\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://laravel-china.github.io/php-the-right-way/\"\u003e《PHP最佳实践》\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://ryancao.gitbooks.io/php-developer-prepares/content/\"\u003e《PHP开发者实践》\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"\"\u003e《PHP核心技术与最佳实践》\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.cunmou.com/phpbook/preface.md\"\u003e《PHP扩展开发及内核应用》\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.php-internals.com/\"\u003e《深入理解PHP内核》\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"java\"\u003eJava\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"\"\u003e《大型网站系统与Java中间件实践》\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"\"\u003e《Effective Java》\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"\"\u003e《深入分析Java Web技术内幕》\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"\"\u003e《深入理解Java虚拟机》\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"\"\u003e《Netty权威指南》\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"js\"\u003eJS\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"\"\u003e《JavaScript高级程序设计（第3版）》\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"\"\u003e《JavaScript语言精粹》\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"\"\u003e《精通JavaScript开发》\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"\"\u003e《深入浅出Node.js》\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"db\"\u003eDB\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"\"\u003e《MySQL技术内幕：SQL编程》\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"\"\u003e《MySQL技术内幕：InnoDB存储引擎》\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"linux\"\u003eLinux\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://www.lzhaohao.info/abs/\"\u003e《高级Bash脚本编程指南》\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://linuxtools-rst.readthedocs.io/zh_CN/latest/\"\u003e《Linux工具快速教程》\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"\"\u003e《UNIX环境高级编程》\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"nginx--lua\"\u003eNginx \u0026amp; Lua\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://tengine.taobao.org/book/index.html\"\u003e《Nginx开发从入门到精通》\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://openresty.org/download/agentzh-nginx-tutorials-zhcn.html\"\u003e《agentzh的Nginx教程》\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://moonbingbing.gitbooks.io/openresty-best-practices/content/lua/brief.html\"\u003e《OpenResty最佳实践》\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://www.codingnow.com/temp/readinglua.pdf\"\u003e《Lua源码欣赏》\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"c\"\u003eC\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"\"\u003e《C程序设计语言 第2版·新版》\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://learncodethehardway.org/c/\"\u003e《Learn C The Hard Way》\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"elasticsearch\"\u003eElasticSearch\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://www.learnes.net/\"\u003e《Elasticsearch权威指南》\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://kibana.logstash.es/content/\"\u003e《ELK中文指南》\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"mq\"\u003eMQ\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"\"\u003e《RabbitMQ实战》\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"tool\"\u003eTool\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000\"\u003e《Git教程》\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://man.lupaworld.com/content/network/wireshark/index.html\"\u003e《Wireshark用户手册》\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"others\"\u003eOthers\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"\"\u003e《卓有成效的程序员》\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"\"\u003e《安全技术大系:Web前端黑客技术揭秘》\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"\"\u003e《高效团队开发 工具与方法》\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://w3ctag.github.io/design-principles/\"\u003e《API Design Principles》\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://growth-in-action.phodal.com/\"\u003e《全栈增长工程师实战》\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"\"\u003e《代码整洁之道》\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"\"\u003e《大型分布式网站架构设计与实践》\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"\"\u003e《淘宝技术这十年》\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"\"\u003e《程序员的自我修养—链接、装载与库》\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e","title":"书单"},{"content":"海量数据存储 分库表基础上，单master多slave横向扩展 master和slave通过binlog近乎实时同步，任意slave可为master实时备份 主业务和辅业务模块数据库分离 多地部署，一处写入多出读取，保证就近读取 架构模式 分层：横向切分 分割：纵向切分 分布式：分层和分割的主要目的是为了切分后的模块便于分布式部署。常用方案： 分布式应用和服务 分布式静态资源 分布式数据和存储 分布式计算 分布式配置 分布式锁 分布式文件 集群：多台服务器部署相同的应用构成一个集群，通过负载均衡设备共同对外提供服务 缓存：将数据放距离计算最近的位置加快处理速度，改善性能第一手段，可以加快访问速度，减小后端负载压力。使用缓存 两个前提条件 ：1.数据访问热点不均衡；2.数据某时段内有效，不会很快过期 CDN 反向代理 本地缓存 分布式缓存 异步：旨在系统解耦。异步架构是典型的消费者生产者模式，特性如下： 提高系统可用性 加快网站访问速度 消除并发访问高峰 冗余：实现高可用。数据库的冷备份和热备份 自动化：包括发布过程自动化，自动化代码管理，自动化测试，自动化安全检测，自动化部署，自动化监控，自动化报警，自动化失效转移，自动化失效恢复，自动化降级，自动化分配资源 安全：密码，手机校验码，加密，验证码，过滤，风险控制 核心要素 性能(Performance) 可用性(Availability) 伸缩性(Scalability) 扩展性(Extensibility) 安全性(Security) CAP 基于水平扩容能力和成本考虑，传统的强一致的解决方案（e.g.单机事务）纷纷被抛弃。其理论依据就是CAP原理，往往为了可用性和分区容错性，忍痛放弃强一致支持，转而追求最终一致性。\nConsistency：强一致性就是在客户端任何时候看到各节点的数据都是一致的（All nodes see the same data at the same time）。 Availability：高可用性就是在任何时候都可以读写（Reads and writes always succeed）。 Partition Tolerance：分区容错性是在网络故障、某些节点不能通信的时候系统仍能继续工作（The system continue to operate despite arbitrary message loss or failure of part of the the system）。以实际效果而言，分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性，就意味着发生了分区的情况，必须就当前操作在C和A之间做出选择。 常见代表\nCA：RDMBS CP：Redis MongoDB HBase AP: CounchDB Cassandra DynamoDB Riak 设计建议 减少单点 去单点首先要识别整个系统所有主链路的单点，如机房（同城异地双机房），应用服务器，DNS服务器，SFTP服务器，LBS，缓存服务器，数据库，消息服务器，代理服务器和专线等，如系统通过专线调用对方服务，需要考虑同时拉联通和电信的专线，联通或电信的专线还是有一定概率会出现问题的，但是同时出问题的概率会小非常多。优先使用软负载，使用硬负载兜底。 减少依赖 减少DNS依赖，减少远程服务依赖，DNS依赖可以尝试设置本地host，用工具给所有服务器推送最新的域名映射关系，通过本地缓存或近端服务减少RPC调用。 限制循环 避免无限死循环，导致CPU利用率百分百，可以设置for循环的最大循环次数，如最大循环1000次。 控制流量 避免异常流量对应用服务器产生影响，可以对指定服务设置流量限制，如QPS，TPS，QPH（每小时总请求量）和QPD（每天总请求量）。 精准监控 对CPU利用率，load，内存，带宽，系统调用量，应用错误量，PV，UV和业务量进行监控，避免内存泄露和异常代码对系统产生影响，配置监控一定要精准，如平时内存利用率是50%，监控可以配置成60%进行报警，这样可以提前感知内存泄露问题，避免应用无响应。 无状态 服务器不能保存用户状态数据，如在集群环境下不能用static变量保存用户数据，不能长时间把用户文件存放在服务器本地。服务器有状态会难以扩容，且出现单点问题。 容量规划 定期对容量进行评估。如大促前进行压测和容量预估，根据需要进行扩容。 功能开关 打开和关闭某些功能，比如消息量过大，系统处理不了，把开关打开后直接丢弃消息不处理。上线新功能增加开关，如果有问题关闭新功能。 设置超时 设置连接超时和读超时设置，不应该太大，如果是内部调用连接超时可以设置成1秒，读超时3秒，外部系统调用连接超时可以设置成3秒，读超时设置成20秒。 重试策略 当调用外部服务异常时可以设置重试策略，每次重试时间递增，但是需要设置最大重试次数和重试开关，避免对下游系统产生影响。 隔离 应用隔离，模块隔离，机房隔离和线程池隔离。可以按照优先级，不变和变几个维度来隔离应用和模块，如抽象和不变的代码放在一个模块，这个模块的代码几乎不会修改，可用性高，经常变的业务逻辑放在一个模块里，这样就算有问题，也只会影响到某一个业务。不同的业务使用不同的线程池，避免低优先级任务阻塞高优先级，或高优先级任务过多时影响低优先级任务永远不会执行。 异步调用 同步调用改成异步调用，解决远程调用故障或调用超时对系统的影响。 热点缓存 对热点数据进行缓存，降低RPC调用。如B系统提供名单服务，B系统可以提供一个client SDK提供近端缓存服务，定期去服务器端取数据，减少RPC调用。 缓存容灾 当数据库不可用时可以使用缓存的数据。并设置分级缓存，如优先读本地缓存，其次读分布式缓存。 分级缓存 优先读本地缓存，其次读分布式缓存。通过推模式更新本地缓存。 系统分级 对系统进行分级，如ABC三个等级，高级别系统不依赖于低级别系统，并且高级别系统比底级别系统高可用率要高。 服务降级 如果系统出现响应缓慢等状况，可以关闭部分功能，从而释放系统资源，保证核心服务的正常运行。需要识别哪些服务可以降级，比如突然有大量消息流入，导致服务不可用，我们会把消息直接丢弃掉。或通过设置流控，拒绝为低级别系统提供服务。 流量蓄洪 当流量陡增时，可以将请求进行蓄洪，如把请求保存在数据库中，再按照指定的QPS进行泄洪，有效的保护下游系统，也保证了服务的可用性。当调用对方系统，对方系统响应缓慢或无响应时，可采取自动蓄洪。 服务权重 在集群环境中，可自动识别高性能服务，拒绝调用性能低的服务。如在集群环境中，对调用超时的服务器进行权重降低，优先调用权重高的服务器。 依赖简化 减少系统之间的依赖，比如使用消息驱动，A和B系统通过消息服务器传递数据，A和B系统使用数据库进行读写分离，A系统负责往数据库中写数据，B系统负责读数据，因为数据存放在数据库中，当A不可用时，短时间内不影响B系统提供服务。 弹性扩容 根据资源的使用率自动或手动进行扩容。如带宽不够用时，快速增加带宽。 灰度和回滚 发布新功能只让部分服务器生效，且观察几天逐渐切流，如果出现问题只影响部分客户。出现问题快速回滚，或者直接下线灰度的机器。 减少远程调用 优先调用本地JVM内服务，其次是同机房服务，然后是同城服务，最后是跨城服务。如A调用B，B调用互联网的C系统获取数据，B系统可以把数据缓存起来，并设置数据的保鲜度，减少B对C的依赖。配置中心把注册服务的地址推送到调用服务的系统本地。参数中心把参数配置信息推送到系统的本地内存，而不是让系统去远程服务器获取参数信息。 熔断机制 增加熔断机制，当监控出线上数据出现大幅跌涨时，及时中断，避免对业务产生更大影响。如我们做指标计算时，指标可以计算慢，但是不能算错，如果发现某个用户的指标环比或同比增长一倍或跌零，会考虑保存所有消息，并中止该用户的指标计算。 运行时加载模块 我们会把经常变的业务代码变成一个个业务模块，使用Java的ClassLoader在运行时动态加载和卸载模块，当某个模块有问题时候，可以快速修复。 代码扫描 使用IDEA代码分析等工具进行代码扫描，识别出程序中的BUG，如空指针异常，循环依赖等。 自动备份 程序，系统配置和数据定期进行备份。可使用linux命令和shell脚本定时执行备份策略，自动进行本地或异地。出现问题时能快速重新部署。 线上压测 系统的对外服务需要进行压测，知道该服务能承受的QPS和TPS，从而做出相对准确的限流。 架构原则 避免过度设计 冗余设计 多活数据中心 无状态设计 可回滚 可禁用／自我保护 问题可追踪 可监控 故障隔离 成熟可控的技术选型 梯级存储 缓存设计 异步设计 前瞻性设计 水平扩展 小步构建和发布 自动化 ","permalink":"http://bug1024.com/2017/01/08/web-architecture/","summary":"\u003ch2 id=\"海量数据存储\"\u003e海量数据存储\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e分库表基础上，单master多slave横向扩展\u003c/li\u003e\n\u003cli\u003emaster和slave通过binlog近乎实时同步，任意slave可为master实时备份\u003c/li\u003e\n\u003cli\u003e主业务和辅业务模块数据库分离\u003c/li\u003e\n\u003cli\u003e多地部署，一处写入多出读取，保证就近读取\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"架构模式\"\u003e架构模式\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e分层：横向切分\u003c/li\u003e\n\u003cli\u003e分割：纵向切分\u003c/li\u003e\n\u003cli\u003e分布式：分层和分割的主要目的是为了切分后的模块便于分布式部署。常用方案：\n\u003cul\u003e\n\u003cli\u003e分布式应用和服务\u003c/li\u003e\n\u003cli\u003e分布式静态资源\u003c/li\u003e\n\u003cli\u003e分布式数据和存储\u003c/li\u003e\n\u003cli\u003e分布式计算\u003c/li\u003e\n\u003cli\u003e分布式配置\u003c/li\u003e\n\u003cli\u003e分布式锁\u003c/li\u003e\n\u003cli\u003e分布式文件\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e集群：多台服务器部署相同的应用构成一个集群，通过负载均衡设备共同对外提供服务\u003c/li\u003e\n\u003cli\u003e缓存：将数据放距离计算最近的位置加快处理速度，改善性能第一手段，可以加快访问速度，减小后端负载压力。使用缓存 两个前提条件 ：1.数据访问热点不均衡；2.数据某时段内有效，不会很快过期\n\u003cul\u003e\n\u003cli\u003eCDN\u003c/li\u003e\n\u003cli\u003e反向代理\u003c/li\u003e\n\u003cli\u003e本地缓存\u003c/li\u003e\n\u003cli\u003e分布式缓存\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e异步：旨在系统解耦。异步架构是典型的消费者生产者模式，特性如下：\n\u003cul\u003e\n\u003cli\u003e提高系统可用性\u003c/li\u003e\n\u003cli\u003e加快网站访问速度\u003c/li\u003e\n\u003cli\u003e消除并发访问高峰\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e冗余：实现高可用。数据库的冷备份和热备份\u003c/li\u003e\n\u003cli\u003e自动化：包括发布过程自动化，自动化代码管理，自动化测试，自动化安全检测，自动化部署，自动化监控，自动化报警，自动化失效转移，自动化失效恢复，自动化降级，自动化分配资源\u003c/li\u003e\n\u003cli\u003e安全：密码，手机校验码，加密，验证码，过滤，风险控制\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"核心要素\"\u003e核心要素\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e性能(Performance)\u003c/li\u003e\n\u003cli\u003e可用性(Availability)\u003c/li\u003e\n\u003cli\u003e伸缩性(Scalability)\u003c/li\u003e\n\u003cli\u003e扩展性(Extensibility)\u003c/li\u003e\n\u003cli\u003e安全性(Security)\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"cap\"\u003eCAP\u003c/h2\u003e\n\u003cp\u003e基于水平扩容能力和成本考虑，传统的强一致的解决方案（e.g.单机事务）纷纷被抛弃。其理论依据就是CAP原理，往往为了可用性和分区容错性，忍痛放弃强一致支持，转而追求最终一致性。\u003c/p\u003e","title":"网站架构"},{"content":"特点 高性能Key-Value存储 丰富的数据结构：string、list、hash、set、zset、hypeloglog 支持数据过期：主动过期+惰性过期 支持多种LRU策略：volatile-lru、volatile-ttl 等 内存管理：tcmaloc、jemalloc 内存存储+磁盘持久化: rdb、aof 支持主从复制 单线程 配置 aof配置\nappendonly yes 是否打开aof日志功能 appendfsync always 每一个命令都立刻同步到aof，安全但是速度慢，此时和传统的DB持久化是类似的 appendfsync everysec 折衷方案每秒一次，一般选用这种。 appendfsync no 交给操作系统，由操作系统判断缓冲区大小，同意写入aof中，频率低速度快。 no-appendfsync-on-rewrite yes 正在导出rdb文件，是否要停止aof auto-aof-rewrite-percentage 100 aof文件比起上次重写时的大小，增长率是百分之百时重写。 auto-aof-rewrite-min-size 64mb 至少超过64m重写。 rdb配置\nsave 10 100 10s后如果至少100个key发生变化则生成rdb save 100 50 可以多个，任意一个条件满足即可触发 dbfilename dump.rdb 指定rdb保存到本地数据库文件名 stop-writes-on-bgsave-error yes 当硬盘因为权限等原因无法写入时，停止写入 rdbchecksum yes 对rdb文件进行校验 主从配置\nslaveof master_ip master_port 设置为某个master的slave slaveof on one 恢复为master，不会丢失已经同步的数据 持久化 同时开启两种持久化方式，当redis重启的时候会优先载入AOF文件来恢复原始的数据，因为在通常情况下AOF文件保存的数据集要比RDB文件 保存的数据集要完整。 虽然SAVE会一直阻塞Redis直到快照生成完毕，但是因为它不需要创建子进程，所以不会像BGSAVE一样因为创建子进程而导致Redis停顿\n主从同步原理 slave向master发送sync指令，master接收到时调用bgsave指令fork一个子进程进行持久化工作，该期间master的写指令都缓存在内存中 bgsave指令完成后master会将rdb文件发送给slave，slave接收到后将其存在磁盘上，然后读入内存，这个动作完成后master会将这段时间缓存的写指令再以redis协议的格式发送给slave 2.8版版本引入增量同步机制 热部署原理 master不负责具体的工作，而是调用worker工作，它只是负责读取配置文件，因此当一个模块修改或者配置文件发生变化，是由master进行读取，因此此时不会影响到worker工作。 在master进行读取配置文件之后，不会立即的把修改的配置文件告知worker。而是让被修改的worker继续使用老的配置文件工作，当worker工作完毕之后，直接当掉这个子进程，更换新的子进程，使用新的规则。\n事务 MULTI用来组装一个事务 EC用来执行一个事 DISCARD用来取消一个事务 WATCH用来监视一些key，一旦这些key在事务执行之前被改变，则取消事务的执行 # 如果在 WATCH 执行之后， EXEC 执行之前， 有其他客户端修改了 mykey 的值， 那么当前客户端的事务就会失败。 程序需要做的， 就是不断重试这个操作， 直到没有发生碰撞为止，这种形式的锁被称作乐观锁 WATCH mykey val = GET mykey val = val + 1 MULTI SET mykey $val EXEC Redis Cluster Redis 集群不像单机Redis 那样支持多数据库功能， 集群只使用默认的 0 号数据库， 并且不能使用 SELECT 命令。 节点之间使用Gossip 协议 来进行以下工作 数据结构 String SDS 二进制安全 记录length HyperLogLog 基数估算 每个键占用的内容都是12K 可以非常省内存的去统计各种计数，比如注册ip数、每日访问IP数、页面实时UV（PV肯定字符串就搞定了）、在线用户数等 为什么会丢数据/产生脏数据 Redis是一个注重性能的NoSQL，在数据一致性方面不强 Redis的复制是异步的，即主从实例之间数据可能存在1～10秒的差距 切换过程当中不会判断主从数据是否一致 分布式方案 Codis 豌豆荚出品 twemproxy 推特出品 ","permalink":"http://bug1024.com/2017/01/05/redis/","summary":"\u003ch2 id=\"特点\"\u003e特点\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e高性能Key-Value存储\u003c/li\u003e\n\u003cli\u003e丰富的数据结构：string、list、hash、set、zset、hypeloglog\u003c/li\u003e\n\u003cli\u003e支持数据过期：主动过期+惰性过期\u003c/li\u003e\n\u003cli\u003e支持多种LRU策略：volatile-lru、volatile-ttl 等\u003c/li\u003e\n\u003cli\u003e内存管理：tcmaloc、jemalloc\u003c/li\u003e\n\u003cli\u003e内存存储+磁盘持久化: rdb、aof\u003c/li\u003e\n\u003cli\u003e支持主从复制\u003c/li\u003e\n\u003cli\u003e单线程\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"配置\"\u003e配置\u003c/h2\u003e\n\u003cp\u003eaof配置\u003c/p\u003e","title":"Redis"},{"content":"360开源的一款分布式配置管理工具\n相关链接 原理 GitHub 特点 一处修改，所有机器实时同步更新 高效读取配置 安装部署方便，使用简单 服务器宕机、网络中断、集群迁移等异常情况对用户透明 支持c/c++、shell、php、python、lua、java、go、node 等语言 服务端 QConf使用ZooKeeper集群作为服务端提供服务 单条配置直接存储在一个ZNode上 利用ZooKeeper的Watch监听功能实现配置变化时对客户端的及时通知 客户端 获取：查共享内存，无记录则向消息队列中加入请求，agent感知消息队列，agent查ZK并更新共享缓存 更新：ZK通知agent变更，agent从ZK中获取新值同时更新共享内存 设计目标：降低与ZooKeeper的链接数，本地缓存，及时更新，容错 特点：无锁，单点写，父子进程keepalive，落盘数据维护 管理端 业务修改配置的管理界面 ","permalink":"http://bug1024.com/2017/01/02/qconf/","summary":"\u003cp\u003e360开源的一款分布式配置管理工具\u003c/p\u003e\n\u003ch2 id=\"相关链接\"\u003e相关链接\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"http://catkang.github.io/2015/06/23/qconf.html\"\u003e原理\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/Qihoo360/QConf/blob/master/README_ZH.md\"\u003eGitHub\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"特点\"\u003e特点\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e一处修改，所有机器实时同步更新\u003c/li\u003e\n\u003cli\u003e高效读取配置\u003c/li\u003e\n\u003cli\u003e安装部署方便，使用简单\u003c/li\u003e\n\u003cli\u003e服务器宕机、网络中断、集群迁移等异常情况对用户透明\u003c/li\u003e\n\u003cli\u003e支持c/c++、shell、php、python、lua、java、go、node 等语言\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"服务端\"\u003e服务端\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eQConf使用ZooKeeper集群作为服务端提供服务\u003c/li\u003e\n\u003cli\u003e单条配置直接存储在一个ZNode上\u003c/li\u003e\n\u003cli\u003e利用ZooKeeper的Watch监听功能实现配置变化时对客户端的及时通知\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"客户端\"\u003e客户端\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e获取：查共享内存，无记录则向消息队列中加入请求，agent感知消息队列，agent查ZK并更新共享缓存\u003c/li\u003e\n\u003cli\u003e更新：ZK通知agent变更，agent从ZK中获取新值同时更新共享内存\u003c/li\u003e\n\u003cli\u003e设计目标：降低与ZooKeeper的链接数，本地缓存，及时更新，容错\u003c/li\u003e\n\u003cli\u003e特点：无锁，单点写，父子进程keepalive，落盘数据维护\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"管理端\"\u003e管理端\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e业务修改配置的管理界面\u003c/li\u003e\n\u003c/ul\u003e","title":"Qconf"},{"content":"今年是让我感觉过的最快的一年，发生的种种事情仿佛就在昨日。 既然是一年的总结那么就写个全面的一点的，包括工作，学习，生活。 作为一个程序员我原本计划这次年终总结应该花更多笔墨在技术编程上，但思考一番后却发现过去一年在技术领域上并没有什么值得写的。\n工作 我是一个热爱工作的人，尽职尽责。 过去一年里最有意义的工作就是与项目成员一起完成了整体网站的重构，不过现在回想起来重构算是失败的。 这一次的重构在设计上还是过于草率了一点，并没有把握好整体的架构方案，在重构的时候更多的还是去妥协历史遗留问题，整套方案并没有太大的进步与创新。 说是重构其实算是重写，因为仅仅只是在代码层面上做了优化，剔除了一些年久失修的问题代码，而对于数据库一块却没有太大的变化设计，而且在日志监控的工作上也尤为欠缺。 所以其实这次重构就好像房子仅仅只是粉刷了一下外墙，连块砖头也没换。 这一年我成了自己项目组的leader，但却没有给项目组带来质的成长，一方面是由于人手太少，另一方面也是因为公司的衰落。 在11月底的时候，我选择了离职，一路北上来到了北京，只希望可以与更优秀的人一起工作，在更大的平台锻炼自己。 目前为止我已经初步具备了架构师的能力，未来几年里我会努力提升自己在架构方面的水平。 人总要学会适当逃离舒适区，去迎接更多的挑战，这样才可能进步。\n学习 过去一年看了大量的技术博客，了解了诸多大厂的技术架构方案，看到了数不清的高可用、高并发类似的字眼，但更多的只是理论上的了解而难以有机会去亲身体验。 走马观花似的浏览文章尽管可以增加自己的见识，但是也容易让自己变得浮躁，而技术这一行恰恰又是需要沉淀的，更多的时间还是应该落到实处。 所以说我应该花更多的时间去掌握基础，而不是沉迷那些所谓看似高大上的技术方案与工具。 年初的时候给自己定的计划里有英语和C语言，但是一年了我并没有很好的完成，只能再次推到明年了。 人总要学会努力，不努力就对不起年轻的自己，我不想以后后悔。\n生活 很庆幸我在过去一年里把体重恢复到了正常水平，并没有成为当初自己厌恶的发福男子。我还是继续保持锻炼，不过腹肌依旧还是没有达到自己的期望。 我基本还是保持每周打一次篮球，我是那么热爱篮球，作为铁杆詹密我很高兴见证了骑士逆转勇士获得队史第一个NBA总冠军。 我还是喜欢看电影，看各种老电影，喜欢港片，喜欢武侠的感觉。此外这一年在电影院里看了15部电影，不过基本没有什么印象，只记得X战警天启那部。 我还是相信自己会有一段圆满的爱情的，所以我可以等待，用心等待。 人总要充满希望，没有梦想就没有动力，我不愿让自己迷失。\n关于2017 我希望2017年我可以花更多的时间去学习，英语是一定要学好的，操作系统也是必须要学好的，MySQL／Nginx／Redis这三个也得更深入去学习。 我依旧会坚持锻炼肌肉，坚持打篮球，高中之后就很少看书了更多的是看电影，新的一年里我要重新拿起书本，争取做到每个月看一本书。 希望我的朋友们开心，希望我的家人们身体健康，希望我自己可以更优秀。\n","permalink":"http://bug1024.com/2017/01/01/2016summary/","summary":"\u003cp\u003e今年是让我感觉过的最快的一年，发生的种种事情仿佛就在昨日。\n既然是一年的总结那么就写个全面的一点的，包括工作，学习，生活。\n作为一个程序员我原本计划这次年终总结应该花更多笔墨在技术编程上，但思考一番后却发现过去一年在技术领域上并没有什么值得写的。\u003c/p\u003e","title":"2016年总结"},{"content":"毕业不知不觉已经两年半了，原本国庆节的时候就应该写这个总结的，现在已经是十二月份了，此时的我已经辞去了第一份工作，一路北上，加入了北漂一族。\n专业选择 高考成绩并没有很理想，选择专业的时候也完全即兴发挥，后面才发现自己选的几个专业都在一个院系里，都是计算机相关的。\n编程选择 大学过的马马虎虎，学过C，学过Java，最后还是选择了PHP，也许是PHP简单，而恰巧我又喜欢简单。\n工作选择 校招时我看到一家公司招聘海报上写着团队成员有来自百度58等大公司，我觉得挺牛逼于是就投了份简历，但面试官说我缺乏自信，我也承认了，不过最后我还是顺利进入这家公司实习，并一直工作到上个月份。\n离职选择 我有点强迫症，一直暗示自己第一份工作一定要满两年半，果然在呆了快三年后我选择了离职，因为觉得团队其他成员太没有追求了，还有就是领导技术水平实在不敢恭维。既然都是闯，那么干脆就去北京闯一闯，也算是圆了自己的一个心愿。\n新工作选择 过了一把面试的瘾，总体还算顺利，算法准备的没有很充分，其实是根本就没有准备算法，所以还是没进期望的公司。最后选了一家后期要转Java的公司，我也不知道为何现在不排斥Java了，或许是自己追求全能的心态在作怪吧，毕竟多学点东西不是坏事。\n流水账 目前为止写的都像是在记流水账，不过这便是我的风格，没有思想，没有情感。想起以前一个语文老师说我的阅读理解简直就是在发电报，就那么几个字。我是一个不善于表达自己的人，更不善于表现自己了。\n天赋与汗水 从前一直不肯承认自己天赋不足，而现在已经坦然接受自己天赋不足的现实。既然天赋不足，那么唯有努力来弥补了，所以我越来越坚信只有努力才能让自己更接近成功，我深信只要我够努力那么我还是可以变得更优秀。\n时间 我的日记里出现最多的话题莫过于时间，每当看到一个优秀的人，我总感慨为何别人那么年轻就有那么大的作为，然后想想自己已经26岁了，顿时觉得自己是多么年迈。留给自己的时间真的没有很多，把握当下吧！\n规划 有回首，那就应该有展望，尽管我不喜欢给自己做规划。2017年好好学Java和C，深入了解Linux操作系统，熟悉MySQL／Redis／RabbitMQ／Thrift／ElasticSearch原理。\n最后 多读书，多运动，做个充实的人，我迟早会成为一个技术牛人的！\n","permalink":"http://bug1024.com/2016/12/12/past-two-years/","summary":"\u003cp\u003e毕业不知不觉已经两年半了，原本国庆节的时候就应该写这个总结的，现在已经是十二月份了，此时的我已经辞去了第一份工作，一路北上，加入了北漂一族。\u003c/p\u003e\n\u003ch2 id=\"专业选择\"\u003e专业选择\u003c/h2\u003e\n\u003cp\u003e高考成绩并没有很理想，选择专业的时候也完全即兴发挥，后面才发现自己选的几个专业都在一个院系里，都是计算机相关的。\u003c/p\u003e","title":"过去两年"},{"content":"我是谁 Bug1024，一名写了十来年代码的程序员。\n90 后，福建人，北漂。职业生涯从 PHP 后端起步，后来写 Java，折腾过 MySQL、Redis、消息队列、分布式架构——这个博客 2017 年前后的五十多篇文章就是那个时期的记录。\n现在我的工作围绕 AI 展开：做 AI 平台与基础设施，重度使用 AI 工具重构自己的研发工作流，也带团队把 AI 真正落到研发流程里。\n这个博客写什么 AI 工程实践：我用 AI 工具解决真实问题的工作流与踩坑记录 AI 平台与架构：平台建设的一手经验与思考 工程师成长：技术人的职业选择与长期主义 更新不快，每月一篇，但每篇都尽量值得你的时间。\n联系我 GitHub: @bug1024 Email: bug1024.com@gmail.com 彩蛋：本站曾用名\u0026quot;杀猪书生的博客\u0026quot;。爱生活，爱运动，有点暴力，有点黄。\n","permalink":"http://bug1024.com/about/","summary":"\u003ch2 id=\"我是谁\"\u003e我是谁\u003c/h2\u003e\n\u003cp\u003eBug1024，一名写了十来年代码的程序员。\u003c/p\u003e\n\u003cp\u003e90 后，福建人，北漂。职业生涯从 PHP 后端起步，后来写 Java，折腾过 MySQL、Redis、消息队列、分布式架构——这个博客 2017 年前后的五十多篇文章就是那个时期的记录。\u003c/p\u003e","title":"关于"}]