<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>耿瑞阳的博客</title>
  
  
  <link href="/atom.xml" rel="self"/>
  
  <link href="https://Gengry.github.io/"/>
  <updated>2018-10-16T10:53:22.150Z</updated>
  <id>https://Gengry.github.io/</id>
  
  <author>
    <name>Geng</name>
    
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title>SpringBoot多模块项目Jsp页面404</title>
    <link href="https://Gengry.github.io/2018/10/16/SpringBoot%E5%A4%9A%E6%A8%A1%E5%9D%97%E9%A1%B9%E7%9B%AEJsp%E9%A1%B5%E9%9D%A2404/"/>
    <id>https://Gengry.github.io/2018/10/16/SpringBoot多模块项目Jsp页面404/</id>
    <published>2018-10-16T10:48:16.000Z</published>
    <updated>2018-10-16T10:53:22.150Z</updated>
    
    <content type="html"><![CDATA[<p>idea开发springboot（多模块）项目，发现使用main方法启动项目jsp页面404。<br>需要配置Run/Debug configuration。<br>spring boot–&gt; configuration–&gt;working directory : $MODULE_DIR$</p><blockquote class="blockquote-center">今天最好的表现，是明天最低的要求。</blockquote>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;idea开发springboot（多模块）项目，发现使用main方法启动项目jsp页面404。&lt;br&gt;需要配置Run/Debug configuration。&lt;br&gt;spring boot–&amp;gt; configuration–&amp;gt;working directory :
      
    
    </summary>
    
    
  </entry>
  
  <entry>
    <title>Spring自动扫描扫不到jar包内的文件</title>
    <link href="https://Gengry.github.io/2018/05/10/Spring%E8%87%AA%E5%8A%A8%E6%89%AB%E6%8F%8F%E6%89%AB%E4%B8%8D%E5%88%B0jar%E5%8C%85%E5%86%85%E7%9A%84%E6%96%87%E4%BB%B6/"/>
    <id>https://Gengry.github.io/2018/05/10/Spring自动扫描扫不到jar包内的文件/</id>
    <published>2018-05-10T02:45:03.000Z</published>
    <updated>2018-05-10T02:54:23.199Z</updated>
    
    <content type="html"><![CDATA[<p>公司内规定的开发模式，所有功能已模块的形式发布，classes目录内没有class文件，每个功能都是一个jar包，放在lib目录内。<br>有需求需要在原有功能给当地客户定义功能，考虑不侵入原有代码。将新开发的功能单独打一个jar包。<br>我使用的是 jar cvf test.jar com/xxx/xxx/xxx.class打包，但是发现打的包放到服务器上报的是404说明Spring mvc没有识别到Controller。<br>使用 jar tf test.jar 可以看到</p><a id="more"></a><figure class="highlight groovy"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">META-INF/MANIFEST.MF  </span><br><span class="line">com<span class="regexp">/xxx/</span>xxx/xxx.<span class="keyword">class</span></span><br></pre></td></tr></table></figure><p>这样spring是扫描不到的<br>我将test.jar解压，重新执行<br><figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">cd</span> <span class="keyword">test</span></span><br><span class="line">jar cvf <span class="keyword">test</span>.jar *</span><br></pre></td></tr></table></figure></p><p>这样重新生成的目录结构就是<br><figure class="highlight avrasm"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">META-INF/MANIFEST.MF</span><br><span class="line"><span class="keyword">com</span>/</span><br><span class="line"><span class="keyword">com</span>/xxx</span><br><span class="line"><span class="keyword">com</span>/xxx/xxx/</span><br><span class="line"><span class="keyword">com</span>/xxx/xxx/xxx.class</span><br></pre></td></tr></table></figure></p><p>如果是使用eclipse导出勾选<code>Add directory entries</code>即可。</p><blockquote class="blockquote-center">今天最好的表现，是明天最低的要求。</blockquote>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;公司内规定的开发模式，所有功能已模块的形式发布，classes目录内没有class文件，每个功能都是一个jar包，放在lib目录内。&lt;br&gt;有需求需要在原有功能给当地客户定义功能，考虑不侵入原有代码。将新开发的功能单独打一个jar包。&lt;br&gt;我使用的是 jar cvf test.jar com/xxx/xxx/xxx.class打包，但是发现打的包放到服务器上报的是404说明Spring mvc没有识别到Controller。&lt;br&gt;使用 jar tf test.jar 可以看到&lt;/p&gt;
    
    </summary>
    
    
  </entry>
  
  <entry>
    <title>MapReduce笔记</title>
    <link href="https://Gengry.github.io/2018/04/06/MapReduce%E7%AC%94%E8%AE%B0/"/>
    <id>https://Gengry.github.io/2018/04/06/MapReduce笔记/</id>
    <published>2018-04-06T06:30:54.000Z</published>
    <updated>2018-04-06T07:49:47.377Z</updated>
    
    <content type="html"><![CDATA[<h2 id="MapReduce原理"><a href="#MapReduce原理" class="headerlink" title="MapReduce原理"></a>MapReduce原理</h2><p><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180406/5.jpg" alt=""> </p><p>在将map的结果集传递给reduce之前对数据进行了分组（类似于对K2做了group by）</p><p><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180406/6.jpg" alt=""> </p><h2 id="执行步骤"><a href="#执行步骤" class="headerlink" title="执行步骤"></a>执行步骤</h2><h3 id="map任务处理"><a href="#map任务处理" class="headerlink" title="map任务处理"></a>map任务处理</h3><ul><li>读取输入文件内容，解析成key、value对。对输入文件的每一行，解析成key、value对。每一个键值对调用一次map函数。</li><li>写自己的逻辑，对输入的key、value处理，转换成新的key、value输出。</li><li>对输出的key、value进行分区。</li><li>对不同分区的数据，按照key进行排序、分组。相同key的value放到一个集合中。</li><li>(可选)分组后的数据进行归约。</li></ul><h3 id="reduce任务处理"><a href="#reduce任务处理" class="headerlink" title="reduce任务处理"></a>reduce任务处理</h3><ul><li>对多个map任务的输出，按照不同的分区，通过网络copy到不同的reduce节点。</li><li>对多个map任务的输出进行合并、排序。写reduce函数自己的逻辑，对输入的key、value处理，转换成新的key、value输出。</li><li>把reduce的输出保存到文件中。</li></ul><blockquote class="blockquote-center">今天最好的表现，是明天最低的要求。</blockquote>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h2 id=&quot;MapReduce原理&quot;&gt;&lt;a href=&quot;#MapReduce原理&quot; class=&quot;headerlink&quot; title=&quot;MapReduce原理&quot;&gt;&lt;/a&gt;MapReduce原理&lt;/h2&gt;&lt;p&gt;&lt;img src=&quot;https://raw.githubuserco
      
    
    </summary>
    
    
  </entry>
  
  <entry>
    <title>HDFS学习笔记</title>
    <link href="https://Gengry.github.io/2018/04/06/HDFS%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    <id>https://Gengry.github.io/2018/04/06/HDFS学习笔记/</id>
    <published>2018-04-06T01:41:24.000Z</published>
    <updated>2018-04-06T04:41:22.844Z</updated>
    
    <content type="html"><![CDATA[<h2 id="HDFS架构体系"><a href="#HDFS架构体系" class="headerlink" title="HDFS架构体系"></a>HDFS架构体系</h2><p><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180406/1.jpg" alt="">  </p><h3 id="元数据"><a href="#元数据" class="headerlink" title="元数据"></a>元数据</h3><p><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180406/2.jpg" alt="">  </p><h2 id="NameNode"><a href="#NameNode" class="headerlink" title="NameNode"></a>NameNode</h2><ul><li>是整个文件系统的管理节点。它维护着整个文件系统的文件目录树，文件/目录的元信息和每个文件对应的数据块列表。接收用户的操作请求。</li><li>文件包括：<ul><li>fsimage:元数据镜像文件。存储某一时段NameNode内存元数据信息。</li><li>edits:操作日志文件。</li></ul></li><li>fstime:保存最近一次checkpoint的时间</li><li>以上这些文件是保存在linux的文件系统中。<h3 id="NameNode工作特点"><a href="#NameNode工作特点" class="headerlink" title="NameNode工作特点"></a>NameNode工作特点</h3></li></ul><ol><li>Namenode始终在内存中保存metedata，用于处理“读请求”</li><li>到有“写请求”到来时，namenode会首先写editlog到磁盘，即向edits文件中写日志，成功返回后，才会修改内存，并且向客户端返回</li><li>Hadoop会维护一个fsimage文件，也就是namenode中metedata的镜像，但是fsimage不会随时与namenode内存中的metedata保持一致，而是每隔一段时间通过合并edits文件来更新内容。Secondary namenode就是用来合并fsimage和edits文件来更新NameNode的metedata的。</li></ol><h2 id="SecondaryNameNode"><a href="#SecondaryNameNode" class="headerlink" title="SecondaryNameNode"></a>SecondaryNameNode</h2><ul><li>HA的一个解决方案。但不支持热备。配置即可。</li><li>执行过程：从NameNode上下载元数据信息（fsimage,edits），然后把二者合并，生成新的fsimage，在本地保存，并将其推送到NameNode，替换旧的fsimage.</li><li>默认在安装在NameNode节点上，但这样…不安全！</li></ul><h3 id="secondary-namenode的工作流程"><a href="#secondary-namenode的工作流程" class="headerlink" title="secondary namenode的工作流程"></a>secondary namenode的工作流程</h3><ol><li>secondary通知namenode切换edits文件</li><li>secondary从namenode获得fsimage和edits(通过http)</li><li>secondary将fsimage载入内存，然后开始合并edits</li><li>secondary将新的fsimage发回给namenode</li><li>namenode用新的fsimage替换旧的fsimage</li></ol><h2 id="DataNode"><a href="#DataNode" class="headerlink" title="DataNode"></a>DataNode</h2><ul><li>提供真实文件数据的存储服务。</li><li>文件块（block）：最基本的存储单位。对于文件内容而言，一个文件的长度大小是size，那么从文件的０偏移开始，按照固定的大小，顺序对文件进行划分并编号，划分好的每一个块称一个Block。HDFS默认Block大小是128MB，以一个256MB文件，共有256/128=2个Block.<br>不同于普通文件系统的是，HDFS中，如果一个文件小于一个数据块的大小，并不占用整个数据块存储空间</li><li>Replication。多复本。默认是三个。 hdfs-site.xml的dfs.replication属性</li></ul><h2 id="HDFS"><a href="#HDFS" class="headerlink" title="HDFS"></a>HDFS</h2><h3 id="读过程"><a href="#读过程" class="headerlink" title="读过程"></a>读过程</h3><blockquote><p>初始化FileSystem，然后客户端(client)用FileSystem的open()函数打开文件<br>FileSystem用RPC调用元数据节点，得到文件的数据块信息，对于每一个数据块，元数据节点返回保存数据块的数据节点的地址。<br>FileSystem返回FSDataInputStream给客户端，用来读取数据，客户端调用stream的read()函数开始读取数据。<br>DFSInputStream连接保存此文件第一个数据块的最近的数据节点，data从数据节点读到客户端(client)<br>当此数据块读取完毕时，DFSInputStream关闭和此数据节点的连接，然后连接此文件下一个数据块的最近的数据节点。<br>当客户端读取完毕数据的时候，调用FSDataInputStream的close函数。<br>在读取数据的过程中，如果客户端在与数据节点通信出现错误，则尝试连接包含此数据块的下一个数据节点。<br>失败的数据节点将被记录，以后不再连接。</p></blockquote><p><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180406/3.jpg" alt="">  </p><h3 id="写过程"><a href="#写过程" class="headerlink" title="写过程"></a>写过程</h3><blockquote><p>初始化FileSystem，客户端调用create()来创建文件<br>FileSystem用RPC调用元数据节点，在文件系统的命名空间中创建一个新的文件，元数据节点首先确定文件原来不存在，并且客户端有创建文件的权限，然后创建新文件。<br>FileSystem返回DFSOutputStream，客户端用于写数据，客户端开始写入数据。<br>DFSOutputStream将数据分成块，写入data queue。data queue由Data Streamer读取，并通知元数据节点分配数据节点，用来存储数据块(每块默认复制3块)。分配的数据节点放在一个pipeline里。Data Streamer将数据块写入pipeline中的第一个数据节点。第一个数据节点将数据块发送给第二个数据节点。第二个数据节点将数据发送给第三个数据节点。<br>DFSOutputStream为发出去的数据块保存了ack queue，等待pipeline中的数据节点告知数据已经写入成功。<br>当客户端结束写入数据，则调用stream的close函数。此操作将所有的数据块写入pipeline中的数据节点，并等待ack queue返回成功。最后通知元数据节点写入完毕。<br>如果数据节点在写入的过程中失败，关闭pipeline，将ack queue中的数据块放入data queue的开始，当前的数据块在已经写入的数据节点中被元数据节点赋予新的标示，则错误节点重启后能够察觉其数据块是过时的，会被删除。失败的数据节点从pipeline中移除，另外的数据块则写入pipeline中的另外两个数据节点。元数据节点则被通知此数据块是复制块数不足，将来会再创建第三份备份。</p></blockquote><p><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180406/4.jpg" alt="">  </p><h2 id="HDFS-shell"><a href="#HDFS-shell" class="headerlink" title="HDFS shell"></a>HDFS shell</h2><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1</span>，Hadoop fs –fs [local | &lt;<span class="keyword">file</span> <span class="built_in">system</span> URI&gt;]：声明hadoop使用的文件系统，如果不声明的话，使用当前配置文件配置的，按如下顺序查找：hadoop jar里的hadoop-default.xml-&gt;$HADOOP_CONF_DIR下的hadoop-default.xml-&gt;$HADOOP_CONF_DIR下的hadoop-site.xml。使用local代表将本地文件系统作为hadoop的DFS。如果传递uri做参数，那么就是特定的文件系统作为DFS。</span><br><span class="line"></span><br><span class="line"><span class="number">2</span>，hadoop fs –<span class="keyword">ls</span> <span class="symbol">&lt;path&gt;</span>：等同于本地系统的<span class="keyword">ls</span>，列出在指定目录下的文件内容，支持pattern匹配。输出格式如filename(full path)   &lt;r n&gt;  size.其中n代表replica的个数，size代表大小（单位bytes）。</span><br><span class="line"></span><br><span class="line"><span class="number">3</span>，hadoop fs –lsr <span class="symbol">&lt;path&gt;</span>：递归列出匹配pattern的文件信息，类似<span class="keyword">ls</span>，只不过递归列出所有子目录信息。</span><br><span class="line"></span><br><span class="line"><span class="number">4</span>，hadoop fs –du <span class="symbol">&lt;path&gt;</span>：列出匹配pattern的指定的文件系统空间总量（单位bytes），等价于unix下的针对目录的du –<span class="keyword">sb</span> <span class="symbol">&lt;path&gt;</span>/*和针对文件的du –<span class="keyword">b</span> <span class="symbol">&lt;path&gt;</span> ，输出格式如name(full path)  size(in bytes)。</span><br><span class="line"></span><br><span class="line"><span class="number">5</span>，hadoop fs –dus <span class="symbol">&lt;path&gt;</span>：等价于-du，输出格式也相同，只不过等价于unix的du -<span class="keyword">sb</span>。</span><br><span class="line"></span><br><span class="line"><span class="number">6</span>，hadoop fs –mv <span class="symbol">&lt;src&gt;</span> <span class="symbol">&lt;dst&gt;</span>：将制定格式的文件 <span class="keyword">move</span>到指定的目标位置。当src为多个文件时，dst必须是个目录。</span><br><span class="line"></span><br><span class="line"><span class="number">7</span>，hadoop fs –<span class="keyword">cp</span> <span class="symbol">&lt;src&gt;</span> <span class="symbol">&lt;dst&gt;</span>：拷贝文件到目标位置，当src为多个文件时，dst必须是个目录。</span><br><span class="line"></span><br><span class="line"><span class="number">8</span>，hadoop fs –rm [-skipTrash] <span class="symbol">&lt;src&gt;</span>：删除匹配pattern的指定文件，等价于unix下的rm <span class="symbol">&lt;src&gt;</span>。</span><br><span class="line"></span><br><span class="line"><span class="number">9</span>，hadoop fs –rmr [skipTrash] <span class="symbol">&lt;src&gt;</span>：递归删掉所有的文件和目录，等价于unix下的rm –rf <span class="symbol">&lt;src&gt;</span>。</span><br><span class="line"></span><br><span class="line"><span class="number">10</span>，hadoop fs –rmi [skipTrash] <span class="symbol">&lt;src&gt;</span>：等价于unix的rm –rfi <span class="symbol">&lt;src&gt;</span>。</span><br><span class="line"></span><br><span class="line"><span class="number">11</span>，hadoop fs –<span class="keyword">put</span> <span class="symbol">&lt;localsrc&gt;</span> … <span class="symbol">&lt;dst&gt;</span>：从本地系统拷贝文件到DFS。</span><br><span class="line"></span><br><span class="line"><span class="number">12</span>，hadoop fs –copyFromLocal <span class="symbol">&lt;localsrc&gt;</span> … <span class="symbol">&lt;dst&gt;</span>：等价于-<span class="keyword">put</span>。</span><br><span class="line"></span><br><span class="line"><span class="number">13</span>，hadoop fs –moveFromLocal <span class="symbol">&lt;localsrc&gt;</span> … <span class="symbol">&lt;dst&gt;</span>：等同于-<span class="keyword">put</span>，只不过源文件在拷贝后被删除。</span><br><span class="line"></span><br><span class="line"><span class="number">14</span>，hadoop fs –<span class="built_in">get</span> [-ignoreCrc] [-crc] <span class="symbol">&lt;src&gt;</span> <span class="symbol">&lt;localdst&gt;</span>：从DFS拷贝文件到本地文件系统，文件匹配pattern，若是多个文件，则dst必须是目录。</span><br><span class="line"></span><br><span class="line"><span class="number">15</span>，hadoop fs –getmerge <span class="symbol">&lt;src&gt;</span> <span class="symbol">&lt;localdst&gt;</span>：顾名思义，从DFS拷贝多个文件、合并排序为一个文件到本地文件系统。</span><br><span class="line"></span><br><span class="line"><span class="number">16</span>，hadoop fs –<span class="keyword">cat</span> <span class="symbol">&lt;src&gt;</span>：展示文件内容。</span><br><span class="line"></span><br><span class="line"><span class="number">17</span>，hadoop fs –copyToLocal [-ignoreCrc] [-crc] <span class="symbol">&lt;src&gt;</span> <span class="symbol">&lt;localdst&gt;</span>：等价于-<span class="built_in">get</span>。</span><br><span class="line"></span><br><span class="line"><span class="number">18</span>，hadoop fs –<span class="built_in">mkdir</span> <span class="symbol">&lt;path&gt;</span>：在指定位置创建目录。</span><br><span class="line"></span><br><span class="line"><span class="number">19</span>，hadoop fs –setrep [-R] [-<span class="keyword">w</span>] <span class="symbol">&lt;rep&gt;</span> &lt;path/<span class="keyword">file</span>&gt;：设置文件的备份级别，-R标志控制是否递归设置子目录及文件。</span><br><span class="line"></span><br><span class="line"><span class="number">20</span>，hadoop fs –chmod [-R] &lt;MODE[,MODE]…|OCTALMODE&gt; PATH…：修改文件的权限，-R标记递归修改。MODE为<span class="keyword">a</span>+r,g-<span class="keyword">w</span>,+rwx等，OCTALMODE为<span class="number">755</span>这样。</span><br><span class="line"></span><br><span class="line"><span class="number">21</span>，hadoop fs -chown [-R] [OWNER][:[GROUP]] PATH…：修改文件的所有者和组。-R表示递归。</span><br><span class="line"></span><br><span class="line"><span class="number">22</span>，hadoop fs -chgrp [-R] GROUP PATH…：等价于-chown … :GROUP …。</span><br><span class="line"></span><br><span class="line"><span class="number">23</span>，hadoop fs –<span class="built_in">count</span>[-q] <span class="symbol">&lt;path&gt;</span>：计数文件个数及所占空间的详情，输出表格的列的含义依次为：DIR_COUNT,FILE_COUNT,CONTENT_SIZE,FILE_NAME或者如果加了-q的话，还会列出QUOTA,REMAINING_QUOTA,SPACE_QUOTA,REMAINING_SPACE_QUOTA。</span><br></pre></td></tr></table></figure><blockquote class="blockquote-center">今天最好的表现，是明天最低的要求。</blockquote>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h2 id=&quot;HDFS架构体系&quot;&gt;&lt;a href=&quot;#HDFS架构体系&quot; class=&quot;headerlink&quot; title=&quot;HDFS架构体系&quot;&gt;&lt;/a&gt;HDFS架构体系&lt;/h2&gt;&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Ge
      
    
    </summary>
    
    
  </entry>
  
  <entry>
    <title>安装单机hadoop-linux虚拟机配置</title>
    <link href="https://Gengry.github.io/2018/04/05/%E5%AE%89%E8%A3%85%E5%8D%95%E6%9C%BAhadoop-linux%E8%99%9A%E6%8B%9F%E6%9C%BA%E9%85%8D%E7%BD%AE/"/>
    <id>https://Gengry.github.io/2018/04/05/安装单机hadoop-linux虚拟机配置/</id>
    <published>2018-04-05T03:38:36.000Z</published>
    <updated>2018-04-05T13:36:34.993Z</updated>
    
    <content type="html"><![CDATA[<p>伪分布模式安装步骤</p><ul><li>关闭防火墙</li><li>修改ip</li><li>修改hostname</li><li>设置ssh自动登录</li><li>安装jdk</li><li>安装hadoop<a id="more"></a></li></ul><h2 id="防火墙"><a href="#防火墙" class="headerlink" title="防火墙"></a>防火墙</h2><p>CentOS 6.5关闭防火墙<br>[root@localhost ~]#servcie iptables stop                    –临时关闭防火墙<br>[root@localhost ~]#chkconfig iptables off                    –永久关闭防火墙</p><p>CentOS 7.2关闭防火墙<br>CentOS 7.0默认使用的是firewall作为防火墙，这里改为iptables防火墙步骤。<br>firewall-cmd –state #查看默认防火墙状态（关闭后显示notrunning，开启后显示running）<br>[root@localhost ~]#firewall-cmd –state<br>not running</p><p>systemctl stop firewalld.service #停止firewall<br>systemctl disable firewalld.service #禁止firewall开机启动</p><h2 id="修改ip"><a href="#修改ip" class="headerlink" title="修改ip"></a>修改ip</h2><blockquote><p>vim /etc/sysconfig/network-script/ifcfg-eth0<br>BOOTPROTO=static<br>IPADDR=192.168.137.3<br>NETMASK=255.255.255.0<br>GATEWAY=192.168.137.1<br>DNS1=8.8.8.8<br>DNS2=8.8.4.4</p></blockquote><h2 id="安装jdk"><a href="#安装jdk" class="headerlink" title="安装jdk"></a>安装jdk</h2><p>下载linux版的jdk，使用xshell上传到虚拟机。</p><blockquote><p>  tar -zxvf jdk-7u80-linux-x64.tar.gz<br>  mv jdk1.7.0_80/ /usr/local/<br>  vim /etc/profile<br>export JAVA_HOME=/usr/local/jdk1.7.0_80　　<br>  export JRE_HOME=/usr/local/jdk1.7.0_80/jre<br>　export PATH=$PATH:/usr/local/jdk1.7.0_80/bin<br>　export CLASSPATH=./:/usr/local/jdk1.7.0_80/lib:/usr/local/jdk1.7.0_80/jre/lib</p></blockquote><p>1.准备Linux环境<br>    1.0点击VMware快捷方式，右键打开文件所在位置 -&gt; 双击vmnetcfg.exe -&gt; VMnet1 host-only -&gt;修改subnet ip 设置网段：192.168.1.0 子网掩码：255.255.255.0 -&gt; apply -&gt; ok<br>        回到windows –&gt; 打开网络和共享中心 -&gt; 更改适配器设置 -&gt; 右键VMnet1 -&gt; 属性 -&gt; 双击IPv4 -&gt; 设置windows的IP：192.168.1.110 子网掩码：255.255.255.0 -&gt; 点击确定<br>        在虚拟软件上 –My Computer -&gt; 选中虚拟机 -&gt; 右键 -&gt; settings -&gt; network adapter -&gt; host only -&gt; ok<br>    1.1修改主机名<br>        vim /etc/sysconfig/network</p><pre><code>    NETWORKING=yes     HOSTNAME=itcast01    ###1.2修改IP    两种方式：    第一种：通过Linux图形界面进行修改（强烈推荐）        进入Linux图形界面 -&gt; 右键点击右上方的两个小电脑 -&gt; 点击Edit connections -&gt; 选中当前网络System eth0 -&gt; 点击edit按钮 -&gt; 选择IPv4 -&gt; method选择为manual -&gt; 点击add按钮 -&gt; 添加IP：192.168.1.119 子网掩码：255.255.255.0 网关：192.168.1.1 -&gt; apply    第二种：修改配置文件方式（屌丝程序猿专用）        vim /etc/sysconfig/network-scripts/ifcfg-eth0        DEVICE=&quot;eth0&quot;        BOOTPROTO=&quot;static&quot;           ###        HWADDR=&quot;00:0C:29:3C:BF:E7&quot;        IPV6INIT=&quot;yes&quot;        NM_CONTROLLED=&quot;yes&quot;        ONBOOT=&quot;yes&quot;        TYPE=&quot;Ethernet&quot;        UUID=&quot;ce22eeca-ecde-4536-8cc2-ef0dc36d4a8c&quot;        IPADDR=&quot;192.168.1.44&quot;       ###        NETMASK=&quot;255.255.255.0&quot;      ###        GATEWAY=&quot;192.168.1.1&quot;        ###1.3修改主机名和IP的映射关系    vim /etc/hosts    192.168.1.44    itcast011.4关闭防火墙    #查看防火墙状态    service iptables status    #关闭防火墙    service iptables stop    #查看防火墙开机启动状态    chkconfig iptables --list    #关闭防火墙开机启动    chkconfig iptables off1.5重启Linux    reboot</code></pre><p>2.安装JDK<br>    2.1上传</p><pre><code>2.2解压jdk    #创建文件夹    mkdir /usr/java    #解压    tar -zxvf jdk-7u55-linux-i586.tar.gz -C /usr/java/2.3将java添加到环境变量中    vim /etc/profile    #在文件最后添加    export JAVA_HOME=/usr/java/jdk1.7.0_55    export PATH=$PATH:$JAVA_HOME/bin    #刷新配置    source /etc/profile</code></pre><p>3.安装Hadoop<br>    3.1上传hadoop安装包</p><pre><code>3.2解压hadoop安装包    mkdir /cloud    #解压到/cloud/目录下    tar -zxvf hadoop-2.2.0.tar.gz -C /cloud/3.3修改配置文件（5个）    第一个：hadoop-env.sh    #在27行修改    export JAVA_HOME=/usr/java/jdk1.7.0_55    第二个：core-site.xml    &lt;configuration&gt;        &lt;!-- 指定HDFS老大（namenode）的通信地址 --&gt;        &lt;property&gt;                &lt;name&gt;fs.defaultFS&lt;/name&gt;                &lt;value&gt;hdfs://itcast01:9000&lt;/value&gt;        &lt;/property&gt;        &lt;!-- 指定hadoop运行时产生文件的存储路径 --&gt;        &lt;property&gt;                &lt;name&gt;hadoop.tmp.dir&lt;/name&gt;                &lt;value&gt;/cloud/hadoop-2.2.0/tmp&lt;/value&gt;        &lt;/property&gt;    &lt;/configuration&gt;    第三个：hdfs-site.xml    &lt;configuration&gt;        &lt;!-- 设置hdfs副本数量 --&gt;        &lt;property&gt;                &lt;name&gt;dfs.replication&lt;/name&gt;                &lt;value&gt;1&lt;/value&gt;        &lt;/property&gt;    &lt;/configuration&gt;    第四个：mapred-site.xml.template 需要重命名： mv mapred-site.xml.template mapred-site.xml    &lt;configuration&gt;        &lt;!-- 通知框架MR使用YARN --&gt;        &lt;property&gt;                &lt;name&gt;mapreduce.framework.name&lt;/name&gt;                &lt;value&gt;yarn&lt;/value&gt;        &lt;/property&gt;    &lt;/configuration&gt;    第五个：yarn-site.xml    &lt;configuration&gt;        &lt;!-- reducer取数据的方式是mapreduce_shuffle --&gt;        &lt;property&gt;            &lt;name&gt;yarn.nodemanager.aux-services&lt;/name&gt;            &lt;value&gt;mapreduce_shuffle&lt;/value&gt;        &lt;/property&gt;    &lt;/configuration&gt;3.4将hadoop添加到环境变量    vim /etc/profile    export JAVA_HOME=/usr/java/jdk1.7.0_55    export HADOOP_HOME=/cloud/hadoop-2.2.0    export PATH=$PATH:$JAVA_HOME/bin:$HADOOP_HOME/bin    source /etc/profile3.5格式化HDFS（namenode）第一次使用时要格式化    hadoop namenode -format3.6启动hadoop    先启动HDFS    sbin/start-dfs.sh    再启动YARN    sbin/start-yarn.sh3.7验证是否启动成功    使用jps命令验证    27408 NameNode    28218 Jps    27643 SecondaryNameNode    28066 NodeManager    27803 ResourceManager    27512 DataNode    http://192.168.1.44:50070  (HDFS管理界面)    在这个文件中添加linux主机名和IP的映射关系    C:\Windows\System32\drivers\etc\hosts    192.168.1.119    itcast    http://192.168.1.44:8088 （MR管理界面）</code></pre><p>4.配置ssh免登陆<br>    生成ssh免登陆密钥<br>    cd ~，进入到我的home目录<br>    cd .ssh/</p><pre><code>ssh-keygen -t rsa （四个回车）执行完这个命令后，会生成两个文件id_rsa（私钥）、id_rsa.pub（公钥）将公钥拷贝到要免登陆的机器上cat ~/.ssh/id_rsa.pub &gt;&gt; ~/.ssh/authorized_keys或ssh-copy-id -i localhost </code></pre><p>5.hdfs基本使用</p><pre><code>1.0查看帮助    hadoop fs -help &lt;cmd&gt;1.1上传    hadoop fs -put &lt;linux上文件&gt; &lt;hdfs上的路径&gt;1.2查看文件内容    hadoop fs -cat &lt;hdfs上的路径&gt;1.3查看文件列表    hadoop fs -ls /1.4下载文件    hadoop fs -get &lt;hdfs上的路径&gt; &lt;linux上文件&gt;</code></pre><p>6.MapReduce示例</p><p>hadoop为我们提供了mr的示例程序，存放在/hadoop/hadoop-2.2.0/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.2.0.jar</p><p>安装hadoop2.4.1<br>    注意：hadoop2.x的配置文件$HADOOP_HOME/etc/hadoop<br>    伪分布式需要修改5个配置文件<br>    3.1配置hadoop<br>    第一个：hadoop-env.sh<br>        vim hadoop-env.sh</p><pre><code>    #第27行    export JAVA_HOME=/usr/java/jdk1.7.0_65第二个：core-site.xml    &lt;!-- 制定HDFS的老大（NameNode）的地址 --&gt;    &lt;property&gt;        &lt;name&gt;fs.defaultFS&lt;/name&gt;        &lt;value&gt;hdfs://itcast01:9000&lt;/value&gt;    &lt;/property&gt;    &lt;!-- 指定hadoop运行时产生文件的存储目录 --&gt;    &lt;property&gt;        &lt;name&gt;hadoop.tmp.dir&lt;/name&gt;        &lt;value&gt;/itcast/hadoop-2.4.1/tmp&lt;/value&gt;    &lt;/property&gt;第三个：hdfs-site.xml    &lt;!-- 指定HDFS副本的数量 --&gt;    &lt;property&gt;        &lt;name&gt;dfs.replication&lt;/name&gt;        &lt;value&gt;1&lt;/value&gt;    &lt;/property&gt;第四个：mapred-site.xml (mv mapred-site.xml.template mapred-site.xml)    mv mapred-site.xml.template mapred-site.xml    vim mapred-site.xml    &lt;!-- 指定mr运行在yarn上 --&gt;    &lt;property&gt;        &lt;name&gt;mapreduce.framework.name&lt;/name&gt;        &lt;value&gt;yarn&lt;/value&gt;    &lt;/property&gt;第五个：yarn-site.xml    &lt;!-- 指定YARN的老大（ResourceManager）的地址 --&gt;    &lt;property&gt;        &lt;name&gt;yarn.resourcemanager.hostname&lt;/name&gt;        &lt;value&gt;itcast01&lt;/value&gt;    &lt;/property&gt;    &lt;!-- reducer获取数据的方式 --&gt;    &lt;property&gt;        &lt;name&gt;yarn.nodemanager.aux-services&lt;/name&gt;        &lt;value&gt;mapreduce_shuffle&lt;/value&gt;    &lt;/property&gt;3.2将hadoop添加到环境变量vim /etc/proflie    export JAVA_HOME=/usr/java/jdk1.7.0_65    export HADOOP_HOME=/itcast/hadoop-2.4.1    export PATH=$PATH:$JAVA_HOME/bin:$HADOOP_HOME/bin:$HADOOP_HOME/sbinsource /etc/profile3.3格式化namenode（是对namenode进行初始化）    hdfs namenode -format (hadoop namenode -format)3.4启动hadoop    先启动HDFS    sbin/start-dfs.sh    再启动YARN    sbin/start-yarn.sh3.5验证是否启动成功    使用jps命令验证    27408 NameNode    28218 Jps    27643 SecondaryNameNode    28066 NodeManager    27803 ResourceManager    27512 DataNode    http://192.168.8.118:50070 （HDFS管理界面）    http://192.168.8.118:8088 （MR管理界面）</code></pre><h2 id="遇到的问题"><a href="#遇到的问题" class="headerlink" title="遇到的问题"></a>遇到的问题</h2><p>启动hdfs，datanode无法启动。<br>可以看到datanode日志文件报错<code>hadoop-root-datanode-localhost.localdomain.log</code><br><code>org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.hdfs.server.protocol.DisallowedDatanodeException): Datanode denied communication with namenode: DatanodeRegistration(0.0.0.0, storageID=DS-1492551125-127.0.0.1-50010-1522922793693, infoPort=50075, ipcPort=50020, storageInfo=lv=-47;cid=CID-0a985653-165f-4fed-8366-d5552fe4abd9;nsid=150074941;c=0)at org.apache.hadoop.hdfs.server.blockmanagement.DatanodeManager.registerDatanode(DatanodeManager.java:739)</code></p><p>解决：<br>    修改hosts文件  vim /etc/hosts<br>    添加 192.168.138.3 localhost<br>解决办法二：<br>    在namenode的hdfs-site.xml 里面添加<br>    <figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">name</span>&gt;</span>dfs.namenode.datanode.registration.ip-hostname-check<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">value</span>&gt;</span>false<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br></pre></td></tr></table></figure></p><p>网上给出的错误原因：<br>错误和原来的hosts中的“127.0.0.1 localhost”没有关系，是增加了的“192.168.1.101 localhost”解决了问题。原因在于RSA没有给局域网ip（192.168.1.101）授权，造成data node没有正常启动。</p><p>项目启动后<a href="http://192.168.137.3:50070页面内的`Browse" target="_blank" rel="noopener">http://192.168.137.3:50070页面内的`Browse</a> the filesystem`无法访问</p><p>解决：<br>    点击<code>Browse the filesystem</code>浏览器中的地址栏为<code>http://localhost:50075/browseDirectory.jsp?namenodeInfoPort=50070&amp;dir=/&amp;nnaddr=192.168.137.3:9000</code><br>    很明显是地址不对，但是用鼠标指着<code>Browse the filesystem</code>显示的地址是对的，说明在browseDirectory.jsp做了一次页面跳转。<br>    将地址手动修改为192.168.137.3:50075后可以正常访问。<br>    猜测：<br>        <code>browseDirectory.jsp</code>这个页面内namenode随机选择了一个datanode的地址做跳转，对于namenode来说，单机模式的datanode地址就是localhost。<br>        我自己配置的时候并没有配置主机名，主机默认就是localhost。<br>    修改：<br>        配置主机名<br>        vim /etc/sysconfig/network<br>        NETWORKING=yes<br>        HOSTNAME=gengry    ###<br>        配置主机名和ip对应关系<br>        vim /etc/hosts<br>        192.168.137.3    gengry<br>        配置windows的hosts<br>        192.168.137.3    gengry<br>    重启hadoop，再次访问，正常。</p><blockquote class="blockquote-center">今天最好的表现，是明天最低的要求。</blockquote>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;伪分布模式安装步骤&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;关闭防火墙&lt;/li&gt;
&lt;li&gt;修改ip&lt;/li&gt;
&lt;li&gt;修改hostname&lt;/li&gt;
&lt;li&gt;设置ssh自动登录&lt;/li&gt;
&lt;li&gt;安装jdk&lt;/li&gt;
&lt;li&gt;安装hadoop
    
    </summary>
    
    
  </entry>
  
  <entry>
    <title>Java多线程--三个线程分别打印a,b,c.请用多线程实现循环打印15次abc</title>
    <link href="https://Gengry.github.io/2018/03/26/Java%E5%A4%9A%E7%BA%BF%E7%A8%8B-%E4%B8%89%E4%B8%AA%E7%BA%BF%E7%A8%8B%E5%88%86%E5%88%AB%E6%89%93%E5%8D%B0a-b-c-%E8%AF%B7%E7%94%A8%E5%A4%9A%E7%BA%BF%E7%A8%8B%E5%AE%9E%E7%8E%B0%E5%BE%AA%E7%8E%AF%E6%89%93%E5%8D%B015%E6%AC%A1abc/"/>
    <id>https://Gengry.github.io/2018/03/26/Java多线程-三个线程分别打印a-b-c-请用多线程实现循环打印15次abc/</id>
    <published>2018-03-26T06:25:32.000Z</published>
    <updated>2018-03-26T06:27:01.650Z</updated>
    
    <content type="html"><![CDATA[<p>Java多线程–三个线程分别打印a,b,c.请用多线程实现循环打印15次abc<br><a id="more"></a></p><figure class="highlight cs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br></pre></td><td class="code"><pre><span class="line">import java.util.concurrent.locks.Condition;</span><br><span class="line">import java.util.concurrent.locks.Lock;</span><br><span class="line">import java.util.concurrent.locks.ReentrantLock;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Created by CHG on 2017-02-23 20:20.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title">PrintABC</span> &#123;</span><br><span class="line">    <span class="keyword">int</span> count = <span class="number">0</span>; <span class="comment">//打印次数</span></span><br><span class="line">    Lock <span class="keyword">lock</span> = <span class="keyword">new</span> ReentrantLock();  <span class="comment">//可重写锁</span></span><br><span class="line">    Condition conditionA = <span class="keyword">this</span>.<span class="keyword">lock</span>.newCondition();</span><br><span class="line">    Condition conditionB = <span class="keyword">this</span>.<span class="keyword">lock</span>.newCondition();</span><br><span class="line">    Condition conditionC = <span class="keyword">this</span>.<span class="keyword">lock</span>.newCondition();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">class</span> <span class="title">PrintA</span> <span class="title">implements</span> <span class="title">Runnable</span> &#123;</span><br><span class="line">        @Override</span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">            <span class="keyword">while</span> (<span class="literal">true</span>)</span><br><span class="line">                <span class="keyword">if</span> (count &lt; <span class="number">15</span>) &#123;</span><br><span class="line">                    <span class="keyword">lock</span>.<span class="keyword">lock</span>();</span><br><span class="line">                    System.<span class="keyword">out</span>.print(<span class="string">"A"</span>);</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        conditionB.signal();  <span class="comment">//线程b唤醒,因为a打印完应该打印b</span></span><br><span class="line">                        conditionA.<span class="keyword">await</span>();  <span class="comment">//线程a进入等待队列</span></span><br><span class="line">                    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                        e.printStackTrace();</span><br><span class="line">                    &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">                        <span class="keyword">lock</span>.unlock();</span><br><span class="line">                    &#125;</span><br><span class="line"></span><br><span class="line">                &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">class</span> <span class="title">PrintB</span> <span class="title">implements</span> <span class="title">Runnable</span> &#123;</span><br><span class="line">        @Override</span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">            <span class="keyword">while</span> (<span class="literal">true</span>)</span><br><span class="line">                <span class="keyword">if</span> (count &lt; <span class="number">15</span>) &#123;</span><br><span class="line">                    <span class="keyword">lock</span>.<span class="keyword">lock</span>();</span><br><span class="line">                    System.<span class="keyword">out</span>.print(<span class="string">"B"</span>);</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        conditionC.signal();</span><br><span class="line">                        conditionB.<span class="keyword">await</span>();</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                        e.printStackTrace();</span><br><span class="line">                    &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">                        <span class="keyword">lock</span>.unlock();</span><br><span class="line">                    &#125;</span><br><span class="line"></span><br><span class="line">                &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">class</span> <span class="title">PrintC</span> <span class="title">implements</span> <span class="title">Runnable</span> &#123;</span><br><span class="line">        @Override</span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">            <span class="keyword">while</span> (<span class="literal">true</span>)</span><br><span class="line">                <span class="keyword">if</span> (count &lt; <span class="number">15</span>) &#123;</span><br><span class="line">                    <span class="keyword">lock</span>.<span class="keyword">lock</span>();</span><br><span class="line">                    System.<span class="keyword">out</span>.println(<span class="string">"C"</span> + count);</span><br><span class="line">                    count++;<span class="comment">//打印完c后,count++</span></span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        conditionA.signal();</span><br><span class="line">                        conditionC.<span class="keyword">await</span>();</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                        e.printStackTrace();</span><br><span class="line">                    &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">                        <span class="keyword">lock</span>.unlock();</span><br><span class="line">                    &#125;</span><br><span class="line"></span><br><span class="line">                &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span>(<span class="params">String[] args</span>) </span>&#123;</span><br><span class="line">        PrintABC printABCD = <span class="keyword">new</span> PrintABC();</span><br><span class="line">        <span class="keyword">new</span> Thread(printABCD.new PrintA()).start();</span><br><span class="line">        <span class="keyword">new</span> Thread(printABCD.new PrintB()).start();</span><br><span class="line">        <span class="keyword">new</span> Thread(printABCD.new PrintC()).start();</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote class="blockquote-center">今天最好的表现，是明天最低的要求。</blockquote>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;Java多线程–三个线程分别打印a,b,c.请用多线程实现循环打印15次abc&lt;br&gt;
    
    </summary>
    
    
  </entry>
  
  <entry>
    <title>Hello World</title>
    <link href="https://Gengry.github.io/2018/03/26/hello-world/"/>
    <id>https://Gengry.github.io/2018/03/26/hello-world/</id>
    <published>2018-03-26T06:22:37.400Z</published>
    <updated>2018-03-26T06:22:37.401Z</updated>
    
    <content type="html"><![CDATA[<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">highlight</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String args[])</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"Highlight"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      
      
        &lt;figure class=&quot;highlight java&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class=
      
    
    </summary>
    
    
  </entry>
  
  <entry>
    <title>JDK并发包</title>
    <link href="https://Gengry.github.io/2018/02/22/JDK%E5%B9%B6%E5%8F%91%E5%8C%85/"/>
    <id>https://Gengry.github.io/2018/02/22/JDK并发包/</id>
    <published>2018-02-22T02:44:02.000Z</published>
    <updated>2018-03-26T06:22:37.400Z</updated>
    
    <content type="html"><![CDATA[<h2 id="同步工具"><a href="#同步工具" class="headerlink" title="同步工具"></a>同步工具</h2><a id="more"></a><h3 id="ReentranLock"><a href="#ReentranLock" class="headerlink" title="ReentranLock"></a>ReentranLock</h3><p>高版本的jdk中已经对synchronized做了足够多的优化，普通的场景下它的性能已经非常接近ReentrantLock。所以一些简单的场景不必过分纠结这两者之间的性能问题。<br>下面这个例子反而使用synchronized的耗时小于使用ReentrantLock。</p><h4 id="可重入"><a href="#可重入" class="headerlink" title="可重入"></a>可重入</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ReenterLock</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>&#123;</span><br><span class="line">    <span class="comment">//可重入锁的使用</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> ReentrantLock lock = <span class="keyword">new</span> ReentrantLock();</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> j=<span class="number">0</span>; j&lt;<span class="number">1000000</span>;j++)&#123;</span><br><span class="line">            <span class="comment">//加锁</span></span><br><span class="line">            lock.lock();</span><br><span class="line">            <span class="keyword">try</span>&#123;</span><br><span class="line">                i++;</span><br><span class="line">            &#125;<span class="keyword">finally</span> &#123;</span><br><span class="line">                <span class="comment">//释放锁</span></span><br><span class="line">                lock.unlock();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*  @Override</span></span><br><span class="line"><span class="comment">    public void run() &#123;</span></span><br><span class="line"><span class="comment">        for(int j=0; j&lt;1000000;j++) &#123;</span></span><br><span class="line"><span class="comment">            synchronized (this)&#123;</span></span><br><span class="line"><span class="comment">                i++;</span></span><br><span class="line"><span class="comment">            &#125;</span></span><br><span class="line"><span class="comment">        &#125;</span></span><br><span class="line"><span class="comment">    &#125;*/</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        <span class="keyword">long</span> time1 = System.currentTimeMillis();</span><br><span class="line">        ReenterLock tl = <span class="keyword">new</span> ReenterLock();</span><br><span class="line">        Thread t1 = <span class="keyword">new</span> Thread(tl);</span><br><span class="line">        Thread t2 = <span class="keyword">new</span> Thread(tl);</span><br><span class="line">        t1.start();t2.start();</span><br><span class="line">        t1.join();t2.join();</span><br><span class="line">        <span class="keyword">long</span> time2 = System.currentTimeMillis();</span><br><span class="line">        System.out.println(i);</span><br><span class="line">        System.out.println(time2-time1);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>如果在一个线程中多次使用了加锁操作，就需要有对应数量的释放锁操作。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> j=<span class="number">0</span>; j&lt;<span class="number">1000000</span>;j++)&#123;</span><br><span class="line">            <span class="comment">//加锁</span></span><br><span class="line">            lock.lock();</span><br><span class="line">lock.lock();</span><br><span class="line">            <span class="keyword">try</span>&#123;</span><br><span class="line">                i++;</span><br><span class="line">            &#125;<span class="keyword">finally</span> &#123;</span><br><span class="line">                <span class="comment">//释放锁</span></span><br><span class="line">                lock.unlock();</span><br><span class="line">lock.unlock();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><p>下面我们加两次锁，只释放一次锁执行一下。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> j=<span class="number">0</span>; j&lt;<span class="number">1000000</span>;j++)&#123;</span><br><span class="line">            <span class="comment">//加锁</span></span><br><span class="line">            lock.lock();</span><br><span class="line">lock.lock();</span><br><span class="line">            <span class="keyword">try</span>&#123;</span><br><span class="line">                i++;</span><br><span class="line">            &#125;<span class="keyword">finally</span> &#123;</span><br><span class="line">                <span class="comment">//释放锁</span></span><br><span class="line">                lock.unlock();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure></p><p>就会发现程序卡住了，一直没有执行结束<br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180222/1.jpg" alt=""><br>我们通过使用jdk的两个命令来看看发生了什么<br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180222/2.jpg" alt=""><br>通过jps获取到这个进程的id<br>通过jstack看看这个进程的栈信息<br>可以看到Thread-1处于waiting状态一直在等在某种条件，就是等待另一个线程释放锁。<br>所在了第13行，也就是lock.lock();</p><h4 id="可中断"><a href="#可中断" class="headerlink" title="可中断"></a>可中断</h4><p>在加锁的同时可以去响应中断，如果发生了死锁，或者意料之外的情况，在一个锁上卡了很久，还是有办法把这个线程唤醒，不至于永久性的卡死下去。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ReenterLockInt</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> ReentrantLock lock1 = <span class="keyword">new</span> ReentrantLock();</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> ReentrantLock lock2 = <span class="keyword">new</span> ReentrantLock();</span><br><span class="line">    <span class="keyword">int</span> lock;</span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">    * 控制加锁顺序，方便构成死锁</span></span><br><span class="line"><span class="comment">    * */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">ReenterLockInt</span><span class="params">(<span class="keyword">int</span> lock)</span></span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.lock = lock;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span>&#123;</span><br><span class="line">            <span class="keyword">if</span>(lock == <span class="number">1</span>)&#123;</span><br><span class="line">                lock1.lockInterruptibly();  <span class="comment">//代表可中断的加锁</span></span><br><span class="line">                <span class="keyword">try</span>&#123;</span><br><span class="line">                    Thread.sleep(<span class="number">500</span>);</span><br><span class="line">                &#125;<span class="keyword">catch</span> (InterruptedException e)&#123;&#125;</span><br><span class="line">                lock2.lockInterruptibly();</span><br><span class="line">            &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">                lock2.lockInterruptibly();</span><br><span class="line">                <span class="keyword">try</span>&#123;</span><br><span class="line">                    Thread.sleep(<span class="number">500</span>);</span><br><span class="line">                &#125;<span class="keyword">catch</span> (InterruptedException e)&#123;&#125;</span><br><span class="line">                lock1.lockInterruptibly();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            <span class="keyword">if</span>(lock1.isHeldByCurrentThread())&#123;</span><br><span class="line">                lock1.unlock();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span>(lock2.isHeldByCurrentThread())&#123;</span><br><span class="line">                lock2.unlock();</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(Thread.currentThread().getId()+<span class="string">":线程退出。"</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        ReenterLockInt r1 = <span class="keyword">new</span> ReenterLockInt(<span class="number">1</span>);</span><br><span class="line">        ReenterLockInt r2 = <span class="keyword">new</span> ReenterLockInt(<span class="number">2</span>);</span><br><span class="line">        Thread t1 = <span class="keyword">new</span> Thread(r1);</span><br><span class="line">        Thread t2 = <span class="keyword">new</span> Thread(r2);</span><br><span class="line">        t1.start();t2.start();</span><br><span class="line">        Thread.sleep(<span class="number">1000</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>上面这段代码，发生了死锁，程序无法正常结束。通过<code>jstack</code>可以看到发现了一个死锁。<br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180222/3.jpg" alt="">  </p><p>实现是个守护线程，来触发死锁后的中断</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DeadLockChecker</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> ThreadMXBean mbean = ManagementFactory.getThreadMXBean();</span><br><span class="line">    <span class="keyword">final</span> <span class="keyword">static</span> Runnable deadlockCheck = <span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">while</span> (<span class="keyword">true</span>)&#123;</span><br><span class="line">                <span class="keyword">long</span>[] deadlockedThreadIds = mbean.findDeadlockedThreads();</span><br><span class="line">                <span class="keyword">if</span>(deadlockedThreadIds != <span class="keyword">null</span>)&#123;</span><br><span class="line">                    ThreadInfo[] threadInfos = mbean.getThreadInfo(deadlockedThreadIds);</span><br><span class="line">                    <span class="keyword">for</span> (Thread t : Thread.getAllStackTraces().keySet())&#123;</span><br><span class="line">                        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>;i&lt;threadInfos.length; i++)&#123;</span><br><span class="line">                            <span class="keyword">if</span>(t.getId() == threadInfos[i].getThreadId())&#123;</span><br><span class="line">                                t.interrupt();</span><br><span class="line">                            &#125;</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    Thread.sleep(<span class="number">5000</span>);</span><br><span class="line">                &#125;<span class="keyword">catch</span> (InterruptedException e)&#123;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">check</span><span class="params">()</span></span>&#123;</span><br><span class="line">        Thread t = <span class="keyword">new</span> Thread(deadlockCheck);</span><br><span class="line">        t.setDaemon(<span class="keyword">true</span>);  <span class="comment">//设置为守护线程</span></span><br><span class="line">        t.start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">       ReenterLockInt r1 = <span class="keyword">new</span> ReenterLockInt(<span class="number">1</span>);</span><br><span class="line">       ReenterLockInt r2 = <span class="keyword">new</span> ReenterLockInt(<span class="number">2</span>);</span><br><span class="line">       Thread t1 = <span class="keyword">new</span> Thread(r1);</span><br><span class="line">       Thread t2 = <span class="keyword">new</span> Thread(r2);</span><br><span class="line">       t1.start();t2.start();</span><br><span class="line">       Thread.sleep(<span class="number">1000</span>);</span><br><span class="line"><span class="comment">//开启死锁检测</span></span><br><span class="line">       DeadLockChecker.check();</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure><h4 id="可限时"><a href="#可限时" class="headerlink" title="可限时"></a>可限时</h4><p>使用<code>lock.trylock(5,TimeUtil.SECOND)</code>的方式获取锁。可以设置一个时间阈值，可以避免无限等待。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TimeLock</span> <span class="keyword">implements</span> <span class="title">Runnable</span></span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> ReentrantLock lock = <span class="keyword">new</span> ReentrantLock();</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span>&#123;</span><br><span class="line">            <span class="keyword">if</span>(lock.tryLock(<span class="number">5</span>, TimeUnit.SECONDS))&#123;</span><br><span class="line">                System.out.println(Thread.currentThread().getId()+<span class="string">":get lock successed"</span>);</span><br><span class="line">                Thread.sleep(<span class="number">6000</span>);</span><br><span class="line">            &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">                System.out.println(Thread.currentThread().getId()+<span class="string">":get lock failed"</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            <span class="keyword">if</span>(lock.isHeldByCurrentThread())&#123;</span><br><span class="line">                lock.unlock();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        TimeLock tl = <span class="keyword">new</span> TimeLock();</span><br><span class="line">        Thread t1 = <span class="keyword">new</span> Thread(tl);</span><br><span class="line">        Thread t2 = <span class="keyword">new</span> Thread(tl);</span><br><span class="line">        t1.start();</span><br><span class="line">        t2.start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="公平锁"><a href="#公平锁" class="headerlink" title="公平锁"></a>公平锁</h4><p>公平锁会保证获取锁的先到先得。公平锁不会产生饥饿问题，但是公平锁的性能要差很多，默认是非公平的。<br>可以通过构造方法指定为公平锁。<br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180222/4.jpg" alt="">  </p><h3 id="Condition"><a href="#Condition" class="headerlink" title="Condition"></a>Condition</h3><h4 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h4><p>类似于Object.wait()和Object.notify()与ReentrantLock结合使用。<br>Condition的执行方式，是当在线程1中调用await方法后，线程1将释放锁，并且将自己沉睡，等待唤醒，<br>线程2获取到锁后，开始做事，完毕后，调用Condition的signal方法，唤醒线程1，线程1恢复执行。</p><h4 id="主要接口"><a href="#主要接口" class="headerlink" title="主要接口"></a>主要接口</h4><p><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180222/5.jpg" alt="">  </p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ReenterLockCondition</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> ReentrantLock  lock = <span class="keyword">new</span> ReentrantLock();</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> Condition condition = lock.newCondition();</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span>&#123;</span><br><span class="line">            lock.lock();</span><br><span class="line">            condition.await();</span><br><span class="line">            System.out.println(<span class="string">"Thread is going on"</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            lock.unlock();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        ReenterLockCondition tl = <span class="keyword">new</span> ReenterLockCondition();</span><br><span class="line">        Thread t1 = <span class="keyword">new</span> Thread(tl);</span><br><span class="line">        t1.start();</span><br><span class="line">        Thread.sleep(<span class="number">2000</span>);</span><br><span class="line">        lock.lock();</span><br><span class="line">        condition.signal();</span><br><span class="line">        lock.unlock();</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="API"><a href="#API" class="headerlink" title="API"></a>API</h4><p>await()方法会使当前线程等待，同时释放当前锁，当其他线程使用signal()时或者signalAll()方法时，线程会重新或得锁并继续执行。或者当线程中断时，也能跳出等待，这和Object.wait()方法类似。<br>awaitUninterruptibly() 和 await()基本相同，但是它并不会在等待的过程中响应中断。<br>signal()方法用于唤醒一个等待中的线程，相对的signalAll会唤醒所有等待中的线程，和Object.notify()类似。</p><h3 id="Semaphore-信号量"><a href="#Semaphore-信号量" class="headerlink" title="Semaphore 信号量"></a>Semaphore 信号量</h3><p>锁是排他的，临界区只能有一个线程占用。<br>信号量是一种共享锁，信号量是许可若干个线程进入临界区，超过许可的上线就必须等待。<br>如果信号量的许可线程为1，就可以当成是排他锁。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SemapDemo</span> <span class="keyword">implements</span> <span class="title">Runnable</span></span>&#123;</span><br><span class="line">    <span class="keyword">final</span> Semaphore semp = <span class="keyword">new</span> Semaphore(<span class="number">5</span>);</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span>&#123;</span><br><span class="line">            semp.acquire();</span><br><span class="line">            Thread.sleep(<span class="number">2000</span>);</span><br><span class="line">            System.out.println(Thread.currentThread().getId()+<span class="string">":done"</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;<span class="keyword">finally</span> &#123;</span><br><span class="line">            semp.release();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        ExecutorService exec = Executors.newFixedThreadPool(<span class="number">20</span>);</span><br><span class="line">        <span class="keyword">final</span> SemapDemo semapDemo  = <span class="keyword">new</span> SemapDemo();</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i=<span class="number">0</span>; i&lt;<span class="number">20</span>; i++)&#123;</span><br><span class="line">            exec.submit(semapDemo);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="主要接口-1"><a href="#主要接口-1" class="headerlink" title="主要接口"></a>主要接口</h4><p>acquire()<br>acquireUninterruptibly()<br>tryAcquire()<br>tryAcquire(long timeout, TimeUnit unit)<br>release()</p><h3 id="ReadWriteLock"><a href="#ReadWriteLock" class="headerlink" title="ReadWriteLock"></a>ReadWriteLock</h3><p>加锁之后，并行度就降为1，只有一个线程可以进入。我们需要通过操作对访问临界区的行为进行划分，当几个线程都是读取数据时，我们是不需要加锁的。</p><p>ReadWriteLock中的read线程都是无等待的并发。ReadWriteLock的实现ReentrantReadWriteLock，使用方法和ReentrantLock类似。<br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> ReentrantReadWriteLock.<span class="function">WriteLock <span class="title">writeLock</span><span class="params">()</span> </span>&#123; <span class="keyword">return</span> writerLock; &#125;</span><br><span class="line"><span class="keyword">public</span> ReentrantReadWriteLock.<span class="function">ReadLock  <span class="title">readLock</span><span class="params">()</span>  </span>&#123; <span class="keyword">return</span> readerLock; &#125;</span><br></pre></td></tr></table></figure></p><h3 id="CountDownLatch"><a href="#CountDownLatch" class="headerlink" title="CountDownLatch"></a>CountDownLatch</h3><h4 id="概念-1"><a href="#概念-1" class="headerlink" title="概念"></a>概念</h4><p>倒数计时器<br>一种典型的场景就是火箭发射器，在火箭发射前，为了保证万无一失，往往需要对各个设备、仪表进行检查，它是一个点火线程，等待所有检查完工后，再执行。</p><h4 id="主要接口-2"><a href="#主要接口-2" class="headerlink" title="主要接口"></a>主要接口</h4><p>static final CountDownLatch end = new CountDownLatch(10);<br>end.countDown();<br>end.await();</p><p>线程完成既定目标后执行end.countDown();<br>当计数器为零后 等待的主线程end.await() 继续执行。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CountDownLatchDemo</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>&#123;</span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> CountDownLatch end = <span class="keyword">new</span> CountDownLatch(<span class="number">10</span>);</span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> CountDownLatchDemo demo = <span class="keyword">new</span> CountDownLatchDemo();</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line"><span class="comment">//模拟检查任务</span></span><br><span class="line">            Thread.sleep(<span class="keyword">new</span> Random().nextInt(<span class="number">10</span>)*<span class="number">1000</span>);</span><br><span class="line">            System.out.println(<span class="string">"check complete"</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;<span class="keyword">finally</span> &#123;</span><br><span class="line">            end.countDown();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        ExecutorService exec = Executors.newFixedThreadPool(<span class="number">10</span>);</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>; i&lt;<span class="number">10</span>; i++)&#123;</span><br><span class="line">            exec.submit(demo);</span><br><span class="line">        &#125;</span><br><span class="line"><span class="comment">//等待检查</span></span><br><span class="line">        end.await();</span><br><span class="line"><span class="comment">//发射火箭</span></span><br><span class="line">        System.out.println(<span class="string">"fire!"</span>);</span><br><span class="line">        exec.shutdown();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="CyclicBarrier"><a href="#CyclicBarrier" class="headerlink" title="CyclicBarrier"></a>CyclicBarrier</h3><p>相当于一个循环的CountDownLatch</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CyclicBarrierDemo</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Solder</span> <span class="keyword">implements</span> <span class="title">Runnable</span></span>&#123;</span><br><span class="line">        <span class="keyword">private</span> String soldier;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> CyclicBarrier cyclic;</span><br><span class="line">        Solder(CyclicBarrier cyclic,String soldierName)&#123;</span><br><span class="line">            <span class="keyword">this</span>.cyclic = cyclic;</span><br><span class="line">            <span class="keyword">this</span>.soldier = soldierName;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">try</span>&#123;</span><br><span class="line">                cyclic.await();</span><br><span class="line">                doWork();</span><br><span class="line">                cyclic.await();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (BrokenBarrierException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line"></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="function"><span class="keyword">void</span> <span class="title">doWork</span><span class="params">()</span></span>&#123;</span><br><span class="line">            <span class="keyword">try</span>&#123;</span><br><span class="line">                Thread.sleep(Math.abs(<span class="keyword">new</span> Random().nextInt()%<span class="number">10000</span>));</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(soldier+<span class="string">":任务完成"</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">BarrierRun</span> <span class="keyword">implements</span> <span class="title">Runnable</span></span>&#123;</span><br><span class="line">        <span class="keyword">boolean</span> flag;</span><br><span class="line">        <span class="keyword">int</span> N;</span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">BarrierRun</span><span class="params">( <span class="keyword">boolean</span> flag,<span class="keyword">int</span> N)</span></span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.flag = flag;</span><br><span class="line">            <span class="keyword">this</span>.N = N;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">if</span>(flag)&#123;</span><br><span class="line">                System.out.println(<span class="string">"司令：[士兵"</span>+N+<span class="string">"个，任务完成！]"</span>);</span><br><span class="line">            &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">                System.out.println(<span class="string">"司令：[士兵"</span>+N+<span class="string">"个，集合完成！]"</span>);</span><br><span class="line">                flag = <span class="keyword">true</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> <span class="keyword">int</span> N = <span class="number">10</span>;</span><br><span class="line">        Thread[] allSoldier = <span class="keyword">new</span> Thread[N];</span><br><span class="line">        <span class="keyword">boolean</span> flag = <span class="keyword">false</span>;</span><br><span class="line">        CyclicBarrier cyclic = <span class="keyword">new</span> CyclicBarrier(N,<span class="keyword">new</span> BarrierRun(flag,N));</span><br><span class="line">        System.out.println(<span class="string">"集合队伍！"</span>);</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i&lt;N;i++)&#123;</span><br><span class="line">            System.out.println(<span class="string">"士兵"</span>+i+<span class="string">"报道！"</span>);</span><br><span class="line">            allSoldier[i] = <span class="keyword">new</span> Thread(<span class="keyword">new</span> Solder(cyclic,<span class="string">"士兵"</span>+i));</span><br><span class="line">            allSoldier[i].start();</span><br><span class="line"><span class="comment">//            if(i==5)&#123;</span></span><br><span class="line"><span class="comment">//                allSoldier[0].interrupt();</span></span><br><span class="line"><span class="comment">//            &#125;</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="LockSupport"><a href="#LockSupport" class="headerlink" title="LockSupport"></a>LockSupport</h3><p>提供线程阻塞原语。</p><h4 id="主要接口-3"><a href="#主要接口-3" class="headerlink" title="主要接口"></a>主要接口</h4><p>LockSupport.park();<br>LockSupport.unpark();</p><blockquote class="blockquote-center">今天最好的表现，是明天最低的要求。</blockquote>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;同步工具&quot;&gt;&lt;a href=&quot;#同步工具&quot; class=&quot;headerlink&quot; title=&quot;同步工具&quot;&gt;&lt;/a&gt;同步工具&lt;/h2&gt;
    
    </summary>
    
      <category term="Java并发编程" scheme="https://Gengry.github.io/categories/Java%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/"/>
    
    
      <category term="Java并发编程" scheme="https://Gengry.github.io/tags/Java%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/"/>
    
  </entry>
  
  <entry>
    <title>高并发网站中的数据库设计</title>
    <link href="https://Gengry.github.io/2018/02/09/%E9%AB%98%E5%B9%B6%E5%8F%91%E7%BD%91%E7%AB%99%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%E5%BA%93%E8%AE%BE%E8%AE%A1/"/>
    <id>https://Gengry.github.io/2018/02/09/高并发网站中的数据库设计/</id>
    <published>2018-02-09T00:42:22.000Z</published>
    <updated>2018-03-26T06:22:37.399Z</updated>
    
    <content type="html"><![CDATA[<h1 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h1><p>数据库其实就是一个普通的计算机系统，为我们提供某种服务。<br>我们对数据库功能的抽闲可以将数据库功能抽象成三个部分<br><a id="more"></a></p><ul><li>用户API</li><li>关系代数和事物引擎</li><li>K-V存储</li></ul><blockquote><p>关系型数据库底层也是K-V模型的，但是他为我们提供了更高层的服务，这些服务牺牲了运算速度实现了原子性，一致性，隔离性。<br>但是有些时候我们需要效率，关系型数据库成了系统的瓶颈。我们需要把速度拿回来，所以一些K-V数据库就产生了，其实就是去掉了关系代数和事物引擎将K-V存储和关于K-V的API暴露给了用户,这就是Nosql，Nosql放弃了事物提高了速度。<br>但是人们发现最简单的K-V存储好像什么事情都干不了，需要我们处理的事情太多了，就产生了newSql，为我们处理了关系代数模型和事物引擎的一部分功能。</p></blockquote><h1 id="Key-Value存储"><a href="#Key-Value存储" class="headerlink" title="Key-Value存储"></a>Key-Value存储</h1><p>本质就是<code>映射</code>，按照key找value。  </p><p>映射的关键特性 <a href="http://blog.sina.cn/dpool/blog/s/blog_693f08470101mccl.html" target="_blank" rel="noopener">扩展</a></p><ul><li>是否支持范围查找</li><li>是否能够处理更新</li><li>读写性能指标</li><li>是否面向磁盘结构</li><li>并行指标</li><li>内存占用</li><li>Etc…</li></ul><p>常见的数据结构</p><ul><li>排序数组</li><li>排序链表</li><li>跳表</li><li>B tree</li><li>LSM tree</li><li>HashMap</li><li>Fractal Tree</li><li>Red-Black-tree</li><li>COLA</li><li>Etc…</li></ul><h1 id="关系代数"><a href="#关系代数" class="headerlink" title="关系代数"></a>关系代数</h1><p>primary key:id  user_id  name</p><p>按照key找value， Primary Key:id 按照id查找其他数据。</p><p>但是如果按照user_id查看记录，则需要遍历所有记录。效率为O(n)</p><h2 id="二级索引"><a href="#二级索引" class="headerlink" title="二级索引"></a>二级索引</h2><p>二级索引就是同样也是个K-V映射表  key为user_id,value为主键id。<br>如果二级索引为Hash结构，效率就下降为0(1),如果是二分查找 Tree，效率为O(logN)<br>这样查询 先按user_id查找到id，在通过id查找到数据。  </p><p>如果按照多条件查询 where user_id = 1 and name = ‘tom’<br>如果按照刚才的索引查找，但是如果user_id为1的记录有一万条，我们就需要遍历一万条记录。</p><h2 id="组合索引"><a href="#组合索引" class="headerlink" title="组合索引"></a>组合索引</h2><p><a href="http://blog.sina.cn/dpool/blog/s/blog_693f08470101pwyy.html" target="_blank" rel="noopener">扩展阅读</a><br><a href="https://www.tuicool.com/articles/7FR3YjI" target="_blank" rel="noopener">扩展阅读</a><br>使用 user_id和name作为key，主键id作为value。</p><h1 id="事物简介"><a href="#事物简介" class="headerlink" title="事物简介"></a>事物简介</h1><p>事物的核心是锁和并发</p><ul><li>优势：方便理解</li><li>劣势：性能较低</li></ul><p>事物其实就是帮助程序员人脑来理解程序到底是怎么运转的。人脑永远是串行的。把一个逻辑整理成第一步，第二步，第三步…<br>但是这要的程序只能在单机单线程中执行。<br>而现实生活中很多事情都是有先后的，例如我们从bob账户中取钱，我们查询账户余额为100，但我们真的去做减的时候，bob账户中的钱已经被别人取走了。<br>人脑不能很好的理解并发的概念，所以就设计了一种模式，就是事物，让我们方便理解并发，但是降低了性能。</p><blockquote><p>容易理解的模型性能都不好，性能好的模型都不容易理解 – 这就是生活。</p></blockquote><h2 id="事物单元"><a href="#事物单元" class="headerlink" title="事物单元"></a>事物单元</h2><p>其实数据库的DDL操作都可以拆分成两个操作，insert 是先查询再插入，update 先查询再更新， delete 先查询再删除，只有select是一个查询操作。<br>每次查询的时候都把数据锁上，锁的概念：在线程上面维持一个对这个访问的独占权，其他线程不能再访问它了。<br>事物所覆盖的所有数据都会被这个线程独占。<br>但是如果都用这么重量级的锁，那性能就太低了，所以事物为我们提供了四种隔离界别</p><ul><li>未提交读</li><li>提交读</li><li>可重复读</li><li>序列化</li></ul><p>这些也是单独的事物单元  </p><ul><li>商品要建立一个基于GMT_Modified的索引</li><li>从数据库中读取一行记录</li><li>向数据库中写入一行记录，同事更新这行记录的所有索引</li><li>删除整张表</li><li>Etc…</li></ul><p>一组事物单元，是顺序执行的，第一个事物单元结束后，第二个事物单元才开始执行。<br>如果两个事物单元没有任何关系的话，A事物操作bob账户，B事物操作tom账户，两个事物是可以并行的。<br>如果两个事物共享同一份数据，事物没有办法并行。</p><h2 id="事物产生原因"><a href="#事物产生原因" class="headerlink" title="事物产生原因"></a>事物产生原因</h2><p><a href="http://www.imooc.com/learn/272" target="_blank" rel="noopener">扩展阅读</a></p><h3 id="事物单元之间的Happen-before关系（数据的四种冲突）"><a href="#事物单元之间的Happen-before关系（数据的四种冲突）" class="headerlink" title="事物单元之间的Happen-before关系（数据的四种冲突）"></a>事物单元之间的Happen-before关系（数据的四种冲突）</h3><ul><li>读写</li><li>写度</li><li>读读</li><li>写写</li></ul><h3 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h3><ul><li>如何能以最快的速度完成</li><li>又能保证上面四种操作的逻辑顺序</li></ul><p>mvcc Multi-Version Concurrency Control 多版本并发控制</p><h1 id="SQL引擎"><a href="#SQL引擎" class="headerlink" title="SQL引擎"></a>SQL引擎</h1><p><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180207/4.jpg" alt=""><br>现在主流的数据库都在使用CBO（基于成本的优化）进行系统的操作。</p><h1 id="分布式存储"><a href="#分布式存储" class="headerlink" title="分布式存储"></a>分布式存储</h1><h2 id="多级K-V存储"><a href="#多级K-V存储" class="headerlink" title="多级K-V存储"></a>多级K-V存储</h2><p>关键特性</p><ul><li>可运维</li><li>高性能</li><li>可以比较容易的扩容</li><li>核心数据结构还是hash和树，部分case针对多机做了一点优化。</li></ul><p>代表性组件</p><ul><li>mongoDB -&gt; mongos服务器</li><li>Hbase -&gt; region server + client jar包</li><li>DRDS(TDDL) -&gt; tddl规则引擎组件</li></ul><p>分布式结构可以理解成map套map的过程，先查询数据在哪个单机，再做单机查询。</p><h2 id="路由"><a href="#路由" class="headerlink" title="路由"></a>路由</h2><p>规则引擎：有状态的数据应该按照什么规则进行写入和读取<br>例如：对pk % 3  —&gt; DB0,DB1,DB2</p><p>本质来说还是个查找的过程  </p><ul><li>hash<ul><li>O(1)效率</li><li>不支持范围查询（按时间这样的查询条件就比较困难）</li><li>不需要频繁调整数据分布</li></ul></li></ul><ul><li>Tree<ul><li>主要是 B Tree</li><li>O(logN)效率</li><li>支持范围查询</li><li>需要频繁分裂和合并</li></ul></li></ul><ul><li>Hash<ul><li>Id%n</li><li>最普通的hash</li><li>如果id%3  -&gt; id%4 总共会走80%的数据发生移动，最好的情况是倍分id%3 -&gt; id%6,这时候会有50%的数据发生移动</li><li>数据移动本身就是个要了亲命的事</li></ul></li></ul><ul><li>hash<ul><li>一致性hash  只要解决数据的扩容和缩容的问题</li><li>虚拟节点<ul><li>解决热点问题，只需要调整对应关系疾苦</li><li>解决n-&gt;n+1问题，规则可以规定只移动需要移动的数据</li><li>方案相对复杂</li><li>一般推荐使用简单方案开始，使用n-&gt;2n方案扩容</li><li>只有需要的情况下，在考虑平滑的扩展到虚拟节点方案。</li></ul></li></ul></li></ul><ul><li>B-Tree<ul><li>Hbase使用的切分方法<ul><li>支持范围查询</li><li>对于发部分场景来说，引导列都是pk.userid一类的单值查询，用树相对复杂。</li><li>需要频繁的进行切分和合并操作 –region server的恶梦</li><li>固定节点情况下，跨度相对较大，查询效率可能会进一步降低</li></ul></li></ul></li></ul><h2 id="一致性"><a href="#一致性" class="headerlink" title="一致性"></a>一致性</h2><p>寻求一种能够保证，在给定多台计算机，并且他们相互之间由网络相互连通，中间的数据没有拜占庭将军问题（数据不会被伪造）的前提下（P Partition tolerance 分区容忍性）能够做到一下两种特性的方法：</p><ul><li>数据的每次成功写入，数据不会丢失，并且按照写入的顺序排列 （C Consistency 一致性）</li><li>给定安全级别，保证服务的可用性，并尽可能减少机器的消耗（A Availability 可用性）<ul><li>数据的可用性</li><li>服务的可用性 （响应时间，例如500ms）</li></ul></li></ul><h3 id="无主机方案"><a href="#无主机方案" class="headerlink" title="无主机方案"></a>无主机方案</h3><ul><li>Dynamo/cassandra/Paxos:gossip ,W+R&gt;N (W&gt;N-R)  N(node) w(write) r(read)</li><li>所有节点可写，不存在单点故障</li><li>读数据的最新版本，需要将所有节点的数据都读出来合并一次</li></ul><h3 id="有主机方案（Raft）"><a href="#有主机方案（Raft）" class="headerlink" title="有主机方案（Raft）"></a>有主机方案（Raft）</h3><p>主从配置</p><ul><li>Mysql MongoDB Oracle+fibreChannel</li><li>只有一个节点可写，切换时存在短暂leader election过程，会出现短暂不可写。</li><li>数据一致性比较好控制，读最新数据只需要读主机就可以，一致性读性能较好。</li></ul><h3 id="实际系统需要考虑的问题"><a href="#实际系统需要考虑的问题" class="headerlink" title="实际系统需要考虑的问题"></a>实际系统需要考虑的问题</h3><ul><li>有些机器负担写任务，因此读压力可能不均衡，因此必须有权重设置。</li><li>单个节点挂掉的时候，TCP超时会导致业务APP的线程花费更多的时间来处理单个请求，这样会降低APP的处理能力，导致雪崩。</li><li>因为突发情况，导致数据库请求书增加，数据库相应变慢，导致雪崩。</li></ul><h1 id="数据库实践"><a href="#数据库实践" class="headerlink" title="数据库实践"></a>数据库实践</h1><p><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180207/5.jpg" alt="">  </p><h2 id="单机优化原则"><a href="#单机优化原则" class="headerlink" title="单机优化原则"></a>单机优化原则</h2><ul><li>二分查找效率&gt;全表遍历<ul><li>选择合适的索引</li></ul></li><li>内存读写&gt;SSD读写&gt;磁盘读写<ul><li>将物理读（磁盘读）换成逻辑读（内存读）</li></ul></li><li>减少锁冲突<ul><li>尽可能通过业务设计，将更新变成插入，来减少加锁去锁的操作</li></ul></li><li>减少临时表使用<ul><li>减少多维度排序</li></ul></li></ul><h2 id="分布式系统优化原则"><a href="#分布式系统优化原则" class="headerlink" title="分布式系统优化原则"></a>分布式系统优化原则</h2><ul><li>减少跨机网络交互<ul><li>尽可能带sharding key</li><li>分页优化（google一下）</li></ul></li><li>减少数据读写热点<ul><li>切分颗粒度尽可能细（用户颗粒度好于省份）</li></ul></li><li>减少锁开销<ul><li>尽可能规避分布式事物</li></ul></li></ul><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p><a href="http://blog.sina.cn/dpool/blog/s/blog_693f08470102vibt.html" target="_blank" rel="noopener">沈询所有资源的索引（会不断更新）</a></p><ul><li>尽一切可能利用单机资源<ul><li>单机事物</li><li>单机join</li></ul></li><li>好的存储模型<ul><li>尽可能走内存</li><li>尽可能将以此要查询到的数据物理的放在一起</li><li>通过合理的数据冗余，减少走网络的次数</li><li>合理并行提升响应时间</li><li>读取数据瓶颈，可以通过加slave节点解决</li><li>写入瓶颈，用规则sharding和扩容来解决</li></ul></li></ul><p><a href="https://www.cnblogs.com/cynchanpin/p/7003390.html" target="_blank" rel="noopener">警惕 InnoDB 和 MyISAM 创建 Hash 索引陷阱</a></p><blockquote class="blockquote-center">今天最好的表现，是明天最低的要求。</blockquote>]]></content>
    
    <summary type="html">
    
      &lt;h1 id=&quot;介绍&quot;&gt;&lt;a href=&quot;#介绍&quot; class=&quot;headerlink&quot; title=&quot;介绍&quot;&gt;&lt;/a&gt;介绍&lt;/h1&gt;&lt;p&gt;数据库其实就是一个普通的计算机系统，为我们提供某种服务。&lt;br&gt;我们对数据库功能的抽闲可以将数据库功能抽象成三个部分&lt;br&gt;
    
    </summary>
    
      <category term="数据库" scheme="https://Gengry.github.io/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
    
      <category term="事物" scheme="https://Gengry.github.io/tags/%E4%BA%8B%E7%89%A9/"/>
    
      <category term="数据库" scheme="https://Gengry.github.io/tags/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
  </entry>
  
  <entry>
    <title>虚拟机安装Centos，安装mysql，配置主从（三）</title>
    <link href="https://Gengry.github.io/2018/02/08/%E8%99%9A%E6%8B%9F%E6%9C%BA%E5%AE%89%E8%A3%85Centos%EF%BC%8C%E5%AE%89%E8%A3%85mysql%EF%BC%8C%E9%85%8D%E7%BD%AE%E4%B8%BB%E4%BB%8E%EF%BC%88%E4%B8%89%EF%BC%89/"/>
    <id>https://Gengry.github.io/2018/02/08/虚拟机安装Centos，安装mysql，配置主从（三）/</id>
    <published>2018-02-08T02:47:14.000Z</published>
    <updated>2018-03-26T06:22:37.399Z</updated>
    
    <content type="html"><![CDATA[<blockquote class="blockquote-center">今天最好的表现，是明天最低的要求。</blockquote>]]></content>
    
    <summary type="html">
    
      
      
        &lt;blockquote class=&quot;blockquote-center&quot;&gt;今天最好的表现，是明天最低的要求。&lt;/blockquote&gt;
      
    
    </summary>
    
    
  </entry>
  
  <entry>
    <title>一个十二年老程序猿的碎碎念（转）</title>
    <link href="https://Gengry.github.io/2018/02/08/%E4%B8%80%E4%B8%AA%E5%8D%81%E4%BA%8C%E5%B9%B4%E8%80%81%E7%A8%8B%E5%BA%8F%E7%8C%BF%E7%9A%84%E7%A2%8E%E7%A2%8E%E5%BF%B5%EF%BC%88%E8%BD%AC%EF%BC%89/"/>
    <id>https://Gengry.github.io/2018/02/08/一个十二年老程序猿的碎碎念（转）/</id>
    <published>2018-02-08T02:31:09.000Z</published>
    <updated>2018-03-26T06:22:37.398Z</updated>
    
    <content type="html"><![CDATA[<p>我是一名程序猿，在95年上初中的时候，别人还都在打篮球、踢足球的时候，我就已经在玩QBasic了，每逢跟其他程序猿说起这段的时候，大家都会投过来羡慕的眼光，其实没有你们想的那么好，反而挺悲催的，当时的同学们都不知道我在说些啥，另外我至今都不会打篮球、踢足球。果然不出意外（不会有意外的，我大学填报的所有志愿都是计算机系）的大学毕业后做了一枚程序猿。<br><a id="more"></a><br>工作到现在有十二个年头了，大部分工作都是做开发，当然也做过些别的，干过销售，跟朋友合伙创业等等，不过我依然还是喜欢做开发。</p><p>就在工作2年，写了2年程序的时候，我觉得自己太蔫儿了，程序猿嘛，更愿意低头做事而不是抬头说话，于是决定辞职去做了半年多销售，就为了练练嘴。现在我还清晰地记得打第一个推销电话的时候，我提前写好了稿子，紧张得面红耳赤，拨通电话就照着稿子念，等我念完了发现对方早挂了。不过就这样一点点地磨过来了，拿了个年度销售冠军，然后毅然辞职，又跑去写程序了。乔丹曾说过：“如果没有去打棒球的话，都不知道自己有多么地爱篮球”。我也借用这句话：如果没有跑去做销售的话，都不知道自己有多么地爱代码。</p><p>我算是比较幸运，把自己的爱好作为了职业，可以亲手将一个产品从无到有地打造出来的喜悦感还是非常满足的。虽然很多时候都是解决需求、改bug这些枯燥的事情吧，这就好像你喜欢玩游戏，但是职业化地一遍又一遍地重复一个游戏也是很郁闷的。我还有一个爱好就是摄影，我绝不去做职业摄影师，保持这个爱好就是爱好，纯玩儿。</p><p>曾有一个段子说：一个妹子问一个程序猿如何让一帮不爱说话的程序猿活跃起来，那个程序猿说了一句PHP是最好的语言。。。很多程序猿都喜欢站队，所谓站队就是自己在玩某某语言的时候，就会觉得这个语言很强大，自然而然地就站了队了。</p><p>我们的身边充斥着写java的看不上写.net的，写c的看不上一切，node异军突起，python批评ruby垃圾性能，高富帅swift从天而降，PHP是最强语言等等。。。</p><p>十二年前，我刚工作的时候，写医疗软件，用VB写界面，用VC写功能封装dll，当时觉得VB，VC太强了，结果现在它们基本都死了。</p><p>同样的还有：</p><p>我写过Dephi，死了。。</p><p>我写过asp，死了。。</p><p>我写过塞班，死了。。</p><p>我们更应当做的是跳出语言的框框，编程注重的是思想，而非语言。</p><p>有人不屑于C#的lambda表达式，认为这就是个语法糖。其实你可以把它看作为将冗余的循环判断重构为一句话，IT行业很多时候都是在给其他行业做提升效率的工作，轮到我们自己为啥就不能提升下开发效率呢，程序猿挺苦逼了，吃块糖咋了？</p><p>有人不屑于.net的闭源，但是微软正在把很多.net的东西开源了，反观oracle跟Google的java官司有一种oracle要玩死java的赶脚啊。</p><p>有人不屑于java的呆板，但是java不计其数的开源框架支撑这个古老而又现代的帝国。</p><p>有人不屑于js就是个脚本，但是node异军突起，正在逐步向后端深入。</p><p>跳出语言的框框吧，作为一枚程序猿，我们更应该重视的并不是语言本身，语言只是一个工具罢了。</p><p>有一篇鸡汤说：两个人在工地搬砖，有人问他们你们在干嘛，一个说我在搬砖，另一个说我在建造大楼。几年后说搬砖的人还在搬砖，而说建造大楼的人通过进修一点点做到工程师了。</p><p>这虽然是一篇鸡汤，但是确实说明白了一个道理，就是你的思想决定了你的行动，影响了你的结果。当然对于程序猿更是如此了，因为我们是码农，没了思想就是一个搬砖的。</p><p>举个例子：如果有一天pm告诉你，要做一个朋友圈这样的产品，你会怎么做？</p><p>初级程序员会怎么做？</p><p>1、建立用户表、用户朋友圈发的内容表、点赞评价表，然后做表表关联。</p><p>高级一点的程序猿还会想到什么？</p><p>2、图片要做压缩吧，现在手机动不动1000多w像素，一张图片好几m，不压缩的话先不说服务器压力，用户刷新一下朋友圈这个月的流量就没了的话，一定会马上删应用骂街的。</p><p>3、图片要分布式存储吧，CDN引入的问题。</p><p>4、辣么多表做关联，响应的问题，并发的问题，缓存怎么搞。</p><p>5、数据量大了的话，分库拆库是否要提前计划好。</p><p>6、发朋友圈要有消息通知吗？如何做？</p><p>7、数据量大了之后用多表关联的方式是否还合适？</p><p>还有一些也许pm并没有说到的细节呢？</p><p>8、朋友圈一定就是9张图片吗，以后会不会要求增加呢，当年微博还要求必须140个字呢，现在也没限制了，如果你数据表只是设计了9个图片字段的话。。。</p><p>9、图片是否要预留加入ps、美颜等功能的考虑呢？</p><p>10、用户选择图片的时候是否可以多选，选择图片的列表是不是应该按照时间倒序排列？</p><p>11、pm只说了发朋友圈，那么修改删除呢？</p><p>12、评论、点赞修改了删除呢？删除后已发出的消息怎么办？</p><p>如果你只考虑第1的话，那么不好意思，你就是在搬砖呢。</p><p>如果你考虑了2-7的话，恭喜你是一个合格的程序猿。</p><p>只有考虑到了8-12，才是那个不仅仅在搬砖的程序猿。</p><p>有人会说了8-12这些应该是pm做的事情啊，pm没说就不做啊。还是那句话，如果pm告诉你什么你就做什么的话，那就是在搬砖，只是在完成工作罢了，而不是在打造一款真正的产品。</p><p>以上，就是我这个十二年的老程序猿的碎碎念。</p><blockquote><p>作者：williamnet<br>链接：<a href="https://www.jianshu.com/p/072b262cd089" target="_blank" rel="noopener">https://www.jianshu.com/p/072b262cd089</a><br>来源：简书</p></blockquote><blockquote class="blockquote-center">今天最好的表现，是明天最低的要求。</blockquote>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;我是一名程序猿，在95年上初中的时候，别人还都在打篮球、踢足球的时候，我就已经在玩QBasic了，每逢跟其他程序猿说起这段的时候，大家都会投过来羡慕的眼光，其实没有你们想的那么好，反而挺悲催的，当时的同学们都不知道我在说些啥，另外我至今都不会打篮球、踢足球。果然不出意外（不会有意外的，我大学填报的所有志愿都是计算机系）的大学毕业后做了一枚程序猿。&lt;br&gt;
    
    </summary>
    
    
  </entry>
  
  <entry>
    <title>nginx+tomcat负载均衡，在nginx层配置http、https转http到tomcat，jsp协议和端口号不对应问题</title>
    <link href="https://Gengry.github.io/2018/02/07/nginx-tomcat%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%EF%BC%8C%E5%9C%A8nginx%E5%B1%82%E9%85%8D%E7%BD%AEhttp%E3%80%81https%E8%BD%AChttp%E5%88%B0tomcat%EF%BC%8Cjsp%E5%8D%8F%E8%AE%AE%E5%92%8C%E7%AB%AF%E5%8F%A3%E5%8F%B7%E4%B8%8D%E5%AF%B9%E5%BA%94%E9%97%AE%E9%A2%98/"/>
    <id>https://Gengry.github.io/2018/02/07/nginx-tomcat负载均衡，在nginx层配置http、https转http到tomcat，jsp协议和端口号不对应问题/</id>
    <published>2018-02-07T06:18:20.000Z</published>
    <updated>2018-03-26T06:22:37.397Z</updated>
    
    <content type="html"><![CDATA[<h1 id="问题描述"><a href="#问题描述" class="headerlink" title="问题描述"></a>问题描述</h1><p>App端部分功能使用h5页面实现，但是偶尔用户反映会有广告。也就是请求被第三方劫持了插入了广告，所以决定全业务切https。在nginx配置https将https的请求转发的tomcat的http端口。<br>但是发现一个问题就是h5页面的资源和ajax请求失败，原因是url中的协议和端口号不对应。<br><a id="more"></a><br><figure class="highlight vbscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">String</span> basePath = <span class="built_in">request</span>.getScheme()+<span class="string">"://"</span>+<span class="built_in">request</span>.getServerName()+<span class="string">":"</span>+<span class="built_in">request</span>.getServerPort()+path+<span class="string">"/"</span>;</span><br></pre></td></tr></table></figure></p><p>结果是协议为http，端口号为 https的端口号，导致静态资源加载、ajax请求失败。<br><a href="http://****:6443/****" target="_blank" rel="noopener">http://****:6443/****</a> 无法请求到服务器。</p><h1 id="解决问题"><a href="#解决问题" class="headerlink" title="解决问题"></a>解决问题</h1><h2 id="nginx配置"><a href="#nginx配置" class="headerlink" title="nginx配置"></a>nginx配置</h2><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">upstream</span> ******&#123;</span><br><span class="line">           <span class="attribute">server</span> <span class="number">127.0.0.1:8680</span> weight=<span class="number">1</span> fail_timeout=<span class="number">600s</span>;</span><br><span class="line">           <span class="attribute">server</span> <span class="number">127.0.0.1:8980</span> weight=<span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"> <span class="section">server</span> &#123;</span><br><span class="line">        <span class="attribute">listen</span>       <span class="number">80</span>;</span><br><span class="line">        <span class="attribute">server_name</span> *******;</span><br><span class="line"></span><br><span class="line">        <span class="attribute">charset</span> utf-<span class="number">8</span>;</span><br><span class="line"></span><br><span class="line">        <span class="comment">#charset koi8-r;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">#access_log  logs/host.access.log  main;</span></span><br><span class="line"></span><br><span class="line">        <span class="attribute">location</span> / &#123;</span><br><span class="line">            <span class="comment">#root   html;</span></span><br><span class="line">            <span class="comment">#index  index.html index.htm;</span></span><br><span class="line">            <span class="comment">#proxy_pass  **********;</span></span><br><span class="line">                <span class="attribute">proxy_redirect</span> <span class="literal">off</span>;</span><br><span class="line">                <span class="attribute">proxy_set_header</span> Host <span class="variable">$host</span>;</span><br><span class="line">                <span class="attribute">proxy_set_header</span> Host <span class="variable">$host</span>:<span class="number">80</span>;</span><br><span class="line">                <span class="comment">#proxy_set_header X-Real-IP $remote_addr;</span></span><br><span class="line">                <span class="comment">#proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;</span></span><br><span class="line">                <span class="attribute">client_max_body_size</span> <span class="number">10m</span>;</span><br><span class="line">                <span class="attribute">client_body_buffer_size</span> <span class="number">128k</span>;</span><br><span class="line">                <span class="attribute">proxy_connect_timeout</span> <span class="number">300</span>;</span><br><span class="line">                <span class="attribute">proxy_send_timeout</span> <span class="number">300</span>;</span><br><span class="line">                <span class="attribute">proxy_read_timeout</span> <span class="number">300</span>;</span><br><span class="line">                <span class="attribute">proxy_buffer_size</span> <span class="number">4k</span>;</span><br><span class="line">                <span class="attribute">proxy_buffers</span> <span class="number">4</span> <span class="number">32k</span>;</span><br><span class="line">                <span class="attribute">proxy_busy_buffers_size</span> <span class="number">64k</span>;</span><br><span class="line">                <span class="attribute">proxy_temp_file_write_size</span> <span class="number">64k</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="attribute">error_page</span>   <span class="number">500</span> <span class="number">502</span> <span class="number">503</span> <span class="number">504</span>  /50x.html;</span><br><span class="line">        <span class="attribute">location</span> = /50x.html &#123;</span><br><span class="line">            <span class="attribute">root</span>   html;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="attribute">access_log</span>  logs/access_http.log;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="section">server</span> &#123;</span><br><span class="line">        <span class="attribute">listen</span>       <span class="number">6443</span> ssl;</span><br><span class="line">        <span class="attribute">server_name</span>  **********;</span><br><span class="line">        <span class="attribute">error_log</span> /usr/local/nginx/logs/error_debug <span class="literal">debug</span>; </span><br><span class="line">        <span class="attribute">ssl_certificate</span>      /usr/local/nginx/ssl/pn.crt;</span><br><span class="line">        <span class="attribute">ssl_certificate_key</span>  /usr/local/nginx/ssl/pn.key;</span><br><span class="line">    </span><br><span class="line">        <span class="attribute">ssl_session_cache</span>    shared:SSL:<span class="number">1m</span>;</span><br><span class="line">        <span class="attribute">ssl_session_timeout</span>  <span class="number">5m</span>;</span><br><span class="line">    </span><br><span class="line">        <span class="attribute">ssl_ciphers</span>  HIGH:!aNULL:!MD5;</span><br><span class="line">        <span class="attribute">ssl_prefer_server_ciphers</span>  <span class="literal">on</span>;</span><br><span class="line">    </span><br><span class="line">        <span class="attribute">location</span> / &#123;  </span><br><span class="line">            <span class="comment">#add_header From /;</span></span><br><span class="line">           <span class="attribute">proxy_set_header</span> X-Forwarded-For <span class="variable">$proxy_add_x_forwarded_for</span>;</span><br><span class="line">           <span class="attribute">proxy_set_header</span> Host <span class="variable">$http_host</span>;</span><br><span class="line">           <span class="attribute">proxy_set_header</span> X-Forwarded-Proto https;</span><br><span class="line">           <span class="attribute">proxy_redirect</span> <span class="literal">off</span>;</span><br><span class="line">           <span class="attribute">proxy_connect_timeout</span>      <span class="number">240</span>;</span><br><span class="line">           <span class="attribute">proxy_send_timeout</span>         <span class="number">240</span>;</span><br><span class="line">           <span class="attribute">proxy_read_timeout</span>         <span class="number">240</span>;</span><br><span class="line"> <span class="comment">#  proxy_pass *********;  </span></span><br><span class="line"><span class="comment">#proxy_set_headerHost$http_host;</span></span><br><span class="line"><span class="comment">#proxy_set_headerX-Real-IP   $remote_addr;</span></span><br><span class="line"><span class="comment">#proxy_set_headerX-Forwarded-For $proxy_add_x_forwarded_for;</span></span><br><span class="line"><span class="comment">#proxy_set_header   Cookie $http_cookie; </span></span><br><span class="line"><span class="comment">#client_max_body_size1000m; </span></span><br><span class="line">        &#125; </span><br><span class="line">      <span class="attribute">access_log</span>  logs/apkaccess.log;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><h2 id="tomcat-server-xml配置"><a href="#tomcat-server-xml配置" class="headerlink" title="tomcat server.xml配置"></a>tomcat server.xml配置</h2><p>在tomcat的<host>标签中加入<br><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">&lt;Valve <span class="attribute">className</span>=<span class="string">"org.apache.catalina.valves.RemoteIpValve"</span>  </span><br><span class="line">                  <span class="attribute">remoteIpHeader</span>=<span class="string">"x-forwarded-for"</span>  </span><br><span class="line">                  <span class="attribute">remoteIpProxiesHeader</span>=<span class="string">"x-forwarded-by"</span>  </span><br><span class="line">                  <span class="attribute">protocolHeader</span>=<span class="string">"x-forwarded-proto"</span>  </span><br><span class="line">                  <span class="attribute">httpsServerPort</span>=<span class="string">"6443"</span></span><br><span class="line">            /&gt;</span><br></pre></td></tr></table></figure></host></p><h1 id="解释分析"><a href="#解释分析" class="headerlink" title="解释分析"></a>解释分析</h1><p>nginx中的核心配置为,这几项配置，会在请求头中设置这几个参数。<br><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">proxy_set_header</span>       Host <span class="variable">$host</span>;  </span><br><span class="line"><span class="attribute">proxy_set_header</span>  X-Real-IP  <span class="variable">$remote_addr</span>;  </span><br><span class="line"><span class="attribute">proxy_set_header</span>  X-Forwarded-For <span class="variable">$proxy_add_x_forwarded_for</span>;  </span><br><span class="line"><span class="attribute">proxy_set_header</span> X-Forwarded-Proto  <span class="variable">$scheme</span>;</span><br></pre></td></tr></table></figure></p><p>我们随便写一个接口，获取请求头。<br><figure class="highlight aspectj"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping</span>(value = <span class="string">"/ggggggg"</span>,method=RequestMethod.GET)</span><br><span class="line"><span class="meta">@ResponseBody</span></span><br><span class="line"><span class="keyword">public</span> <span class="function">Object <span class="title">ggggggg</span><span class="params">( HttpServletRequest request)</span> <span class="keyword">throws</span> ParseException </span>&#123;</span><br><span class="line">Enumeration enumeration = request.getHeaderNames();</span><br><span class="line"><span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><p>经过debug我们可以看到 request的请求头中已经加入了这几个参数<br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180207/1.jpg" alt="">  </p><p>配置tomcat后可以查看request获取的协议和端口号信息。<br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180207/2.jpg" alt=""><br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180207/3.jpg" alt="">  </p><p>tomcat的配置文件其实就是指定tomcat如何将http请求包装成request对象。我们打开tomcat的api看一看RemoteIpValve这个类。<br><a href="http://tomcat.apache.org/tomcat-8.0-doc/api/org/apache/catalina/valves/RemoteIpValve.html" target="_blank" rel="noopener">tomcat API</a></p><blockquote><p>public class RemoteIpValve<br>extends ValveBase<br>Tomcat port of mod_remoteip, this valve replaces the apparent client remote IP address and hostname for the request with the IP address list presented by a proxy or a load balancer via a request headers (e.g. “X-Forwarded-For”).<br>Another feature of this valve is to replace the apparent scheme (http/https) and server port with the scheme presented by a proxy or a load balancer via a request header (e.g. “X-Forwarded-Proto”).</p></blockquote><p>这样tomcat会从请求头中获取这几个参数，实例化request。<br>如果https走的是443端口则不用设置 httpsServerPort默认值为443。我这里https走的是6443，所以需要配置。</p><h1 id="参考文档"><a href="#参考文档" class="headerlink" title="参考文档"></a>参考文档</h1><blockquote><p><a href="http://blog.csdn.net/vfush/article/details/51086274" target="_blank" rel="noopener">http://blog.csdn.net/vfush/article/details/51086274</a><br><a href="https://www.cnblogs.com/gentoo/archive/2012/10/13/2722463.html" target="_blank" rel="noopener">https://www.cnblogs.com/gentoo/archive/2012/10/13/2722463.html</a><br><a href="http://blog.csdn.net/newtelcom/article/details/50782950" target="_blank" rel="noopener">http://blog.csdn.net/newtelcom/article/details/50782950</a><br><a href="http://blog.csdn.net/RKun595/article/details/71012484" target="_blank" rel="noopener">http://blog.csdn.net/RKun595/article/details/71012484</a></p></blockquote><blockquote class="blockquote-center">今天最好的表现，是明天最低的要求。</blockquote>]]></content>
    
    <summary type="html">
    
      &lt;h1 id=&quot;问题描述&quot;&gt;&lt;a href=&quot;#问题描述&quot; class=&quot;headerlink&quot; title=&quot;问题描述&quot;&gt;&lt;/a&gt;问题描述&lt;/h1&gt;&lt;p&gt;App端部分功能使用h5页面实现，但是偶尔用户反映会有广告。也就是请求被第三方劫持了插入了广告，所以决定全业务切https。在nginx配置https将https的请求转发的tomcat的http端口。&lt;br&gt;但是发现一个问题就是h5页面的资源和ajax请求失败，原因是url中的协议和端口号不对应。&lt;br&gt;
    
    </summary>
    
      <category term="nginx" scheme="https://Gengry.github.io/categories/nginx/"/>
    
    
      <category term="nginx" scheme="https://Gengry.github.io/tags/nginx/"/>
    
      <category term="tomcat" scheme="https://Gengry.github.io/tags/tomcat/"/>
    
  </entry>
  
  <entry>
    <title>sourcetree免登陆授权</title>
    <link href="https://Gengry.github.io/2018/02/07/sourcetree%E5%85%8D%E7%99%BB%E9%99%86%E6%8E%88%E6%9D%83/"/>
    <id>https://Gengry.github.io/2018/02/07/sourcetree免登陆授权/</id>
    <published>2018-02-07T05:51:03.000Z</published>
    <updated>2018-03-26T06:22:37.398Z</updated>
    
    <content type="html"><![CDATA[<p>git桌面客户端sourcetree需要注册登录，但是sourcetree官网注册的验证码是走的google，国内无法完成注册。<br><a id="more"></a><br>安装后修改配置文件：C:\Users\lenovo\AppData\Local\Atlassian\SourceTree\accounts.json<br><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">[</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">"$id"</span>: <span class="string">"1"</span>,</span><br><span class="line">    <span class="attr">"$type"</span>: <span class="string">"SourceTree.Api.Host.Identity.Model.IdentityAccount, SourceTree.Api.Host.Identity"</span>,</span><br><span class="line">    <span class="attr">"Authenticate"</span>: <span class="literal">true</span>,</span><br><span class="line">    <span class="attr">"HostInstance"</span>: &#123;</span><br><span class="line">      <span class="attr">"$id"</span>: <span class="string">"2"</span>,</span><br><span class="line">      <span class="attr">"$type"</span>: <span class="string">"SourceTree.Host.Atlassianaccount.AtlassianAccountInstance, SourceTree.Host.AtlassianAccount"</span>,</span><br><span class="line">      <span class="attr">"Host"</span>: &#123;</span><br><span class="line">        <span class="attr">"$id"</span>: <span class="string">"3"</span>,</span><br><span class="line">        <span class="attr">"$type"</span>: <span class="string">"SourceTree.Host.Atlassianaccount.AtlassianAccountHost, SourceTree.Host.AtlassianAccount"</span>,</span><br><span class="line">        <span class="attr">"Id"</span>: <span class="string">"atlassian account"</span></span><br><span class="line">      &#125;,</span><br><span class="line">      <span class="attr">"BaseUrl"</span>: <span class="string">"https://id.atlassian.com/"</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">"Credentials"</span>: &#123;</span><br><span class="line">      <span class="attr">"$id"</span>: <span class="string">"4"</span>,</span><br><span class="line">      <span class="attr">"$type"</span>: <span class="string">"SourceTree.Model.BasicAuthCredentials, SourceTree.Api.Account"</span>,</span><br><span class="line">      <span class="attr">"Username"</span>: <span class="string">""</span>,</span><br><span class="line">      <span class="attr">"Email"</span>: <span class="literal">null</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">"IsDefault"</span>: <span class="literal">false</span></span><br><span class="line">  &#125;</span><br><span class="line">]</span><br></pre></td></tr></table></figure></p><blockquote class="blockquote-center">今天最好的表现，是明天最低的要求。</blockquote>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;git桌面客户端sourcetree需要注册登录，但是sourcetree官网注册的验证码是走的google，国内无法完成注册。&lt;br&gt;
    
    </summary>
    
      <category term="工具" scheme="https://Gengry.github.io/categories/%E5%B7%A5%E5%85%B7/"/>
    
    
      <category term="sourcetree" scheme="https://Gengry.github.io/tags/sourcetree/"/>
    
  </entry>
  
  <entry>
    <title>虚拟机安装Centos，安装mysql，配置主从（二）</title>
    <link href="https://Gengry.github.io/2018/02/06/%E8%99%9A%E6%8B%9F%E6%9C%BA%E5%AE%89%E8%A3%85Centos%EF%BC%8C%E5%AE%89%E8%A3%85mysql%EF%BC%8C%E9%85%8D%E7%BD%AE%E4%B8%BB%E4%BB%8E%EF%BC%88%E4%BA%8C%EF%BC%89/"/>
    <id>https://Gengry.github.io/2018/02/06/虚拟机安装Centos，安装mysql，配置主从（二）/</id>
    <published>2018-02-06T04:59:41.000Z</published>
    <updated>2018-03-26T06:22:37.396Z</updated>
    
    <content type="html"><![CDATA[<h1 id="下载mysql"><a href="#下载mysql" class="headerlink" title="下载mysql"></a>下载mysql</h1><p>仍然使用<a href="http://mirrors.ustc.edu.cn/" target="_blank" rel="noopener">中国科学技术大学</a>镜像站下载mysql。<br>最新版本的<a href="http://iso.mirrors.ustc.edu.cn/mysql-ftp/Downloads/MySQL-5.7/mysql-5.7.20-linux-glibc2.12-i686.tar" target="_blank" rel="noopener">mysql</a>。<br>这里下载的mysql是二进制包，没有使用linux的包管理工具。<br><a id="more"></a></p><h1 id="阅读mysql安装文档"><a href="#阅读mysql安装文档" class="headerlink" title="阅读mysql安装文档"></a>阅读mysql安装文档</h1><p>通过百度打开mysql的官网，找到mysql5.7GA的文档。<br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180205/19.jpg" alt=""><br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180205/20.jpg" alt="">  </p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">shell&gt;</span><span class="bash"> groupadd mysql</span></span><br><span class="line"><span class="meta">shell&gt;</span><span class="bash"> useradd -r -g mysql -s /bin/<span class="literal">false</span> mysql</span></span><br><span class="line"><span class="meta">shell&gt;</span><span class="bash"> <span class="built_in">cd</span> /usr/<span class="built_in">local</span></span></span><br><span class="line"><span class="meta">shell&gt;</span><span class="bash"> tar zxvf /path/to/mysql-VERSION-OS.tar.gz</span></span><br><span class="line"><span class="meta">shell&gt;</span><span class="bash"> ln -s full-path-to-mysql-VERSION-OS mysql</span></span><br><span class="line"><span class="meta">shell&gt;</span><span class="bash"> <span class="built_in">cd</span> mysql</span></span><br><span class="line"><span class="meta">shell&gt;</span><span class="bash"> mkdir mysql-files</span></span><br><span class="line"><span class="meta">shell&gt;</span><span class="bash"> chown mysql:mysql mysql-files</span></span><br><span class="line"><span class="meta">shell&gt;</span><span class="bash"> chmod 750 mysql-files</span></span><br><span class="line"><span class="meta">shell&gt;</span><span class="bash"> bin/mysqld --initialize --user=mysql </span></span><br><span class="line"><span class="meta">shell&gt;</span><span class="bash"> bin/mysql_ssl_rsa_setup              </span></span><br><span class="line"><span class="meta">shell&gt;</span><span class="bash"> bin/mysqld_safe --user=mysql &amp;</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> Next <span class="built_in">command</span> is optional</span></span><br><span class="line"><span class="meta">shell&gt;</span><span class="bash"> cp support-files/mysql.server /etc/init.d/mysql.server</span></span><br></pre></td></tr></table></figure><h1 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h1><p>使用xshell工具通过ssh连接到centos，ssh协议支持xftp协议，可以将本地的文件上传到虚拟机中的centos中。<br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180205/21.jpg" alt=""><br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180205/22.jpg" alt="">  </p><h2 id="创建用户及相关"><a href="#创建用户及相关" class="headerlink" title="创建用户及相关"></a>创建用户及相关</h2><p><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180205/23.jpg" alt=""><br>将mysql目录及其子目录的所有者设置为mysql</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">mv mysql-5.7.21-linux-glibc2.12-x86_64 mysql</span><br><span class="line">cd /usr/local</span><br><span class="line">ln -s /home/mysql/mysql mysql</span><br><span class="line">cd /home/mysql</span><br><span class="line">mkdir mysql-data</span><br><span class="line">mkdir mysql-logs</span><br><span class="line">mkdir mysql-tmp</span><br><span class="line">chown mysql:mysql -R mysql/</span><br><span class="line"><span class="meta">#</span><span class="bash"> 初始化mysql的data文件夹</span></span><br><span class="line">[root@localhost mysql]# ./bin/mysqld  --initialize --user=mysql --basedir=/home/mysql/mysql --datadir=/home/mysql/mysql-data</span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180205/24.jpg" alt="">  </p><h2 id="mysql配置文件"><a href="#mysql配置文件" class="headerlink" title="mysql配置文件"></a>mysql配置文件</h2><p>将下面的配置复制到 /etc/my.cnf中<br><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[client]</span></span><br><span class="line"><span class="attr">default_character_set</span> = utf8</span><br><span class="line"><span class="attr">port</span> = <span class="number">3306</span></span><br><span class="line"><span class="comment">#这个路径需要和mysqld中socket的路径相同</span></span><br><span class="line"><span class="attr">socket</span> = /tmp/mysql.sock</span><br><span class="line"></span><br><span class="line"><span class="section">[mysqld]</span></span><br><span class="line"><span class="attr">basedir</span> = /home/mysql/mysql</span><br><span class="line"><span class="attr">datadir</span> = /home/mysql/mysql-data</span><br><span class="line"><span class="attr">user</span> = mysql</span><br><span class="line"><span class="attr">port</span> = <span class="number">3306</span></span><br><span class="line"><span class="attr">server_id</span> = <span class="number">1</span></span><br><span class="line"><span class="attr">character_set_server</span> = utf8</span><br><span class="line"><span class="attr">socket</span> = /tmp/mysql.sock</span><br><span class="line"><span class="attr">pid-file</span> = /tmp/mysql.pid</span><br><span class="line"><span class="attr">log-bin</span> = /home/mysql/mysql-logs/bin_log  # 二进制日志，用户主从复制</span><br><span class="line"><span class="attr">relay-log</span> = /home/mysql/mysql-logs/relay_log  #从mysql的IO thread将主的bin_log复制到这个文件</span><br><span class="line"><span class="attr">log-error</span> = /home/mysql/mysql-logs/mysql_error.log</span><br><span class="line"><span class="attr">explicit_defaults_for_timestamp</span> = <span class="literal">true</span></span><br><span class="line"><span class="attr">expire_logs_days</span> = <span class="number">10</span></span><br><span class="line"><span class="attr">max_binlog_size</span> = <span class="number">100</span>M</span><br><span class="line"><span class="attr">binlog-do-db</span> =    #复制数据库名称</span><br><span class="line"><span class="attr">binlog-ignore-db</span> = mysql #忽略二进制日志的数据库名</span><br></pre></td></tr></table></figure></p><h2 id="配置启动脚本"><a href="#配置启动脚本" class="headerlink" title="配置启动脚本"></a>配置启动脚本</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">shell&gt;</span><span class="bash"> cp support-files/mysql.server /etc/init.d/mysql.server</span></span><br></pre></td></tr></table></figure><h2 id="启动mysql"><a href="#启动mysql" class="headerlink" title="启动mysql"></a>启动mysql</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">service mysql start</span><br></pre></td></tr></table></figure><p>报错<br><code>MySQL.2018-02-06T06:07:04.427707Z mysqld_safe error: log-error set to &#39;/home/mysql/mysql-logs/mysql_error.log&#39;, however file don&#39;t exists. Create writable for user &#39;mysql&#39;</code></p><p>需要手动建立error_log文件<br><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">touch /home/mysql/mysql-logs/mysql_error.log</span><br><span class="line">service mysql start</span><br></pre></td></tr></table></figure></p><p>mysql已正常启动，可以使用mysql/bin目录下的mysql和之前记录的默认密码登录mysql<br>为root账户设置密码<br><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">alter</span> <span class="keyword">user</span> <span class="string">'root'</span>@<span class="string">'localhost'</span> <span class="keyword">identified</span> <span class="keyword">by</span> <span class="string">'root'</span>;</span><br></pre></td></tr></table></figure></p><p>把mysql注册成开机启动的服务<br><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">chkconfig --<span class="keyword">add</span><span class="bash"> mysql</span></span><br></pre></td></tr></table></figure></p><h2 id="加入环境变量"><a href="#加入环境变量" class="headerlink" title="加入环境变量"></a>加入环境变量</h2><p>修改/etc/profile文件使其永久性生效，并对所有系统用户生效，在文件末尾加上如下两行代码<br>PATH=$PATH:/home/mysql/mysql:/home/mysql/mysql/bin<br>export PATH<br>最后：执行 命令source /etc/profile或 执行点命令 ./profile使其修改生效，执行完可通过echo $PATH命令查看是否添加成功。</p><h2 id="配置账户"><a href="#配置账户" class="headerlink" title="配置账户"></a>配置账户</h2><p>登录mysql配置一个可以远程访问的账户<br><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">GRANT</span> ALL <span class="keyword">PRIVILEGES</span> <span class="keyword">ON</span> *.* <span class="keyword">TO</span> <span class="string">'myuser'</span>@<span class="string">'%'</span><span class="keyword">IDENTIFIED</span> <span class="keyword">BY</span> <span class="string">'myuser'</span> <span class="keyword">WITH</span> <span class="keyword">GRANT</span> <span class="keyword">OPTION</span>;</span><br><span class="line"><span class="keyword">FLUSH</span> <span class="keyword">PRIVILEGES</span></span><br></pre></td></tr></table></figure></p><p>暂时关闭防火墙，否则外面访问不了<br>systemctl stop firewalld.service</p><h1 id="使用Navicat连接mysql"><a href="#使用Navicat连接mysql" class="headerlink" title="使用Navicat连接mysql"></a>使用Navicat连接mysql</h1><p>使用账户myuser 密码 myuser登录，<br>第一次登录没有成功，在本地用myuser登录一下mysql就可以用navicat连接上了。<br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180205/25.jpg" alt="">  </p><blockquote class="blockquote-center">今天最好的表现，是明天最低的要求。</blockquote>]]></content>
    
    <summary type="html">
    
      &lt;h1 id=&quot;下载mysql&quot;&gt;&lt;a href=&quot;#下载mysql&quot; class=&quot;headerlink&quot; title=&quot;下载mysql&quot;&gt;&lt;/a&gt;下载mysql&lt;/h1&gt;&lt;p&gt;仍然使用&lt;a href=&quot;http://mirrors.ustc.edu.cn/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;中国科学技术大学&lt;/a&gt;镜像站下载mysql。&lt;br&gt;最新版本的&lt;a href=&quot;http://iso.mirrors.ustc.edu.cn/mysql-ftp/Downloads/MySQL-5.7/mysql-5.7.20-linux-glibc2.12-i686.tar&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;mysql&lt;/a&gt;。&lt;br&gt;这里下载的mysql是二进制包，没有使用linux的包管理工具。&lt;br&gt;
    
    </summary>
    
      <category term="linux" scheme="https://Gengry.github.io/categories/linux/"/>
    
      <category term="mysql" scheme="https://Gengry.github.io/categories/linux/mysql/"/>
    
    
  </entry>
  
  <entry>
    <title>虚拟机安装Centos，安装mysql，配置主从（一）</title>
    <link href="https://Gengry.github.io/2018/02/05/%E8%99%9A%E6%8B%9F%E6%9C%BA%E5%AE%89%E8%A3%85Centos%EF%BC%8C%E5%AE%89%E8%A3%85mysql%EF%BC%8C%E9%85%8D%E7%BD%AE%E4%B8%BB%E4%BB%8E%EF%BC%88%E4%B8%80%EF%BC%89/"/>
    <id>https://Gengry.github.io/2018/02/05/虚拟机安装Centos，安装mysql，配置主从（一）/</id>
    <published>2018-02-05T05:20:59.000Z</published>
    <updated>2018-03-26T06:22:37.396Z</updated>
    
    <content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>公司线上使用阿里云的mysql数据库，一直是单点，也是系统中最大的瓶颈。因为开始考虑的是单点，所以第一个负责人将RDS的配置设置的很高，造成了特别大的资源浪费。平时cpu的内存的使用率都特别低。<br>现在的负责人觉得RDS高配置很浪费，做了降配处理，春节前活动直接被查询宕机。所以现在需要考虑优化方案<br><a id="more"></a></p><h2 id="方案一"><a href="#方案一" class="headerlink" title="方案一"></a>方案一</h2><p>直接使用阿里云的RDS配置主从，RDS自动支持读写分离，简单易用，能用钱解决的问题都是小问题，暂定也是使用这个方案。</p><h2 id="方案二"><a href="#方案二" class="headerlink" title="方案二"></a>方案二</h2><p>使用阿里云的ECS自己搭建mysql的集群。配置mysql读写分离，高可用，防止单点故障造成直接宕机。<br>虽然定的方案是使用RDS，但是我还是在本地搭建一下这个环境，以备不时之需。  </p><h3 id="安装VMware"><a href="#安装VMware" class="headerlink" title="安装VMware"></a>安装VMware</h3><p>此步骤略过。</p><h3 id="安装Centos"><a href="#安装Centos" class="headerlink" title="安装Centos"></a>安装Centos</h3><p>下载Centos的ISO包，但是官网的速度简直是巨慢无比无法忍受，可以在中国的镜像站下载。<br>可以从我的博客<a href="/2018/01/29/国内开源镜像站/">国内开源镜像站</a>获取开源镜像站<br>推荐使用<a href="http://mirrors.ustc.edu.cn/" target="_blank" rel="noopener">中国科学技术大学</a>。<br>页面中可以<code>Ctrl+f</code>搜索centos快速定位。在文件目录下找到centos官方推荐使用的最新版本。<a href="http://mirrors.ustc.edu.cn/centos/7.4.1708/isos/x86_64/CentOS-7-x86_64-DVD-1708.iso" target="_blank" rel="noopener">CentOS7</a></p><blockquote><p>CentOS-7-x86_64-DVD-1708.iso               标准安装版，一般下载这个就可以了<br>CentOS-7-x86_64-NetInstall-1708.iso        网络安装镜像<br>CentOS-7-x86_64-Everything-1708.iso        对完整版安装盘的软件进行补充，集成所有软件。<br>CentOS-7-x86_64-LiveGNOME-1708.iso     GNOME桌面版<br>CentOS-7-x86_64-LiveKDE-1708.iso           KDE桌面版<br>CCentOS-7-x86_64-LiveKDE-1708-livecd.iso            光盘上运行的系统，类拟于winpe   </p></blockquote><h4 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h4><p><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180205/1.jpg" alt=""><br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180205/2.jpg" alt=""><br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180205/3.jpg" alt=""><br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180205/4.jpg" alt=""><br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180205/5.jpg" alt=""><br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180205/6.jpg" alt=""><br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180205/7.jpg" alt=""><br>新手最简单安装一路继续，安装成功后登陆。<br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180205/8.jpg" alt=""><br>配置网络，在安装完虚拟就后一般会自动生成两个网络适配器，这个可以删除也可以自定义，但是本次我们使用默认生成的<code>VMware Network Adapter VMnet8</code><br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180205/9.jpg" alt=""><br>现在需要将可以上网的网卡的网络共享给虚拟机的网络适配器。<br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180205/10.jpg" alt=""><br>现在看VMware Network Adapter VMnet8的属性，可以看到为他生成了ip地址。<br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180205/11.jpg" alt=""><br>根据这个信息配置，虚拟机的虚拟网络（编辑-&gt;虚拟网络编辑器）<br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180205/12.jpg" alt="">  </p><h4 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h4><p>虚拟机启动默认网络是不自动开启的，编辑网络的配置文件<br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180205/13.jpg" alt=""><br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180205/14.jpg" alt=""><br>重启network服务，已经获取到ip地址，测试实体机可以ping通。<br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180205/15.jpg" alt=""><br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180205/16.jpg" alt=""><br>开启ssh外网连接。<br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180205/17.jpg" alt=""><br>重启centos。<br>使用<code>xshell</code>连接。<br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180205/18.jpg" alt="">  </p><blockquote><p><a href="http://blog.csdn.net/bao19901210/article/details/51917641" target="_blank" rel="noopener">http://blog.csdn.net/bao19901210/article/details/51917641</a><br><a href="http://blog.csdn.net/u012961566/article/details/70237548" target="_blank" rel="noopener">http://blog.csdn.net/u012961566/article/details/70237548</a><br><a href="http://blog.csdn.net/djcode/article/details/78621772" target="_blank" rel="noopener">http://blog.csdn.net/djcode/article/details/78621772</a>  </p></blockquote><blockquote class="blockquote-center">今天最好的表现，是明天最低的要求。</blockquote>]]></content>
    
    <summary type="html">
    
      &lt;h1 id=&quot;前言&quot;&gt;&lt;a href=&quot;#前言&quot; class=&quot;headerlink&quot; title=&quot;前言&quot;&gt;&lt;/a&gt;前言&lt;/h1&gt;&lt;p&gt;公司线上使用阿里云的mysql数据库，一直是单点，也是系统中最大的瓶颈。因为开始考虑的是单点，所以第一个负责人将RDS的配置设置的很高，造成了特别大的资源浪费。平时cpu的内存的使用率都特别低。&lt;br&gt;现在的负责人觉得RDS高配置很浪费，做了降配处理，春节前活动直接被查询宕机。所以现在需要考虑优化方案&lt;br&gt;
    
    </summary>
    
      <category term="linux" scheme="https://Gengry.github.io/categories/linux/"/>
    
      <category term="mysql" scheme="https://Gengry.github.io/categories/linux/mysql/"/>
    
    
      <category term="mysql" scheme="https://Gengry.github.io/tags/mysql/"/>
    
  </entry>
  
  <entry>
    <title>SpringMVC hibernate-validator校验请求参数</title>
    <link href="https://Gengry.github.io/2018/02/03/SpringMVC%20hibernate-validator%E6%A0%A1%E9%AA%8C%E8%AF%B7%E6%B1%82%E5%8F%82%E6%95%B0/"/>
    <id>https://Gengry.github.io/2018/02/03/SpringMVC hibernate-validator校验请求参数/</id>
    <published>2018-02-03T07:04:51.000Z</published>
    <updated>2018-03-26T06:22:37.395Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>By default use of @EnableWebMvc or <mvc:annotation-driven> automatically registers Bean Validation support in Spring MVC through the LocalValidatorFactoryBean when a Bean Validation provider such as Hibernate Validator is detected on the classpath.</mvc:annotation-driven></p></blockquote><a id="more"></a><blockquote><p>注意 需要检验的bean需要被 context:component-scan 扫描到</p><p>如果不指定校验器，classpath内有hibernate validoter，spring会默认使用它。</p></blockquote><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@ApiOperation</span>(value=<span class="string">"提交商城订单"</span>,tags=<span class="string">"商城"</span>)</span><br><span class="line"><span class="meta">@Auth</span></span><br><span class="line"><span class="meta">@RequestMapping</span>(value = <span class="string">"/submitMallOrder"</span>,method=RequestMethod.POST)</span><br><span class="line"><span class="meta">@ResponseBody</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> Object <span class="title">submitMallOrder</span><span class="params">(@RequestBody @Valid MallOrderInfosVO mallOrderInfoVO, BindingResult binding)</span> </span>&#123;</span><br><span class="line"><span class="keyword">if</span>(binding.hasErrors())&#123;</span><br><span class="line"><span class="keyword">return</span> ResultMessage.getValidFail(<span class="keyword">new</span> HashMap&lt;String,Object&gt;()).setBindingResult(binding);</span><br><span class="line">&#125;</span><br><span class="line">Map&lt;String,Object&gt; result = mallOrderInfoService.submitMallOrder(mallOrderInfoVO);</span><br><span class="line"><span class="keyword">return</span> ResultMessage.newInstance().setCode(MapUtils.getInteger(result, <span class="string">"code"</span>)).setMessage(MapUtils.getString(result, <span class="string">"message"</span>)).setData(MapUtils.getObject(result, <span class="string">"data"</span>));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.jsz.peini.bean.mall;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.math.BigDecimal;</span><br><span class="line"><span class="keyword">import</span> java.util.ArrayList;</span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.validation.Valid;</span><br><span class="line"><span class="keyword">import</span> javax.validation.constraints.DecimalMin;</span><br><span class="line"><span class="keyword">import</span> javax.validation.constraints.NotNull;</span><br><span class="line"><span class="keyword">import</span> javax.validation.constraints.Size;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.hibernate.validator.constraints.Range;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> io.swagger.annotations.ApiModelProperty;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MallOrderInfosVO</span> </span>&#123;</span><br><span class="line"></span><br><span class="line"><span class="meta">@NotNull</span></span><br><span class="line"><span class="meta">@Size</span>(min=<span class="number">1</span>)</span><br><span class="line"><span class="meta">@Valid</span></span><br><span class="line"><span class="meta">@ApiModelProperty</span>(<span class="string">"商城订单列表"</span>)</span><br><span class="line"><span class="keyword">public</span> ArrayList&lt;MallSellerOrderInfoVo&gt; sellerOrderInfoVos;</span><br><span class="line"></span><br><span class="line"><span class="meta">@NotNull</span></span><br><span class="line"><span class="meta">@DecimalMin</span>(<span class="string">"0.00"</span>)</span><br><span class="line"><span class="meta">@ApiModelProperty</span>(<span class="string">"订单总额"</span>)</span><br><span class="line"><span class="keyword">public</span> BigDecimal totalMoney;</span><br><span class="line"></span><br><span class="line"><span class="comment">//@NotNull</span></span><br><span class="line"><span class="comment">//@Range(min=1,max=3)</span></span><br><span class="line"><span class="comment">//@ApiModelProperty("支付方式 0金币；1微信；2支付宝")</span></span><br><span class="line"><span class="comment">//public Integer payType;</span></span><br><span class="line"></span><br><span class="line"><span class="meta">@ApiModelProperty</span>(<span class="string">"如果是通过购物车提交的订单，传过来购物车的id"</span>)</span><br><span class="line"><span class="keyword">public</span> List&lt;Integer&gt; mallShopCartIds;</span><br><span class="line"></span><br><span class="line"><span class="meta">@NotNull</span></span><br><span class="line"><span class="meta">@ApiModelProperty</span>(<span class="string">"收货地址id"</span>)</span><br><span class="line"><span class="keyword">public</span> Integer mallAddressId;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> ArrayList&lt;MallSellerOrderInfoVo&gt; <span class="title">getSellerOrderInfoVos</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="keyword">return</span> sellerOrderInfoVos;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setSellerOrderInfoVos</span><span class="params">(ArrayList&lt;MallSellerOrderInfoVo&gt; sellerOrderInfoVos)</span> </span>&#123;</span><br><span class="line"><span class="keyword">this</span>.sellerOrderInfoVos = sellerOrderInfoVos;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> BigDecimal <span class="title">getTotalMoney</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="keyword">return</span> totalMoney;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setTotalMoney</span><span class="params">(BigDecimal totalMoney)</span> </span>&#123;</span><br><span class="line"><span class="keyword">this</span>.totalMoney = totalMoney;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//public Integer getPayType() &#123;</span></span><br><span class="line"><span class="comment">//return payType;</span></span><br><span class="line"><span class="comment">//&#125;</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">//public void setPayType(Integer payType) &#123;</span></span><br><span class="line"><span class="comment">//this.payType = payType;</span></span><br><span class="line"><span class="comment">//&#125;</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> List&lt;Integer&gt; <span class="title">getMallShopCartIds</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="keyword">return</span> mallShopCartIds;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setMallShopCartIds</span><span class="params">(List&lt;Integer&gt; mallShopCartIds)</span> </span>&#123;</span><br><span class="line"><span class="keyword">this</span>.mallShopCartIds = mallShopCartIds;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> Integer <span class="title">getMallAddressId</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="keyword">return</span> mallAddressId;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setMallAddressId</span><span class="params">(Integer mallAddressId)</span> </span>&#123;</span><br><span class="line"><span class="keyword">this</span>.mallAddressId = mallAddressId;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.jsz.peini.bean.mall;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.math.BigDecimal;</span><br><span class="line"><span class="keyword">import</span> java.util.ArrayList;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.validation.Valid;</span><br><span class="line"><span class="keyword">import</span> javax.validation.constraints.DecimalMin;</span><br><span class="line"><span class="keyword">import</span> javax.validation.constraints.Min;</span><br><span class="line"><span class="keyword">import</span> javax.validation.constraints.NotNull;</span><br><span class="line"><span class="keyword">import</span> javax.validation.constraints.Size;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.hibernate.validator.constraints.Length;</span><br><span class="line"><span class="keyword">import</span> org.hibernate.validator.constraints.Range;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> io.swagger.annotations.ApiModelProperty;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MallSellerOrderInfoVo</span> </span>&#123;</span><br><span class="line"></span><br><span class="line"><span class="meta">@NotNull</span></span><br><span class="line"><span class="meta">@ApiModelProperty</span>(<span class="string">"店铺id"</span>)</span><br><span class="line"><span class="keyword">private</span> Integer sellerId;</span><br><span class="line"><span class="meta">@NotNull</span></span><br><span class="line"><span class="meta">@DecimalMin</span>(<span class="string">"0.00"</span>)</span><br><span class="line"><span class="meta">@ApiModelProperty</span>(<span class="string">"金额合计"</span>)</span><br><span class="line"><span class="keyword">private</span> BigDecimal totalMoney;</span><br><span class="line"><span class="meta">@NotNull</span></span><br><span class="line"><span class="meta">@DecimalMin</span>(<span class="string">"0.00"</span>)</span><br><span class="line"><span class="meta">@ApiModelProperty</span>(<span class="string">"商品总价"</span>)</span><br><span class="line"><span class="keyword">private</span> BigDecimal goodsMoney;</span><br><span class="line"><span class="meta">@NotNull</span></span><br><span class="line"><span class="meta">@DecimalMin</span>(<span class="string">"0"</span>)</span><br><span class="line"><span class="meta">@ApiModelProperty</span>(<span class="string">"支付金额"</span>)</span><br><span class="line"><span class="keyword">private</span> BigDecimal payMoney;</span><br><span class="line"><span class="meta">@NotNull</span></span><br><span class="line"><span class="meta">@DecimalMin</span>(<span class="string">"0"</span>)</span><br><span class="line"><span class="meta">@ApiModelProperty</span>(<span class="string">"快递费用"</span>)</span><br><span class="line"><span class="keyword">private</span> BigDecimal expressPrice;</span><br><span class="line"><span class="meta">@NotNull</span></span><br><span class="line"><span class="meta">@DecimalMin</span>(<span class="string">"0"</span>)</span><br><span class="line"><span class="meta">@ApiModelProperty</span>(<span class="string">"积分补贴"</span>)</span><br><span class="line"><span class="keyword">private</span> BigDecimal scoreMoney;</span><br><span class="line"><span class="meta">@NotNull</span></span><br><span class="line"><span class="meta">@DecimalMin</span>(<span class="string">"0"</span>)</span><br><span class="line"><span class="meta">@ApiModelProperty</span>(<span class="string">"积分消耗"</span>)</span><br><span class="line"><span class="keyword">private</span> Integer scoreUse;</span><br><span class="line"><span class="meta">@NotNull</span></span><br><span class="line"><span class="meta">@Min</span>(<span class="number">1</span>)</span><br><span class="line"><span class="meta">@ApiModelProperty</span>(<span class="string">"购买件数"</span>)</span><br><span class="line"><span class="keyword">private</span> Integer buyNum;</span><br><span class="line"></span><br><span class="line"><span class="meta">@NotNull</span></span><br><span class="line"><span class="meta">@Range</span>(min=<span class="number">0</span>,max=<span class="number">3</span>)</span><br><span class="line"><span class="meta">@ApiModelProperty</span>(<span class="string">"发票类型 0:不要发票 1:个人 2:企业 "</span>)</span><br><span class="line"><span class="keyword">private</span> Integer invoiceType;</span><br><span class="line"><span class="meta">@Length</span>(max=<span class="number">200</span>)</span><br><span class="line"><span class="meta">@ApiModelProperty</span>(<span class="string">"发票抬头"</span>)</span><br><span class="line"><span class="keyword">private</span> String invoiceTitle;</span><br><span class="line"><span class="meta">@Length</span>(max=<span class="number">200</span>)</span><br><span class="line"><span class="meta">@ApiModelProperty</span>(<span class="string">"留言"</span>)</span><br><span class="line"><span class="keyword">private</span> String leaveMsg;</span><br><span class="line"></span><br><span class="line"><span class="meta">@NotNull</span></span><br><span class="line"><span class="meta">@ApiModelProperty</span>(<span class="string">"收货人"</span>)</span><br><span class="line"><span class="keyword">private</span> String receiveUser;</span><br><span class="line"></span><br><span class="line"><span class="meta">@NotNull</span></span><br><span class="line"><span class="meta">@ApiModelProperty</span>(<span class="string">"收货电话"</span>)</span><br><span class="line"><span class="keyword">private</span> String receiveTel;</span><br><span class="line"><span class="meta">@Length</span>(max=<span class="number">200</span>)</span><br><span class="line"><span class="meta">@NotNull</span></span><br><span class="line"><span class="meta">@ApiModelProperty</span>(<span class="string">"收货地址"</span>)</span><br><span class="line"><span class="keyword">private</span> String receiveAddress;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Size</span>(min=<span class="number">1</span>)</span><br><span class="line"><span class="meta">@ApiModelProperty</span>(<span class="string">"商品订单列表"</span>)</span><br><span class="line"><span class="meta">@Valid</span></span><br><span class="line"><span class="keyword">private</span> ArrayList&lt;MallGoodsOrderInfoVO&gt; mallGoodsOrderInfoVOs;</span><br><span class="line"><span class="function"><span class="keyword">public</span> Integer <span class="title">getSellerId</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="keyword">return</span> sellerId;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setSellerId</span><span class="params">(Integer sellerId)</span> </span>&#123;</span><br><span class="line"><span class="keyword">this</span>.sellerId = sellerId;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> BigDecimal <span class="title">getTotalMoney</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="keyword">return</span> totalMoney;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setTotalMoney</span><span class="params">(BigDecimal totalMoney)</span> </span>&#123;</span><br><span class="line"><span class="keyword">this</span>.totalMoney = totalMoney;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> BigDecimal <span class="title">getPayMoney</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="keyword">return</span> payMoney;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setPayMoney</span><span class="params">(BigDecimal payMoney)</span> </span>&#123;</span><br><span class="line"><span class="keyword">this</span>.payMoney = payMoney;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> BigDecimal <span class="title">getExpressPrice</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="keyword">return</span> expressPrice;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setExpressPrice</span><span class="params">(BigDecimal expressPrice)</span> </span>&#123;</span><br><span class="line"><span class="keyword">this</span>.expressPrice = expressPrice;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> BigDecimal <span class="title">getScoreMoney</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="keyword">return</span> scoreMoney;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setScoreMoney</span><span class="params">(BigDecimal scoreMoney)</span> </span>&#123;</span><br><span class="line"><span class="keyword">this</span>.scoreMoney = scoreMoney;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> Integer <span class="title">getScoreUse</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="keyword">return</span> scoreUse;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setScoreUse</span><span class="params">(Integer scoreUse)</span> </span>&#123;</span><br><span class="line"><span class="keyword">this</span>.scoreUse = scoreUse;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> Integer <span class="title">getBuyNum</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="keyword">return</span> buyNum;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setBuyNum</span><span class="params">(Integer buyNum)</span> </span>&#123;</span><br><span class="line"><span class="keyword">this</span>.buyNum = buyNum;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> Integer <span class="title">getInvoiceType</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="keyword">return</span> invoiceType;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setInvoiceType</span><span class="params">(Integer invoiceType)</span> </span>&#123;</span><br><span class="line"><span class="keyword">this</span>.invoiceType = invoiceType;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">getInvoiceTitle</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="keyword">return</span> invoiceTitle;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setInvoiceTitle</span><span class="params">(String invoiceTitle)</span> </span>&#123;</span><br><span class="line"><span class="keyword">this</span>.invoiceTitle = invoiceTitle;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">getLeaveMsg</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="keyword">return</span> leaveMsg;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setLeaveMsg</span><span class="params">(String leaveMsg)</span> </span>&#123;</span><br><span class="line"><span class="keyword">this</span>.leaveMsg = leaveMsg;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">getReceiveUser</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="keyword">return</span> receiveUser;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setReceiveUser</span><span class="params">(String receiveUser)</span> </span>&#123;</span><br><span class="line"><span class="keyword">this</span>.receiveUser = receiveUser;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">getReceiveTel</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="keyword">return</span> receiveTel;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setReceiveTel</span><span class="params">(String receiveTel)</span> </span>&#123;</span><br><span class="line"><span class="keyword">this</span>.receiveTel = receiveTel;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">getReceiveAddress</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="keyword">return</span> receiveAddress;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setReceiveAddress</span><span class="params">(String receiveAddress)</span> </span>&#123;</span><br><span class="line"><span class="keyword">this</span>.receiveAddress = receiveAddress;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> ArrayList&lt;MallGoodsOrderInfoVO&gt; <span class="title">getMallGoodsOrderInfoVOs</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="keyword">return</span> mallGoodsOrderInfoVOs;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setMallGoodsOrderInfoVOs</span><span class="params">(ArrayList&lt;MallGoodsOrderInfoVO&gt; mallGoodsOrderInfoVOs)</span> </span>&#123;</span><br><span class="line"><span class="keyword">this</span>.mallGoodsOrderInfoVOs = mallGoodsOrderInfoVOs;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> BigDecimal <span class="title">getGoodsMoney</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="keyword">return</span> goodsMoney;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setGoodsMoney</span><span class="params">(BigDecimal goodsMoney)</span> </span>&#123;</span><br><span class="line"><span class="keyword">this</span>.goodsMoney = goodsMoney;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>一个完整实例<br><a href="http://blog.csdn.net/vbirdbest/article/details/72620957" target="_blank" rel="noopener">http://blog.csdn.net/vbirdbest/article/details/72620957</a></p><blockquote class="blockquote-center">今天最好的表现，是明天最低的要求。</blockquote>]]></content>
    
    <summary type="html">
    
      &lt;blockquote&gt;
&lt;p&gt;By default use of @EnableWebMvc or &lt;mvc:annotation-driven&gt; automatically registers Bean Validation support in Spring MVC through the LocalValidatorFactoryBean when a Bean Validation provider such as Hibernate Validator is detected on the classpath.&lt;/mvc:annotation-driven&gt;&lt;/p&gt;
&lt;/blockquote&gt;
    
    </summary>
    
      <category term="spring" scheme="https://Gengry.github.io/categories/spring/"/>
    
    
      <category term="spring" scheme="https://Gengry.github.io/tags/spring/"/>
    
  </entry>
  
  <entry>
    <title>Mysql主从架构读写分离</title>
    <link href="https://Gengry.github.io/2018/02/02/Mysql%E4%B8%BB%E4%BB%8E%E6%9E%B6%E6%9E%84%E8%AF%BB%E5%86%99%E5%88%86%E7%A6%BB/"/>
    <id>https://Gengry.github.io/2018/02/02/Mysql主从架构读写分离/</id>
    <published>2018-02-02T06:15:32.000Z</published>
    <updated>2018-03-26T06:22:37.394Z</updated>
    
    <content type="html"><![CDATA[<p>百度云：<br>11.高性能必学之Mysql主从架构实践<br>主从配置<br><a href="http://blog.csdn.net/u012961566/article/details/70237548" target="_blank" rel="noopener">http://blog.csdn.net/u012961566/article/details/70237548</a></p><p><a href="http://blog.csdn.net/djcode/article/details/78621772" target="_blank" rel="noopener">http://blog.csdn.net/djcode/article/details/78621772</a></p><p>读写分离 mybatis插件<br><a href="https://gitee.com/qiangzigege/MyRWSplit" target="_blank" rel="noopener">https://gitee.com/qiangzigege/MyRWSplit</a></p><p>mysql半同步方案</p><blockquote class="blockquote-center">今天最好的表现，是明天最低的要求。</blockquote>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;百度云：&lt;br&gt;11.高性能必学之Mysql主从架构实践&lt;br&gt;主从配置&lt;br&gt;&lt;a href=&quot;http://blog.csdn.net/u012961566/article/details/70237548&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;
      
    
    </summary>
    
      <category term="mysql" scheme="https://Gengry.github.io/categories/mysql/"/>
    
    
  </entry>
  
  <entry>
    <title>JDK动态代理引发的Spring事物不能回滚原因分析</title>
    <link href="https://Gengry.github.io/2018/02/02/JDK%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E5%BC%95%E5%8F%91%E7%9A%84Spring%E4%BA%8B%E7%89%A9%E4%B8%8D%E8%83%BD%E5%9B%9E%E6%BB%9A%E5%8E%9F%E5%9B%A0%E5%88%86%E6%9E%90/"/>
    <id>https://Gengry.github.io/2018/02/02/JDK动态代理引发的Spring事物不能回滚原因分析/</id>
    <published>2018-02-02T01:59:52.000Z</published>
    <updated>2018-03-26T06:22:37.394Z</updated>
    
    <content type="html"><![CDATA[<p>12.架构师不得不知道的Spring事物不能回滚的深层次原因<br><a href="https://pan.baidu.com/mbox/streampage?from_uk=684610632&amp;msg_id=8376247896642219120&amp;fs_id=476303219573352&amp;to=763122753997696274&amp;type=2&amp;name=12.%E6%9E%B6%E6%9E%84%E5%B8%88%E4%B8%8D%E5%BE%97%E4%B8%8D%E7%9F%A5%E9%81%93%E7%9A%84Spring%E4%BA%8B%E7%89%A9%E4%B8%8D%E8%83%BD%E5%9B%9E%E6%BB%9A%E7%9A%84%E6%B7%B1%E5%B1%82%E6%AC%A1%E5%8E%9F%E5%9B%A0.mp4&amp;path=%2FB12%E3%80%81%E9%9D%A2%E8%AF%95%E4%B8%93%E5%B1%9E%2F12.%E6%9E%B6%E6%9E%84%E5%B8%88%E4%B8%8D%E5%BE%97%E4%B8%8D%E7%9F%A5%E9%81%93%E7%9A%84Spring%E4%BA%8B%E7%89%A9%E4%B8%8D%E8%83%BD%E5%9B%9E%E6%BB%9A%E7%9A%84%E6%B7%B1%E5%B1%82%E6%AC%A1%E5%8E%9F%E5%9B%A0%2F12.%E6%9E%B6%E6%9E%84%E5%B8%88%E4%B8%8D%E5%BE%97%E4%B8%8D%E7%9F%A5%E9%81%93%E7%9A%84Spring%E4%BA%8B%E7%89%A9%E4%B8%8D%E8%83%BD%E5%9B%9E%E6%BB%9A%E7%9A%84%E6%B7%B1%E5%B1%82%E6%AC%A1%E5%8E%9F%E5%9B%A0.mp4&amp;md5=53444f5643355dab35b28dabd3e0b0f1" target="_blank" rel="noopener">https://pan.baidu.com/mbox/streampage?from_uk=684610632&amp;msg_id=8376247896642219120&amp;fs_id=476303219573352&amp;to=763122753997696274&amp;type=2&amp;name=12.%E6%9E%B6%E6%9E%84%E5%B8%88%E4%B8%8D%E5%BE%97%E4%B8%8D%E7%9F%A5%E9%81%93%E7%9A%84Spring%E4%BA%8B%E7%89%A9%E4%B8%8D%E8%83%BD%E5%9B%9E%E6%BB%9A%E7%9A%84%E6%B7%B1%E5%B1%82%E6%AC%A1%E5%8E%9F%E5%9B%A0.mp4&amp;path=%2FB12%E3%80%81%E9%9D%A2%E8%AF%95%E4%B8%93%E5%B1%9E%2F12.%E6%9E%B6%E6%9E%84%E5%B8%88%E4%B8%8D%E5%BE%97%E4%B8%8D%E7%9F%A5%E9%81%93%E7%9A%84Spring%E4%BA%8B%E7%89%A9%E4%B8%8D%E8%83%BD%E5%9B%9E%E6%BB%9A%E7%9A%84%E6%B7%B1%E5%B1%82%E6%AC%A1%E5%8E%9F%E5%9B%A0%2F12.%E6%9E%B6%E6%9E%84%E5%B8%88%E4%B8%8D%E5%BE%97%E4%B8%8D%E7%9F%A5%E9%81%93%E7%9A%84Spring%E4%BA%8B%E7%89%A9%E4%B8%8D%E8%83%BD%E5%9B%9E%E6%BB%9A%E7%9A%84%E6%B7%B1%E5%B1%82%E6%AC%A1%E5%8E%9F%E5%9B%A0.mp4&amp;md5=53444f5643355dab35b28dabd3e0b0f1</a><br><a href="https://www.cnblogs.com/hanxue53/p/5280099.html" target="_blank" rel="noopener">https://www.cnblogs.com/hanxue53/p/5280099.html</a><br><a href="https://www.cnblogs.com/doudouxiaoye/p/5789282.html" target="_blank" rel="noopener">https://www.cnblogs.com/doudouxiaoye/p/5789282.html</a><br><a href="https://www.cnblogs.com/puyangsky/p/6661638.html" target="_blank" rel="noopener">https://www.cnblogs.com/puyangsky/p/6661638.html</a></p><blockquote class="blockquote-center">今天最好的表现，是明天最低的要求。</blockquote>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;12.架构师不得不知道的Spring事物不能回滚的深层次原因&lt;br&gt;&lt;a href=&quot;https://pan.baidu.com/mbox/streampage?from_uk=684610632&amp;amp;msg_id=8376247896642219120&amp;amp;fs_
      
    
    </summary>
    
      <category term="java" scheme="https://Gengry.github.io/categories/java/"/>
    
      <category term="spring" scheme="https://Gengry.github.io/categories/java/spring/"/>
    
    
  </entry>
  
  <entry>
    <title>Spring事物源码分析</title>
    <link href="https://Gengry.github.io/2018/02/01/Spring%E4%BA%8B%E7%89%A9%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/"/>
    <id>https://Gengry.github.io/2018/02/01/Spring事物源码分析/</id>
    <published>2018-02-01T09:11:52.000Z</published>
    <updated>2018-03-26T06:22:37.393Z</updated>
    
    <content type="html"><![CDATA[<p><a href="https://www.cnblogs.com/lcxdever/p/4570090.html" target="_blank" rel="noopener">https://www.cnblogs.com/lcxdever/p/4570090.html</a><br><a href="http://www.cnblogs.com/lcxdever/p/4579126.html" target="_blank" rel="noopener">http://www.cnblogs.com/lcxdever/p/4579126.html</a><br><a href="http://www.cnblogs.com/lcxdever/p/4579240.html" target="_blank" rel="noopener">http://www.cnblogs.com/lcxdever/p/4579240.html</a></p><blockquote class="blockquote-center">今天最好的表现，是明天最低的要求。</blockquote>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;&lt;a href=&quot;https://www.cnblogs.com/lcxdever/p/4570090.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.cnblogs.com/lcxdever/p/4570090.html&lt;
      
    
    </summary>
    
      <category term="spring" scheme="https://Gengry.github.io/categories/spring/"/>
    
    
  </entry>
  
  <entry>
    <title>Mybatis返回Map带null值</title>
    <link href="https://Gengry.github.io/2018/01/31/Mybatis%E8%BF%94%E5%9B%9EMap%E5%B8%A6null%E5%80%BC/"/>
    <id>https://Gengry.github.io/2018/01/31/Mybatis返回Map带null值/</id>
    <published>2018-01-31T01:58:53.000Z</published>
    <updated>2018-03-26T06:22:37.392Z</updated>
    
    <content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>为客户端提供api接口，返回json数据，规定好了返回的字段，但是当使用Mybatis时如果使用map作为返回值，如果数据库中的值为null，则不会在map中生成对应的key。<br>有的时候一些必要的字段，想要添加上这些key需要使用实体bean作为返回值，但是很多时候，表中的字段很多，很多业务务求只需要部分字段，用表生成bean不适用，单独定义一个bean又嫌麻烦，用map需要在查询之后再补key，很难受。<br>今天看mybatis官方文档，突然看到一个设置，用来解决这个问题。<br>没事多看看官方文档，会有意想不到的收获。<br><a id="more"></a></p><h1 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h1><p><a href="http://www.mybatis.org/mybatis-3/configuration.html#" target="_blank" rel="noopener">Mybatis官方文档</a><br><img src="https://raw.githubusercontent.com/Gengry/blogImage/master/20180131/QQ%E6%88%AA%E5%9B%BE20180131101846.jpg" alt="Mybatis"></p><p>Mybatis官方文档的目录结构很清楚，我们本次需要关注的是 Configuration XML中的setting</p><blockquote><p>callSettersOnNulls<br>Specifies if setters or map’s put method will be called when a retrieved value is null. It is useful when you rely on Map.keySet() or null value initialization. Note primitives such as (int,boolean,etc.) will not be set to null.<br>true | false<br>默认 false  </p></blockquote><h2 id="XML配置"><a href="#XML配置" class="headerlink" title="XML配置"></a>XML配置</h2><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- mybatis configuration --&gt;</span></span><br><span class="line"><span class="php"><span class="meta">&lt;?</span>xml version=<span class="string">"1.0"</span> encoding=<span class="string">"UTF-8"</span> <span class="meta">?&gt;</span></span>  </span><br><span class="line"><span class="meta">&lt;!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" </span></span><br><span class="line"><span class="meta"> "http://mybatis.org/dtd/mybatis-3-config.dtd"&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">settings</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">setting</span> <span class="attr">name</span>=<span class="string">"callSettersOnNulls"</span> <span class="attr">value</span>=<span class="string">"true"</span>/&gt;</span>  <span class="comment">&lt;!-- 配置属性值为true--&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">settings</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">plugins</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">plugin</span> <span class="attr">interceptor</span>=<span class="string">"com.github.pagehelper.PageHelper"</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"dialect"</span> <span class="attr">value</span>=<span class="string">"mysql"</span> /&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"rowBoundsWithCount"</span> <span class="attr">value</span>=<span class="string">"true"</span>/&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"pageSizeZero"</span> <span class="attr">value</span>=<span class="string">"true"</span> /&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"reasonable"</span> <span class="attr">value</span>=<span class="string">"false"</span> /&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">plugins</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br></pre></td></tr></table></figure><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--spring configuration xml--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"sessionFactory"</span> <span class="attr">class</span>=<span class="string">"org.mybatis.spring.SqlSessionFactoryBean"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"dataSource"</span> <span class="attr">ref</span>=<span class="string">"dataSource"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"configLocation"</span> <span class="attr">value</span>=<span class="string">"classpath:spring-mybatis.xml"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"mapperLocations"</span> <span class="attr">value</span>=<span class="string">"classpath*:com/***/***/mapping/*/*.xml"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"typeAliasesPackage"</span> <span class="attr">value</span>=<span class="string">"com.***.bean"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure><h2 id="java配置"><a href="#java配置" class="headerlink" title="java配置"></a>java配置</h2><p>mybatis配置文件中的set属性其实对应的是org.apache.ibatis.session.Configuration中的变量。<br>例如：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">protected</span> <span class="keyword">boolean</span> safeRowBoundsEnabled;</span><br><span class="line"><span class="keyword">protected</span> <span class="keyword">boolean</span> safeResultHandlerEnabled = <span class="keyword">true</span>;</span><br><span class="line"><span class="keyword">protected</span> <span class="keyword">boolean</span> mapUnderscoreToCamelCase;</span><br><span class="line"><span class="keyword">protected</span> <span class="keyword">boolean</span> aggressiveLazyLoading;</span><br><span class="line"><span class="keyword">protected</span> <span class="keyword">boolean</span> multipleResultSetsEnabled = <span class="keyword">true</span>;</span><br><span class="line"><span class="keyword">protected</span> <span class="keyword">boolean</span> useGeneratedKeys;</span><br><span class="line"><span class="keyword">protected</span> <span class="keyword">boolean</span> useColumnLabel = <span class="keyword">true</span>;</span><br><span class="line"><span class="keyword">protected</span> <span class="keyword">boolean</span> cacheEnabled = <span class="keyword">true</span>;</span><br><span class="line"><span class="keyword">protected</span> <span class="keyword">boolean</span> callSettersOnNulls;</span><br><span class="line"><span class="keyword">protected</span> <span class="keyword">boolean</span> useActualParamName = <span class="keyword">true</span>;</span><br><span class="line"><span class="keyword">protected</span> <span class="keyword">boolean</span> returnInstanceForEmptyRow;</span><br></pre></td></tr></table></figure></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">DataSource dataSource = BlogDataSourceFactory.getBlogDataSource();</span><br><span class="line">TransactionFactory transactionFactory =</span><br><span class="line">  <span class="keyword">new</span> JdbcTransactionFactory();</span><br><span class="line">Environment environment =</span><br><span class="line">  <span class="keyword">new</span> Environment(<span class="string">"development"</span>, transactionFactory, dataSource);</span><br><span class="line">Configuration configuration = <span class="keyword">new</span> Configuration(environment);</span><br><span class="line">configuration.addMapper(BlogMapper.class);</span><br><span class="line">configuration.setCallSettersOnNulls = <span class="keyword">true</span>;</span><br><span class="line">SqlSessionFactory sqlSessionFactory =</span><br><span class="line">  <span class="keyword">new</span> SqlSessionFactoryBuilder().build(configuration);</span><br></pre></td></tr></table></figure><h2 id="业务代码"><a href="#业务代码" class="headerlink" title="业务代码"></a>业务代码</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Auth</span></span><br><span class="line"><span class="meta">@RequestMapping</span>(value = <span class="string">"/sdfs"</span>,method= RequestMethod.POST)</span><br><span class="line"><span class="meta">@ResponseBody</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> Object <span class="title">sdfs</span> <span class="params">()</span></span>&#123;</span><br><span class="line">    List&lt;Map&lt;String,Object&gt;&gt; dd = awardBaseMapper.getUserSignStatuss();</span><br><span class="line">    System.out.println(dd);</span><br><span class="line">    <span class="keyword">return</span> dd;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">AwardBaseMapper</span> </span>&#123;</span><br><span class="line"><span class="meta">@Select</span>(<span class="string">"select * from user_sign"</span>)</span><br><span class="line">    List&lt;Map&lt;String,Object&gt;&gt; getUserSignStatuss();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">[</span><br><span class="line">&#123;</span><br><span class="line"><span class="attr">"sign_year_week"</span>:<span class="number">4</span>,</span><br><span class="line"><span class="attr">"sign_year_day"</span>:<span class="number">23</span>,</span><br><span class="line"><span class="attr">"sign_year_month"</span>:<span class="number">0</span>,</span><br><span class="line"><span class="attr">"user_id"</span>:<span class="string">"cfeb266707c94b8a92d00c8c05d8b1f7"</span>,</span><br><span class="line"><span class="attr">"sign_week_day"</span>:<span class="number">3</span>,</span><br><span class="line"><span class="attr">"award_ticket_id"</span>:<span class="literal">null</span>,</span><br><span class="line"><span class="attr">"id"</span>:<span class="number">7</span>,</span><br><span class="line"><span class="attr">"sign_award"</span>:<span class="string">"未获取到奖励。"</span>,</span><br><span class="line"><span class="attr">"sign_type_index"</span>:<span class="number">1</span>,</span><br><span class="line"><span class="attr">"sign_year"</span>:<span class="number">2018</span>,</span><br><span class="line"><span class="attr">"award_type"</span>:<span class="number">2</span>,</span><br><span class="line"><span class="attr">"sign_time"</span>:<span class="string">"2018-01-23 16:56:19"</span></span><br><span class="line">&#125;,</span><br><span class="line">&#123;</span><br><span class="line"><span class="attr">"sign_year_week"</span>:<span class="number">5</span>,</span><br><span class="line"><span class="attr">"sign_year_day"</span>:<span class="number">30</span>,</span><br><span class="line"><span class="attr">"sign_year_month"</span>:<span class="number">0</span>,</span><br><span class="line"><span class="attr">"user_id"</span>:<span class="string">"1e11281446b84655813ad08fd9da32a1"</span>,</span><br><span class="line"><span class="attr">"sign_week_day"</span>:<span class="number">3</span>,</span><br><span class="line"><span class="attr">"award_ticket_id"</span>:<span class="number">-1</span>,</span><br><span class="line"><span class="attr">"id"</span>:<span class="number">8</span>,</span><br><span class="line"><span class="attr">"sign_award"</span>:<span class="literal">null</span>,</span><br><span class="line"><span class="attr">"sign_type_index"</span>:<span class="number">1</span>,</span><br><span class="line"><span class="attr">"sign_year"</span>:<span class="number">2018</span>,</span><br><span class="line"><span class="attr">"award_type"</span>:<span class="number">2</span>,</span><br><span class="line"><span class="attr">"sign_time"</span>:<span class="string">"2018-01-30 09:25:43"</span></span><br><span class="line">&#125;</span><br><span class="line">]</span><br></pre></td></tr></table></figure><p>上面可见，返回的json串中已经携带了null值的key。不同版本中的属性差异还是挺大的，官网现在是3.4.6，我用的3.2.6中很多属性就没有，如果需要使用新特性，需要升级mybatis版本。</p><h1 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h1><ul><li>最后在提醒下，对于map中null值引发的空指针问题，可以很好的用 apache commons包中MapUtils解决，可以减少很多不必要的bug。</li><li>给客户端返回的json数据中，数组，集合，字典，对象不要有null值，如果是null需要put一个空HashMap或ArrayList，否则客户端反序列化会异常。</li></ul><blockquote class="blockquote-center">今天最好的表现，是明天最低的要求。</blockquote>]]></content>
    
    <summary type="html">
    
      &lt;h1 id=&quot;前言&quot;&gt;&lt;a href=&quot;#前言&quot; class=&quot;headerlink&quot; title=&quot;前言&quot;&gt;&lt;/a&gt;前言&lt;/h1&gt;&lt;p&gt;为客户端提供api接口，返回json数据，规定好了返回的字段，但是当使用Mybatis时如果使用map作为返回值，如果数据库中的值为null，则不会在map中生成对应的key。&lt;br&gt;有的时候一些必要的字段，想要添加上这些key需要使用实体bean作为返回值，但是很多时候，表中的字段很多，很多业务务求只需要部分字段，用表生成bean不适用，单独定义一个bean又嫌麻烦，用map需要在查询之后再补key，很难受。&lt;br&gt;今天看mybatis官方文档，突然看到一个设置，用来解决这个问题。&lt;br&gt;没事多看看官方文档，会有意想不到的收获。&lt;br&gt;
    
    </summary>
    
      <category term="mybatis" scheme="https://Gengry.github.io/categories/mybatis/"/>
    
    
  </entry>
  
</feed>
