精华内容
下载资源
问答
  • 有什么好处?相信不用说大家都知道。 目前笔者在做一个Java开发的Web项目项目启动的时候需要将大量不变的平台数据放入缓存中,方便快速读取。一开始笔者很疑惑,Java是不能直接操作内存的,但是我们缓存却是要...

    目录

     

    ●What & Why

    ●静态变量实现缓存

    ●单例模式实现缓存

    ●小结


    ●What & Why

    缓存是什么?他有什么好处?相信不用说大家都知道。

    目前笔者在做一个Java开发的Web项目,项目启动的时候需要将大量不变的平台数据放入缓存中,方便快速读取。一开始笔者很疑惑,Java是不能直接操作内存的,但是我们缓存却是要把数据放入内存中,那这是怎么实现的呢?抛开市面上已有的memcached、redis等缓存服务不说,我们来思考一下,如果不依赖与它们,自己手动去实现缓存,应该怎么做呢?

    ●静态变量实现缓存

    首先,第一种方式,利用静态变量来实现缓存。

    我们要理清头绪,缓存机制是利用内存的高速读写性。只要把数据放入内存, 并直接从内存中,而不是磁盘中(如文件、数据库)或者网络中(如Http请求、远程调用)读取,就称为缓存,这和Java是否能直接操作内存没有关系。因为我们都知道这样的尝试,程序一定是在内存中运行的,数据则来源于不同地方。我们要做的只是把待缓存数据固定在内存中,保证程序每次(或绝大多数)都是直接从内存读取即可。

    而Java的静态变量天生就具备这样的特点。相信大家学习Java的时候都知道,static修饰的变量是线程共享的,他在内存中只有一份拷贝,位于方法区/静态区。可以通过类名直接访问,不用实例化对象。当然,就算你实例化了多个对象,该静态变量也不会随之拷贝增多,有且仅有一份。同时,还可以认为静态变量的生命周期同类的生命周期一样,可以贯穿整个程序的运行过程。大家最初对于静态变量的作用可能仅仅停留在用于数据共享,但是别忘了,静态变量之所以能共享数据,本质上是因为它在内存中的存在形式

    基于此,我们可以在项目启动的时候把数据保存在静态变量中,做缓存使用。以Web项目为例,我们在启动的时候,配置一个InitServlet,将数据库或文件中需要缓存的数据解析出来并放在静态变量中。后续使用的时候,不再去进行磁盘IO。

    首先,需要在web.xml中配置InitServlet。load-on-startup的值不小于0时,代表这个Servlet在Web容器(如Tomcat)启动的时候将会自动加载执行。

    <!-- 初始化servlet -->
    <servlet>
    	<servlet-name>InitServlet</servlet-name>
    	<servlet-class>com.xxx.InitServlet</servlet-class>
    	<load-on-startup>1</load-on-startup>
    </servlet>

    接下来,看看InitServlet中相关的代码是如何实现的。功能很简单,从数据库中读取所有应用(App)的信息,并把它们的Url存入缓存。用户在使用这些应用的时候,肯定要获取到Url的,为了避免频繁去数据库查询,放内存缓存是一个好的调优办法,可以提升用户体验。

    public class InitServlet extends HttpServlet {
    
        public void init(ServletConfig servletConfig) throws ServletException {
            initAllAppUrlCache();
        }
    
        private void initAllAppUrlCache() {
            AppServiceable aservice = AppContext.getBean("appService");
            List<App> apps = aservice.findAllApps();
            for(App a : apps){
                if(StringUtils.isNotBlank(a.getUrl())){
                    AllAppUrlCache.add(a.getUrl());
                }
            }
        }
    }

    AllAppUrlCache是我们定义的一个缓存类,它的成员变量用来缓存数据,相关函数用来操作数据。我们采用HashSet静态变量保存数据。

    public class AllAppUrlCache {
    	private static Set<String> ALL_URL_CACHE = new HashSet<String>();
    	public static void add(String url) {
    		ALL_URL_CACHE.add(url);
    	}
    	
    	public static void addAll(Collection<String> url) {
    		ALL_URL_CACHE.addAll(url);
    	}
    	
    	public static boolean isContainUrl(String url){
    		return ALL_URL_CACHE.contains(url);
    	}
    	
    	public static Set<String> getAll(){
    		return ALL_URL_CACHE;
    	}
    	
    }

    以上,就是利用静态变量实现了简单的缓存机制,这在项目中具有普适性。同样的,你也可以通过xml配置文件读取待缓存的数据。总之,利用项目启动时(正式投入使用前)就将高频数据准备好,这就是一个简单且高效的缓存实现。

    ●单例模式实现缓存

    接下来,我们看看第二种实现方式,利用单例模式。

    我们来改写一下这个InitServlet。此时的缓存类我们采用getInstance()来获取它的实例。

    public class InitServlet extends HttpServlet {
    
        public void init(ServletConfig servletConfig) throws ServletException {
            initAllAppUrlCache();
        }
    
        private void initAllAppUrlCache() {
            AppServiceable aservice = AppContext.getBean("appService");
            List<App> apps = aservice.findAllApps();
            for(App a : apps){
                if(StringUtils.isNotBlank(a.getUrl())){
                    AllAppUrlCache.getInstance().add(a.getUrl());
                }
            }
        }
    }

    改写一下AllAppUrlCache的实现方式。采用单例模式的时候有很小的概率在第一次生成对象时会生成多个,这是因为并发导致的,因此考虑加上synchronized进行修饰,确保程序中对象单例

    public class AllAppUrlCache {
        private Set<String> all_url_cache;
        private static volatile AllAppUrlCache allAppUrlCache;
    	
        //私有的构造方法,不能直接调用new
        private AllAppUrlCache(){
    		all_url_cache = new HashSet<>();
    	}
       
        //获取单例对象的正确打开方式
        public static final InMemCache getInstance(){
    		if(allAppUrlCache != null){
    			return allAppUrlCache;
    		}
    		synchronized (AllAppUrlCache.class) {
    			allAppUrlCache = new AllAppUrlCache();
    			return allAppUrlCache;
    		}
    	}
    
        //对数据的操作
        public void add(String val){
    		if(val == null){
    			throw new IllegalArgumentException("val is empty");
    		}
            else
                all_url_cache.add(val);
    	}
    
        public Set<String> getAll(){
    		return all_url_cache;
    	}
    }

    采用单例模式之所以也可以作为缓存,是因为单例模式本身的特性就是全局对象唯一,数据共享,满足缓存的条件之一。同时,在第一次进行写操作的时候产生了该对象,生命周期贯穿程序始终,满足缓存的另一条件。

    相比静态变量,采用单例模式的好处在于它能约束类的实例是唯一的,避免内存的额外分配。例如在第一种实现方式中,如果程序员采用new的方式去创建AllAppUrlCache类,确实缓存数据是共享的,一致的,但是浪费了资源。为了避免多人协同开发,认为失误,采用单例模式,直接从源头上就抑制了new的使用。

    小结

    缓存其实没有那么高深,简单的静态变量或者单例模式就可以实现,根据实际需要,不一定非要采用memcached或者redis等第三方的缓存,额外增加学习成本和维护成本(当然,作为程序员,这两个还是建议只收会使用的),自己动手就可以写出轻量的代码。通常,我们会在程序启动的时候从数据库读取系统字典,或从xml配置文件读取相关配置项,而不是直接在代码中写出静态变量具体值是什么。今天,你学会了吗?

    展开全文
  • 写这篇文章的原因是最近在研究PWA如何在项目中落地实施,这就无可避免的需要接触到浏览器缓存的相关知识,因此特意写下这篇文章巩固下自己浏览器缓存的认识。 什么是HTTP缓存 缓存是一种保存资源副本并在下次请求...

    前言

    写这篇文章的原因是最近在研究PWA如何在项目中落地实施,这就无可避免的需要接触到浏览器缓存的相关知识,因此特意写下这篇文章巩固下自己对浏览器缓存的认识。

    什么是HTTP缓存

    缓存是一种保存资源副本并在下次请求时直接使用该副本的技术。当web缓存发现请求的资源已经被存储,它会拦截请求,返回该资源的拷贝,而不会去源服务器重新下载。这样带来的好处有:缓解服务器端压力,提升性能(获取资源的耗时更短了)。

    HTTP缓存的作用

    我们都知道浏览器是基于HTTP协议和服务端进行通信的,一个网站一旦同时请求过多或者请求过大就容易造成页面渲染时长过长等性能问题,而且并非所有资源都需要实时更新的,将长久或一段时间内的资源进行缓存,能很大的缓解服务器压力和提升网站性能。
    毫不夸张的说,HTTP缓存是达到高性能的重要组成部分。

    注意:缓存需要合理配置,因为并不是所有资源都是永久不变的:重要的是对一个资源的缓存应截止到其下一次发生改变(即不能缓存过期的资源)。

    HTTP头缓存相关字段及优先级

    强缓存:Expires: Date/Cache-Control:max-age=N
    协商缓存:Last-Modified:DateEtag:String

    通过查询标准我们知道Cache-Control和Etag属于HTTP1.1版本,Expires和Last-Modified属于HTTP1.0版本,所以得出以下优先级:
    强缓存:Cache-Control > Expires
    协商缓存:Etag > Last-Modified

    注意:
    Expires存在的缺陷是返回的到期时间是服务器端的时间,可能与客户端的时间有较大的时间差,所以在HTTP1.1版开始使用Cache-Control: max-age=秒替代
    Last-Modified的缺陷:由于只能精确到秒,如果一个文件在1秒内多次修改,这时客户端无法识别,因此HTTP1.1版本使用Etag标识资源内容是否有变更来确认资源是否需要更新,相对来说更加精确

    强缓存与协商缓存

    强缓存:资源一旦被强缓存,在缓存时间内,浏览器发起二次请求时会直接读取本地缓存,不与服务器进行通讯。 强缓存时间过期的,浏览器会判断资源的响应头是否有Last-Modified和Etag字段,有的话执行协商缓存策略

    协商缓存:如果响应头中的包括有Etag和Last-Modified字段,则客户端将If-None-Match:Etag的值和If-Modified-Since:Last-Modified的值添加到请求头发送给服务器,由源服务器校验,如果资源未过期则返回304状态码,浏览器直接使用缓存,否则返回200OK状态码和新资源。

    当两种情况都存在时,强缓存优先级要高于协商缓存

    Chrome浏览器的三种缓存策略

    选择Chrome是因为它是现在最流行的网页调试工具也是最多人用的浏览器。 Chrome浏览器返回缓存http状态码总共有以下三个 1、200 from memory cache 客户端不与服务器通讯,直接从内存中读取缓存。此时的数据时缓存到内存中的,当关闭浏览器后,数据自然就被当垃圾回收清空。

    2、200 from disk cache 客户端不与服务器通讯,直接从磁盘中读取缓存,因为数据存在磁盘中,就算关闭浏览器数据还是存在,下次打开只要数据不过期就可以直接读取。

    3、304 Not Modified 客户端与服务器通讯,服务器验证资源是否需要更新,如果不需要更新服务器返回304状态码,然后客户端直接从缓存中读取数据

    注意:经过测试,我发现Safari和Firefox都有三种缓存策略,IE和其他浏览器大家可以各自测试一下

    浏览器三种缓存示例图

    Chrome和Safari似乎没有办法在浏览器中直接查看缓存情况,因此只能实践中查看。 Chrome示例图: 状态码:200 OK

    状态码:200 from memeory cache
    状态码:200 from disk cache
    状态码:304 Not Modified
    )

    Safari示例图: 响应头:

    状态码:200 OK
    状态码:200 内存
    状态码:200 磁盘

    Firefox:在url上输入about:cache 可以看到对应的缓存情况,大家可以试一下

    从截图中可以看到Firefox也分为内存缓存和磁盘缓存,304Not Modified自然也是有的。
    资源被强缓存后状态码依然是200 OK,不过会在传输列下显示已缓存,但是无法看出是内存缓存还是磁盘缓存。
    Firefox的304与Chrome和Safari差别不大。

    三种缓存策略实际执行的条件

    我在网上看到有人写文章说 js、图片和字体保存在内存中而css则保存在磁盘,很明显,只要自己稍微测试一下就知道这种说法是站不住脚的,那么这三种情况究竟是怎样的呢?

    经过简单的测试以后我发现这三种策略并不复杂,默认配置情况下,Chrome第一次请求资源后,如果资源的响应头有Cache-Control或者Expires且有效期大于现在,则加载数据后将强缓存资源到内存和磁盘。
    刷新页面,Chrome发起整个页面的二次请求后,通过开发者工具可以看到强缓存资源都会从内存进行读取,这就是200 from memory cache的情况。

    示例:
    这时关闭浏览器后,重新打开浏览器并打开关闭前的页面,通过开发者工具可以看到之前强缓存资源都会从磁盘中读取,这是因为关闭了浏览器后系统回收了内存资源,因此内存没有了之前的强缓存资源,需要从磁盘中读取,这就是200 from disk cache的情况。

    示例:
    如果这时使用ctrl + f5强刷页面则会发现全部资源都是200 OK状态要从服务器中获取新数据。

    304 Not Modified的情况则完全不同,如果资源的响应头是Last-Modified或Etag,第一次请求资源后缓存到本地磁盘,但第二次也必须发起请求到服务器进行查询该资源是否过期或被修改过,当服务器验证资源没有过期后才会返回304 Not Modified状态码,同时响应体为空,这样可以节省流量并提高响应速度,客户端接收到304状态码后从本地读取数据,因此304比200 from cache响应速度要慢,但比200 OK快得多。

    Chrome浏览器缓存机制流程图

    上述说法均为个人想法,如有不对,敬请指出,谢谢大家的阅读!

    展开全文
  • <ol><li>什么是持久化缓存,为什么做持久化缓存?</li><li>webpack 如何做持久化缓存?</li><li>webpack 做缓存的一些注意点。</li></ol> 持久化缓存 首先我们需要去解释一下,什么是持久化缓存&#...
  • JT项目-1

    千次阅读 2018-04-18 18:11:06
     火(用户量广)· 技术难点多,高(高并发,高可用)尤其是在中国谷歌是全球并发最高的网站· 学习成本低(无需精通业务部分)2 学习完京淘项目对我们的就业有什么好处· 代替1-2年工作经验· 技术就业范围广,就业重心...

    DAY01

    学习京淘的意义

    1 为什么选择电商项目作为java培优部分的重要项目

    · (用户量广)

    · 技术难点多,高(高并发,高可用)尤其是在中国

    谷歌是全球并发最高的网站

    · 学习成本低(无需精通业务部分)

    2 学习完京淘项目对我们的就业有什么好处

    · 代替1-2年工作经验

    · 技术就业范围广,就业重心多(附录1-京淘项目的技术点)

    电商架构

    redis缓存

    搜做+爬虫

    · 高薪保证

    3 如何学好京淘(建议和要求)

    · 认真听讲

    挑错字

    · 当天内容当天消化

    理论和代码,根据当天的问题,第二天早上第一节课会有知识回顾+遗留

    问题;

    · 利用好小组,集体资源,朋友的力量

    · 预习的问题

    当天结束后,我会告知第二天的技术点;可以根据这些技术点自行查看一些资料,带着目的看资料:

    这是什么;在哪用;

    京淘简介(过一下)

    2017124

    10:08

    电商行业特点

    1 分布式

    数十台服务器,甚至百台、千台、万台,包括:Nigix负载均衡集群、Tomcat集群、Redis缓存集群、RabbitMQ消息队列集群、MySQL主从、Solr全文检索集群等。

    分布式集群

    集群:从任务为单位的角度区分,集群属于单个实例完成单个任务,集中单例群体完成整体功能的过程

    分布式:单个任务拆分成众多的子任务,单个实例完成其中之一,众多实例合作完成一个任务的过程;

    2 高并发

    要面对高并发用户,大流量访问。Google日均PV数35亿,日均IP访问数3亿。腾讯QQ最大在线人数4亿。淘宝2015年“双十一”,活动交易额975亿,2016年第一天交易额超过千亿,活动开始第一分钟独立访问用户达1000万。

    3 高可用

    系统7X24小时不间断运行。大型互联网网站宕机事件通常会成为新闻焦点。如2010年百度域名被黑客劫持导致不能访问,带来不可估量的经济损失。

    4 海量数据

    B KB MB GB TB PB YB EB ZB BB NB DB

    存储、管理海量数据,需要使用大量服务器。facebook每周上传的照片数量近10亿,百度收录的网页数量数百亿,Google有近百万台服务器为全球用户提供服务。

    京淘简介

    京淘网上商城是一个综合性的B2C(Busines-to-custmer)平台,<预言>C2C类似京东商城、天猫商城。会员可以在商城浏览商品、添加商品到购物车、下订单,以及参加各种活动。商家可以入驻京淘商城,在该平台上开店出售自己的商品,并且得到京淘商城提供的可靠服务。管理员、运营人员可以在后台管理系统中管理商品、订单、会员等。客服人员可以在后台管理系统中处理用户的询问和投诉。

    开发工具

    Windows7/CentOS 6.5/VMworkstation10

    Power Designer 15.6

    Eclipse neon

    JDK 1.7以上 必须。一些高级应用需要高版本支持1.8

    Maven 3.5

    Tomcat 7.0.59

    Nginx 1.9.9

    Redis 3.2.11

    MySQL 5.5.27(注意5.0导入jt.sql会报错必须升级) + Amoeba 3.0.4

     

     

     

     

    京淘架构

    2018110

    9:57

    传统架构是如何开发一个项目

    不分功能不分模块不分任务的全都放到一个工程完成

     

    优点:结构简单,开发过程不需要考虑分布式的难题,不需要考虑jar包的

    依赖管理;

    缺点:高可用能力低,一旦某一个模块失效,整体失效,团队开发的配合那难度大

     

    京淘如此庞大的一个电商系统能否单人独立开发完成?

    一个大型项目需要众多的工程团队配合完成,或者小组,单个的人相互配合,由不同

    的团队开发不同的模块

    京淘中我们引入多个工程系统;分为两部分

    1 业务系统(启动的这些系统):

    前台系统(jt-web):访问首页;登录连接,注册连接,购物车连接,订单连接

    后台系统(jt-manage):商品增删改查(web前端技术EasyUI KindEditor)

    购物车系统:选择商品,数量,支付金额;

    订单系统:从购物车发起的连接,生成订单,收货人信息,付款方式,商品内容

    登录系统:权限管理,用户信息的获取;

    2 支撑系统:

    父工程:管理所有依赖的jar包(maven继承);本质就是准备好pom文件

    工具工程:管理所有工程的公用工具类(maven依赖);代码

    以上的每一个工程系统都是一个单独的maven工程

    <问题>如何按团队分功能分模块开发呢?

    一个大型项目,业务划分成多个子系统的过程就是所谓的拆分过程中的业务

    纵向拆分

     

     

    <同理>

    每一个子业务系统当功能非常复杂,结构烦琐,也很难由同一个团队或者小组

    单独开发完成,引出二级拆分(横向拆分);本质就是三层架构的拆分工作

    (持久层(pojo,mapper接口,mapper.xml),业务层(service),控制层(controller))

    注意:parent和common是没有横向拆分的;主要负责提供资源

    每一个横向拆分出来的部分也需要单独成立一个maven工程,但是本次版本的

    京淘没有做横向拆分

    如果进行拆分,以下图样貌展示

     

    本次京淘以包的形式代替横向拆分中的子系统

     

     

    京淘的整体布局结构

    多个工程,根据项目的纵向拆分,分为不同功能的不同工程系统;

     

    <问题>

    一个业务系统manage,内部如何组成的后台系统

    controller,service,mapper,pojo

     

    对于支撑子系统(parent,common);只做资源的提供

     

    解释业务系统需要具体的实时开发的代码问题;

    对于某一个业务系统,三层架构包括:持久层,业务层,控制层;

    可以从前向后的开发(页面分析-controller-service-mapper,pojo,mapper.xml),也可以从后向前(pojo,mapper--service--controller-页面解析)

     

     

     

     

    京淘开发的环境基础

    2018110

    11:30

    maven环境基础

    1 配置eclipse和maven

    eclipse的属性(preferences中)

     

     

     

     

     

    2 maven仓库的设置

    maven下的set.xml的53

     

     

    maven工程的继承

    情景分析

    在一个庞大的项目中,由于业务拆分给了多个工程团队开发不同的模块,每个团队有管理自己开发工程的权利;

    导致一个问题,每个工程都有不同的自己依赖的jar包;如果各自为政;

    例如mybatis包,jar包有不同版本,后台系统需要;登录系统;购物车系统,订单系统

    版本不一致导致,当系统间需要相互调用和交互的时候,有可能会造成代码冲突的bug;这种bug很致命,也很难处理;

     

    所以我们引入maven工程的继承特点来完成父类工程的创建,将所有的jar包管理交给parent

     

    搭建父类maven工程和普通maven工程区别只有一个pom文件中的类型

    不是jar也不是war而是pom

     

     

    准备数据库的数据

    资源文件:设计--jt.sql

    1 创建一个叫jtdb的数据库

     

    2 右键数据库将sql文件导入

     

    浏览文件选中jt.sql

     

    点击导入完成

     

    如果导入时候出现错误,是由于数据库版本导致的问题

    解决办法删除你当前的mysql,重新安装我给的版本

     

     

     

     

    预习内容

    2018110

    11:49

     

    1 pd中观察一下商品分类,商品列表,观察字段,主键,类型,和汇通比较一下

    2 了解一下EASYUI

    3 观察一下课程资料中的代码中

    manage工程中的自工程jt-manage-web中的src文件夹下的resource文件中

    的配置文件

    4 观察代码中的parent里的pom文件

    5 common工程中的工具类


    DAY02

    回顾+遗留问题

    2018110

    22:35

    知识回顾

    京淘的架构

    1 大型项目根据业务和功能模块交给不同团队开发--纵向拆分

    拆成2部分子系统

    支撑子系统:parent和common;

    业务子系统:前台后台订单等

    2 每一个业务子系统在京淘的开发中也要有三层架构

    mybatis:原来做类与表的对应是在xml文件中

    在京淘中使用JPA注解,无需在sql语句中写表字段和类属性的对应关系

    通用mapper:单表增删改查.无需写sql

    controller返回给页面jsp的数据原来使用model返回一个map对象,list对象,到页面用el表达式处理

    京淘中使用json和jsonp

    3 二级拆分,本质就是三层开发模式的拆分;

     

    maven继承

    和创建普通maven工程非常类似jt-parent

    pom文件引入后,所有公共依赖的jar包就存在于parent这个工程中;pom文件中的类型不能jar或者war;

     

    遗留问题:

    1 更换了maven库后,创建maven工程提示骨架错误,

    原因就是因为maven库中的文件有损坏;或者maven库的文件版本不支持你的操作环境;

    解决办法:开网,删除对应的骨架文件,重新创建;

     

    2 当一个项目被拆分多个模块时,在真实企业中是如何管理的?CVS SVN;

    涉及到的问题就是:软件的资源管理和版本管理;

     

    常见的管理这些内容的软件:CVS(早期),SVN(用的多);GIT(软件版本管理比较强)

    资源包括:静态页面css,html,img;系统对接的接口文件;开发需求书;jar包();工具类等

     

    不同的开发团队下载对应的资源文件

    在各自的环境中开发工程,最终将完成的任务以war包形式上传到SVN服务器上,或者setup或者update

    当某一个版本的系统需要发布时,就把SVN上整合的一批war同时发布到不同的测试环境/生产环境/现场环境

     

     

    创建父工程和工具工程

    2018112

    9:26

    parent工程

    maven工程的常用骨架quickstart和webapp

    支撑的工程parent 和common都是使用quickstart

    1 创建一个maven工程
     

     

    2 选择qu

     

    ickstart

    3 命名

     

    4 完成创建后修改3处

    · java build path

    · java complier

    · workspaceencoding

     

    回忆:

    parent工程的作用是什么?

    解决所有工程的jar包依赖

    5 导入依赖的pom文件

    资料位置:课前资料--常用配置文件--parent-pom.xml

    不要一次性copy文件进行覆盖;全部copy有可能导致mvven库加载文件失败

     

    在创建环境时注意的问题:

    1 所有路径不能有空格和中文,编译出现%

    2 validation关掉;因为当前的京淘中没有新编写的配置文件或jsp文件

    3 eclipse视图模式中的2个package explorer和navigator

    前者展示工程结构,后者展示资源结构

     

    搭建common工程

    1 maven选择quickstart

    2 命名

    3修改3处

    4 导入准备好的common工具类资源

    资源位置:课前资料--基础框架--工具类--jt-common--src文件

    里面的main文件夹直接全部copy到工具类工程

    main文件夹放到src下,点击yestoall

     

    5 依赖父类

    pom视图界面完成依赖的配置

     

     

     

     

     

     

    后台工程

    2018112

    10:25

    完成后台代码需要创建一个后台工程

     

    1 创建maven工程(quickstart/webapp)

    两个骨架的却别

    一个是java工程

    一个是web工程

    在京淘中判断工程是否是web可以根据工程是否需要接收

    前台请求来判断;有没有controller

    例如:sso.jt.com;如果有请求地址:http://sso.jt.com/login

     

     2 修改属性(4处)

    多了一个project facets

     

    3 继承parent同时依赖common

     

     


     

    4 发布当前创建的工程

    右键工程,点击-run--maven install进行发布

    有可能碰到问题是提示ERROR

    你没有使用jdk可以在使用jre

    解决办法:需要修改eclipse绑定的jdk环境

     

     

    商品分类

    2018112

    10:43

    开发的功能是根据什么东西来完成的?

    企业中是根据严格的需求说明书来进行开发的,京淘暂时没有那么严谨;

     

    完成需求一:

    展示商品分类的所有数据到浏览器

    前台需要后台传递json格式的数据

    数据来源--数据库--商品分类表

     

    查看数据库设计

    资料位置:设计--pdm文件

     

    分类id:

    数据库id类型的三种选择

    · int(int):优点,性能高;缺点,会重复

    · long(bigint):优点,性能高;缺点,会重复;

    · 数据存储量比int大,在同样情况下考虑量的问题时使用long

    · string(varchar):在分布式环境中,多个数据库产生的问题就是,分开的数据自增int或者long会产生重复,这时使用string类型(uuid);

    电商中的数据库是分布式的吗?

    对于电商系统;数据库不是分布式的,而是中央集中(大量的查询已经被缓存所替代--京淘中的缓存是redis)

    父类id

    体现层级关系的字段

    名称

    状态

    1 正常 2 删除(伪删除)

    排序号

    京淘项目中没有用

    电商项目中有非常多的类似的字段

    热度,销量,人气

    是否父类

    与分类树展现相关;如果不是父类,说明是末尾分类

    创建和修改时间

    商品分类根据修改时间排序

     

    开发代码的过程

    1 pojo

    2 mapper.xml

    3 mapper接口

    4 service结合controller

    5 controller页面分析

    页面分析三元素

    · 请求地址

    · 请求参数

    · 返回类型

     

    pojo(ItemCat)

    插入:序列化的意义

    将内存中的对象数据在存储到磁盘或者传输时根据序列化id区分

    对象同时获取对象数据

    继承BasePojo

    具体代码见课下资料

     

    mapper.xml(itemCatMapper.xml)

    使用通用mapper可以帮助完成单表增删改查

    查询item-cat的所有数据,属于单表查询,所以无需编写sql

    语句,ItemCatMapper.xml留作框架扩展

    copy一个文件和文件目录结果过来;

    资料位置:课前资料--基础框架--managewebresource--resources--

    mybatis中的mapper.xml

     

     

    mapper接口文件(ItemCatMapper)

    需要继承通用mapper的使用,自定义SysMapper来

    继承通用mapper的功能供后续mapper接口使用

    通用mapper不支持批量删除,自定义SysMapper继承通用mapper后支持批量删除

     

    创建一个mapper接口类,继承SysMapper即可

     

    业务层(ItemCatService)

    和以往的习惯不一样在于没有接口,直接实现类;

    业务逻辑是什么?

    查寻当前tb_item_cat中的所有数据;

    List<ItemCat>

    需要继承一个父类的Service叫BaseService

    自动注入了SysMapper同时封装了一些方法的调用

    例如queryAll

    引入BaseService

    资料位置:课前资料--基础框架--BaseService,将其拷贝到

    common的service包中供后续众多service继承使用

     

    控制层(ItemCatController)

    没有页面分析,自定义访问路径,不是从网页发起的访问请求地址

    /item/cat

     

    存在的问题:

    1 通用mapper怎么知道isParent对应表格字段是

    is_parent

    2 还缺少三大框架的配置文件;

    3 没有运行tomcat插件;

    4 缺少静态资源;css,js等

    5 缺少web.xml

     

    解决第一个问题

    不在xml文件里写对应关系,利用JPA注解

    java提供的一套持久层注解,利用这套注解,持久层框架

    就可以直接读取其中对应的属性名称与表中字段关联;

    @Table(name="表名"):把类和表对应

    @Id:在主键属性上添加,对应表中的主键字段

    @GeneratedValue(strategy=GenerationType.IDENTITY):对应自增字段

    @Column(name="parent_id"):把剩下的属性一一与表中字段对应

     

    解决第二个问题

    SSM(SPRING+SPRINGMVC+MYBATIS)

    MYBATIS

    资料位置:课前资料--基础框架--配置文件--managewebresources--mybatis

     

    查看一下当中的配置信息

    <settings>

    <!-- 开启驼峰自动映射 -->驼峰映射规则就是代替

    JPAColumn注解的使用,这就是为什么column可以

    省略

    <setting name="mapUnderscoreToCamelCase" value="true" />

    <!-- 二级缓存的总开关 -->后期缓存有第三方技术redis

    代替数据库二级缓存

    <setting name="cacheEnabled" value="false" />

    </settings>

     

    <plugins>

    <!-- 分页插件:com.github.pagehelper为PageHelper类所在包名 -->//讲分页时候再说

    <plugin interceptor="com.github.pagehelper.PageHelper">

    <!-- 方言 -->

    <property name="dialect" value="mysql" />

    <!-- 该参数默认为false -->

    <!-- 设置为true时,使用RowBounds分页会进行count查询,查询数据总条数 -->

    <property name="rowBoundsWithCount" value="true" />

    </plugin>

     

    <!-- 通用Mapper插件 -->//基于拦截器来实现,就是在查询时拦截查询语句,将sql进行整理拼接等操作

    <plugin interceptor="com.github.abel533.mapperhelper.MapperInterceptor">

    <!--主键自增回写方法,默认值MYSQL,详细说明请看文档 -->

    <property name="IDENTITY" value="MYSQL" />

    <!--通用Mapper接口,多个通用接口用逗号隔开 -->

    <property name="mappers"

    //包名与sysmapper不一致,需要修改

    value="com.jt.common.mapper.SysMapper" />

    </plugin>

    </plugins>

     

    Spring配置文件

    资料位置:课前资料--基础框架--配置文件--resources-spring

    applicationContext.xml

     

    将文件拷贝到对应的目录中

    查看当前的文件内容

    <!-- 使用spring自带的占位符替换功能,可以实现注解方式获取属性文件中的配置值 -->

    //写代码过程中如果有字符串出现,为了解耦进行属性替换

    //Property,this.getclass.getclassloader.getresource.getpath

    //最后调用prop.getProperty进行解耦

    <bean

    class="com.jt.common.spring.exetend.ExtendedPropertyPlaceholderConfigurer">

    <!-- 允许JVM参数覆盖 -->//不同jvm实力的参数覆盖;

    <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />

    <!-- 忽略没有找到的资源文件 -->

    <property name="ignoreResourceNotFound" value="true" />

    <!-- 配置资源文件 -->

    <property name="locations">

    <list>

    <value>classpath:jdbc.properties</value>

    <value>classpath:env.properties</value>

    //以下三个配置文件可以删除,暂时用不到

    <value>classpath:redis.properties</value>

    <value>classpath:httpclient.properties</value>

    <value>classpath:rabbitmq.properties</value>

    </list>

    </property>

    </bean>

     

    <!-- 扫描包 -->

    <context:component-scan base-package="com.jt" />

     

    <!-- 配置连接池 -->

    <bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">

    <!-- 数据库驱动 -->

    <property name="driverClass" value="${jdbc.driver}" />

    <!-- 相应驱动的jdbcUrl -->

    <property name="jdbcUrl" value="${jdbc.url}" />

    <!-- 数据库的用户名 -->

    <property name="username" value="${jdbc.username}" />

    <!-- 数据库的密码 -->

    <property name="password" value="${jdbc.password}" />

    <!-- 检查数据库连接池中空闲连接的间隔时间,单位是分,默认值:240,如果要取消则设置为0 -->

    <property name="idleConnectionTestPeriod" value="60" />

    <!-- 连接池中未使用的链接最大存活时间,单位是分,默认值:60,如果要永远存活设置为0 -->

    <property name="idleMaxAge" value="30" />

    <!-- 每个分区最大的连接数 -->

    <property name="maxConnectionsPerPartition" value="150" />

    <!-- 每个分区最小的连接数 -->

    <property name="minConnectionsPerPartition" value="5" />

    </bean>

     

    需要将jdbc.properties和env.properties导入

    资料位置:课前资料--基础框架--resources中找到

    配置文件,copy到工程中的resources下

     

     

    spring的实务管理文件

    applicationContext-transaction.xml

    资料位置:课前资料--基础框架--resources,copy到工程的spring文件夹下

     

    查看内容

    <bean id="transactionManager"

    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">//必须和applciationContext中的连接池配置id一致

    <property name="dataSource" ref="dataSource" />

    </bean>

     

    <!-- 定义事务策略 -->

    <tx:advice id="txAdvice" transaction-manager="transactionManager">

    <tx:attributes>

    <!--定义查询方法都是只读的 -->

    <tx:method name="query*" read-only="true" />

    <tx:method name="find*" read-only="true" />

    <tx:method name="get*" read-only="true" />

    <!-- 主库执行操作,事务传播行为定义为默认行为 -->

    <tx:method name="save*" propagation="REQUIRED" />

    <tx:method name="update*" propagation="REQUIRED" />

    <tx:method name="delete*" propagation="REQUIRED" />

    <!--其他方法使用默认事务策略 -->//

    增删改查 insert--sava,delete,update

    注意在service业务层的方法名称,新增不能使用insert

    <tx:method name="*" />

    </tx:attributes>

    </tx:advice>

     

    <aop:config>

    <!-- 定义切面,所有的service的所有方法 -->

    <aop:pointcut id="txPointcut" expression="execution(* com.jt.manage.service.*.*(..))" />

    <!-- 应用事务策略到Service切面 -->

    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>//扫描的包名称要根据不同的工程修改

    </aop:config>

     

    applicationContext-mybatis.xml与mybatis整合文件

    copy到spring目录下

    查看内容

    <!-- 构造SqlSessionFactory -->

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

    <!-- 定义数据源 -->

    <property name="dataSource" ref="dataSource"/>

    <!-- mybatis-config.xml -->

    <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>

    <!-- 别名包 -->

    //省略返回值的全路径名称

    <property name="typeAliasesPackage" value="com.jt.manage.pojo"/>

    <!-- mapper.xml -->

    //扫描mapper的xml文件

    <property name="mapperLocations" value="classpath:mybatis/mappers/*.xml"/>

    </bean>

     

    <!-- 定义Mapper接口扫描器 -->

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">

    <!-- 扫描mapper包 -->

    <property name="basePackage" value="com.jt.manage.mapper"/>

    </bean>

     

    springmvc的框架配置文件

    <!-- MVC注解驱动 -->

    <mvc:annotation-driven/>

     

    <!-- 配置扫描器,使得@Controller注解生效 -->

    <context:component-scan base-package="com.jt.manage.controller" />

     

    <!-- 定义视图解析器 -->

    //返回index,最终根据试图解析器访问的具体资源

    /WEB-INF/views/index.jsp

    <!-- prefix="/WEB-INF/jsp/", suffix=".jsp", viewname="test" -> "/WEB-INF/jsp/test.jsp" -->

    <bean

    class="org.springframework.web.servlet.view.InternalResourceViewResolver">

    <!-- 前缀 -->

    <property name="prefix" value="/WEB-INF/views/" />

    <!-- 后缀 -->

    <property name="suffix" value=".jsp" />

    </bean>

     

    <!-- 处理静态资源被“/”所拦截的问题 -->

    //拦截器配置标签,manage暂时用不到

    <mvc:default-servlet-handler />

     

    <!-- 定义文件上传解析器 -->

    //新增商品时的图片上传类

    <bean id="multipartResolver"

    class="org.springframework.web.multipart.commons.CommonsMultipartResolver">

    <!-- 设定默认编码 -->

    <property name="defaultEncoding" value="UTF-8"></property>

    <!-- 设定文件上传的最大值10MB,10*1024*1024 -->

    <property name="maxUploadSize" value="10485760"></property>

    </bean>

     

    三大框架整合完毕

    启动maven工程需要

    解决第三个问题

    解决tomcat插件问题

    manage工程的pom文件里引入tomcat的插件文本

     

    配置configuration的运行或者debug

     

    添加其他所有工程文件到source中

     

    代码修改之后,需要将manage工程重新发布

     

    解决第四个问题

    资料位置:课前资料--基础框架--静态资源--后台系统

    将所有资料copy到manage工程的src下的main下webapp中,覆盖所有

     

     

    另外如果想打印启动的日志详情,可以在工程文件中的src--main--resources添加日志properties

     

    重新发布,执行maven工程,在浏览器中输入访问地址,查看返回数据

    利用responseBody注解将返回对象转化成json字符串

    从前台浏览器查看到一片字符串,是否是json,可以调用json查看软件

     

     

    后台的页面访问

    2018112

    15:43

    动态页面跳转分析

    后台页面包括首页,新增商品,修改商品的页面;

    想做页面的访问工作,就是利用springmvc做视图的跳转拼接

    访问index.jsp 实际资源位置/WEB-INF/views/index.jsp

    访问item-add.jsp; 实际资源位置/WEB-INF/views/item-add.jsp

     

    页面跳转的逻辑

    做一个controller

    做一个方法负责跳转到index

    返回值String “index”;

     

    做另外一个方法负责跳转到item-add

    返回值String “item-add”;

     

    以上的习惯性的方法有缺陷,页面越多,代码越多,但是逻辑都一样

    所以需要一种方法能够动态的跳转页面

    获取不同的参数来判断跳转页面,

    http://localhost:8081/page/index 访问首页

    http://localhost:8081/page/item-add 访问新增商品页面

    以上两个请求地址,有相似路径page之前的都一直,只有最后的一个拼接不一样,可以作为参数传递给controller,只要把参数作为返回值,就可以形成动态的访问效果

     

    这个参数要怎么传递,怎么接受呢?

    RestFul的传参引入过来

    springmvc对restful支持,可以按照参数的逻辑进行接受,传递给controller 需要调用注解

    @PathVariable

     

    代码的编写逻辑

    只需要一个controller

    一个方法

     

     

     

     

     

     

    当天问题

    2018112

    9:48

     

    在导入pom文件内容时,如果出现问题,在problem中查看对应的报错内容,根据报错提示解决

    有可能在problem中看到update project的提示

    可以在show view中把problem选出来

     

     

     

     

    这个问题是因为eclipse插件与maven的兼容

     

    在创建完common并且继承了parent之后,还是有错误提示

    需要你删除override注解

    原因complier版本不一样

     

    骨架问题

    artifact missing

    artifact相关问题,查看maven库是否修改;

    找对提示的artifact删除,联网重新下载

     

    在展示商品分类所有数据中出现如下异常

    org.springframework.beans.factory.CannotLoadBeanClassException: Error loading class [com.jt.manage.service.ItemCatService] for bean with name 'itemCatService' defined in file [C:\developertools\eclipsenew\workspace\jt-manage\target\classes\com\jt\manage\service\ItemCatService.class]: problem with class file or dependent class; nested exception is java.lang.NoClassDefFoundError: com/jt/common/service/BaseService

     

    根据提示,BaseService无法加载,原因是common添加了BaseService后没有

    重新发布,加载失败,需要重新发布common工程

     

    访问路径http://localhost:8081/item/cat

     

    无法访问,但是根据断点测试发现,可以进入controller并且查询到的list正确,但是springmvc却自动拼接前缀后缀,导致响应无效

     

    原因在于不处理的controller返回值,都会经过一个Spring**Converter

    对所有的默认返回都拼接试图解析器的前后缀

    自定义返回值时使用其他的converter

    解决:在controller对应的方法中利用注解来完成

    @ResponseBody

     


    展开全文
  •  既然要用,说明已经对redis是干什么的,特点是什么,对项目有什么好处,需要缓存什么东西等问题都了解过了,所以我们直接开搞: 怎么获取redis  安装redis,linux下wget到github的源码,然后直接make就行了,...

    前言

      这两天项目用到redis,而我自己也正准备看这个,所以就从头开始学习了一遍。

      既然要用,说明已经对redis是干什么的,特点是什么,对项目有什么好处,需要缓存什么东西等问题都了解过了,所以我们直接开搞:

    怎么获取redis

      安装redis,linux下wget到github的源码,然后直接make就行了,比较简单。

      我是在windows下用的,所以来说下:到从redis官网连接过去的redisServer下载redis-2.8.19.zip,解压之后运行redis-server.exe即可,然后打开redis-cli.exe就可以使用了。一般这个只是用来测试连接和查看monitor用的。

    java端如何使用redis

      在java项目中,redis提供了很多客户端库,我用的jedis,它封装了对redis数据库的所有操作。

      一般web应用中,我们还会用到spring,方便的地方在于spring本身也提供了对redis的支持--spring-data-redis,可以到官网查看文档,并有实例。

      具体步骤:

      1.引入pom依赖(如果没用maven的话,自行引入jar包吧)

    <dependencies>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>1.5.0.RELEASE</version>
        </dependency>
    </dependencies>

      同时将jedis也依赖上,因为spring-data-redis底层就是用的jedis:

         <dependency>
                <groupId>redis.clients</groupId>
                <artifactId>jedis</artifactId>
                <version>2.6.0</version>
                <type>jar</type>
                <scope>compile</scope>
            </dependency>

     

      2.在容器中配置RedisTemplate实例

    <bean id="jedisConnFactory" 
        class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" 
        p:use-pool="true"/>
    
    <!-- redis template definition -->
    <bean id="redisTemplate" 
        class="org.springframework.data.redis.core.RedisTemplate" 
        p:connection-factory-ref="jedisConnFactory"/>

      注意:这是官网直接复制过来的,我这样直接放在xml中,会报错,即使是引入p的命名空间。然后我就尝试将p属性写成property后,就没有报错了,但是在后面用的时候会key和value会出现类似"\xac\xed\x00\x05t\x00\tb "这样的情况,查询得知这是因为spring-data-redis需要将数据存储到jedis中,这中间需要序列化,再由jedis存储到数据库,问题就出在序列化上了,它会将key和value的类型信息也序列化后带上,这显然不是我们想要的结果。

      所以RedisTemplate提供了对key和value序列化类,于是我打算这样:

    <bean id="redisTemplate"
              class="org.springframework.data.redis.core.RedisTemplate">
            <property name="connectionFactory" ref="jedisConnFactory"/>
            <property name="keySerializer">
                <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
            </property>
            <property name="hashKeySerializer">
                <bean class="org.springframework.data.redis.serializer.GenericToStringSerializer"/>
            </property>
            <property name="valueSerializer">
                <bean class="org.springframework.data.redis.serializer.GenericToStringSerializer"/>
            </property>
            <property name="hashValueSerializer">
                <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
            </property>
        </bean>

      可是中间两个序列化类还是报错,没有无参构造器,所以就准备采用构造器注入的方式,但是要求注入的参数是一个Object.class类型,我也不知道怎么注入这种类型的,搞来搞去还是干脆就不要xml了,直接写配置类:

    @Configuration
    public class RedisConfig {
        @Bean
        JedisConnectionFactory jedisConnectionFactory() {
            return new JedisConnectionFactory();
        }
    
        @Bean
        RedisTemplate<String, Object> redisTemplate() {
            final RedisTemplate<String, Object> template = new RedisTemplate<>();
            template.setConnectionFactory(jedisConnectionFactory());
            template.setKeySerializer(new StringRedisSerializer());
            template.setHashKeySerializer(new GenericToStringSerializer<>(Object.class));
            template.setValueSerializer(new GenericToStringSerializer<>(Object.class));
            return template;
        }
    }

      这下可算可以了(当然要注意扫描包)。

      有了RedisTemplate之后,就可以写具体的实现业务类了,RedisTemplate基本支持所有redis操作,比如:

    @Component
    public class SpringRedisClientImpl implements SpringRedisClient {
        @Autowired
        private RedisTemplate<String, Object> template;
        @Autowired
        private JedisConnectionFactory jedisConnectionFactory;
    
        @Override
        public void setKey(String key, String value) {
            template.opsForValue().set(key, value);
        }
    
        @Override
        public Object getKey(String key) {
            return template.opsForValue().get(key);
        }
    
        @Override
        public void incr(String key) {
            template.opsForValue().increment(key, 1);
        }
    
        @Override
        public void lPush(String key, String value) {
            template.opsForList().leftPush(key, value);
        }
    
        @Override
        public boolean checkKey(String key) {
            return template.hasKey(key);
        }
    
        @Override
        public Object lIndex(String key) {
            return template.opsForList().index(key, 0);
        }
    
        @Override
        public Long llength(String key) {
            return template.opsForList().size(key);
        }
    
        @Override
        public String lpop(String key) {
    
            return (String) template.opsForList().leftPop(key);
        }
    
        @Override
        public Set<String> getKeys(String pattern) {
            return template.keys(pattern);
        }
    
        @Override
        public void flushAll() {
            Jedis jedis = jedisConnectionFactory.getShardInfo().createResource();
            jedis.flushAll();
            jedis.close();
        }
    }

      最后,启动redis-server.exe就可以了(这里要注意要先启动这个,再启动web项目,否则启动不了,原因未知),如果对redis比较熟悉的,可以自行配置redis.windows.conf文件。其实我也不太熟悉conf文件里面的配置,尤其是持久化到磁盘那个。所以在我的项目里,我是将数据以每天为单位保存到mysql中,并清空redis。

    推荐

      要使用RedisTemplate相应方法的时候,应该要对其的作用非常熟悉,这里推荐一个redis命令参考

      

      

    转载于:https://www.cnblogs.com/yl0822/p/4424752.html

    展开全文
  • 项目0223

    2020-02-23 19:00:18
    1.为什么需要 课程主页的访问人数非常多, 以不发请求静态页面代替要发请求静态页面或者动态页面.没有后台数据获取 的页面访问人数很多,但是在一定时间段内不会改变(数据没变化).页面静态化. 2.静态化的好处 ...
  • 思考:有什么问题? 1、 模块之间耦合度太高,其中一个升级其他都得升级 2、 开发困难,各个团队开发最后都要整合一起 3、 系统的扩展性差 4、不能灵活的进行分布式部署。 2.3.2. 分布式系统架构 ...
  • 什么是NoSQL数据库?

    2014-07-21 23:24:20
    希望顺畅地数据进行缓存(Cache)处理 希望对数组类型的数据进行高速处理 希望进行全部保存 多样的NoSQL数据库 NoSQL数据库存在着“key-value存储”、“文档型数据库”、“列存储数据库”等各种各样的种类,每种...
  • 有什么限制? 7 2、Java有没有goto? 8 3、说说&和&&的区别。 8 4、在JAVA中如何跳出当前的多重嵌套循环? 8 5、switch语句能否作用在byte上,能否作用在long上,能否作用在String上? 9 6、short s1 = 1; s1 = s1 + 1...
  • 深信服面经

    2020-10-26 09:50:36
    一面:10.13-视频面 (40min) 简单的问实习,做过什么项目,实现了哪些功能? Spring Bean的生命周期? Spring容器每次启动的时候,都会触发每个bean的实例化吗?...怎么一个Map集合进行遍历,这样遍历有什么好处
  • 谷歌的代码管理

    2020-08-24 00:34:21
    我一直很困惑,为什么要这样做,不同语言的项目放在一个库有什么好处? 最新一期的《ACM通信》(59卷第7期)有一篇论文《为什么 Google 要把几十亿行代码放在一个库?》,作者是谷歌基础设施小组的工程师,可以看作...
  •  这里不说用某个框架对项目的优势,先扯扯用框架的好处。 java经历这么多年的成长,前辈们都总结出来了,不用考虑了,一般都是那些个,ssh,s2sh,ssi,可能再加上view模板,缓存等等。而且刚上道的新手也知道怎么...
  • 对项目整体设计的一个感受(面试官可能会让你画系统的架构图) 在这个项目中你负责了什么、做了什么、担任了什么角色 从这个项目中你学会了那些东西,使用到了那些技术,学会了那些新技术的使用 另外项目描述中,...
  • 使用消息队列有什么好处? Spring MVC 面经 Spring经典面试题总结 史上最全多线程面试题 ! Docker入门视频教程 Docker详细讲解 CORS跨域讲解 MySQL索引面试题 数据库分库分表shardingJDBC-数据迁移难题 优秀开源...
  • Java面试题56.ibatis和hibernate有什么不同 Java面试题57.hibernate对象状态及其转换 Java面试题58:hibernate的缓存 Java面试题59.webservice的使用场景 Java面试题60.activiti的简单介绍 Java面试题61.linux的使用...
  • 52、 常见的Caching技术://ASP.NET Cache //数据库缓存 //通过静态变量缓存//Memory-Mapped Files 53、 授权包括://用户的权限//代码的执行权限 54、 在构思阶段,各种角色的职责是://根据质量目标提供反馈//...
  • 最新Java面试宝典pdf版

    热门讨论 2011-08-31 11:29:22
    有什么限制? 7 2、Java有没有goto? 7 3、说说&和&&的区别。 8 4、在JAVA中如何跳出当前的多重嵌套循环? 8 5、switch语句能否作用在byte上,能否作用在long上,能否作用在String上? 9 6、short s1 = 1; s1 = s1 + 1...
  • Java面试宝典2010版

    2011-06-27 09:48:27
    有什么限制? 2、Java有没有goto? 3、说说&和&&的区别。 4、在JAVA中如何跳出当前的多重嵌套循环? 5、switch语句能否作用在byte上,能否作用在long上,能否作用在String上? 6、short s1 = 1; s1 = s1 + 1;...
  • Fourinone分布式计算框架

    热门讨论 2011-08-29 15:21:33
    这样做的好处是,开发者更大能力去深入控制并行计算的过程,去保持使用并行计算实现业务逻辑的完整性,而且各种不同类型的并行计算场景也能灵活处理,不会因为某些特殊场景被map/reduce的框架限制住思维,并且...
  • 看到网上个方案说:主项目负责加载组件,由于主项目和组件之间是隔离的,那么主项目如何调用组件ApplicationLike的生命周期方法呢,目前采用的是基于编译期字节码插入的方式,扫描所有的ApplicationLike类(其一...
  • java面试宝典

    2013-02-28 16:04:01
    8、int 和Integer 有什么区别? 9 9、&和&&的区别? 9 10、简述逻辑操作(&,|,^)与条件操作(&&,||)的区别? 9 11、heap 和stack 有什么区别? 9 12、Math.round(11.5) 等于多少? Math.round(-11.5)等于多少? 9 13、...
  • 千方百计笔试题大全

    2011-11-30 21:58:33
    8、int 和Integer 有什么区别? 9 9、&和&&的区别? 9 10、简述逻辑操作(&,|,^)与条件操作(&&,||)的区别? 9 11、heap 和stack 有什么区别? 9 12、Math.round(11.5) 等于多少? Math.round(-11.5)等于多少? 9 13、...
  • 这样做的好处是,开发者更大能力去深入控制并行计算的过程,去保持使用并行计算实现业务逻辑的完整性,而且各种不同类型的并行计算场景也能灵活处理,不会因为某些特殊场景被map/reduce的框架限制住思维,并且...
  • 我会按照几个维度对项目进行分类,以便大家查阅。当然,如果你觉得不错的话,欢迎给本项目点个 Star。我会用我的业余时间持续完善这份名单,谢谢 。 欢迎大家推荐自己觉得不错的 Java 项目,下面项目的排序很大程度...
  • 需要使用leveldb对项目进行更改的更改可能会被拒绝,而对项目没有足够的好处。 测试:所有更改都必须伴随着新的(或更改的)测试,或关于为什么不需要新的(或更改的)测试的充分说明。 风格一致:该项目符合《 ...

空空如也

空空如也

1 2 3
收藏数 54
精华内容 21
关键字:

缓存对项目有什么好处