论缓存之第一<道>

本文深入探讨缓存的原理、应用场景、属性及介质选择,并从理论角度出发总结实践经验,强调理论与实践并重的重要性。通过分析缓存存在的必要性、缓存可以存在的位置、缓存的属性如命中率、最大元素与清空策略,以及介质选择如内存、硬盘、数据库,以及本地缓存与远程缓存的区别,为读者提供全面的缓存解决方案。
看一粒沙中的世界, 一朵野花中的天堂。 把无限握于掌中, 把永恒握于瞬间。——威廉• 布莱克

开始讨论缓存之前,让我们先来讨论讨论另外一个问题:理论和实践.从ahuaxuan接触的程序员来看,有的程序员偏实践,有的程序员偏理论,但是这都是不好的行为,理论和实践同样重要,我们在做很多核心的算法的时候,没有理论根本无从下手,而在我们多年的实践中,不总结理论就不能加深自己的理解.所以理论和实践同等重要.

缓存是当今各种软件或者硬件系统中不可缺少的技术之一,所以对每个程序员来说都显得异常重要,对ahuaxuan来说亦是如此.如果说用dfa实现文字过滤是从理论到实践,那么本文便是从实践中总结出得理论.

在讨论缓存功能之前,我们首先来了解一下缓存这个东西本身.ahuaxuan根据自己的经验把缓存问题细分为4类小问题.

1缓存为什么要存在?
2缓存可以存在于什么地方?
3缓存有哪些属性?
4缓存介质?

搞清楚这4个问题,那么我们就可以随意的通过应用的场景来判断使用何种缓存了.

下面ahuaxuan和大家一一分析这4个问题.
1. 缓存为什么要存在?
一般情况下,一个网站,或者一个应用,它的一般形式是,浏览器请求应用服务器,应用服务器做一堆计算后再请求数据库,数据库收到请求后再作一堆计算后把数据返回给应用服务器,应用服务器再作一堆计算后把数据返回给浏览器.这个是一个标准流程.但是随着互连网的普及,上网的人越来越多,网上的信息量也越来越多,在这两个越来越多的情况下,我们的应用需要支撑的并发量就越来越多.然后我们的应用服务器和数据库服务器所做的计算也越来越多,但是往往我们的应用服务器资源是有限的,数据库每秒中接受请求的次数也是有限的(谁叫俺们的硬盘转速有限呢).如果利用有限的资源来提供尽可能大的吞吐量呢,一个办法:减少计算量,缩短请求流程(减少网络io或者硬盘io),这时候缓存就可以大展手脚了.缓存的基本原理就是打破上图中所描绘的标准流程,在这个标准流程中,任何一个环节都可以被切断.请求可以从缓存里取到数据直接返回.这样不但节省了时间,提高了响应速度,而且也节省了硬件资源.可以让我们有限的硬件资源来服务更多的用户.

2  缓存可以存在于什么地方?

Java代码 
  1. 浏览器---浏览器和app之间---分过层的app-数据库 
" name="code" style="">浏览器---浏览器和app之间---分过层的app-数据库



在上图中,我们可以看到一次请求的一般流程,下面我们重新绘制这张图,让我们的结构稍微复杂一点点.
(将app分层)
浏览器---浏览器和app之间---分过层的app-数据库


理论上来将,请求的任何一个环节都是缓存可以作用的地方.第一个环节,浏览器,如果数据存在浏览器上,那么对用户来说速度是最快的,因为这个时候根本无需网络请求.第二个环节,浏览器和app之间,如果缓存加在这个地方,那么缓存对app来说是透明的.而且这个缓存中存放的是完整的页面.第三个节点,app中本身就有几个层次,那么缓存也可以放在不同的层次上,这一部分是情况或者场景比较复杂的部分.选择缓存时需要谨慎.第四个环节,数据库中也可以有缓存,比如说mysql的querycache.

那么也就是说在整个请求流程的任何一点,我们都可以加缓存.但是是所有的数据都可以放进缓存的吗.当然不是,需要放进缓存的数据总是有一些特征的,要清楚的判断数据是否可以被缓存,可以被怎样缓存就必须要从数据的变化特征下手.

数据有哪些变化特征?最简单的就是两种,变和不变.我们都知道,不会变化的数据不需要每次都进行计算.问题是难道所有的数据理论上来讲都会变化,变化是世界永恒的主题.也就是说我们把数据分为变和不变两种是不对的,那么就让我们再加一个条件:时间.那么我们就可以把数据特征总结为一段时间内变或者不变.那么根据这个数据特征,我们就可以在合适的位置和合适的缓存类型中缓存该数据.

3缓存有哪些属性
从面向对象的角度来看,缓存就是一个对象,那么是对象,必然有属性.那么下面我们来探讨一下缓存有哪些属性.以下列举我们常用到的3个属性.
(1) 命中率
命中率是指请求缓存次数和缓存返回正确结果次数的比例.比例越高,就证明缓存的使用率越高.

命中率问题是缓存中的一个非常重要的问题,我们都希望自己缓存的命中率能达到100%,但是往往事与愿违,而且缓存命中率是衡量缓存有效性的重要指标.

(2) 最大元素
缓存中可以存放得最大元素得数量,一旦缓存中元素数量超过这个值,那么将会起用缓存清空策略,根据不同的场景合理的设置最大元素值往往可以一定程度上提高缓存的命中率.从而更有效的时候缓存.

(3) 清空策略

1 FIFO ,first in first out ,最先进入缓存得数据在缓存空间不够情况下(超出最大元素限制时)会被首先清理出去
2 LFU , Less Frequently Used ,一直以来最少被使用的元素会被被清理掉。这就要求缓存的元素有一个hit 属性,在缓存空间不够得情况下,hit 值最小的将会被清出缓存。
2 LRU ,Least Recently Used ,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。

4缓存介质
从硬件介质上来将无非就是两种,内存和硬盘(对应应用层的程序来讲不用考虑寄存器等问题).但是往往我们不会从硬件上来划分,一般的划分方法是从技术上划分,可以分成几种,内存,硬盘文件.数据库.
(1) 内存.将缓存放在数据库中是最快的选择,任何程序直接操作内存都比操作硬盘要快的多,但是如果你的数据要考虑到break down的问题,因为放在内存中的数据我们称之为没有持久话的数据,如果硬盘上没有备份,机器down机之后,很难或者无法恢复.

(2) 硬盘.一般来说,很多缓存框架会结合使用内存和硬盘,比如给内存分配的空间有满了之后,会让用户选择把需要退出内存空间的数据持久化到硬盘.当然也选择直接把数据放一份到硬盘(内存中一份,硬盘中一份,down机也不怕).也有其他的缓存是直接把数据放到硬盘上.


(3) 数据库.说到数据库,可能有的人会想,之前不是讲到要减少数据库查询的次数,减少数据库计算的压力吗,现在怎么又用数据库作为缓存的介质了呢.这是因为数据库又很多种类型,比如berkleydb,这种db不支持sql语句,没有sql引擎,只是key和value的存储结构,所以速度非常的快,在当代一般的pc上,每秒中十几w次查询都是没有问题的(当然这个是根据业务特征来决定的,如果您访问的数据在分布上是均匀的,那ahuaxuan可不能保证这个速度了).

除了缓存介质之外,ahuaxuan根据缓存和应用的耦合程度将其划分为local cache和remote cache.
Local cache是指包含在应用之中的缓存组件.而remote cache指和应用解耦在应用之外的缓存组件.典型的local cache有ehcache,oscache,而remote cache有大名鼎鼎的memcached.

Localcache最大的优点是应用和cache的时候是在同一个进程内部,请求缓存非常快速,完全不需要网络开销等.所以单应用,不需要集群或者集群情况下cache node不需要相互通知的情况下使用local cache比较合适.这也是java中ehcache和oscache这么流行的原因.
但是Local cache是有一定的缺点的,一般这种缓存框架(比如java中的ehcache或者oscache)都是local cache.也就是跟着应用程序走的,多个应用程序无法直接共享缓存,应用集群的情况下这个问题更加明显,当然也有的缓存组件提供了集群节点相互通知缓存更新的功能,但是由于这个是广播,或者是环路更新,在缓存更新频繁的情况下会导致网络io开销非常大,严重的时候会影响应用的正常运行.而且如果缓存中数据量较大得情况下使用localcache意味着每个应用都有一份这么大得缓存,着绝对是对内存的浪费.

所以这个情况下,往往我们会选择remote cache,比如memcached.这样集群或者分布式的情况下各个应用都可以共享memcached中的数据,这些应用都通过socket和基于tcp/ip协议上层的memcached协议直接连接到memcached,有一个app更新了memcached中的值,所有的应用都能拿到最新的值.虽然这个时候多了很多了网络上的开销,但是往往这种方案要比localcache广播或环路更新cache节点要普遍的多,而且性能也比后者高.由于数据只需要保存一份,所以也提高了内存的使用率.

通过以上分析可以看出,不管是local cache,还是remote cache在缓存领域都有自己的一席之地,所以ahuaxuan建议在选择或者使用缓存时一定要根据缓存的特征和我们的业务场景准确判断使用何种缓存.这样才能充分发挥缓存的功能.

Ahuaxuan认为,缓存的使用是架构师的必备技能,好的架构师能够根据数据的类型,业务的场景来准确的判断出使用何种类型的缓存,并且如何使用这种类型的缓存.在缓存的世界里也没有银弹,目前还没有一种缓存可以解决任何的业务场景或者数据类型,如果这种技术出现了,那架构师就又更不值钱了.呵呵.

本文是ahuaxuan从自己的实践中总结出来的一些小小的心得,未参考任何文章,,所以可能未必好,未必全面,未必令您满意,欢迎拍砖.

最后说一说写这篇文章的初衷,周末有人让我说说我对缓存的理解,我的回答的是对缓存的理解无法用一句话来表述,起码写5篇文章.那本文只是第一篇. 待续-------------

 

转载地址:http://ahuaxuan.iteye.com/blog/345693


<!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <meta name="renderer" content="webkit|ie-comp|ie-stand"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"/> <meta http-equiv="Cache-Control" content="no-siteapp"/> <!--[if lt IE 9]> <script type="text/javascript" src="../lib/html5shiv.js"></script> <script type="text/javascript" src="../lib/respond.min.js"></script> <![endif]--> <link rel="stylesheet" type="text/css" href="../static/h-ui/css/H-ui.min.css"/> <link rel="stylesheet" type="text/css" href="../static/h-ui.admin/css/H-ui.admin.css"/> <link rel="stylesheet" type="text/css" href="../lib/Hui-iconfont/1.0.8/iconfont.css"/> <link rel="stylesheet" type="text/css" href="../static/h-ui.admin/skin/default/skin.css" id="skin"/> <link rel="stylesheet" type="text/css" href="../static/h-ui.admin/css/style.css"/> <!--[if IE 6]> <script type="text/javascript" src="../lib/DD_belatedPNG_0.0.8a-min.js"></script> <script>DD_belatedPNG.fix('*');</script> <![endif]--> <title>销售明细查询(长春)</title> <style type="text/css"> /**tabs**/ /*.tabPanel ul{height:30px;border-bottom:1px solid #aaa;}*/ /*.tabPanel ul li{*/ /* float:left;margin:0 2px 0 0;border:1px solid #aaa;font-size:11px;height:29px;line-height:30px;width:111px;text-align:center;cursor:pointer;*/ /* text-shadow:0 1px 0 #fff;*/ /* border-radius:4px 4px 0 0;*/ /* box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.5);*/ /* background:#ddd;*/ /* background:-moz-linear-gradient(top, #eee, #ddd);*/ /* background:-webkit-gradient(linear, left top, left bottom, from(#eee), to(#ddd));*/ /*}*/ /*.tabPanel .hit{*/ /* border-bottom:1px solid #fff;cursor:pointer;color:black;text-shadow:0 1px 0 #fff;*/ /* background:#fff;*/ /* background:-webkit-gradient(linear, left top, left bottom, from(#e1e1e1), to(#fff));*/ /* background:-moz-linear-gradient(top, #e1e1e1, #fff);*/ /*}*/ /*.pane{border:1px solid #aaa;border-top:0;min-height:100px;background-color:#fff;display:none;}*/ /*.pane p{padding:15px 15px 0 10px;}*/ /*.pane h4{padding:15px 15px 0 10px;font-size:14px;font-weight:bold;}*/ td { text-align: center; } .overLoading { display: none; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: #f5f5f5; opacity: 0.5; z-index: 1000; } .layoutLoading { display: none; position: absolute; top: 40%; left: 40%; width: 20%; height: 20%; z-index: 1001; text-align: center; } </style> </head> <body> <!-- 新增加载提示元素(解决JS报错) --> <div class="overLoading" id="over"></div> <div class="layoutLoading" id="layout">加载中...</div> <nav class="breadcrumb"> <i class="Hui-iconfont"></i> 首页 <span class="c-gray en">></span>销售明细查询 <span class="c-gray en">></span>销售明细查询(长春) <a class="btn btn-success radius r" style="line-height:1.6em;margin-top:3px" href="javascript:location.replace(location.href);" title="刷新"><i class="Hui-iconfont"></i></a> </nav> <div class="page-container"> <div class="mt-20"> <div class="page-container" style="margin-top: 0px;padding-top: 0px;"> <div class="row cl"> <table style="margin-left: 50px;margin-top:0px;border-collapse:separate; border-spacing:0px 5px; width: calc(100% - 100px);"> <tr> <td colspan="2">下单日期: <input type="text" id="date1" onfocus="WdatePicker({ dateFmt:'yyyy-MM-dd',})" class="Wdate"/> - <input type="text" id="date2" onfocus="WdatePicker({ minDate:'#F{$dp.$D(\'date1\')}',maxDate:'2029-12-31', })" class="Wdate"/> </td> <td colspan="1"> <input id="date11" name="selectDate" type="radio" value="本年" onclick="selectDate1()"/>本年 <input id="date22" name="selectDate" checked type="radio" value="近3年" onclick="selectDate2()"/>近3年 <input id="date33" name="selectDate" type="radio" value="近10年" onclick="selectDate3()"/>近10年 </td> <td colspan="3" style="text-align: left;"> <button class="btn btn-secondary-outline radius" id="search" style="float: left" onclick="submit_order()"> <i class="Hui-iconfont"></i>检索 </button> </td> </tr> <tr> <!-- 发货客户编号 --> <td style="alignment: left">发货客户编号: <select id="fhkhbh"> <option value="0">所有</option> <option value="60009">60009</option> <option value="2000000108">2000000108</option> <option value="1000200000">1000200000</option> </select> </td> <!-- 领料单位 --> <td style="alignment: left">领料单位: <select id="lldw"> <option value="0">所有</option> <option value="中国铁路北京局集团有限公司">中国铁路北京局集团有限公司</option> <option value="北京动车段">北京动车段</option> <option value="北京北所">北京北所</option> <option value="北京南动车所">北京南动车所</option> <option value="朝阳所">朝阳所</option> <option value="石家庄动车所">石家庄动车所</option> <option value="雄安所">雄安所</option> <option value="北京东动车所">北京东动车所</option> <option value="中车长春轨客车股份有限公司">中车长春轨客车股份有限公司</option> <option value="北京西所">北京西所</option> </select> </td> <!-- 物料来源 --> <td style="alignment: left">物料来源: <select id="wlly"> <option value="0">所有</option> <option value="供应商寄售">供应商寄售</option> <option value="配件公司直采">配件公司直采</option> <option value="配件公司库存">配件公司库存</option> <option value="销售退货">销售退货</option> </select> </td> <!-- 库存地点 --> <td style="alignment: left">库存地点: <select id="kcdd"> <option value="0">所有</option> <option value="配件中心-北京动车段">配件中心-北京动车段</option> <option value="配件中心-北京北所">配件中心-北京北所</option> <option value="配件中心-北京中心库销货库">配件中心-北京中心库销货库</option> <option value="配件中心-北京动车段中心库">配件中心-北京动车段中心库</option> </select> </td> <!-- 开票状态 --> <td style="alignment: left">开票状态: <select id="kpzt"> <option value="0">所有</option> <option value="YES">YES</option> <option value="NO">NO</option> </select> </td> <td style="alignment: left"> <button class="btn btn-secondary-outline radius" id="huizong" onclick="downloadExl1()"> <i class="Hui-iconfont"></i>导出 </button> </td> </tr> <tr> <!-- 车型 --> <td style="alignment: left">车型: <select id="cx"> <option value="0">所有</option> <option value="CR400BF">CR400BF</option> <option value="CRH380B">CRH380B</option> <option value="CRH5A">CRH5A</option> <option value="CRH380CL">CRH380CL</option> <option value="CRH3A">CRH3A</option> <option value="CR400BF-G">CR400BF-G</option> <option value="CRH5G">CRH5G</option> <option value="CRH380BL">CRH380BL</option> <option value="CR400BF-C">CR400BF-C</option> <option value="CRH3">CRH3</option> <option value="CR400BF-A">CR400BF-A</option> <option value="CRH380BG">CRH380BG</option> <option value="CRH400BF">CRH400BF</option> <option value="CRH380B/BL">CRH380B/BL</option> <option value="CRH380BK">CRH380BK</option> <option value="CRH5">CRH5</option> <option value="CR400BF-Z">CR400BF-Z</option> <option value="CR400BF-GZ">CR400BF-GZ</option> </select> </td> <!-- 修程 --> <td style="alignment: left">修程: <select id="xc"> <option value="0">所有</option> <option value="CR03">CR03</option> <option value="A42">A42</option> <option value="L3">L3</option> <option value="A21">A21</option> <option value="CR00">CR00</option> <option value="CR01">CR01</option> <option value="CR02">CR02</option> <option value="A31">A31</option> <option value="A32">A32</option> <option value="A11">A11</option> <option value="CR04">CR04</option> </select> </td> <td colspan="4"></td> </tr> <!-- 复选框区域 --> <tr> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option1"> <span class="checkbox-icon"></span> <span class="checkbox-label">出库单号</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option2" checked> <span class="checkbox-icon"></span> <span class="checkbox-label">出库单序号</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option3"> <span class="checkbox-icon"></span> <span class="checkbox-label">出库单状态</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option4"> <span class="checkbox-icon"></span> <span class="checkbox-label">创建时间</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option5"> <span class="checkbox-icon"></span> <span class="checkbox-label">创建人</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option6" checked> <span class="checkbox-icon"></span> <span class="checkbox-label">销售办公室</span> </label> </td> </tr> <tr> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option7"> <span class="checkbox-icon"></span> <span class="checkbox-label">发货客户编号</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option8"> <span class="checkbox-icon"></span> <span class="checkbox-label">客户名称</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option9"> <span class="checkbox-icon"></span> <span class="checkbox-label">领料单位</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option10"> <span class="checkbox-icon"></span> <span class="checkbox-label">领料人</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option11"> <span class="checkbox-icon"></span> <span class="checkbox-label">过账日期</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option12"> <span class="checkbox-icon"></span> <span class="checkbox-label">计划编号</span> </label> </td> </tr> <tr> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option13" checked> <span class="checkbox-icon"></span> <span class="checkbox-label">计划行号</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option14" checked> <span class="checkbox-icon"></span> <span class="checkbox-label">路局计划号</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option15" checked> <span class="checkbox-icon"></span> <span class="checkbox-label">路局采购单号</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option16" checked> <span class="checkbox-icon"></span> <span class="checkbox-label">SAP物料</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option17"> <span class="checkbox-icon"></span> <span class="checkbox-label">物料描述</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option18" checked> <span class="checkbox-icon"></span> <span class="checkbox-label">基本计量单位</span> </label> </td> </tr> <tr> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option19" checked> <span class="checkbox-icon"></span> <span class="checkbox-label">物资编码</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option20"> <span class="checkbox-icon"></span> <span class="checkbox-label">数量</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option21"> <span class="checkbox-icon"></span> <span class="checkbox-label">不含税单价</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option22"> <span class="checkbox-icon"></span> <span class="checkbox-label">税率</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option23"> <span class="checkbox-icon"></span> <span class="checkbox-label">含税金额合计</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option24" checked> <span class="checkbox-icon"></span> <span class="checkbox-label">价格来源</span> </label> </td> </tr> <tr> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option25" checked> <span class="checkbox-icon"></span> <span class="checkbox-label">退货数量</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option26" checked> <span class="checkbox-icon"></span> <span class="checkbox-label">应开票数量</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option27" checked> <span class="checkbox-icon"></span> <span class="checkbox-label">应开票金额</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option28" checked> <span class="checkbox-icon"></span> <span class="checkbox-label">已开票数量</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option29" checked> <span class="checkbox-icon"></span> <span class="checkbox-label">已开票税前金额</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option30" checked> <span class="checkbox-icon"></span> <span class="checkbox-label">已开票税后金额</span> </label> </td> </tr> <tr> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option31" checked> <span class="checkbox-icon"></span> <span class="checkbox-label">未开票数量</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option32" checked> <span class="checkbox-icon"></span> <span class="checkbox-label">未开票税前金额</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option33" checked> <span class="checkbox-icon"></span> <span class="checkbox-label">未开票税后金额</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option34" checked> <span class="checkbox-icon"></span> <span class="checkbox-label">批次</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option35"> <span class="checkbox-icon"></span> <span class="checkbox-label">物料来源</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option36"> <span class="checkbox-icon"></span> <span class="checkbox-label">库存地点</span> </label> </td> </tr> <tr> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option37"> <span class="checkbox-icon"></span> <span class="checkbox-label">开票状态</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option38"> <span class="checkbox-icon"></span> <span class="checkbox-label">车型</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option39" checked> <span class="checkbox-icon"></span> <span class="checkbox-label">单价</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option40" checked> <span class="checkbox-icon"></span> <span class="checkbox-label">车组号</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option41"> <span class="checkbox-icon"></span> <span class="checkbox-label">修程</span> </label> </td> <td style="alignment: left"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option42" checked> <span class="checkbox-icon"></span> <span class="checkbox-label">货主</span> </label> </td> </tr> <tr> <td style="alignment: left" colspan="2"> <label class="checkbox-item"> <input type="checkbox" name="option" value="option43" checked> <span class="checkbox-icon"></span> <span class="checkbox-label">总价</span> </label> </td> <td colspan="4"></td> </tr> </table> </div> <div class="row cl" style="margin-top: 20px;"></div> <div id="testTable" style="margin: auto;"> <table class="table table-border table-bordered table-hover table-bg table-sort" id="testCheck" style="margin-top: 30px; width: auto; table-layout: auto; word-wrap: break-word; word-break: break-all;"> <thead id="title"> <tr class="text-c"> <th data-column="option1" style="text-align: center;">出库单号</th> <th data-column="option2" style="text-align: center;">出库单序号</th> <th data-column="option3" style="text-align: center;">出库单状态</th> <th data-column="option4" style="text-align: center;">创建时间</th> <th data-column="option5" style="text-align: center;">创建人</th> <th data-column="option6" style="text-align: center;">销售办公室</th> <th data-column="option7" style="text-align: center;">发货客户编号</th> <th data-column="option8" style="text-align: center;">客户名称</th> <th data-column="option9" style="text-align: center;">领料单位</th> <th data-column="option10" style="text-align: center;">领料人</th> <th data-column="option11" style="text-align: center;">过账日期</th> <th data-column="option12" style="text-align: center;">计划编号</th> <th data-column="option13" style="text-align: center;">计划行号</th> <th data-column="option14" style="text-align: center;">路局计划号</th> <th data-column="option15" style="text-align: center;">路局采购单号</th> <th data-column="option16" style="text-align: center;">SAP物料</th> <th data-column="option17" style="text-align: center;">物料描述</th> <th data-column="option18" style="text-align: center;">基本计量单位</th> <th data-column="option19" style="text-align: center;">物资编码</th> <th data-column="option20" style="text-align: center;">数量</th> <th data-column="option21" style="text-align: center;">不含税单价</th> <th data-column="option22" style="text-align: center;">税率</th> <th data-column="option23" style="text-align: center;">含税金额合计</th> <th data-column="option24" style="text-align: center;">价格来源</th> <th data-column="option25" style="text-align: center;">退货数量</th> <th data-column="option26" style="text-align: center;">应开票数量</th> <th data-column="option27" style="text-align: center;">应开票金额</th> <th data-column="option28" style="text-align: center;">已开票数量</th> <th data-column="option29" style="text-align: center;">已开票税前金额</th> <th data-column="option30" style="text-align: center;">已开票税后金额</th> <th data-column="option31" style="text-align: center;">未开票数量</th> <th data-column="option32" style="text-align: center;">未开票税前金额</th> <th data-column="option33" style="text-align: center;">未开票税后金额</th> <th data-column="option34" style="text-align: center;">批次</th> <th data-column="option35" style="text-align: center;">物料来源</th> <th data-column="option36" style="text-align: center;">库存地点</th> <th data-column="option37" style="text-align: center;">开票状态</th> <th data-column="option38" style="text-align: center;">车型</th> <th data-column="option39" style="text-align: center;">单价</th> <th data-column="option40" style="text-align: center;">车组号</th> <th data-column="option41" style="text-align: center;">修程</th> <th data-column="option42" style="text-align: center;">货主</th> <th data-column="option43" style="text-align: center;">总价</th> </tr> </thead> <tbody id="info"> </tbody> </table> </div> </div> </div> </div> <!--_footer 作为公共模版分离出去--> <script type="text/javascript" src="../lib/jquery/1.9.1/jquery.min.js"></script> <script type="text/javascript" src="../lib/layer/2.4/layer.js"></script> <script type="text/javascript" src="../static/h-ui/js/H-ui.min.js"></script> <script type="text/javascript" src="../static/h-ui.admin/js/H-ui.admin.js"></script> <script type="text/javascript" src="../js/apply.js"></script> <!--/_footer 作为公共模版分离出去--> <!--业务相关脚本--> <script type="text/javascript" src="../lib/hcharts/Highcharts/5.0.6/js/highcharts.js"></script> <script type="text/javascript" src="../lib/hcharts/Highcharts/5.0.6/js/modules/exporting.js"></script> <script type="text/javascript" src="../lib/My97DatePicker/4.8/WdatePicker.js"></script> <script type="text/javascript" src="../lib/datatables/1.10.0/jquery.dataTables.min.js"></script> <script type="text/javascript" src="../lib/laypage/1.2/laypage.js"></script> <script type="text/javascript" src="../js/xlsx.full.min.js"></script> <script type="text/javascript" src="../js/sheetJson.js"></script> <script type="text/javascript"> var baseurl = getURL(); $(function () { startCookie(); selectDate2(); // submit_order(); }); // 日期选择相关函数 function getThisYear() { var now = new Date(); var year = now.getFullYear(); return [year + "-01-01", year + "-12-31"]; } function getThreeYear() { var now = new Date(); var year = now.getFullYear(); return [(year - 2) + "-01-01", year + "-12-31"]; } function getTenYear() { var now = new Date(); var year = now.getFullYear(); return [(year - 9) + "-01-01", year + "-12-31"]; } function selectDate1() { var thisYear = getThisYear(); $("#date1").val(thisYear[0]); $("#date2").val(thisYear[1]); } function selectDate2() { var threeYear = getThreeYear(); $("#date1").val(threeYear[0]); $("#date2").val(threeYear[1]); } function selectDate3() { var tenYear = getTenYear(); $("#date1").val(tenYear[0]); $("#date2").val(tenYear[1]); } // 生成复选框选中状态数组 function generateOptionList() { const checkboxes = document.querySelectorAll('input[name="option"]'); return Array.from(checkboxes).map(checkbox => checkbox.checked ? 1 : 0); } // 复选框与表格列同步逻辑 document.addEventListener('DOMContentLoaded', function () { const checkboxes = document.querySelectorAll('input[name="option"]'); const tableHeaders = document.querySelectorAll('#testCheck th'); const tableRows = document.querySelectorAll('#testCheck tbody tr'); // 初始化表格列显示 updateTableColumns(); // 监听复选框变化 checkboxes.forEach(checkbox => { checkbox.addEventListener('change', updateTableColumns); }); // 更新表格列显示状态 function updateTableColumns() { const selectedColumns = Array.from(checkboxes) .filter(cb => cb.checked) .map(cb => cb.value); // 更新表头 tableHeaders.forEach(header => { const columnName = header.getAttribute('data-column'); header.style.display = selectedColumns.includes(columnName) ? 'table-cell' : 'none'; }); // 更新数据行 tableRows.forEach(row => { const cells = row.querySelectorAll('td'); cells.forEach((cell, index) => { cell.style.display = tableHeaders[index].style.display; }); }); } window.updateTableColumns = updateTableColumns; }); // 查询函数 var printCase = []; function submit_order() { var pkStr = ""; var date1 = $("#date1").val(); var date2 = $("#date2").val(); // 获取下拉框选中的文本内容 var fhkhbh = document.querySelector('#fhkhbh option:checked')?.textContent || ''; var lldw = document.querySelector('#lldw option:checked')?.textContent || ''; var wlly = document.querySelector('#wlly option:checked')?.textContent || ''; var kcdd = document.querySelector('#kcdd option:checked')?.textContent || ''; var kpzt = document.querySelector('#kpzt option:checked')?.textContent || ''; var cx = document.querySelector('#cx option:checked')?.textContent || ''; var xc = document.querySelector('#xc option:checked')?.textContent || ''; // 拼接日期条件 if (date1) pkStr += "cjsj>='" + date1 + "'&&"; if (date2) pkStr += "cjsj<='" + date2 + "'&&"; // 拼接下拉框条件(包含查询) if (fhkhbh !== "所有") pkStr += "fhkhbh conta'" + fhkhbh + "'&&"; if (lldw !== "所有") pkStr += "lldw conta'" + lldw + "'&&"; if (wlly !== "所有") pkStr += "wlly conta'" + wlly + "'&&"; if (kcdd !== "所有") pkStr += "kcdd conta'" + kcdd + "'&&"; if (kpzt !== "所有") pkStr += "kpzt conta'" + kpzt + "'&&"; if (cx !== "所有") pkStr += "cx conta'" + cx + "'&&"; if (xc !== "所有") pkStr += "xc conta'" + xc + "'&&"; // 处理末尾多余的&& if (pkStr.length >= 2 && pkStr.slice(-2) === "&&") { pkStr = pkStr.slice(0, -2); } console.log("查询条件:", pkStr); $.ajax( { type: "post", url: baseurl + "chazhao/", dataType: 'json', data: { tablename: "`jjmx(c)`", pk: pkStr, }, beforeSend: function () { $("#over").show(); $("#layout").show(); }, success: function (res) { console.log("查询结果:", res); var result = res.data || []; var newResult = []; for (var i = 0; i < result.length; i++) { if (result[i]) newResult.push(result[i]); } // 表格配置 // 处理空值 console.log("newResult:"); console.log(newResult); var ifLeft = 1; var ifTop = 1; var title = [ "出库单号", "出库单序号", "出库单状态", "创建时间", "创建人", "销售办公室", "发货客户编号", "客户名称", "领料单位", "领料人", "过账日期", "计划编号", "计划行号", "路局计划号", "路局采购单号", "SAP物料", "物料描述", "基本计量单位", "物资编码", "数量", "不含税单价", "税率", "含税金额合计", "价格来源", "退货数量", "应开票数量", "应开票金额", "已开票数量", "已开票税前金额", "已开票税后金额", "未开票数量", "未开票税前金额", "未开票税后金额", "批次", "物料来源", "库存地点", "开票状态", "车型", "单价", "车组号", "修程", "货主", "总价"] var titledisplay = generateOptionList(); var ifDetailInfo = ["0",]; var ifCheckBox = 0; var ifDetail = []; var operating = []; var rowArray = [ "ckdh", "ckdxh", "ckdzt", "cjsj", "cjr", "ssbgs", "fhkhbh", "khmc", "lldw", "llr", "gzrq", "jhbh", "jjhh", "ljjhh", "ljcgdh", "sapwl", "wpms", "jbjldw", "wzbm", "number", "bhsjg", "sl", "hsjehj", "jgly", "thsl", "ykpsl", "ykpje", "ykpsl-already", "ykpsqje", "ykpshje", "wkpsl", "wkpsqje", "wkpshje", "pc", "wlly", "kcdd", "kpzt", "cx", "dj", "czh", "xc", "hz", "zj"]; for (var i = 0; i < newResult.length; i++) { for (var j = 0; j < rowArray.length; j++) { if (newResult[i][rowArray[j]] === null || newResult[i][rowArray[j]] === "" || newResult[i][rowArray[j]] === undefined) { newResult[i][rowArray[j]] = ""; } } } console.log("newResult:"); console.log(newResult); var rowdisplay = titledisplay var allCon = showTable(ifLeft, ifTop, title, newResult, ifDetailInfo, ifCheckBox, ifDetail, operating, rowArray, titledisplay, rowdisplay); $("#testCheck").dataTable().fnDestroy();//彻底清空表格数据 $('#title').empty().append(allCon[0]); $('#info').empty().append(allCon[1]); $('.table-sort').dataTable({ "aaSorting": [ [0, "asc"] ], //从第0列开始,第1列倒序排序 "bStateSave": true, //状态保存 "bRetrieve": true, "aoColumnDefs": [ //{"bVisible": false, "aTargets": [ 3 ]} //控制列的隐藏显示 {"orderable": false} // 制定列不参与排序 // { "orderable": false, "aTargets": [1] } // 制定列不参与排序 ] }); }, complete: function () { // 可以在这里隐藏加载提示 } }); } // 导出Excel函数 function downloadExl1() { var pkStr = ""; var date1 = $("#date1").val(); var date2 = $("#date2").val(); // 获取下拉框选中的文本内容 var fhkhbh = document.querySelector('#fhkhbh option:checked')?.textContent || ''; var lldw = document.querySelector('#lldw option:checked')?.textContent || ''; var wlly = document.querySelector('#wlly option:checked')?.textContent || ''; var kcdd = document.querySelector('#kcdd option:checked')?.textContent || ''; var kpzt = document.querySelector('#kpzt option:checked')?.textContent || ''; var cx = document.querySelector('#cx option:checked')?.textContent || ''; var xc = document.querySelector('#xc option:checked')?.textContent || ''; // 拼接日期条件 if (date1) pkStr += "cjsj>='" + date1 + "'&&"; if (date2) pkStr += "cjsj<='" + date2 + "'&&"; // 拼接下拉框条件(包含查询) if (fhkhbh !== "所有") pkStr += "fhkhbh conta'" + fhkhbh + "'&&"; if (lldw !== "所有") pkStr += "lldw conta'" + lldw + "'&&"; if (wlly !== "所有") pkStr += "wlly conta'" + wlly + "'&&"; if (kcdd !== "所有") pkStr += "kcdd conta'" + kcdd + "'&&"; if (kpzt !== "所有") pkStr += "kpzt conta'" + kpzt + "'&&"; if (cx !== "所有") pkStr += "cx conta'" + cx + "'&&"; if (xc !== "所有") pkStr += "xc conta'" + xc + "'&&"; // 处理末尾多余的&& if (pkStr.length >= 2 && pkStr.slice(-2) === "&&") { pkStr = pkStr.slice(0, -2); } $.ajax({ type: "post", url: baseurl + "chazhao/", dataType: 'json', data: { tablename: "`jjmx(c)`", pk: pkStr, }, beforeSend: function () { $("#over").show(); $("#layout").show(); }, success: function (res) { var result = res.data || []; var newResult = []; for (var i = 0; i < result.length; i++) { if (result[i]) newResult.push(result[i]); } // 导出字段配置 var sheetNameMap = { "出库单号": "ckdh", "出库单序号": "ckdxh", "出库单状态": "ckdzt", "创建时间": "cjsj", "创建人": "cjr", "销售办公室": "ssbgs", "发货客户编号": "fhkhbh", "客户名称": "khmc", "领料单位": "lldw", "领料人": "llr", "过账日期": "gzrq", "计划编号": "jhbh", "计划行号": "jjhh", "路局计划号": "ljjhh", "路局采购单号": "ljcgdh", "SAP物料": "sapwl", "物料描述": "wpms", "基本计量单位": "jbjldw", "物资编码": "wzbm", "数量": "number", "不含税单价": "bhsjg", "税率": "sl", "含税金额合计": "hsjehj", "价格来源": "jgly", "退货数量": "thsl", "应开票数量": "ykpsl", "应开票金额": "ykpje", "已开票数量": "ykpsl-already", "已开票税前金额": "ykpsqje", "已开票税后金额": "ykpshje", "未开票数量": "wkpsl", "未开票税前金额": "wkpsqje", "未开票税后金额": "wkpshje", "批次": "pc", "物料来源": "wlly", "库存地点": "kcdd", "开票状态": "kpzt", "车型": "cx", "单价": "dj", "车组号": "czh", "修程": "xc", "货主": "hz", "总价": "zj" }; // 转换导出数据格式 var exportData = newResult.map(item => { var data = {}; Object.keys(sheetNameMap).forEach(key => { data[key] = item[sheetNameMap[key]] || ""; }); return data; }); // 导出Excel var workbook = sheetJson.toSheet({ sheetName: Object.keys(sheetNameMap), datas: exportData }); sheetJson.downloadExl(workbook, "销售明细查询(长春)汇总"); }, complete: function () { $("#over").hide(); $("#layout").hide(); }, error: function (err) { console.error("导出失败:", err); $("#over").hide(); $("#layout").hide(); } }); } </script> </body> </html>前端页面不显示数据,我基金崩溃
最新发布
11-28
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值