2019java后端面试集合篇最值得收藏的(一)
Java面試最值得收藏的文章(共4部分):
2019java后端面試集合篇最值得收藏的(一)
2019java后端面試集合篇最值得收藏的(二)
2019java后端面試集合篇最值得收藏的(三)
2019java后端面試集合篇最值得收藏的(四)
目錄
介紹下dubbo和zookeeper: 5
dubbo+zookeerper怎樣實現session共享(在消費端): 5
為什么用dubbo+zeekeeper?介紹一下? 5
生產者和消費者是怎么交互的? 5
你看過dubbo底層嗎? 5
zookeeper的作用: 6
項目安全性怎么解決? 6
購物車在redis中是怎么存的? 6
問靜態化的商品詳情頁面,如果數據庫價格變動,頁面會重新生成嗎? 6
問購物車的商品會存到redis里面,假如有一件襯衣賣68,有一千萬人將其加入購物車,而第二天老板將數據庫價格改成88了,那購物車里面的價格會變化嗎? 6
solr搜索引擎: 6
購物車實現cookie+redis: 7
redis講解 9
Redis可能出現的問題: 9
Redis持久化方面: 9
Redis主從同步: 10
如何在項目中使用redis的: 10
redis常見性能問題和解決方案: 10
mongoDB主要在什么場景下使用? 并介紹spring和momongoDB如何整合: 11
Webservice + httpclient 13
服務器調優 14
Redis解決session共享 14
nginx+tomcat負載均衡的配置(被動說) 14
poi 15
nginx+Tomcat 集群介紹,輪詢,session共享如何實現 15
數據庫篇 16
數據庫的主從同步讀寫分離: 16
主從同庫延遲問題? 16
Sql優化: 16
索引、存儲過程、函數語法及各自的優缺點: 16
分區和分表的區別: 19
防sql注入 20
數據庫連接池: 20
索引概述 20
數據庫三范式: 20
Oracle存儲過程基本語法 存儲過程 20
登錄注冊: 21
使用aop實現mongodb日志存儲,請寫出實現思路和偽代碼(500字) 21
電商系列問題: 22
產品詳情頁(freemarker) 22
靜態化介紹 22
涉及到一個靜態化頁面ajax異步請求的問題 24
如何解決跨域問題? 24
支付: 24
商品管理模塊 24
報表統計 24
統計分析模塊: 24
購物車及訂單支付(redis): 25
每秒處理十萬訂單的支付系統思路 25
Junit單元測試: 25
框架篇: 26
SpringMVC的運行原理是: 26
struts2和springMVC的區別 26
hibernate緩存概述: 26
Hibernate和Mybatis的區別 27
mybatis和ibatis的區別 27
【$與#號的區別】 27
Oracle和Mysql的區別 28
為什么做java的web開發我們會使用struts2,springMVC和spring這樣的框架? 28
下面我要談談spring了。 29
基礎方面: 30
BS和CS的區別以及優缺點 30
五險一金,和上交比例 30
HttpClient 30
事務的隔離級別和傳播特性 31
Ajax 32
Vector & ArrayList的區別 32
運行時異常與一般異常有何異同? 33
HashMap的底層代碼/原理 33
什么是單例多例 35
懶漢式單例模式: 36
餓漢式單例模式 36
線程安全式單例模式: 36
冒泡排序: 37
Sql語句: 37
二叉樹 37
JDK版本特性! 37
接口與抽象類的區別? 38
get和post請求的區別? 38
&和&&的區別。 38
"=="和equals方法的區別? 38
Integer與int的區別 39
面向對象的特征有哪些方面 39
linux中的命令: 39
Jvm相關 39
Jvm優化: 40
多線程介紹、列舉線程池和業務場景: 41
jQuery的10個常用方法,常用選擇器(五大類),ajax常用的屬性 42
Tomcat優化 42
Hibernate優化: 42
序列化和反序列化 43
集群 43
非專業知識: 44
大學情況: 44
上家公司: 45
有沒有上過保險: 45
沒有上五險一金的原因: 45
五險一金的名稱: 45
三個詞形容自己: 45
談談你的對軟件行業發展前景的理解: 45
為什么離職: 45
如何看待你上家公司: 45
你憑什么要這么高的薪資? 45
四年漲薪: 46
跳槽的看法: 46
你的五年規劃 46
談談你對加班的看法: 46
分庫分表: 46
最后你還想有什么了解嗎? 46
?
?
?
X經理,你好!我叫,今天來咱公司面試JAVA開發工程師,之前在北京路都科技有限公司任職,從事這一行已經有4個年頭了。這幾年開發,主要涉及的行業項目包括拍拍貸網貸系統,深圳網上天虹商城系統,碼頭幫物流管理系統,中國電信人力資源管理平臺等。在開發過程中,也用過好些框架,比如:dubbo+zookeeper、springboot、springmvc、spring、Mybatis等框架,熟練掌握框架之間的整合技術。
有時候因為項目需求或是為了開發的高效性,自己也會研究一些技術,使用一些常用的主流java技術,例如:solr全文檢索,redis緩存框架、jms消息隊列,activieMQ異步調用,shiro安全認證框架,activiti工作流等。此外還有一些比較簡單的POI導入導出、highcharts報表,restful、HttpClient遠程調用,powerdesigner建模,spring定時器。前端的技術也研究過一些。如jquery、Ajax、Easyui、BootStrap。
在秒創后期擔任的是高級java工程師,主要的任務是:與項目經理到客戶現場溝通并確認需求,并參與需求文檔的編寫。在設計階段,參與詳細設計,包括框架的一些基類、工具類的封裝,使用powerdesigner完成數據庫的設計。對數據庫設計有一定的經驗,常用的數據庫包括mysql、oracle等關系型數據庫,還有mongodb、redis等非關系型數據庫,并在linux上搭建集群和哨兵和部署項目。編碼過程中,主要負責一些功能模塊的編碼實現,并使用junit做單元測試。項目管理上,與項目經理溝通協調過項目的進度,使用maven對項目進行管理,還幫助其他開發人員解決一些開發過程中的問題。
平時呢還喜歡上一些技術網站比如csdn、開源中國、博客園等這些網站來提高自己的知識量和擴展知識面,畢竟時代在發展,科技在進步。要跟上時代的步伐,避免被淘汰啊!
(在閑暇時間,我也會去訪問一些像CSDN 、開源中國、博客園等這些技術網站,研究一些新的技術點,來增加自己的行業知識。在研究這些技術的同時呢也總結出了一點點經驗比如我研究時會根據內容在云筆記上進行分類,比如將一些關于新技術方面的技術博客的鏈接放在一個文件夾,然后將用到的一些jar包啊js之類的放到一個文件夾,然后通過看這些資料自己寫一個小的demo例子放在一個文件夾下,最后再把自己研究的過程以及心得,還有容易忽略的問題寫在一個總結文檔的文件夾下, 然后與項目組的同事一起分享交流、共同進步,我一直堅信,一個人的能力是有限的但是團隊的能力是無限的,只有這樣才能來給公司創造更大的價值)
(1)項目名稱:優配良品網上商城
- 開發時間:2016/12-至今
- 項目描述:
項目框架: ?
后臺: shiro + Spring + Mybatis + SpringMVC(基于注解) + Bootstrap + ?OScache + Solr + ActiviMQ(消息隊列)?+?dubbo?+?zookeeper?+ ?Echarts +?WebService
前臺: Spring + Mybatis + SpringMVC(基于注解) + FreeMarker + Redis + Solr集群 +?spring定時器 + jQquery
該項目主要有會員注冊及登錄、商品分類展示、商品信息檢索、購物車、生成訂單、訂單查詢、商品排行、反饋留言、商品類別管理、商品品牌展示、商品管理、會員管理、訂單管理、新聞管理等。包括嚴格的權限管理部分,客服登錄系統后可以對客戶所下訂單進行查詢和取消備注等操作,在取消的同時會對客戶所下訂單進行積分,款項返還等操作。
- 開發環境:idea + tomcat7.0 + jdk1.7 +?Maven +?git
- 使用技術:SpringMVC4.0 + Spring3 + Mybatis + dubbo?+ zookeeper?+ ActiviMQ +?Solr + Nginx?+ FreeMarker?+ ECharts??
- 運行環境:linux +?Tomcat?+?Mysql?+ Redis?+ MongoDB?+?JDK1.7
- 本人角色:高級程序員
- 責任描述:在項目中,我參與架構選型與搭建框架,技術攻關,并且負責后臺權限管理、商品管理、報表統計(ECharts)、商品信息檢索引擎搭建(Solr)及部分核心代碼的編寫(大數據量poi導出、shiro安全認證整合)。負責前臺的產品詳情頁(FreeMarker,Redis)、購物車及訂單支付(ActiviMQ +?WebService)、產品評論(MongoDB)、支付成功的短信提醒、服務器搭建(Nginx負載均衡Tomcat7.0集群)等,后期還對項目進行優化和安全測試,在項目中擔任高級工程師,并帶了一個新人。
項目總體采用的是Dubbo+zookeeper的分布式框架,可以理解問拆分成了三個項目,前端項目、服務端項目和緩存項目,前端項目包含頁面、靜態資源和控制層;服務端項目包含業務層和數據庫操作層;緩存項目緩存前端項目和服務端項目公用的數據。用戶請求進入前先通過負載均衡設備進行請求分發,采用nginx的負載均衡實現動靜分離,首先呢我們使用nginx+keepalived雙機熱備的方式來實現負載均衡調度器的高可用性,其中keepalived主要是解決了nginx的單點故障,用來檢測服務器狀態,如果一臺web服務器掛了,keepalived將檢測到,并將有故障的機器剔除掉,然后人工進行修復。通過nginx中server標記下添加location規則信息,將css,js這些動態資源交給nginx來處理,將動態請求通過proxy_pass
介紹下dubbo和zookeeper:
Duboo是一個分布式框架,zookeeper是duboo生產者暴露服務的注冊中心。起一個調度和協調功能,當然注冊中心也可以用redis 或者duboo自帶的Multicast 來注冊。
Duboo 通信方式采用長鏈接方式,所以當spring啟動后鏈接就接通,duboo的消費者和生產者就可以直接調用。性能上高于其他http協議的請求。(httpclient數據屬于短請求,一次請求,一次響應,dubbo通道一旦建立(一旦連接),一直處于聯通狀態)dubbo基于tcp/ip協議的,交互性能非常高,支持匿名傳參,隱式傳參,泛化調用(隱式傳參:不是以括號的形勢傳參,將參數存儲到當前請求里面,到了服務端再從請求里面拿出來,request不能傳參。泛化調用:是指采用一個service接口和一個service實現類來實現多個方法的調用)當時是為了解決單個服務器站點的壓力,將項目拆分成頁面加controller屬于消費者,service+dao屬于生產者,所有生產者暴露的端口都注冊在zookeeper里面。這時候,消費者要調用生產者去zookeeper中取就可以了。所以我們部署了多套生產者,所有的消費者的請求可以由多個生產者去提供,具體由哪個生產者提供可以由zookeeper的配置去決定。如果某個生產者掛掉,zookeeper會加壓力導向其他生產者,當這個生產者恢復狀態的時候。Zookeeper會重新啟用它。因為我們用n的執行,如果想讓單個tomcat執行的action---service—dao 請求又多個tomcat來執行就可以使用?zookeeper+duboo ?這時候一般是一個tomcat里面部署的是jsp+action所有的service接口都注冊到了zookeeper里面,action去zookeeper里面通過duboo去調用哪個?service+dao 的組合。而且service+dao的組合可以配置多套。一套掛了其他的service+dao組合可以繼續使用
dubbo框架的體系結構有5個核心組成部分,分別是提供者provider,它的作用是為消費者提供數據。注冊中心registry,它的作用是用來注冊和發現服務。消費者consumer,它的作用是調用遠程提供者提供的服務。監控中心Monitor用來統計服務的調用次數以及調用時間,還有container用來充當容器來加載,運行服務提供者。新建dubbo-provider.xml配置文件,通過dubbo:application配置提供者應用名,通過dubbo:registry配置注冊中心的地址,通過dubbo:protocol配置協議,以及通過dubbo:service來暴露要發布的接口。
最后我們在需要使用dubbo接口的項目中配置消費者信息,新建dubbo-consumer.xml文件,通過dubbo:application配置消費者應用名,通過dubbo:registry指明要訂閱的注冊中心地址,通過dubbo:reference指定要訂閱的服務接口。除此之外考慮到dubbo的健壯性和性能我們對它的參數項進行的調優。通過在dubbo:protocol中threadpool="fixed" threads="200"來啟用線程池,通過在dubbo:service中connections=5來指定建立長連接的數量。
配置dubbo集群來提高健壯性以及可用性。dubbo默認的集群容錯機制是Failover即失敗自動切換,默認的重試次數為2,可以通過retries調整。dubbo默認的負載均衡策略是Random隨機,可以按權重設置隨機概率。我們在寫完dubbo提供者之后,為了測試接口的正確性,我們會進行直連測試。首先會在提供者端,通過將dubbo:registry的register設置為false,使其只訂閱服務而不注冊現在正在開發的服務;
在消費者端,通過設置dubbo:reference的url,直連提供者進行測試。被動說:
所謂dubbo集群就是將dubbo的提供者部署多份,在不同的機器上或者說在同一臺機器上用不同的端口號。從而在啟動時可以向注冊中心進行注冊,這樣結合dubbo的集群容錯策略以及負載均衡策略可以提高可用性。
dubbo負載均衡策略:隨機,輪詢,最少活躍調用數。
dubbo的集群容錯:失敗自動切換,快速失敗,失敗安全。
dubbo+zookeerper怎樣實現session共享(在消費端):
我們的消費者只有一個模塊,所有的請求首先都是進入這個模塊里面,生產者有多個模塊,session都在消費者這個action里面,所有的請求都是首先進入這個項目里面,我們的生產者有多個模塊。如果有多個消費者的情況下,會存在session共享問題,我們可以將session的id作為key值,用戶對象作為value值存儲到redis里面。當每次發送的請求的時候,拿著瀏覽器的session的id去redis里面取,如果能取到,證明用戶已經存在,如果不能取到,就重新登錄。
為什么用dubbo+zeekeeper?介紹一下?
實現了分布式部署,如果不用的話,傳統的項目就是action>servcie>dao,有三部分的請求,單個兒tomcat,用了dubbo+zookeerper后,分成了消費者和生產者,劃分成不同的模塊,有幾個模塊就有幾個tomcat,大大降低了tomcat的壓力,而且后期隨著訪問量的增加,我們可以不斷的增加生產者,每個單個web服務節點者所受到的壓力明顯降低。
生產者和消費者是怎么交互的?
dubbo首先向zookeerper暴露端口,消費者向它們這邊訂閱服務通過zookeerper,消費者發送請求,zookeerper用來調度,調度的方式有三種,輪循,隨機,把這些請求都拿給生產者,如果其中一個生產者掛掉,如果有新的生產者,會把請求分發給新的生產者。
你看過dubbo底層嗎?
生產者跟消費者之間相當于長連接長請求,傳統的request請求,response響應,請求一次,響應一次,開關一次,dubbo是基于 tcp/ip協議的,其他的源碼閑的時候,基本上通過maven來看過沒有刻意的去了解,因為平時這個業務開發狀況很繁瑣。
zookeeper的作用:
dubbo是把項目實現分離,分為消費端跟服務端,在消費者這邊的配置文件中添上zookeeper地址,讓它連上zookeeper,每個服務端都暴露一個端口給zookeeper,這樣就實現服務端在zookeeper中注冊,消費者發送請求給zookeeper,zookeeper接收請求,zookeeper再分發給這些服務端。
項目安全性怎么解決?
是指攻擊安全還是訪問量過大安全還是數據安全?
如果是攻擊性的話,input框都采用了js驗證,用java代替重復效驗,避免輸入不必要的空格或者sql注入。
如果是訪問的安全的話,頁面做了大量的頁面靜態化,緩存,通常訪問量不會增加服務器造成負擔。
如果是數據安全這一塊的話,系統用的是linux,數據庫的賬號密碼都做了加密處理。
如果是數據遺失或是自然災害,數據庫做了讀寫分離,而且一個主庫,兩個從庫,其中一個從庫做了備份,而且是定時備份。
在登錄過程中,為了防止程序直接登錄,也做了一些驗證碼,包括支付的資金賬戶安全,我們的系統沒有錢,主要是通過超鏈接將錢存儲到網絡支付寶qq賬號,最主要還是支付寶的安全和網民的安全,而且這個賬號只能出不能進。
購物車在redis中是怎么存的?
???我們的購物車,用的是redis 來實現的。 當加入購物車的時候 用戶id作為redis 的key,產品集合作為redis的value。商品存的是 ,商品id 商品名稱,和商品購買數量。
???當加入商品到購物車的時候,首先判斷當前用戶id對應的的產品集合里面是否含有當前產品,有則數量加一。沒有則新添加該商品。
?
問靜態化的商品詳情頁面,如果數據庫價格變動,頁面會重新生成嗎?
?答:不會重新生成。我們的價格和數量是來自redis緩存的。一般我們將商品更新到,redis中,key是表名加id例如 ?sm_product_proid ?, value是產品對象。存儲價格數量。
問購物車的商品會存到redis里面,假如有一件襯衣賣68,有一千萬人將其加入購物車,而第二天老板將數據庫價格改成88了,那購物車里面的價格會變化嗎?
??答:會變化。我的購物車用戶id做為key,value是產品集合,而且默認過期時間是7天,產品集合只存儲產品id ,數量,名稱。 當顯示該商品的時候我需要用產品id 去其他redis 庫里面獲取價格。其他的redis庫里面已經存儲了所有產品id作為key,value是商品 價格數量。當老板變動數據庫價格的時候我只需要更新,單獨存儲的這邊redis產品。
solr搜索引擎:
在整個項目中實現商品搜索功能電商項目中,因為用戶有時候不是多么清楚他所需要的東西的名稱或者商店的名稱,有時候僅僅是只知道他所需要的商品是干嘛用的,又或者是有多個要求,為了滿足用戶的諸多需求更準確的查詢到用戶所需要的商品,所以就用到了Solr搜索引擎
solr是一個基于Lucene的全文搜索服務器,相比Lucene更高效、使用更便捷,在進行模糊匹配的時候,他可以 用來替代數據庫中的like ,從而在匹配準確性以及性能進行大幅度的提高。因為官方的分詞器對中文支持不好所以使用了第三方的IK分詞器來進行分詞。在建立索引的時候我們通過在schema.xml配置IK分詞器來完成中文分詞。從而實現了高亮顯示關鍵詞,分頁,排序,多字段,多條件的高性能搜索。
其實目前有很多優秀的中文分詞組件?:像mmseg4j,IK Analyzer ,Paoding
通過查詢資料發現用?IKAnalyzer比較好IK 比其他中文分詞維護的勤快,和 Solr 集成也相對容易。
其中我們在配IK分詞器的時候,當時遇到了三個問題:
分詞器版本與solr服務版本的匹配:
當時用的solr是4.10.4版本的因為這個版本比較好用,穩定,5.以上的版本bug比較多,配IK分詞器的2012FF_u1版本,開始時用的是u6,然后配完效果出不來,上網查了好多資料,又問了之前加的一個搜索引擎群,才知道是版本問題,u3,u5,u6的都不好用,只有u1的和solr4.10版本的合適,改完之后問題確實解決了
加入分詞器的schema文件要把version改為1.5基本的CRUD操作都可以。
但是搜索卻只能全字匹配或者只能單個字符匹配出結果。這是絕對不能容忍的。定位問題接近了一天,找有經驗的同事給 排查也沒排查出來問題。最后我自己一點一點比對multicore文件夾下的配置文件跟F:\solr\solr-4.6.0\example\solr \collection1這個文件夾下的配置文件的配置區別。當我把schema.xml的version屬性從1.1升到跟collection1下的相同文件的1.5一致之后。重啟服務器,問題解決了!、
分詞器的詞典編碼格式為UTF-8無BOM格式
在從數據中取數據生成索引的時候,因為表中的數據量比較大,防止一次取出所導致內存溢出問題,我采用了分段批量提取的方式進行,
此外我們為了提高solr搜索的性能對其進行了主從配置。
1. 我們solr使用的是solr4.7版本
2. 通過修改schema.xml來添加要進行索引的字段以及增加ik分詞器
3. 通過solrj將數據庫中的數據生成solr中的索引文件,注:solrj是java程序調用solr服務所用的jar包。
4. 通過在solrconfig.xml中配置requestHandler name=“/Replication”來進行主從同步的配置,在從solr中通過masterUrl指明要從哪些主solr服務器中同步數據
我們為了提高用戶體驗度還使用了solr的spellCheck可以用于查詢輸入的自動完成功能auto-complete。他是基于動態代碼方式建立內容,suggestion可通過讀文件方式建立內容,并有點擊率排序。使用facet在查詢結果上根據分類添加了count信息, 然后用戶根據count信息做進一步的查詢, facet的主要好處就是可以任意對搜索條件進行組合, 避免無效搜索, 改善搜索體驗.
購物車實現cookie+redis:
一、未登錄狀態下添加商品到購物車?
在不登陸的情況下也可以添加購物車。把購物車信息寫入cookie。
優點:?
1、不占用服務端存儲空間
2、用戶體驗好。
3、代碼實現簡單。
缺點:?
1、cookie中保存的容量有限。最大4k
2、把購物車信息保存在cookie中,更換設備購物車信息不能同步
實現思路:
(1) 從cookie中獲取商品列表信息(單獨提出來寫成個通用的方法)
(2) 遍歷購物車列表,判斷需要添加的商品在購物車列表是否存在
(3) 商品存在的話,那么取出該商品原來的數量+添加的數量作為該商品現在的數量
(4) 如果商品不存在,那么調用服務,根據傳來的商品id查詢商品數量,設置商品的數量為頁面傳來的數量,取商品的第一張圖片(購物車列表只展示一張圖片)。
(5) 把修改后的購物車列表重新存入到cookie中
(6) 返回邏輯視圖”cartSuccess”
2、展示購物車列表
單擊“去購物車結算按鈕”向服務端發送請求,服務端應該返回邏輯視圖”cart”
請求地址:8090/cart/cart.html
返回邏輯視圖:”cart”也就是購物車列表頁面
3、登錄狀態下購物車列表頁面修改商品數量
購物車列表頁面單擊”+”,”-”會向服務端發送ajax請求。
頁面需要根據調整的數量重新顯示商品總計(已經實現了也就是輸入框的值*價格)和小計(用js,待實現)
服務端要求修改cookie中對應商品的數量
4、未登錄狀態下刪除購物車商品?
(1)從cookie中獲取購物車列表?
(2)遍歷,查找到要刪除的商品?
(3)將該商品從購物車列表移除?
(4)更新后的購物車列表重新寫入cookie?
(5)重定向到購物車列表頁面
二、登錄狀態下購物車功能的實現
功能分析:?
1、購物車數據保存的位置:?
未登錄狀態下,把購物車數據保存到cookie中。?
登錄狀態下,需要把購物車數據保存到服務端。需要永久保存,可以保存到數據 庫中。可以把購物車數據保存到redis中。?
2、redis使用的數據類型?
a) 使用hash數據類型?
b) Hash的key應該是用戶id。Hash中的field是商品id,value可以是把商品信息轉換成json?
3、添加購物車?
登錄狀態下直接把商品數據保存到redis中。?
未登錄狀態保存到cookie中。?
4、如何判斷是否登錄??
a) 從cookie中取token?
b) 取不到未登錄?
c) 取到token,到redis中查詢token是否過期。?
d) 如果過期,未登錄狀態?
e) 沒過期登錄狀態。
實現:
1、登錄攔截器?
幾乎在購物車所有功能執行 都要判斷用戶是否登錄。利用aop思想,應該編寫個攔截器,來判斷用戶是否登錄。登錄的話用戶信息需要存在request域中?
(1) 從cookie中取token?
(2) 判斷token是否存在?
(3) 不存在,說明用于未登錄,放行?
(4) 如果token存在,調用服務,根據token從redis中取用戶信息?
(5) 取不到用戶信息,說明已經過期,放行?
(6) 取到了用戶信息,說明用戶已經登錄,用戶信息存到request中?
(7) 放行?
2、登錄狀態下,商品添加功能實現
向redis中添加購物車
比未登錄多一個登錄判斷而已
3、登錄狀態下,商品列表展示?
分析:?
(1)從cookie中取購物車列表?
(2)判斷用戶是否登錄?
(3)用戶已經登錄的話,則調用服務層,合并cookie中的列表和redis中的列表。存入到redis中。?
(4)同時刪除cookie中的購物車列表?
(5)根據用戶id,調用服務查詢redis中所有的商品,返回購物車列表。?
(6)未登錄狀態還是跟前面一樣?
(7)將列表綁定到參數,返回購物車列表頁面
4、登錄狀態下修改購物車商品數量?
分析?
單擊”+”,”-”修改商品的數量的時候,要求redis中該商品的數量發生改變?
(1) 根據用戶id,商品id從redis中取出對應的商品?
(2) 設置商品的數量?
(3) 該商品更新到redis中?
5、登錄狀態下,刪除購物車商品?
分析?
單擊刪除的時候,刪除redis中該商品。重定向到列表頁面?
(1) 直接用jedisClient的del的方法根據用戶id跟商品id 商品?
(2) 返回成功
redis講解
另外為了保證高并發訪問量大的情況,避免過多的連接一下子查詢到數據庫造成數據庫的崩潰呢,我們采用了redis來實現數據的緩存,這樣呢就會查詢數據的時候,先從redis緩存中查詢數據是否存在,如果緩存中存在我們就直接從緩存中取,這樣可以減少多數據庫的訪問,如果緩存中不存在數據再去數據庫查詢,并且將查詢出來的數據添加到緩存中,因為redis的查詢速度是相當快的(11000次/s),另外為了保證redis服務器的安全通常會在redis.conf中綁定具體的ip地址這樣只有該地址才能訪問redis服務器,并且設置密碼,為了保證redis不會因為占用內存過大而導致系統宕機,通常在將redis當做緩存服務器使用時,設置存儲數據的過期時間,并且通過設置maxmemory【最大內存】和maxmemory-policy【數據清除策略】為allkeys-lru來達到預期的效果。我在項目中通常使用redis來充當緩存服務器來緩存分類列表,品牌列表,熱銷商品,推薦商品以及該商品的關聯商品等等。使用了jedis作為客戶端,并考慮到性能問題使用了jedis連接池。考慮到redis服務器的高可用性,我們做了redis的主從復制,并且通過加入哨兵來使redis主服務器宕機時,從服務器自動轉換為主服務器繼續提供服務。
Redis可能出現的問題:
1:緩存穿透的問題:
一般出現這樣的問題,是因為當我們查詢一條肯定不存在的數據的時候,緩存中沒有,就會透過緩存來查詢數據庫,數據庫也不存在,這樣就不會將值保存在緩存中,最后還是緩存和數據庫中都沒有,如果一直訪問這條數據。我們就對數據庫進行頻繁的查詢,給數據庫帶來壓力;
解決方法:當查詢的時候,如果緩存和數據庫中都沒有,我們就將這個數據以空的形式存放在緩存中,(或者是給一個false的標示)這樣就不用去數據庫就可以知道不存在,減少對數據庫查詢的次數,當我們這個值發生改變的時候,我們在重新進行賦值;
2:并發情況:
當我們大量訪問都是查詢一個緩存中沒有的數據時,這樣就會都去數據庫中進行查詢,可能會造成數據庫的宕機;
解決方法:在查詢的時候,我給他添加了一個同步鎖,只有第一條數據去數據庫中查并且返回到redis中后才能查詢,這是數據庫中已近存在了值,這樣也可以避免;
3:雪崩:
大量數據的訪問時間失效,這樣用戶就會訪問到數據庫,第一臺數據庫崩潰了,訪問就會到第二臺數據庫進行查詢,這樣會導致第二臺的也崩潰;
解決方法,就是設置失效時間時,不要一起失效,或者是設置在訪問量少的時候,或者設置為永遠不失效;
Redis持久化方面:
redis的一大特點就是可以將數據進行持久化,在一定程度上確保了數據的安全性,但不是絕對的;
首先持久化分為rdb(快照持久化)和aof(精細持久化);
快照持久化,是默認開啟的;會自動保存數據,當啟動時會在文件夾中生成dump.rdb文件;存放持久化后的數據;
當然我們也可以設置持久化的頻率,在redis.conf文件中通過save進行設置,默認有三種情況,每秒超過一萬數據或每5分鐘有10條數據的時候再或者每15分鐘有1條記錄,都會執行快照持久化,
當然也可以通過bgsave的方法來手動進行一個快照持久化;(也可以通過ip和端口號就給別人進行手動持久化);
如果頻繁的快照持久化,會降低性能和效率,
但是這樣也出現了一個問題,就是當一分鐘內如果有一萬條數據時,不會提交,但是在下一次提交之前,停電了,這樣就會丟失掉這些數據;
當時想到的解決方法呢就是和(AOF)精細持久化進行一個結合,達到一個秒級的持久化;
這個持久化需要我們手動進行開啟,(注意,AOF開啟之后,之前的數據都會丟失,所以要在一開始使用時就要配置好)開啟的方法就是在配置redis.conf,將appendonly 改為yes;同時還可以更改文件名稱;然后重新啟動服務,這時精細化持久化就啟動好了;
?
在快照持久化的同時,我們進行精細持久化,
比如,我們每隔一個小時進行一次快照持久化,這中間我們添加精細持久化;當55分的時候宕機了,我們還是可以通過RDB和AOF來恢復我們的數據,盡可能減少了損失;等到一個小時以后我們進行了快照持久化,數據就會保存在rdb的文件中,我們就可以將aof的持久化文件重新開始;
?
關于精細持久化也存在三個配置,
always只要發生改變就會發生持久化,這樣是很浪費性能的,不推薦使用(我們的CPU不用干其他工作了,就在這里看著持久化)
everysec每秒進行一次快照持久化;推薦使用這種
no 是不確定,看服務器的使用情況(心情)來定(不安全,不推薦)
我們還可以通過把rdb文件和aof文件復制到另外一個redis服務器上,就可以共享數據;
Redis主從同步:
我們還可以對redis服務器配置主從同步,來減輕redis服務器的壓力,
修改從服務對應的主服務地址(修改時可以直接搜索slaveof關鍵字)
?
這樣訪問時會讀寫分離,查詢的時候會走從服務器,而更新操作的時候走主服務器;
與memcached的區別?(問到再說)
1,redis并不是把所有的數據都存放在內存,還可以將一些長期不使用的值存放在磁盤當中。而memcached只能存放在內存當中的;
2,redis的數據類型比memcached的數據類型豐富,除了string外,還有set,list,sortd set,hash等;
3:redis是可以持久化數據的,在一定程度上避免了數據的丟失,而memcached的安全性較低,一旦遇到停電,宕機的情況數據就會丟失;
4設置過期時間,memchched是在set key的時候直接設定時間(memcache.set(key,value,new Date(50)) 設置為50秒過期),而redis設置過期時間是通過expire來設置的;
如何在項目中使用redis的:
我們的項目采用的是maven來進行管理的,可以通過maven來進行包的依賴管理,保證jar包版本的一致性,所以只需要在pom.xml里添加對應的<dependency>信息即可自動下載jar包,
1:在項目中我們是通過jedis來操作redis的,jedis是java提供的用來操作redis的API
2:我們需要導入一些相關的jar包,目的是為了一些工具類的使用;
3:配置redis.xml文件,
1)我們配置了連接池;設置了最大鏈接數,最大空閑數;然后用靜態語句塊初始化連接池信息,在獲得jedis實例
2)配置Jedis ConnectionFactory,通過IP和端口號來鏈接相對應的redis數據庫;
3)配置了模板,并且在模板中引入了redistemplate的相關jar包;
4:在web.xml文件中引入了?redis.xml文件;
5:我們封裝了相對應的工具類;通過操作模板來調用其中的方法,進行增刪改查;在service層中獲得jedis的實例,通過jedis實例來調用Redis中set類型對應的方法,就可以實現在Redis緩存中放入和取出查詢到的商品的信息了,需要注意的是redis里只能存儲字節,所以相對應的實體類要實現serializable這個接口;
redis常見性能問題和解決方案:
(1) Master最好不要做任何持久化工作,如RDB內存快照和AOF日志文件
(2) 如果數據比較重要,某個Slave開啟AOF備份數據,策略設置為每秒同步一次
(3) 為了主從復制的速度和連接的穩定性,Master和Slave最好在同一個局域網內
(4) 盡量避免在壓力很大的主庫上增加從庫
(5) 主從復制不要用圖狀結構,用單向鏈表結構更為穩定,即:Master <- Slave1 <- Slave2 <- Slave3...
這樣的結構方便解決單點故障問題,實現Slave對Master的替換。如果Master掛了,可以立刻啟用Slave1做Master,其他不變。
還有就是Redis的秒殺場景
使用的是Redis的事務功能,先通過watch()監控一個字段,且這個字段為0,之后對于秒殺數進行判斷。當監控字段小于秒殺數時在IF條件內部內開啟事務通過multi,當有人搶購成功的時候這個監控字段加1,且通過Exec執行事務,事務執行成功則搶購成功,否則搶購失敗。搶購成功之后將相應的用戶也存儲到數據庫中然后進行相應的訂單處理。當監控字段大于秒殺數的時候也就是搶購完畢。無法進行搶購。
緩存的策略是每次數據在增刪改之后就更新,主要是為了避免修改之后緩存更新不及時造成臟數據的出現
mongoDB主要在什么場景下使用? 并介紹spring和momongoDB如何整合:
MongoDB是NoSQL的非關系型數據庫,他的存儲數據可以超過上億條(老版本的mongodb有丟數據的情況,新版本不會有,網上說的),mongodb適合存儲 一些量大表關系較簡單的數據,易于擴展,可以進行分布式文件存儲,適用于大數據量、高并發、弱事務的互聯網應用,
,例如用戶信息,用戶注冊信息,公司注冊信息,留言,評論,操作日志,mongodb還能用分布式文件存儲信息,我們主要用mongodb來存儲我們項目里面的操作日志(銀行的付款轉賬記錄,角色權限的變動日志),我們主要是結合aop來使用的,首先我們來配置一個aop的切面類,再給aop的使用規則,哪個類里面的哪個方法使用當前切面類,利用后置通知類獲取當前方法的操作日志,將操作日志存儲到mongodb,然后進行分類管理查看。利用后置通知傳到數據庫。
從目前阿里云?MongoDB 云數據庫上的用戶看,MongoDB的應用已經滲透到各個領域,比如游戲、物流、電商、內容管理、社交、物聯網、視頻直播等,之所以采用mongodb是因為:
?
以下是幾個實際的應用案例:
游戲場景,使用MongoDB存儲游戲用戶信息,用戶的裝備、積分等直接以內嵌文檔的形式存儲,方便查詢、更新
物流場景,使用MongoDB存儲訂單信息,訂單狀態在運送過程中會不斷更新,以MongoDB內嵌數組的形式來存儲,一次查詢就能將訂單所有的變更讀取出來。
社交場景,使用MongoDB存儲存儲用戶信息,以及用戶發表的朋友圈信息,通過地理位置索引實現附近的人、地點等功能
物聯網場景,使用MongoDB存儲所有接入的智能設備信息,以及設備匯報的日志信息,并對這些信息進行多維度的分析
視頻直播,使用MongoDB存儲用戶信息、禮物信息等
在我們實際項目中:
1. 我們主要用mongodb來存儲我們項目里面的操作日志(銀行的付款轉賬記錄,角色權限的變動日志),我們主要是結合aop來使用的,首先我們來配置一個aop的切面類,再給aop的使用規則,哪個類里面的哪個方法使用當前切面類,利用后置通知類獲取當前方法的操作日志,將操作日志存儲到mongodb,然后進行分類管理查看。利用后置通知傳到數據庫。
2. 我們在項目中使用它來存儲電商產品詳情頁的評論信息(評論id,商品id,標題,評分,內容,評論人信息,評論的發布時間,評論標簽組)并且為了提高可用性和高并發用了3臺服務器做了mongodb的副本集,其中一臺作為主節點,另外兩臺作為副本節點,這樣在任何一臺mongodb服務器宕機時就會自動進行故障轉移,不會影響應用程序對mongodb的操作,為了減輕主節點的讀寫壓力過大的問題,我還對mongodb副本集做了讀寫分離,使寫操作在主節點進行,讀取操作在副本節點進行。為了控制 留言,我們留言的界面設置在了訂單狀態,只有狀態為5,也就是交易成功收貨后才能評論,并在評論成功后將訂單狀態改為6
【補充:如果問到副本集是怎么搭建的,就說我們有專門的運維人員來負責搭建,我只負責用Java程序去進行操作】
MongoDB 副本集(Replica Set)是有自動故障恢復功能的主從集群,有一個Primary節點和一個或多個Secondary節點組成。
在副本集的環境中,要是所有的Secondary都宕機了,只剩下Primary。最后Primary會變成Secondary,不能提供服務。
副本集的同步和主從同步一樣,都是異步同步的過程,不同的是副本集有個自動故障轉移的功能。其原理是:slave端從primary端獲取日志,然后在自己身上完全順序的執行日志所記錄的各種操作(該日志是不記錄查詢操作的)
Spring和mongodb整合步驟:
1. 添加依賴的jar包
要想整合Spring和Mongodb必須下載相應的jar,這里主要是用到兩種jar一種是spring-data-document和spring-data-commons兩種類型的jar
2.定義實體類
3.Spring配置
新建application.xml配置文件
這個必須要的引入mongodb標簽
xmlns:mongo="http://www.springframework.org/schema/data/mongo"在配置文件中加入鏈接mongodb客服端
<mongo:mongo host="localhost" port="27017"> ??</mongo:mongo>注入mogondb的bean對象?
??<bean id="mongoTemplate" class="org.springframework.data.document.mongodb.MongoTemp"> ?<constructor-arg ref="mongo"/> ?<constructor-arg name="databaseName" value="db"/> ?<constructor-arg name="defaultCollectionName" value="person" /> ?</bean> ?<bean id="personRepository" class="com.mongo.repository.PersonRepository"> ?<property name="mongoTemplate" ref="mongoTemplate"></property> ?</bean> ?4.然后編寫操作mongodb增刪查改的接口
? ?public interface AbstractRepository { ?public void insert(Person person); ?public Person findOne(String id); ?public List<Person> findAll(); ?public List<Person> findByRegex(String regex); ?public void removeOne(String id); ?public void removeAll(); ?public void findAndModify(String id); ?} ?再寫對應接口的實現類:
??import java.util.List; ?import java.util.regex.Pattern; ?????import org.springframework.data.document.mongodb.MongoTemplate; ?import org.springframework.data.document.mongodb.query.Criteria; ?import org.springframework.data.document.mongodb.query.Query; ?import org.springframework.data.document.mongodb.query.Update; ?import com.mongo.entity.Person; ?import com.mongo.intf.AbstractRepository; ?public class PersonRepository implements AbstractRepository{ ?private MongoTemplate mongoTemplate; ?@Override ?public List<Person> findAll() { ?return getMongoTemplate().find(new Query(), Person.class); ?} ?@Override ?public void findAndModify(String id) { ??getMongoTemplate().updateFirst(new Query(Criteria.where("id").is(id)), new Update().inc("age", 3));} ?@Override ?public List<Person> findByRegex(String regex) { ?Pattern pattern = Pattern.compile(regex,Pattern.CASE_INSENSITIVE); ?Criteria criteria = new Criteria("name").regex(pattern.toString()); ???????????return getMongoTemplate().find(new Query(criteria), Person.class); ???????} ?@Override ?public Person findOne(String id) { ?return getMongoTemplate().findOne(new Query(Criteria.where("id").is(id)), Person.class); ?} ?@Override ?public void insert(Person person) { ?getMongoTemplate().insert(person); ?} ?@Override ?public void removeAll() { ?List<Person> list = this.findAll(); ?if(list != null){ ?for(Person person : list){ ?getMongoTemplate().remove(person); ?} ?} ?} ?@Override ?public void removeOne(String id){ ?Criteria criteria = Criteria.where("id").in(id); ?if(criteria == null){ ?Query query = new Query(criteria); ?if(query != null && getMongoTemplate().findOne(query, Person.class) != null) ?getMongoTemplate().remove(getMongoTemplate().findOne(query, Person.class)); ???????????}} ?public MongoTemplate getMongoTemplate() { ?return mongoTemplate; ?} ?public void setMongoTemplate(MongoTemplate mongoTemplate) { ?this.mongoTemplate = mongoTemplate; ?}}5.實現類注入到service層調用
?
Webservice?+?httpclient
我在做個人信息的時候涉及到了給用戶下發短信的一個業務,當時調用的是一家公司的webservice短信接口,webservice有三種實現框架CXF,Xfire,axis2,用的最多的也是CXF因為他是可以和spring進行整合的,為了保證webservice的安全性我們采用了基于WS-Security標準的安全驗證(使用CXF回調函數,WS-Security主要涉及三個反面,身份驗證,簽名和加密,通過<jaxws:outinterceptors>攔截器的方式設置用戶名密碼,簽名就主要防止消息在傳輸過程中被進行攻擊,加密就是對soap包加密)。首先通過wsdl2java根據發布的webservice服務端地址的wsdl生成客戶端調用的中間橋梁java類,將生成的java類拷貝到客戶端項目中,配置spring-client.xml文件,通過jaxws:client定義一個bean,并通過address屬性指明要訪問的webservice的服務地址,通過serviceClass指明充當中間橋梁的服務類,之后獲取該bean,就可以通過它結合服務端給我們提供的開發文檔來訪問發布的webservice接口中的方法。
HttpClient---顧名思義,這是http協議的一個客戶端封裝包,它將http協議的通信規范進行了包裝,提供了一些通用的API來進行基于http協議的通信的編程,基本上我們在瀏覽器上進行的訪問http網站的操作(瀏覽器本身就是一個富客戶端),都可以使用httpClient提供的API來代替。在編程中我們一般是基于它編程來代替“人”訪問http網站的操作。
WebSevice---是基于SOAP協議,它的目的是:使用開放的XML(標準通用標記語言下的一個子集)標準,使得運行在不同機器上的不同應用無須借助附加的、專門的第三方軟件或硬件, 就可相互交換數據或集成。它的核心是解決不同應用間的數據交換,因為SOAP使用XML消息調用遠程方法,這樣web services可以通過HTTP協議的post和get方法與遠程機器交互。 ?
http和soap協議的區別。http速度效率更高,soap能處理復雜的數據。
WebService和httpcllient 區別。:(這個必背)
HttpClient對認證機制提供了全面的支持。用戶認證過程需要一組用戶名/密碼進行認證用戶身份。HttpClient附帶多個AuthScheme的實現。 ?AuthScheme接口表示一個抽象的面向挑戰-應答的認證機制。解析和處理目標服務器發送的挑戰并且對受保護資源的請求做出應答。
WebService一般通過iis進行匿名調用。這種方式不安全。我們可以使用CXF的攔截器通過自定義的Interceptor,可以改變請求和響應的一些消息處理,其中最基本的原理還是一個動態代理。設置入攔截器。來驗證用戶的賬號和密碼。
服務端的配置
首先要導入cxf的jar包
然后在web.xml中配置cxf的webservice服務
發布一個接口并添加@WebService注解,同時也要在實現類上添加@WebService注解 并說明實現了哪個接口,之后在spring-webservice.xml中發布webService服務
通過jaxws:endpoint配置implementor和address來表明實現服務的類,以及發布的地址,
最后在瀏覽器中輸入相關的webservice地址?wsdl來驗證服務是否發布成 功。
webservice客戶端的配置
首先通過wsdl2java根據發布的webservice服務端地址的wsdl生成客戶端調用的中間橋梁java類,將生成的java類拷貝到客戶端項目中,
配置spring-client.xml文件,通過jaxws:client定義一個bean,并通過address屬性指明要訪問的webservice的服務地址,通過serviceClass指明充當中間橋梁的服務類,
之后獲取該bean,就可以通過它來訪問發布的webservice接口中的方法。
?
WebService安全性淺談
第一、禁止匿名訪問,對WebService進行認證,這步主要是通過操作系統的安全機制來實現的,也就是只有滿足一定要求的帳號才能訪問到服務器,才能訪問IIS;
第二、在第一種方法的基礎上對WebService里的方法進行加密,比如有個WebService方法是根據顧客ID獲取數據庫中的顧客的詳細資料為GetCustomerDetailByCustomerID(string custID);如果只提供一個參數,則很容易被別人訪問調用,因此我們對這個方法進行加密GetCustomerDetailByCustomerID(string scustID,string custID,ecustID);這樣,只有提供正確的scustID與ecustID這二個參數才能成功調用這個方法,而對于這二個參數scustID與ecustID,則可以通過加密方法生成一個字符串,也可以寫一個加密的工具類。
?
服務器調優
其實每個公司都關心的問題,根據不同的情況去采用不同的解決方法,像之前我們在做項目時,考慮到服務器性能的問題,最開始想到使用縱向擴展,來增加硬件的配置提高其性能,但這樣做比較耗費資金,而且服務器內存空間也是有限的;所以后來就使用橫向擴展來達到這一目的
當時我們使用nginx+tomcat進行負載均衡,在我們不進行負載均衡之前,那所有的請求都由一臺tomcat進行處理,這樣會使我們的tomcat所承受的壓力增大,而我們進行負載均衡之后,同樣數量的請求經過nginx將其分發到多臺tomcat進行處理,從而降低每臺tomcat所承受的壓力,而且當其中一臺機器宕機時,其他機器還可以繼續提供服務,保證服務不間斷。
Redis解決session共享
當時項目在部署完成后,遇到一個問題,用戶登錄輸入驗證碼的時候,明明驗證碼輸入的正確,但總是提醒說驗證碼不正確從而不能正常登錄,經過分析后發現有可能第一次請求被發送到t1上,那么放在session中的驗證碼就被放到了t1上,當用戶輸入驗證碼點擊登錄時,新發送的請求有可能被發送到t2上面,這樣在進行對比時就肯定會不一致從而提示驗證碼輸入錯誤,后來我就考慮使用ip_hash這種負載均衡策略來代替默認的輪詢策略,雖然解決了驗證碼錯誤問題,但是在后續的測試中發現如果用戶在使用過程中突然一臺服務器宕機了,那么因為session在這臺服務器上存儲著,所以就會提示用戶重新登錄,這樣使用戶的體驗度非常不好,最后就通過將session信息保存到redis服務器中從而在多臺web服務器中實現session共享,這樣就解決了上面所說的那些問題。
nginx+tomcat負載均衡的配置(被動說)?
1.首先在nginx的conf文件夾下找到nginx.conf文件
2.其次在該文件中的http標記下添加upstream?backend并配置要轉發到的多臺tomcat及其端口號,設置負載均衡策略(當時我采用的是基于weight的負載均衡策略)
4.最后再在各臺tomcat中找到server.xml配置文件,更改Connector標簽中的端口號保持和nginx配置文件中tomcat的端口號一致即可。
其實在這幾年做項目中,我感覺難的點就是性能優化以及安全方面的問題,我自己也進行了一些研究和總結,比如sql優化,緩存技術。
當時數據庫用了3臺mysql采用讀寫分離來同步。前端網站和后端運營中心是兩個獨立的項目。兩個項目指向同一數據庫。
MySQL的讀寫分離的基本原理:
讓master(主數據庫)來響應事務性操作,讓slave(從數據庫)來響應select非事務性操作,然后再采用主從復制來把master上的事務性操作同步到slave數據庫中。
poi
POI主要是對office文件的讀寫控制,通過程序解析文件中的內容,或者將數據內容生成文件導出,主要就是當我們通過條件查詢出相關的數據,這時候點擊導出按鈕,把相關查詢參數傳到action層,調用service層和dao層查詢出相關的數據信息,返回給action層,然后調用POI的API方法,通過HSSFWorkBook創建工作薄,然后創建sheet頁,創建行。通過行創建單元格。最后通過cell的setValue方法給單元格賦值。當然,可以根據需要通過Style來實現設置單元格格式。包括邊框、背景色高亮等。做數據導出的時候,因為2003版本的excel,最大行數是65535行,所以如果數據比較多的時候,就做多個sheet頁。
導入數據,當我們點擊導出按鈕時,首先彈出一個dialog框,選擇對應的excel文件,上傳到文件服務器,然后點擊開始導入按鈕,調用action層,使用poi對excel進行解析,首先通過上傳文件的路徑,從服務器上獲得這個文件,考慮到客戶上傳的excel文件版本不好統一,所以我們通過上傳的excel后綴判斷屬于03版本,或者07版本,因此來判斷使用的解析類HSSFWORKBOOK,XSSFWORKBOOK,來獲得對應的工作簿解決這個問題,再通過getNumberOfSheets獲得所有的sheet頁,循環sheet頁,循環里面的行,循環里面的格將獲得的值放入對象,對象放入集合,傳到service層,再傳到數據庫
nginx+Tomcat 集群介紹,輪詢,session共享如何實現
(反向代理的解釋:反向代理(Reverse Proxy)方式是指以代理服務器來接受internet上的連接請求,然后將請求轉發給內部網絡上的服務器,并將從服務器上得到的結果返回給internet上請求連接的客戶端,此時代理服務器對外就表現為一個服務器。)
重點兩部分:一、負載均衡二、tomcat集群
所謂tomcat集群,就是可以向外提供并行服務的多臺機器,任何一臺服務器宕機,其它服務器可以替代它向外提供服務,而不影響用戶訪問。
nginx是一個常用的反向代理服務,可自定義模塊,實現請求轉發及負載均衡(根具體采用策略有關)。為了tomcat集群的高可用性,還需要實現nginx的雙機熱備。
一,如果僅是對外提供一個頁面訪問,不用區分單一用戶(不區分每個訪問session,不涉及用戶權限,用戶資料等內容),僅僅配置nginx負載均衡策略即可。
?nginx負載均衡策略主要分一下四種:
1)、輪詢(默認)
每個請求按時間順序逐一分配到不同的后端服務器,如果后端服務器宕機,能自動剔除。
2)、ip_hash 每個請求按訪問ip的hash結果分配,這樣每個訪客固定訪問一個后端服務器。
3)、fair 按后端服務器的響應時間來分配請求,響應時間短的優先分配。
4)、url_hash 按訪問url的hash結果來分配請求,使每個url定向到同一個后端服務器,后端服務器為緩存時比較有效。
二,如果涉及到用戶session,做一些鑒權緩存、存放臨時信息時,就必須做tomcat的session共享。
目前可參考到的session共享方式主要分為兩種。
1)利用tomcat自帶的組播機制,實現session復制。
對tomcat及應用的若干配置文件進行配置即可實現,網上有很多資料可參考。但這種方式些弊端,看過一些資料,不建議用session復制的方式。在實際使用過程中,也發現有存在session莫名失蹤的現象。
2)利用第三方機制存儲session。
比較常見的是tomcat集成memcached服務器來存儲session。實際項目中,我們采用過利用redis實現session存儲,redis高效的存取性能為高效的訪問提供了保障,但是目前redis的集群功能似乎沒有發布,如何解決redis的單點故障需要研究。
?小結:是否實現session共享與nginx的負載策略有很大關系。比如采用輪詢策略,就必須實現session共享,因為客戶端會訪問到每臺服務器;而如果采用ip_hash策略,就可以不用考慮session共享的問題了,但是ip_hash有些缺陷使它不能隨便使用(如多臺pc使用同一個外網ip)。
最近發現一個nginx的粘連模塊(類似session粘連),可以看做nginx的第5種均衡策略。它利用客戶端cookie,對其寫入一個route參數,每次訪問可以根據route的值,固定的訪問一臺服務器,解決的session共享的問題
四、總結
誰能想到實現一個高性能的負載均衡集群會如此簡單。Nginx的功能如此強大,配置卻如此簡單,我們還有什么理由拒絕它呢?這比我們動不動就十多萬至幾十萬人民幣的F5 BIG-IP、NetScaler等硬件負載均衡交換機廉價了不知多少。此外,大家別忘了Nginx不僅僅是一個反向代理服務器,它本身也可以托管網站,作為Web服務器,進行Http服務處理。
數據庫篇
數據庫的主從同步讀寫分離:
當時我們給數據庫也做了優化,配置了主從同步和通過mycat進行讀寫分離;
MYSQL主從同步架構是目前使用最多的數據庫架構之一,尤其是負載比較大的網站。
原理是:從服務器的IO線程到主服務器獲取二進制日志,并在本地保存為中繼日志,然后通過SQL線程來在從庫上執行中繼日志中的內容,從而使從庫和主庫保持一致。配置好主從同步之后我們還通過mycat來配置了讀寫分離;讀寫分離:數據分布,負載均衡,高可用性和容錯,備份.
使用:就是我們搭建兩臺數據庫服務器,一臺作為主服務器master,一臺作為從服務器slave,
1.要更改mysql數據庫中的my-defult.ini文件,將文件名改為my.ini,然后更改里面的配置,包括數據庫路徑,端口號。編碼集、log-bin文件名,開放的數據庫等信息。
2.在主數據庫,新增一個用戶,并指定replication權限
3.在主數據庫里面運行show?master?status;記下file和position字段對應的參數。
4.在從庫設置它的master
5.?stop?slave;?#停止服務再輸入#指定用戶名密碼,將里面的master_log_file和master_log_pos對應剛才show?master?status記下的參數
6.開啟服務,start?slave?
7.?通過show?slave?status來查看同步的狀態
這樣就實現了主從同步。
?
主從同庫延遲問題?
1.主庫和同庫盡可能在同一個局域網內,交換機網卡采用千兆網卡。
2.主數據庫更新完成之后產生的操作日志不是瞬間產生的,我們可以通過設置sync_binlog=1,?讓它瞬間產生磁盤日志,(n=1指主數據庫只要操作一次,就產生一次磁盤日志,n=10,就是操作10次,產生一次),從數據庫可以依賴磁盤日志,瞬間產生同步,可以達到減低延遲的效果。
3.?設置主庫和從庫讀取日志失敗之后,及時重新建立連接,延遲縮短。
Sql優化:
避免在?where 子句中對有索引的字段進行運算,這會導致索引失效,從而進行全表掃描。外鍵必須加索引
在?where 及?order by 涉及的列上建立索引,要盡量避免全表掃描。
在設計表時要避免表中字段出現null的情況,通常要為其設置默認值。
避免在查找時放棄使用索引而進行全表掃描。
Sql語句字段盡量大寫。
SELECT語句中避免使用'*’,只查詢需要返回的字段?,這樣可以減少oracle解析sql語句的時間。
索引、存儲過程、函數語法及各自的優缺點:
索引
索引是表的索引目錄,在查找內容之前先查目錄中查找索引位置,從而快速定位查詢數據;
a、普通索引
# 創建表 + 索引
create table in1(nid int not null auto_increment primary key,name varchar(32) not null,email varchar(64) not null,extra text,index ix_name (name))# 創建索引
create index index_name on table_name(column_name)# 刪除索引
drop index_name on table_name;# 查看索引
show index from table_name;#注意:對于創建索引時如果是BLOB 和 TEXT 類型,必須指定length。
create index ix_extra on in1(extra(32));如何正確使用索引
# like '%xx',避免%_寫在開頭
select * from tb1 where name like '%n';?
存儲過程:
存儲過程是一個SQL語句集合,類似函數,需要主動調用。
1創建存儲過程
# 無參數存儲過程
# 創建存儲過程
delimiter //create procedure p1()BEGINselect * from t1;END//delimiter ;# 執行存儲過程
call p1()
都說了類似函數,那必須得可以接收參數,且參數有三類:
in ?????????僅用于傳入參數用
out ???????僅用于返回值用
inout ????既可以傳入又可以當作返回值
# 有參數存儲過程
# 創建存儲過程
delimiter \\ ???# 結尾分號改為\\
create procedure p1(in i1 int,in i2 int,inout i3 int,out r1 int) BEGINDECLARE temp1 int; ???# 創建申明局部變量DECLARE temp2 int default 0;set temp1 = 1;set r1 = i1 + i2 + temp1 + temp2;set i3 = i3 + 100;end\\delimiter ;
# 執行存儲過程
DECLARE @t1 INT default 3;DECLARE @t2 INT;CALL p1 (1, 2 ,@t1, @t2);SELECT @t1,@t2; ?函數
函數,與存儲過程不同的是有return值。
1自定義函數
delimiter \\create function f1(i1 int,i2 int)returns intBEGINdeclare num int;set num = i1 + i2;return(num);END \\delimiter ; ?索引優缺點:
優點:??1.創建唯一索引,保證數據庫表中每一行數據的唯一性
2.大大加快數據的檢索速度,這也是創建索引的最主要原因
3.減少磁盤IO(像字典一樣可以直接定位)
缺點: ??1.創建索引和維護索引要耗費時間,這種時間隨著數據量的增加而增加
2.索引需要占用額外的物理空間
3.當對表中的數據進行增加、刪除和修改的時候,索引也要動態維護,降低了數據的維護速度 ?
存儲過程?優缺點
優點:??1.簡化了復雜的業務邏輯,根據需要可以重復使用
2.屏蔽了底層細節,不暴露表結構即可完成操作
3.降低網絡通信量,多條語句可以封裝成一個存儲過程來執行
4.設置訪問權限來提高安全性
5.提高執行效率,因為它是預編譯的以及存儲在數據庫中
缺點;??1.可移植性差,相同的存儲過程并不能跨多個數據庫操作
2.大量使用存儲過程后,首先會造成服務器壓力大,而且維護難度頁逐漸增加 ?
函數?優缺點:
優點:??1.函數允許標準組件式編程,提高了SQL語句的重用性、共享性和可移植性。
2.函數可以被作為一種安全機制來利用。
3.函數能夠實現較快的執行速度,能夠減少網絡流量。
缺點:??1.函數的編寫比單句SQL語句復雜。
2.在編寫函數時,需要創建這些數據庫對象的權限。
分區和分表的區別:
分表就是按照一定的規則把一張大表給分成多張小表,在數據庫中看到的是幾張不同的表,在硬盤上也是不同的文件,因此在進行增刪改查操作的時候要根據同樣的規則去找到具體操作的表。
分區是按照一定的規則把一張大表分成不同的區塊,在數據庫中看到的還是一張表,只不過在硬盤上存儲的時候分成了幾個不同的文件。這樣在進行增刪改查操作的時候就像操作一張普通的表一樣簡單方便。
他們都是為了處理單張表的大數據量問題,都能提高性能。
防sql注入
針對防sql注入,我們通常是這樣做的:
?????首先在前臺頁面對用戶輸入信息進行js驗證,對一些特殊字符進行屏蔽, ???比如:or ,單引號,--,= ,還有就是限制用戶名輸入的長度,我們一般將其限制在6---13位。另外,對于用戶的敏感信息我們進行Md5加密,還有,為了增加用戶體驗度和用戶友好度,為了不使用戶看到一些詳細的異常信息我們會進行錯誤信息頁面的定制,像404,500錯誤。另一個我層面講,這樣做也是為了保護我們的一些重要信息。此外,我們會給特定的人分配定定的權限,而不是給其分配管理員權限!
數據庫連接池:
數據庫連接池的優點運行原理:
在我們不使用數據庫連接池的時候,每次訪問數據庫都需要創建連接,
使用完成之后需要釋放關閉連接,而這樣是很耗費資源的。當我們使用
數據庫連接池的時候,在tomcat啟動的時候就創建了指定數量的連接,
之后當我們程序使用的時候就直接從連接池里面取,而不需要創建,同理,
當我們使用完的時候也不需要關閉連接,而是將連接返回到連接池中,供其他請求繼續使用。DBCP:比較穩定。C3P0: 性能比較高。
?
數據庫三范式:
??第一范式(1NF):強調的是列的原子性,即列不能夠再分成其他幾列。
??第二范式(2NF): 首先是滿足第一范式,另外包含兩部分內容,一是表必須有一個主鍵,二是沒有包含在主鍵中的列必須完全依賴于主鍵,而不是部分依賴。
??第三范式(3NF): 首先滿足第二范式,非主鍵列直接依賴于主鍵,消除傳遞依賴。
?
Oracle存儲過程基本語法?存儲過程?
Oracle的存儲過程:
存儲過程就是封裝一些sql的集合,也就是一條條的sql語句,過程的優點就是簡化了SQL命令加上他是預編譯的,所以他的執行效率相對較高。再者如果不調用過程的話就會和數據庫發生多次交互,調用過程只需要傳達一個命令多有的那些執行業務邏輯都在數據庫端執行,所以它降低了網絡的通信量,其次存儲過程大大提高了安全性,這就是優點。
缺點就是不同的數據庫對過程支持的關鍵字都是不一樣的,所以它的移植性是非常差的,再者他的維護難度也比較大,因為他沒有專業的調試和維護工具,所以維護起來比較麻煩,這就是存儲過程的基本概述。
行1: create or replace procedure 是一個SQL語句通知Oracle數據庫去創建一個叫做skeleton存儲過程, 如果存在就覆蓋它;
行2: IS關鍵詞表明后面將跟隨一個PL/SQL體。
行3: begin關鍵詞表明PL/SQL體的開始。
行4: null pl/sql語句表明什么事都不做,這句不能刪去,因為PL/SQL體中至少需要有一句;
行5: END關鍵詞表明PL/SQL體的結束
登錄注冊:
關于登錄,我們當時考慮到以后用戶量增大情況,我們隊數據庫中的表進行了分表。從來來提高查詢的效率,這個分表的方法可以是時間,id等;
用戶注冊,首先需要用戶手機號的驗證,這時用戶填寫手機號后,我們會先將用戶手機號和驗證碼保存在緩存中,并且是要設置獲過期時間,一般為15分鐘,然后調用短信接口將隨機生成的驗證碼發送給用戶,當用戶輸入驗證碼點擊提交時,我們會根據用戶手機號去緩存中進行查詢,如果驗證碼正確,才能跳轉到填寫賬號信息頁面?,進行賬號的填寫;這是用戶填寫用戶名時,在失去焦點是我們會進行一個驗證。查看數據庫中是否存在這個用戶名,如果存在就提示該賬戶以存在,請更換用戶名,還有兩次的密碼都必須一致可以,
登錄時用戶可以根據手機號,用戶名,郵箱進行登錄,首先因為這些都是具有唯一性的,不會存在重復的情況,所以我們都可用來登錄;只要有一個條件錯誤,我們就會告訴用戶,用戶名和密碼不匹配,并且提醒用戶是忘記密碼或者忘記用戶名,然后可以進行找回;
除了正常的登錄注冊外,當時我們還想到了單賬號登錄這個功能;具體原理是:當用戶登錄之后,我們會以當前用戶信息(唯一標示id,code等)為鍵,而sessionid為值,來存放在緩存中,只要瀏覽器不關閉,或者不跨瀏覽器和電腦,sessionid是相同的;
除此之外,我們還會以sessionid為鍵,用戶信息(全部信息)為值也存放在redis中;這個是為了攔截器的使用,springmvc的攔截器是在每次進入控制層之前執行一次方法,在這個方法中,我們通過session去redis中查,如果存在對象,說明是在登錄狀態,我們就會讓其執行方法(return true ),如果不存在,還要走一些我們需要攔截的方法,我們就會讓其返回到登錄頁面(return false);
如果現在在別的地方也登錄同一賬戶,我們首先會先獲取當前sessionid ,第二我們會通過用戶信息(唯一標示id,code等)去redis中獲取以前存放的sessionid,如果兩次sessionid相同說明在同一瀏覽器,如果不相同,說明在不同的瀏覽器;我們就會刪除掉原來在redis中存放的數據,將新的數據存放進去,這樣原來瀏覽器在執行其他操作的時候就會被攔截到登錄頁面。
使用aop實現mongodb日志存儲,請寫出實現思路和偽代碼(500字)
1).在Spring中引入AOP功能
<dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>${srping.version}</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.7.2</version></dependency>2).實現Web層的日志切面
1. 實現AOP的切面主要有以下幾個要素:
●?使用 @Aspect 注解將一個java類定義為切面類。
●?使用 @Pointcut 定義一個切入點,可以是一個規則表達式,比如下例中某個package下的所有函數,也可以是一個注解等。
●?根據需要在切入點不同位置的切入內容
●?使用 @Before 在切入點開始處切入內容
●?使用 @After 在切入點結尾處切入內容
●?使用 @AfterReturning 在切入點return內容之后切入內容(可以用來對處理返回值做一些加工處理)
●?使用 @Around 在切入點前后切入內容,并自己控制何時執行切入點自身的內容
●?使用 @AfterThrowing 用來處理當切入內容部分拋出異常之后的處理邏輯
?
電商系列問題:
項目二:深圳網上天虹商城(?2015/10 - 2016/9)[開發團隊:10人]
?
責任描述:參與設計數據庫以及框架的選型。后期負責商品模塊(商品類別管理(Redis),商品品牌以及商品的詳情頁(freemarker靜態化)),報表的統計(highcharts,poi),用戶管理和相關接口(webService:CXF)等模塊的開發,最后配合測試部門進行相應模塊的調整。
?
項目簡介:不同于市場上大眾化的電商系統平臺,天虹商城實施“聚焦”戰略,采用實體店與網上商城相結合,城鄉互通的方式,提供了簡易的操作,豐富的功能和完善的權限管理,涉及水果蔬菜,海鮮及日用食品銷售的電子商務平臺。項目分為前臺訪問系統和后臺管理系統,采用dubbo+zookeeper分布式框架,使用Lucene來進行商品搜索,使用highcharts實現報表的統計,頁面采用了FreeMarker模塊技術。后臺模塊采用SpringMVC+MyBatis框架,前臺與后臺相交互,前臺頁面使用jQuery展示并使用Oscache緩存減少與數據庫訪問。后臺管理員對產品類別和產品進行管理后,前臺用戶通過購物車進行網上選購產品,并生成訂單,期間可以修改訂單信息,再由后臺根據產品的發貨情況對訂單進行狀態設置。
功能模塊:前臺:個人中心、產品搜索、商品留言、積分兌換、支付方式、商品促銷、登錄、購物車、會員中心等模塊。
????后臺:商品管理、用戶管理、公告管理、留言管理、訂單管理、促銷管理、報表統計、物流管理、供貨商維護、權限管理等模塊。
在做項目時主要考慮到以下這幾個問題:
第一就是互聯網項目,訪問量大,高并發,單個數據庫壓力較大。
第二就是網站的搶購,秒殺后續可能會上,架構自身要能接受這樣的瞬間遞增訪問量。
第三就是大量的留言日志,包括后續用戶注冊量達到千萬級,單一數據庫表性能會降低。
產品詳情頁(freemarker)
對于產品詳情頁來說因為用戶的訪問量比較大,所以考慮到性能,我們會通過spring的定時器結合freemarker模板引擎將產品信息進行靜態化,這樣就可以防止因為訪問頻繁而造成的服務器壓力過大問題。然后用查到數據庫的商品詳情數據調用freemaker的封裝方法就可以了生成靜態頁面,只需要傳遞3各參數就可以了,一模板名稱,二要展示的數據對象,三?輸出頁面的位置?freemaker,并且我們會根據產品的分類和熱銷程度等信息采用不同的更新策略,對于需要及時更新我們會將spring定時器改為每30分鐘就執行一次,對于不太重要的我們會在每天晚上凌晨2點鐘對產品信息進行重新發布。也可以當運營中心添加商品,可以在業務邏輯層增加數據到數據庫之后,通過AOP后置通知傳遞商品ID觸發網站的生成詳情頁的方法生成詳情頁。
靜態化介紹
我們在靜態化的時候,主要涉及到網頁的單頁頁面,訪問量較大,更新少,我們可以將該頁面用freemaker(velocity)生成靜態化頁面,這個時候訪問的時候,只需要訪問靜態化頁面,不需要訪問數據庫,大大降低了數據庫的壓力,像我們招聘網的公司詳情,崗位詳情(app里面的商品詳情,還有app里面的新聞詳情,都用freemaker生成的靜態化頁面),這個生成的靜態化頁面當時涉及到一個同步問題,數據庫的數據已經更新,靜態化沒有更新,我們的處理方式,當新增或修改一條記錄到數據庫的同時,在業務邏輯層連著調用freemaker封裝方法,重新生成靜態化頁面,將當前記錄的表名+id作為生成靜態化頁面的名稱,以此來防止靜態化頁面相互覆蓋,我們的freemaker模板工具里封裝當時是傳三個參數,第一,傳遞模板名稱,第二,傳遞當前的數據對象,第三,指?定生成的靜態化頁面存儲的位置。
Freemarker靜態化空值問題如何解決?
空值處理運算符
FreeMarker的變量必須賦值,否則就會拋出異常。而對于FreeMarker來說,null值和不存在的變量是完全一樣的,因為FreeMarker無法理解null值。
FreeMarker提供兩個運算符來避免空值:
1. !: 指定缺失變量的默認值;
2. ??:判斷變量是否存在。
!運算符有兩種用法:variable!或variable!defaultValue。第一種用法不給變量指定默認值,表明默認值是空字符串、長度為0的集合、或長度為0的Map對象。
使用!運算符指定默認值并不要求默認值的類型和變量類型相同。
| 測試空值處理: <#-- ${sss} 沒有定義這個變量,會報異常! --> ${sss!} <#--沒有定義這個變量,默認值是空字符串! --> ${sss!"abc"} <#--沒有定義這個變量,默認值是字符串abc! --> |
?
??運算符返回布爾值,如:variable??,如果變量存在,返回true,否則返回false。
?
Freemarker靜態化比jsp的好處?
1、類加載沒有 PermGen 問題
如果你已經開發Java Web應用程序一段時間,那么對于 JVM 的 PermGen 問題可能并不陌生。由于 FreeMarker 模板不編譯成類,它們不占用 PermGen 空間,并不需要一個新的類加載器加載
2、模板加載器
直接從數據源加載頁面和模板豈不是很好?也許從?CMS 或數據庫。也許你只想把它們放在一個地方,可以不重新部署整個應用程序就能更新它們。那么在 JSP 中你是很難做到這一點的,但 FreeMarker 提供的模板加載器就是為了 這個目的。你可以使用內建類或者創建你自己的實現
3、可以在運行時嵌入模板
FreeMarker 能讓你創建真正的模板,而不只是片段 ,還記得 JSP 中的 header 和 footer 嗎?FreeMarker 允許你使用一個模板(在本例中為 head.ftl)
4、沒有導入
JSP 要求你導入每個你需要使用的類,就像一個常規的 Java 類一樣。FreeMarker 模板,嗯,僅僅是模板。可以被包括在另一個模板中,但目前還不需要導入類
5、支持 JSP 標簽
使用?Jsp 的一個理由是有可用性很好的標簽庫。好消息是 FreeMarker 支持 JSP 標簽。壞消息是它們使用 FreeMarker 的語法,不是 JSP 語法。
6、表達式語言中的方法調用
除非你的目標是?Servlet 3.0/El 2.2 標準的容器,那么表達式語言中方法調用是不可用的。不是所有人都同意 EL 表達式中方法調用是一件好事,但是當你需要它們的時候,使用 JSP 真的太痛苦了。 但是 FreeMarker 同等對待其中每個引用。
7. 內置空字符串處理
FreeMarker 和 Jsp 都可以在表達式語言中處理空值,但 FreeMarker 在可用性上更先進一些
8、共享變量
FreeMarker 的共享變量是我最喜歡的“隱藏”功能之一。此功能可以讓你設置自動添加到所有模板的值。 例如,可以設置應用程序的名稱作為共享變量。
9、支持 JSON
FreeMarker 內置 JSON 支持。 比方說你有以下的 JSON 存儲到變量命名 user 的字符串中
10、不只是為了 Web 開發
最后,與?JSP 不同的是FreeMarker 模板可以在 servlet 容器之外使用。可以使用它們來生成電子郵件、 配置文件、 XML 映射等。甚至可以使用它們來生成 web 頁 并將它們保存在服務器端的緩存中
如果用戶要改界面,多寫幾套JSP代碼供用戶選擇不就完了嗎?
是,這樣確實也能一定程度上支持模板化。但是這種模板必須要寫代碼、編譯,然后發布版本。而FreeMarker的很重要的一點是定義一個新的視圖,不需要寫代碼,不需要發版本,只需要定義一套新的模板即可。
所以總結下來,FreeMarker在類似于淘寶店的商品展示場景下使用,會比JSP更方便。
因為用戶要把產品放到淘寶店的展臺上,展示的商品會經常發生變化,有時候要對UI做一些美化、內容展示位置的調整等等。在這種情況下,只需要使用一個新的模板,就可以把UI進行改變。而無需對淘寶的平臺代碼進行修改。
?
涉及到一個靜態化頁面ajax異步請求的問題
頁面通過ajax發送請求到handle.ashx一般處理程序,處理程序判斷請求是否由頁面發出并獲取參數,然后初始化全局控制變量和起到控制和標識作用的變量;傳遞參數和SQL語句給后臺方法更新數據庫中訪問量數據。獲取訪問量數據原理同理,只是SQL語句和調用的取數據的后臺方法不同罷了。
如何解決跨域問題?
跨域一般情況下有三種解決方法。
第一種就是干掉產生跨域的源頭——瀏覽器,修改瀏覽器的設置就可以了,這個不建議。
第二種,是生產環境下最常用的,就是用服務器設置解決。你請求自己的服務器,讓自己的服務器去請求別的服務器上的資源,就規避了跨域問題。
第三種,就是自己解決,用JSONP解決。最簡單的方法,就還是用jQ。在jQ的官方文檔里搜索jQuery.ajax(),之后頁面內搜索crossDoamin,然后仔細看看就可以了。
支付:
(支付我們提交企業營業執照等信息,需要申請支付寶商戶號和密鑰,支付寶那邊會給出示例接口代碼,具體的我這這,?點擊訂單需要提交價格到我們的項目做價格校驗,我們需要調用支付寶接口,傳遞我們的訂單編號,價格,支付寶密鑰,商鋪號,我們項目的回調的URl給支付寶接口,完了網站頁面就會支付寶頁面,客戶就可以完成一系列支付動作,當支付完成后,支付寶網站會調用我們發給他的我們網站的URl我們網站通過這個URl回調,獲取到支付的,訂單編號,流水號,價格后,進行校驗存儲交易日志等動作后,返回SUCCESS給銀行那邊銀行的支付操作事物完成)。
支付安全問才說:支付的時候,很多數據都是用MD5加密過的,在一個請求先進入我們的?項目,我們會先校驗,價格是否被F12 修改過完了調用支付寶接口,轉到支付寶頁面,后續的客戶輸入賬號密碼,或者網銀轉賬都是在支付寶,和銀行之間完成的,錢在銀行數據庫,支付寶的密碼,在支付寶數據庫他們有自己的安全措施,而且都走的是https協議都是經過加密的。我們項目再整個過程中只是通知支付寶交錢,具體的交錢動作都有支付寶,和銀行系統來完成。所以安全性沒問問題。及時是網絡抓包工具也只是類似知道客戶要付錢給誰。具體賦的過程任何操作都是支付寶,和銀行的交易。所以沒有安全問題。
商品管理模塊
?
這個模塊包括商品管理,商品分類管理,商品參數管理,商品屬性管理,規格管理,品牌管理;
在數據庫中涉及到的表有產品表,產品圖片表,品牌表,分類表,產品參數組表,產品參數表,產品參數值表等。
通常先在商品分類管理模塊中建立產品的分類,該分類是一個樹形表結構,我通過全部取出數據并對取出的數據進行遞歸算法生成樹形結構的數據,并將其數據渲染為具有層次嵌套關系的下拉列表以及表格控件從而在頁面進行使用因為在后臺的很多地方都使用到分類信息,而分類信息又不容易發生變化,所以我就結合oscache將分類信息進行緩存,并封裝到BaseController中,從而方便在其他Controller中直接調用該方法。
建立分類后可以在商品參數管理模塊中建立和指定分類綁定的參數組以及參數信息,之后在添加產品時就可以選擇產品所屬的分類然后就會出現和該分類綁定的參74 數組以及參數信息供公司內部業務人員填寫,保存后將參數信息保存到參數值表中,普通用戶可以在?產品詳情頁?的?商品參數?中找到。
規格管理,屬性管理的操作流程和上述流程類似。
報表統計
(spring定時器+poi+javamail+echarts)
我在做報表統計這個模塊的時候采用了highcharts這項技術,使用了柱狀圖,餅狀圖,組合圖按照時間以及分類進行了各種統計(銷售渠道,客戶群體,客戶偏好,信息來源,產品分類,產品月銷量,季度銷量,年銷量),除此之外因為經理要求要在每月月底將指定分類的產品信息通過excel的形式發送到相關人員的郵箱中,所以我就采用了spring定時器+poi+javamail的形式完成了上述要求。
統計分析模塊:
統計模塊由?會員統計,店鋪統計,銷量統計等構成,其中會員統計可以按天、周、月通過highcharts的折線圖對新增的會員進行統計分析,通過highcharts的餅狀圖對會員所在區域進行統計,并且可以根據會員的下單量,下單商品件數,下單金額分別進行統計分析計算出買家排行top10,并支持將這會員信息通過poi導出excel結合javamail發送到指定人的郵箱中。
購物車及訂單支付(redis):
關于購物車,我們當時考慮到怕水軍來回CRUD(增讀更刪)購物車,對數據庫造成巨大壓力,當時決定采用redis來做這個購物車。
這個購物車當時想到了兩種情況一種是淘寶的模式就是在用戶在未登錄狀態下,可以查看商品,當在詳情頁點擊“加入購物車”或者“查看購物車”的時候我們會判斷用戶是否登錄,如果沒有登錄我們會彈出一個彈框,讓用戶先登錄,成功后跳轉到登錄頁面,并且把商品的信息傳到后臺,進行保存,如果用戶是登錄狀態,直接將商品信息傳到后臺,進行保存,
另一種就是京東不管用戶是否登錄都可以添加和查看購物車,先將數據全部都保存在cookie中去,然后當用戶登錄上去以后就會直接將cookie中的信息保存在緩存中;
我們當時有這樣一個考慮,就是第一個人在查看商品添加到了購物車,但是沒有登錄,只是保存在了cookie中,后來第二個人也來上jd,結果第一個人的購物車商品保存在了第二個人的賬戶中,存在弊端,最后我們還是選用了淘寶的模式;
在保存時候我們選擇的是保存到redis緩存當中,將信息傳到后臺之后,我們會將數據全部都存放在一個對象當中,在將對象存放在list當中,然后以用戶id(唯一標示)為鍵,list集合為值存放在緩存當中,當用戶有新的商品添加的時候,我們通過用戶id查詢出來原來的信息?,將新的信息存放在list集合中去,然后將集合在放入緩存當中,但是這個過程中需要有一點注意的地方,就是當新添加的商品本來在購物中存在,這時我們就需要進行一個判斷。如果存在我們只要在原來的基礎上數量添加就行了;
購物車商品的刪除,點擊刪除的時候,我們會將商品的id獲取到,同時也獲取到用戶id,通過用戶id查詢出該用戶的購物車商品,然后將要刪除的商品從list集合當中刪除掉,再保存回去;
之后當用戶點擊“提交訂單”時會將redis中的信息取出來插入到數據庫的訂單表中,并清除reidis中該購物車的信息,同時將訂單表中該條記錄的狀態設置為1(未付款),設置過期時間,在規定時間內用戶可以選擇進行支付,支付成功后會將訂單的狀態改為2,并將財付通返回的交易信息存入數據庫的交易記錄表中,同時調用webservice接口發送短信通知用戶支付成功,此時的訂單已進入后臺去處理,前臺再查看訂單時,
如果在規定時間內,用戶沒有支付,我們會取消訂單,這樣是避免其他用戶不能購買到商品,我們會根據狀態顯示不同的信息,比如:狀態1是未支付訂單,狀態為2的是支付成功等待審核狀態,當后臺審核通過狀態會改為3,當發貨時狀態會改為4,這時客戶就可以確認收貨,確認收貨后狀態改為5。注意:訂單支付采用的是?財付通(騰訊),支付寶(淘寶)
每秒處理十萬訂單的支付系統思路
支付系統要處理每秒十萬筆訂單,需要的是每秒數十萬的數據庫更新操作(insert加update),這在任何一個獨立數據庫上都是不可能完成的任務,所以我們首先要做的是對訂單表(簡稱order)進行分庫與分表。
分庫策略我們選擇了“二叉樹分庫”,所謂“二叉樹分庫”指的是:我們在進行數據庫擴容時,都是以2的倍數進行擴容。并將每個分庫中都將order表拆分成10份。
如果要支持每秒處理10萬訂單,那每秒將至少需要生成10萬個訂單ID,通過數據庫生成自增ID顯然無法完成上述要求。所以我們只能通過內存計算獲得全局唯一的訂單ID。使用Twitter的Snowflake算法,實現了全局唯一ID。訂單id由分庫分表信息+時間戳+機器號+自增序號組成。這樣只根據訂單ID,我們也能快速的查詢到對應的訂單信息。
我們通過對order表uid維度的分庫分表,實現了order表的超高并發寫入與更新,并能通過uid和訂單ID查詢訂單信息。但作為一個開放的集團支付系統,我們還需要通過業務線ID(又稱商戶ID,簡稱bid)來查詢訂單信息,所以我們引入了bid維度的order表集群,將uid維度的order表集群冗余一份到bid維度的order表集群中,要根據bid查詢訂單信息時,只需查bid維度的order表集群即可。
我們引入了消息隊列進行異步數據同步,來實現數據的最終一致性。當然消息隊列的各種異常也會造成數據不一致,所以我們又引入了實時監控服務,實時計算兩個集群的數據差異,并進行一致性同步。
沒有任何機器或服務能保證在線上穩定運行不出故障。比如某一時間,某一數據庫主庫宕機,這時我們將不能對該庫進行讀寫操作,線上服務將受到影響。
所謂數據庫高可用指的是:
當數據庫由于各種原因出現問題時,能實時或快速的恢復數據庫服務并修補數據,從整個集群的角度看,就像沒有出任何問題一樣。需要注意的是,這里的恢復數據庫服務并不一定是指修復原有數據庫,也包括將服務切換到另外備用的數據庫。數據庫高可用的主要工作是數據庫恢復與數據修補
支付系統除了最核心的支付訂單表與支付流水表外,還有一些配置信息表和一些用戶相關信息表。如果所有的讀操作都在數據庫上完成,系統性能將大打折扣,所以我們引入了數據分級機制。
我們簡單的將支付系統的數據劃分成了3級:
1級:訂單數據和支付流水數據;這兩塊數據對實時性和精確性要求很高,所以不添加任何緩存,讀寫操作將直接操作數據庫。
第2級:用戶相關數據;這些數據和用戶相關,具有讀多寫少的特征,所以我們使用redis進行緩存。
第3級:支付配置信息;這些數據和用戶無關,具有數據量小,頻繁讀,幾乎不修改的特征,所以我們使用本地內存進行緩存。
http請求在進入web集群前,會先經過一層粗細管道。入口端是粗口,我們設置最大能支持100萬請求每秒,多余的請求會被直接拋棄掉。出口端是細口,我們設置給web集群10萬請求每秒。剩余的90萬請求會在粗細管道中排隊,等待web集群處理完老的請求后,才會有新的請求從管道中出來,給web集群處理。這樣web集群處理的請求數每秒永遠不會超過10萬,在這個負載下,集群中的各個服務都會高校運轉,整個集群也不會因為暴增的請求而停止服務。
Junit單元測試:
我在編寫完自己的功能模塊后,為了保證代碼的準確性,一般都會使用junit進行單元測試,當時使用的是junit4這種基于注解的方式來進行單元測試。為了和spring集成獲取配置的bean,通常使用?@RunWith來加載springjunit這個核心類,使用?@ContextConfiguration來加載相關的配置的文件,通過?@Resource按名字來注入具體的bean,最后在需要測試的方法上面加上
@Test 來進行單元測試。并且在編寫單元測試的時候還要遵守一定的原則如:
源代碼和測試代碼需要分開;測試類和目標源代碼的類應該位于同一個包下面,即它們的包名應該一樣;測試的類名之前或之后加上Test,測試的方法名通常也以test開頭。
框架篇:
SpringMVC的運行原理是:
整個處理過程從一個HTTP請求開始:
1.Tomcat在啟動時加載解析web.xml,找到spring mvc的前端總控制器DispatcherServlet,并且通過DispatcherServlet來加載相關的配置文件信息。
2.DispatcherServlet接收到客戶端請求,找到對應HandlerMapping,根據映射規則,找到對應的處理器(Handler)。
3.調用相應處理器中的處理方法,處理該請求后,會返回一個ModelAndView。
4.DispatcherServlet根據得到的ModelAndView中的視圖對象,找到一個合適的ViewResolver(視圖解析器),根據視圖解析器的配置,DispatcherServlet將要顯示的數據傳給對應的視圖,最后顯示給用戶。
struts2和springMVC的區別
1、Struts2是類級別的攔截,?一個類對應一個request上下文,SpringMVC是方法級別的攔截,一個方法對應一個request上下文,而方法同時又跟一個url對應,所以說從本身上SpringMVC就容易實現restful url,而struts2的架構實現起來要費勁,因為Struts2中Action的一個方法可以對應一個url,而其類屬性卻被所有方法共享,這也就無法用注解或其他方式標識其所屬方法了。
2、由上邊原因,SpringMVC的方法之間基本上獨立的,獨享request response數據,請求數據通過參數獲取,處理結果通過ModelMap交回給框架,方法之間不共享變量,而Struts2搞的就比較亂,雖然方法之間也是獨立的,但其所有Action變量是共享的,這不會影響程序運行,卻給我們編碼?讀程序時帶來麻煩,每次來了請求就創建一個Action,一個Action對象對應一個request上下文。
3、由于Struts2需要針對每個request進行封裝,把request,session等servlet生命周期的變量封裝成一個一個Map,供給每個Action使用,并保證線程安全,所以在原則上,是比較耗費內存的。
4、?攔截器實現機制上,Struts2有以自己的interceptor機制,SpringMVC用的是獨立的AOP方式,這樣導致Struts2的配置文件量還是比SpringMVC大。
5、SpringMVC的入口是servlet,而Struts2是filter(這里要指出,filter和servlet是不同的。以前認為filter是servlet的一種特殊),這就導致了二者的機制不同,這里就牽涉到servlet和filter的區別了。
6、SpringMVC集成了Ajax,使用非常方便,只需一個注解@ResponseBody就可以實現,然后直接返回響應文本即可,而Struts2攔截器集成了Ajax,在Action中處理時一般必須安裝插件或者自己寫代碼集成進去,使用起來也相對不方便。
7、SpringMVC驗證支持JSR303,處理起來相對更加靈活方便,而Struts2驗證比較繁瑣,感覺太煩亂。
8、?MVC和Spring是無縫的。從這個項目的管理和安全上也比Struts2高(當然Struts2也可以通過不同的目錄結構和相關配置做到SpringMVC一樣的效果,但是需要xml配置的地方不少)。
9、?設計思想上,Struts2更加符合OOP的編程思想,?SpringMVC就比較謹慎,在servlet上擴展。
10、SpringMVC開發效率和性能高于Struts2。
11、SpringMVC可以認為已經100%零配置。
hibernate緩存概述:
hibernate分為一級緩存即session緩存也叫事務級別的緩存以及
二級緩存sessionFactory即應用級別的緩存,還有查詢緩存即三級緩存.
一級緩存的生命周期和session的生命周期保持一致,
hibernate默認就啟用了一級緩存,
不能將其關閉,可以通過session.clear()和session.evict(object)來管理一級緩存。其中get,load,iterate都會使用一級緩存,一級緩存緩存的是對象。
二級緩存的生命周期和sessionFactory的生命周期保持一致,可以跨session,被多個session共享,hibernate3默認開啟二級緩存,也可以手動開啟并指定緩存插件如ehcache,oscache
等。二級緩存也只能緩存對象。
三級緩存也叫查詢緩存,查詢緩存是針對普通屬性結果集的緩存,
對實體對象的結果集只緩存id。對query.list()起作用,query.iterate不起作用,也就是query.iterate不使用查詢緩存
?
Hibernate和Mybatis的區別
兩者相同點
·?Hibernate與MyBatis都可以是通過SessionFactoryBuider由XML配置文件生成SessionFactory,然后由SessionFactory?生成Session,最后由Session來開啟執行事務和SQL語句。其中SessionFactoryBuider,SessionFactory,Session的生命周期都是差不多的。
·?Hibernate和MyBatis都支持JDBC和JTA事務處理。
Mybatis優勢
1?MyBatis可以進行更為細致的SQL優化,可以減少查詢字段。
2?MyBatis容易掌握,而Hibernate門檻較高。
Hibernate優勢
1 Hibernate的DAO層開發比MyBatis簡單,Mybatis需要維護SQL和結果映射。
2 Hibernate對對象的維護和緩存要比MyBatis好,對增刪改查的對象的維護要方便。
3 Hibernate數據庫移植性很好,MyBatis的數據庫移植性不好,不同的數據庫需要寫不同SQL。??
4 Hibernate有更好的二級緩存機制,可以使用第三方緩存。MyBatis本身提供的緩存機制不佳。
?
mybatis一個項目中用到的復雜查詢基本沒有,就是簡單的增刪改查,這樣選擇hibernate效率就很快了,因為基本的sql語句已經被封裝好了,根本不需要你去寫sql語句,這就節省了大量的時間,但是對于一個大型項目,復雜語句較多,這樣再去選擇hibernate就不是一個太好的選擇,選擇就會加快許多,而且語句的管理也比較方便。
兩者比較
因為Hibernate對查詢對象有著良好的管理機制,用戶無需關心SQL。所以在使用二級緩存時如果出現臟數據,系統會報出錯誤并提示。
而MyBatis在這一方面,使用二級緩存時需要特別小心。如果不能完全確定數據更新操作的波及范圍,避免Cache的盲目使用。否則,臟數據的出現會給系統的正常運行帶來很大的隱患。
mybatis和ibatis的區別
1.以前用的parameterClass在mybatis中已經用不了了,mybatis里應該使用parameterType。另外resultMap里面也不能繼續使用了改成了type
2.dynamic標簽不能使用了
3.數據類型的聲明和ibatis有了很大的差別,ibatis可以像下面這樣寫
#FCODE:VARCHAR2#, mybatis的話一般是這樣弄的#{FMARK,jdbcType=VARCHAR}
4.mybatis現在已經沒有SqlMapClient了,使用的則是SqlSession.在原來的基礎上加了像selectMap,selectList,selectOne這樣的方法,使用更方便了
5.加了一個叫映射器的新東西,只需要寫出接口而不需要實現類就能夠操作數據如
6 需要注意的是spring3.0一下的版本并不支持mybatis,
?
【$與#號的區別】
1. #將傳入的數據都當成一個字符串,會對自動傳入的數據加一個雙引號。如:order by #user_id#,如果傳入的值是111,那么解析成sql時的值為order by "111", 如果傳入的值是id,則解析成的sql為order by "id".
2. $將傳入的數據直接顯示生成在sql中。如:order by $user_id$,如果傳入的值是111,那么解析成sql時的值為order by user_id, ?如果傳入的值是id,則解析成的sql為order by id.
3. #方式能夠很大程度防止sql注入。
4.$方式無法防止Sql注入
5.$方式一般用于傳入數據庫對象,例如傳入表名
6.一般能用#的就別用$.
Oracle和Mysql的區別
1.?MYSQL有自動增長的數據類型,插入記錄時不用操作此字段,會自動獲得數據值。ORACLE沒有自動增長的數據類型,需要建立一個自動增長的序列號
2.單引號處理:MYSQL里可以用雙引號包起字符串,ORACLE里只可以用單引號包起字符串。在插入和修改字符串前必須做單引號的替換:把所有出現的一個單引號替換成兩個單引號。
3. ?MYSQL處理翻頁的SQL語句比較簡單,用LIMIT 開始位置, 記錄個數;PHP里還可以用SEEK定位到結果集的位置。ORACLE處理翻頁的SQL語句就比較繁瑣
4. ??長字符串的處理ORACLE也有它特殊的地方。INSERT和UPDATE時最大可操作的字符串長度小于等于4000個單字節, 如果要插入更長的字符串, 請考慮字段用CLOB類型
5. ?MYSQL日期字段分DATE和TIME兩種,ORACLE日期字段只有DATE
6. ?MYSQL的非空字段也有空的內容,ORACLE里定義了非空字段就不容許有空的內容。按MYSQL的NOT NULL來定義ORACLE表結構, 導數據的時候會產生錯誤。因此導數據時要對空字符進行判斷,如果為NULL或空字符,需要把它改成一個空格的字符串。
7. ?MYSQL里用?字段名?like '%字符串%',ORACLE里也可以用?字段名?like '%字符串%' 但這種方法不能使用索引, 速度不快,用字符串比較函數?instr(字段名,'字符串')>0 會得到更精確的查找結果。
9. ?程序和函數里,操作數據庫的工作完成后請注意結果集和指針的釋放。
為什么做java的web開發我們會使用struts2,springMVC和spring這樣的框架?
今年我一直在思考web開發里的前后端分離的問題,到了現在也頗有點心得了,?隨著這個問題的深入,再加以現在公司很多web項目的控制層的技術框架由struts2遷移到springMVC,我突然有了一個新的疑問無法得到正確的?解釋,為什么我們現在做java的web開發,會選擇struts2或者springMVC這樣的框架,而不是使用servlet加jsp這樣的技術呢??特別是現在我們web的前端頁面都是使用velocity這樣的模板語言進行開發,拋棄了jsp,這樣的選擇又會給我們java的web開發帶來什么樣的?好處,延著這個問題的思路,我又發現新的疑問,為什么現在很多java企業級開發都會去選擇spring框架,spring框架給我們開發的應用帶來了什?么?這么一想還真是問倒我了,我似乎很難找到一串能讓人完全信服的答案,最終我發現,這些我認為我很熟悉很常用的技術,其實還有很多讓我陌生不解的地方,?這些陌生和不解的地方也正是我是否能更高層次使用它們的關鍵,今天這篇文章我就來講講這些問題,不過struts2,spring這樣的技術經過這么多年?的積累已經是相當龐大和復雜,它們的面很廣,本人雖然已經用了它們多年,還是有很多技術不熟悉和不清楚,所以本文不是全面對我題目做出解答的文章,而是根?據我現有知識結構來理解這個問題。
軟件里有很多優秀的框架,有一種類型的框架,它的特點是建立在一個現有技術的基礎上,提供和現有技術一樣業務功能的技術框架,這個新的技術框架?比原技術更加易用,更加健壯同時功能更加強大,例如:jQuery,以及本文所要談到的struts2和springMVC,深究這些框架都是相當之復?雜,但是它們的優點其實只有一個:就是讓使用者只關心核心業務的開發,框架幫你屏蔽原有技術跟業務開發無關的各類技術問題。像?jQuery,struts2或springMVC這類框架之所以優秀,就是它們在這點上做的太好了,以至于很多使用它的程序員都已經不清楚原有技術的真?實面目,因此我們要將struts2理解的更好,使用的更加熟練和深入,這里我們就要跳出struts2的技術,到struts2技術的源頭?servlet,仔細研究下servlet的特點,只有這樣我們才能把struts2框架學的更好。
Servlet的作用是接收瀏覽器傳給服務端的請求(request),并將服務端處理完的響應(response)返回給用戶的瀏覽器,瀏覽?器和服務端之間通過http協議進行溝通,其過程是瀏覽器根據用戶的選擇將相關信息按http協議報文的規范組裝請求的http報文,報文通過網絡傳輸到?指定的服務器,服務器通過特定的web容器接收這個報文信息,例如:tomcat,jetty,jboss這樣的web容器,web容器會將http報文?解析出來,如果是用戶請求,最終解析出來的報文信息會用一個request對象存儲起來,服務端使用這個request做完相應的處理后,服務端程序將結?果信息封裝到response對象里,然后將response對象交給web容器,web容器則把這個response對象轉變為http協議的報文,并?將報文回傳給瀏覽器,瀏覽器最后解析這個響應報文,將最終結果展示給用戶。
Web容器創造了servlet接口,servlet接口就是開發人員自己實現業務邏輯的地方,程序員開發servlet就好比做填空題,而填?空題的語境或者說上下文提示就是由request和response對象,但是javaEE規范里的servlet接口很簡單,就三個方法?init,service和destory,但是這個接口太籠統,所以規范里還提供了一個HttpServlet類,這個類根據http請求類型提供了?doGet,doPost等方法,servlet接口最大的特點就是根據http協議的特點進行定義,因此做servlet開發時候如果使用者對http 協議特點不是特別熟悉,都會碰到或多或少令人迷惑的問題,特別是碰到一些復雜特殊的請求時候:例如文件上傳,返回特殊的文件格式到瀏覽器,這時候使用?servlet開發就不是很方便了,servlet開發還有個問題可能大家常常被忽視,就是請求的數據的類型轉化,http協議傳輸都是文本形式,到了?web容器解析后也是文本類型,如果碰到貨幣,數字,日期這樣的類型需要我們根據實際情況進行轉化,如果頁面傳送的信息非常多,我們就不得不做大量類型轉?化,這種工作沒有什么技術含量,是個體力活而且很容易導致程序錯誤。同時java的企業開發都是圍繞javabean進行,類型轉化好的數據還要封裝到對?應的javabean里,這種轉來轉去的事情對于項目開發絕對不是什么好事情,所以古老的struts1為這種問題找到了一種解決方案,就是定義了一個?DTO對象(數據傳輸對象),專門負責做這樣的事情,不過到了struts2,整個替代servlet的action本身就是一個javabean。
Java的企業開發一個技術特點就是使用javabean進行的,struts2的特點之一就是它替代servlet的操作類就是一個典型的?javabean,首先struts2框架將頁面傳輸的數據進行類型轉化和封裝后將請求信息封裝到了這個javabean的屬性里,這樣我們開發web程?序時候就省去了煩心的類型轉化和封裝的問題,前面我講到傳統的servlet是根據http協議進行定義的,它會按你請求方式(post還是get方式)?來處理用戶的請求,但是對于一名程序開發人員而言,一個請求,具體到一個url,其實對于服務端而言就是服務端對外提供的一個功能,或者說是服務端對外的?一個動作,如果我們使用servlet開發程序我們就得把http的動作轉化為具體的業務動作,這就讓程序開發變得繁瑣,增強了開發的難度,所以?struts2替代servlet的javabean就屏蔽了servlet里http的請求方式和具體業務動作轉化的問題,javabean里的每一個?方法都可以和每一個url請求一一對應,這必然減輕了開發的難度問題。
Servlet另一個作用就是構造response對象,讓頁面獲得正確的響應,其實現代的瀏覽器是一個多媒體工具,文字,圖片,視屏等等東西都可?以在瀏覽器里顯示,資源的不同就會導致http響應報文的差別,如果我們使用servlet開發就要根據資源的不同在java程序里用硬編碼的形式處理,?這樣的程序很難復用,而且如果程序員對某種資源的處理理解不到位,就會導致問題的出現,struts2通過配置文件的形式將這樣的邏輯從java程序里剝?離出來,使用配置的方式進行統一管理,這個做法和spring的AOP方式類似,這樣就讓結果處理方式更加統一,更加利于管理,同時也提升了程序的健壯性?以及降低了開發的難度。
Servlet在MVC開發模式里就是其中C層即控制層,控制層就像俄羅斯的雙頭鷹(一個頭向東看一個頭向西看)一樣,一個頭向M層模型層看,?一個頭向V層視圖層看,模型層也是用java編寫的,控制層也屬于服務端語言開發,所以M層和C層的溝通沒有天然的障礙,但是和V層視圖層就不一樣了,這?是一個跨語言的溝通,對于瀏覽器,它只懂得html,javascript和css,瀏覽器是理解不了java這種語言的東西,但是要讓服務端的東西能被?瀏覽器理解接受,我們就必須得把服務端的響應信息放到頁面里,因此就需要一個技術把java的信息轉化到html頁面里,這就是javaEE規范里提供了?jsp技術,jsp其實是一種服務端技術而非客戶端技術,不過它看起來似乎更像html技術,最早的jsp開發里都是直接將java代碼寫到頁面里,這種?壞處誰都知道,之后javaEE規范提供了自定義標簽技術,使用一種類似html標簽的方式來解析java代碼,struts2框架提供了一整套完整的自?定義標簽技術,這似乎聽起來不算啥,但是它的作用非凡,因為自定義標簽之所以叫自定義就是每個人都可以自己來定義,如果沒有一個規范必然產生混亂,而且一?套完善的自定義標簽是個系統工程,一套完整的自定義標簽相當于我們在自己定義一套新的開發語言,做程序的人聽到這個一定就會明白開發一套完整的自定義標簽?的工作量和開發難度都是難以想象的,而且自定義標簽都是和控制層緊密相連,其難度又會增加一個維度,所以struts2提供的自定義標簽對于業務開發帶來?的將是質的飛越。
Servlet里還有兩個重要的技術:監聽器和過濾器,對于監聽器在web開發里使用的場景比較少,都是一些十分特別的情況才會使用,大部分?web開發里可以忽略它的使用,我們用的最多的監聽器可能就是對ServletContext創建和銷毀的監聽器,ServletContext是整個?web應用的全局對象,它和Web應用的生命周期綁定在一起,因此使用這個監聽器對Web應用的全局信息進行初始化和銷毀操作,例如spring容器的初?始化操作。比較有意思的是過濾器,在struts2里有個攔截器,它們的作用相同都是用來攔截請求的,因為攔截器是struts2的特有功能,在?struts2里使用攔截器自然比使用過濾器更順手,其實攔截器所用的技術比過濾器更加先進,因為攔截器使用了反射技術,因此攔截器攔截的面更大,控制請?求的能力更強,它能完成的任務也會更加的豐富多彩。
在我第一次接觸struts2時候,有人告訴我struts設計的一個目的就是想屏蔽在控制層里操作request和response對象,因?為這兩個http協議的兒子會造成web開發里思路的混亂,但是我在實際開發里卻經常不自覺的使用這兩個對象。而且本人做前端開發非常喜歡使用ajax,?使用ajax技術時候我就很討厭struts2的自定義標簽,我更加喜歡在頁面里用javascript技術處理各種信息,最終struts2在我眼里就?是一個servlet的變體,因此曾經有段時間我常常在想是不是可以拋棄struts2,直接用servlet,因為struts2里用到了太多反射機?制,特別是使用注解做配置(注解是用反射實現的),在java里反射的執行效率是非常低的,直接使用servlet一定能提升web應用的執行效率。其實?這個倒很難做到,因為當時我沒法在servlet里靈活的運用spring技術。
下面我要談談spring了
spring技術可以說是java企業開發里最重要的技術,不過真的理解spring的作用和意義還真是一件麻煩的事情,很多人對spring 理解其實都是停留在使用階段(例如:聲明式事務很好用等等),當今的spring技術生態環境里可謂是蔚為壯觀,spring已經包羅萬象,它的內容之多?完全不亞于它的本源java語言了,而spring這么大的框都是建立在ioc和aop技術之上,只有深入理解了這兩個技術我們才能明白為什么?spring這個框能裝的下那么多東西了。
首先是ioc,ioc技術第一個解釋叫做控制反轉,它還有個解釋就是依賴注入,這兩個名字很難從字面理解,但是當你理解它的原理后就會發現它們?的描述是何等準確。Ioc技術的本質就是構建對象的技術換句話說就是將一個類實例化成對象的技術,在java里實例化類通過new關鍵字進行的,每次?new一個類都會產生一個新的實例對象,這么做視乎很浪費,有時這種浪費還挺危險,因為在程序開發時候我們常常只需要某個類永遠只能產生一個的實例對象這?個時候就得使用單例模式,此外在設計模式里還可以通過工廠方式產生對象,使用過spring的人看到上面的文字就知道了,spring里bean的定義就?和上面的內容一一對應,scope屬性single產生單例對象,prototype產生新對象,bean還可以通過工廠方式產生對象,可以說?spring的bean就是制造對象的工具。面向對象編程里對象相當于顯示生活中的一個實體,例如我們有個對象作用是完成打獵的操作,那么打獵這個對象內?部包含兩個輔助對象:人和槍,只有人和槍賦予了打獵這個對象,那么打獵對象才能完成打獵的操作,但是構建一個人和槍的對象并不是看起來那么簡單,這里以槍?為例,要創造一把槍我們需要金屬,需要機床,需要子彈,而機床和子彈又是兩個新對象,這些對象一個個相互嵌套相互關聯,大伙試想下如果我們在java代碼?里構建一個槍的對象那是何其的復雜,假如我們要構造的不是簡單的槍對象而是更加復雜的航空母艦,那么構造這個對象的成本之高是讓人難以想象的,怎么來消除?這種對象相互嵌套相互依賴的關系了?spring提供了一種方式,這種方式就是spring提供一個容器,我們在xml文件里定義各個對象的依賴關系,由?容器完成對象的構建,當我們java代碼里需要使用某個實例的時候就可以從容器里獲取,那么對象的構建操作就被spring容器接管,所以它被稱為控制反?轉,控制反轉的意思就是本來屬于java程序里構建對象的功能交由容器接管,依賴注入就是當程序要使用某個對象時候,容器會把它注入到程序里,這就叫做依?賴注入。在java開發里我們想使用某個類提供的功能,有兩種方式,一種就是構造一個新的類,新的類繼承該類,另一種方式則是將某個類定義在新類里,那么?兩個類之間就建立一種關聯關系,
spring的ioc容器就是實現了這種關聯關系(記住不是繼承關系哦),那么某個類要被賦予到新類有哪些辦法了?一般只?有兩種:一種就是通過構造函數,一種就是通過setXXX方式,這也是spring容器使用到了兩種標準的注入方式。
不管是上面說的繼承方式,還是關聯方式其實都是增強目標對象能力的開發手段,在設計模式里有一種代理模式,
代理模式將繼承模式和關聯模式結合在?一起使用,代理模式就是繼承模式和關聯模式的綜合體,不過這個綜合體的作用倒不是解決對象注入的問題,而是為具體操作對象找到一個保姆或者是秘書,這就和?小說里的二號首長一樣,這個二號首長對外代表了具體的實例對象,實例對象的入口和出口都是通過這個二號首長,因為具體的實例對象是一號首長,一號首長是要?干大事的,所以一些事務性,重復性的工作例如泡茶,安排車子,這樣的工作是不用勞煩一號首長的大駕,而是二號首長幫忙解決的,這就是aop的思想,aop 解決程序開發里事務性,和核心業務無關的問題,但這些問題對于業務場景的實現是很有必要的,在實際開發里aop也是節省代碼的一種方式。
Spring的核心技術的作用本質就是一個?溝通機制,spring總是盡全力的讓溝通的雙方信息暢通,同時降低雙方的溝通成本,在現實機構里一個善于溝通的人肯定是該公司的領導,很會溝通的領導能?調動起各種資源的積極性,善于溝通的領導就會做到海納百川,讓各種不同人追隨他,所以當今的spring就是一個大容器,什么都可以往里裝。
Spring很像銀行,它不能直接創造物質財富,但是一切資源都要通過它進行流通,它能控制經濟發展的走向,回到程序的世界,spring的作?用是被標榜為程序之間的解耦,spring能降低不同模塊之間的耦合度,原因就是在程序開發里不同模塊之間信息的溝通是通過對象傳遞完成的,而對象能否順?利傳遞就是要合理的構建好對象,而管理好對象的構建方式就能管理好對象傳遞,這就是spring給系統架構設計帶來的好處。
?
?
基礎方面:
BS和CS的區別以及優缺點
C/S又稱Client/Server或客戶/服務器模式。服務器通常采用高性能的PC、工作站或小型機,并采用大型數據庫系統,如Oracle、Sybase、Informix或 SQL Server。客戶端需要安裝專用的客戶端軟件。
B/S是Brower/Server的縮寫,客戶機上只要安裝一個瀏覽器(Browser),如Netscape Navigator或InternetExplorer,服務器安裝Oracle、Sybase、Informix或 SQL Server等數據庫。瀏覽器通過Web Server 同數據庫進行數據交互。 ?C/S的優點是能充分發揮客戶端PC的處理能力,很多工作可以在客戶端處理后再提交給服務器。對應的優點就是客戶端響應速度快 C/S客戶端的計算機電腦配置要求較高。
B/S客戶端的計算機電腦配置要求較低。
C/S每一個客戶端都必須安裝和配置軟件,客戶端不必安裝,使用瀏覽器訪問,易推廣。
B/S最大的優點就是可以在任何地方進行操作而不用安裝任何專門的軟件。
C/S每一個客戶端都要升級程序。可以采用自動升級。BS客戶端不必安裝及維護。
C/S一般面向相對固定的用戶群,程序更加注重流程,它可以對權限進行多層次校驗,提供了更安全的存取模式,對信息安全的控制能力很強。一般高度機密的信息系統采用C/S結構適宜。
五險一金,和上交比例
五險一金的名稱:養老保險,醫療保險,失業保險,工傷保險,生育險,住房公積金
比例:五險一金的標準:最低?工資的30% * 12% ????最高 工資*12%
HttpClient
httpClient是apache旗下的子項目適用于多項目之間的數據傳輸,httpClinet與webservice不同,webservice是一個重量級的框架,
適用于跨域和跨項目之間的數據傳輸,而httpClient是一個輕量級的框架,使用起來相對比較靈活、易用,?
httpClient使用步驟,
1、創建HttpClient實例;
2、創建連接方式實例,在這里有兩種連接方式:GetMethod和PostMethod
3、執行httpClient對象的excute方法;
4、讀取response方法;
5、處理返回的結果,
首先判斷狀態碼為200的說明連接成功,然后在執行?HttpEntity entity=response.getEntity();;獲得相應的實體;
使用super.outString(EntityUtils.toString(entity),responsed)
將數據傳輸到前臺
6、關閉資源,釋放連接;httpclient.close();
項目中的應用以及遇到的問題:
當時我們在做大眼睛房地產項目時候,其中一個功能模塊,需要調用本公司另一個項目組中數據,當時項目經理讓我去完成這個項目,
我就想到使用httpClient技術來實現這個功能,通過上網查找資料和查閱以前的筆記,
首先導入httpClient相關的jar包,通過以上6步連接要調用的項目,
開始在做添加時候出現了亂碼問題,后來在postMothed中加上編碼集設置?postMethod.setRequestHeader("Content-Type","application/x-www-form-urlencoded;charset=utf-8");
后解決了該問題,在文件上傳時候應該注意上傳的文件名,和要調用的項目中接收的文件名一致。
事務的隔離級別和傳播特性
在數據庫中,所謂事務是指一組邏輯操作單元即一組sql語句。當這個單元中的一部分操作失敗,整個事務回滾,只有全部正確才完成提交。
事務的ACID屬性
1. 原子性(Atomicity)
原子性是指事務是一個不可分割的工作單位,事務中的操作要么都發生,
要么都不發生。??
2. 一致性(Consistency)
事務必須使數據庫從一個一致性狀態變換到另外一個一致性狀態。(數據不被破壞)
3. 隔離性(Isolation)
事務的隔離性是指一個事務的執行不能被其他事務干擾.
4. 持久性(Durability)
持久性是指一個事務一旦被提交,
它對數據庫中數據的改變就是永久性的.
在JDBC中,
事務默認是自動提交的,
每次執行一個?SQL 語句時,如果執行成功,
就會向數據庫自動提交,而不能回滾
為了讓多個?SQL 語句作為一個事務執行:
(1)執行語句前調用?Connection 對象的?setAutoCommit(false);
?????以取消自動提交事務
(2)在所有的?SQL 語句都成功執行后,調用?commit(); 方法提交事務
(3)在出現異常時,調用?rollback(); 方法回滾事務。
五個事務隔級別分別為:
lsolation的屬性值
1,default
默認的事務隔離級別
2,read_uncommitted
讀未提交,一個事務可以操作另外一個未提交的事務,不能避免臟讀,不可重復讀,幻讀,隔離級別最低,并發性?能最高
3,read_committed
讀已提交,一個事務不可以操作另外一個未提交的事務,?能防止臟讀,不能避免不可重復讀,幻讀。
4,repeatable_read
能夠避免臟讀,不可重復讀,不能避免幻讀
5,serializable
隔離級別最高,消耗資源最低,代價最高,能夠防止臟讀,?不可重復讀,幻讀。
七個事務的傳播行為
1,propagation_required
如果一個事務存在,則支持當前事務,如果不存在,則創建新的事務
2,propagation_supports
如果一個事務存在,則支持當前事務,如果不存在,則非事務的方法運行
3,propagation_mendatory
如果一個事務存在,則支持當前事務,如果存在,則拋出異常
4,propagation_requires_new
總是要開啟一個新的事務,如果事務存在,將該事務掛起
5,propagation_not_supported
總是非事務方法運行,并掛起所有的事務
6,propagation_never
總是非事務方法運行,如果事務存在則拋出異常
7,propagation_nested
某一個事務存在,則運行在一個嵌套的事務中
Ajax
ajax本身不支持跨域,可以通過jsonp來達到跨域目的。jsonp的本質就是通過script標簽在發送url請求時多加了一個callback參數,服務端通過request獲取callback參數的值也就是回調的函數名,將要傳遞的json數據作為參數響應給客戶端進行回調。
通過eval可以將后臺返回的json格式的字符串轉換為json對象。
jquery的ajax默認情況下是沒有超時限制的,可以通過timeout【單位:毫秒】設置超時時間。
Vector & ArrayList的區別
1)??Vector的方法都是同步的(Synchronized),是線程安全的(thread-safe),而ArrayList的方法不是,由于線程的同步必然要影響性能,因此,ArrayList的性能比Vector好。
2)?當Vector或ArrayList中的元素超過它的初始大小時,Vector會將它的容量翻倍,而ArrayList只增加50%的大小,這樣,ArrayList就有利于節約內存空間。
?
hashMap和hashtable的區別:
map是一個鍵值對的存儲接口,Map有兩個具體的實現類是HashMap和HashTable,
hashmap是非線程安全的,hashtable是線程安全的,所以hashmap的效率高于hashtable;
hashmap允許空值空鍵,table不許空值空鍵;
關于map的底層,是通過數組加鏈表的形式來進行存放的,比如我們要存放一會key , value,我們會根據key的hashcode()值與數組的長度進行取余,通過余數放入到對應的數組位置上,然后通過key取值得時候,我們也是通過傳過來的key的hashcode()與數組長度取余,然后就能很快的找到我們存放的位子。但是這樣會存在一個問題,就是余數會有重復的情況,我們就加上一個鏈表。通過key取到鏈表之后,我們就將鏈表進行循環,然后相比較來查詢出相對應的值;
?
String ,stringbuffer ,stringbuilder 的區別:
首先這些都是用來定義字符串的;
String是一個字符串常量,被final修飾過的,長度不可變,拼接字符串的時候使用+=,
每一次拼接字符串都會是一個新的內存空間;
Stringbuffer是字符串變量,存在緩存區,長度是可以變得,只需要通過append來進行追加就可以,不需要開辟新的內存空間;有synchronized ?所以線程是安全;
Stringbuilder 也是字符串變量,和Stringbuffer差不多,但是沒有同步鎖。線程不安全;
在項目當中,我們最常用的是string ,因為使用的比較簡單,不需要new對象,還提供了許多的方法;雖然stringbuffer的效率比這個要高,但是在數據量小的時候,相差不了多少,
只有在大數據量拼接的時候才會使用stringbuffer和stringbuilder;
Set,list ,conllection,conllections的區別?
?
List 和set都是接口,他們都繼承與接口conllection,
List是一個有序的可以重復的集合,而set是無序的可以重復的集合;
conllection是集合的頂層接口;
conllections是一個封裝了眾多關于集合操作的靜態化方法的工具類,因為構造方法是私有的不能實例化;
List接口中有arraylist ,linkedlist 和vector,arraylist和vector都是基于數組實現的,所以查詢的時候速度快,而在進行增加刪除的時候數據要比linkedlist 慢,linkedlist 是基于鏈式存儲結構,所以在查詢的速度上相對慢一點;
?
抽象類和接口的區別(抽象類特點)
?
抽象類通過abstract聲明;
抽象類允許普通屬性和普通方法存在;抽象類允許抽象方法存在;
使用abstract修飾的方法,就是抽象方法。抽象方法與普通方法的區別是:抽象方法沒有方法體(沒有{});
抽象類不能被實例化;
抽象類只能通過普通類實現后進行使用,普通類通過extends關鍵字來實現抽象類,并且必須實現抽象類的所有抽象方法;
?
接口(interface)接口特點;
接口通過interface聲明;
接口只允許常量和抽象方法存在,常量可以省略public static final,抽象方法可以省略public abstract;
接口可以實現多繼承(繼承多個接口);
接口不能被實例化;接口通過類來實現接口,實現的關鍵字是implements,類要實現接口的所有抽象方法,類可以實現多個接口;
抽象類也可以通過implements實現接口,并且允許不實現里面的抽象方法;
?
運行時異常與一般異常有何異同?
Java提供了兩類主要的異常:
運行時異常runtime exception和一般異常checked exception。checked 異常。對于后者這種異常,JAVA要求程序員對其進行catch。所以,面對這種異常不管我們是否愿意,只能自己去寫一大堆catch塊去處理可能的異常。
?
運行時異常我們可以不處理。這樣的異常由虛擬機接管。出現運行時異常后,系統會把異常一直往上層拋,一直遇到處理代碼。如果不對運行時異常進行處理,那么出現運行時異常之后,要么是線程中止,要么是主程序終止。
?
HashMap的底層代碼/原理
HashMap底層就是一個數組結構,數組中的每一項又是一個鏈表。
當新建一個HashMap的時候,就會初始化一個數組。
Entry就是數組中的元素,每個?Entry?其實就是一個key-value對,
它持有一個指向下一個元素的引用,這就構成了鏈表。
?
?
HashMap?在底層將?key-value?當成一個整體進行處理,這個整體就是一個?Entry?對象。
HashMap?底層采用一個?Entry[]?數組來保存所有的?key-value?對,
當需要存儲一個?Entry?對象時,會根據hash算法來決定其在數組中的存儲位置,
再根據equals方法決定其在該數組位置上的鏈表中的存儲位置;當需要取出一個Entry時,
也會根據hash算法找到其在數組中的存儲位置,
再根據equals方法從該位置上的鏈表中取出該Entry。
?
默認是構建一個初始容量為?16,負載因子為?0.75?的?HashMap。
?
也就是說,默認情況下,數組大小為16,那么當HashMap中元素個數超過16*0.75=12的時候,
就把數組的大小擴展為?2*16=32,即擴大一倍,然后重新計算每個元素在數組中的位置,
而這是一個非常消耗性能的操作,所以如果我們已經預知HashMap中元素的個數,
那么預設元素的個數能夠有效的提高HashMap的性能。
?
堆和棧的區別
?堆內存用來存放由new創建的對象和數組,通過new關鍵字和構造器創建的對象放在堆空間,大量的對象都是放在堆空間,整個內存包括硬盤上的虛擬內存都可以被當成堆空間來使用
棧里面存放的是所有基本數據類型和引用數據類型,我們定義一個基本數據類型的變量,一個對象的引用,還有就是函數調用的現場保存都使用內存中的棧空間,棧空間操作最快但是也很小
arrayList和linkedList的區別
我們知道ArrayList是List接口的一個實現類,它的特點是查詢效率高,增刪效率低,線程不安全?
原因是因為ArrayList底層是封裝了一個數組,它是用數組實現的。?
數組在內存中的存儲方式:
現在定義一個int[] a數組,假設它的首地址是2000,int類型占4個字節,所以a[0]的首地址是2000,a[1]的首地址就是2004,以此類推….到a[n]?
就很形象的解釋了,為什么ArrayList的查詢效率高,每次只需要一個偏移量就可查到?
但是它的增刪效率為什么會低呢??
再往下看:
如果想在這個數組的中間或是第一項前插入一項,它的插入過程是以迭代的方式,讓它后面的每一項依次往后挪,就如圖上的要在第二項的位置上插入一項,其實這個過程是比較慢的,如果是你每次都在最后插入,這是個例外,因為它不用再去影響其它的元素,直接插在最后面;當然刪也是同一個道理?
看完了ArrayList,我們再去研究一下LinkedList?
它的特點是:增刪效率比較高,而查詢效率低?
LinkedList是底層用雙向循環鏈表實現的List,鏈表的存儲特點是不挨著,它存儲的每個元素分為三段:上一項的地址、下一項的地址、元素的內容,而數組卻沒有上一項,下一項這種情況?,因為數組只需要根據一個偏移量,就可以找到下一項或上一項
雙向鏈表的底層結構圖:
?
每個元素在內存中的排列像是隨機的,中間沒有連續性,通過地址來找到上一項或下一項,從圖上應該可以理解了?
那么現在問題來了,如果查詢LinkedList中的某一項,腫么辦??
沒有好辦法,只能把元素全部過一遍,這樣就會比較的慢?
而它的好處體現在它的增刪效率非常的快,為什么呢??
假如我把右上的一個元素刪掉,可以看到左上和右下的兩個元素會直接連上,至于它們兩個是怎么牽上手的,這里不多講了,你懂的…………….?
同理,在下面增加一個的時候,也是同一個道理,也就是說,當你增加或刪除一個元素的時候,在LinkedList里,它最多只會影響兩個元素,而不像ArrayList里,當在中間插入一個元素時,它后面的所有的元素都要受到影響,那么這樣在一定程度上LinkedList的增刪效率就會明顯的高于ArrayList的
?
什么是單例多例
單例:就是所有的請求都用一個對象來處理,service和dao層的對象通常都是單例的,?之所以用單例,是因為沒必要每個請求都新建一個對象,這樣子???既浪費CPU又浪費內存;
單例就是該類只能返回一個實例。
單例所具備的特點:
1.私有化的構造函數
2.私有的靜態的全局變量
3.公有的靜態的方法
多例:
指每個請求用一個新的對象來處理,比如action;??之所以用多例,是為了防止并發問題;即一個請求改變了對象的狀態,此時對象又處理另一個請求,而之前請求對對象狀態的改變導致了對象對另一個請求做了錯誤的處理;
?用單例和多例的標準只有一個,?當對象含有可改變的狀態時則多例,否則單例;??
?
懶漢式單例模式:
public class Singleton {private static Singleton singleton = null;private Singleton(){}synchronized public static getInstance(){if(singleton == null){singleton = new Singleton();}return singleton;}}?
餓漢式單例模式
public class Singleton {private static final Singleton singleton = new Singleton();public Singleton(){}public static getInstance(){return singleton ;}}?
線程安全式單例模式:
public class Singleton{private static Singleton singleton;private Singleton(){}public static getInstance(){if(null == singleton){synchronized(Singleton.class){if(null == singleton){singleton = new Singleton();}}}return singleton;}}?
冒泡排序:
for(int i=0;i<sort.length-1;i++){for(int j=0;j<sort.length-1-i;j++){If(sort[j]<sort[j+1]){temp=sort[j];sort[j]=sort[j+1];sort[j+1]=temp;}}}Sql語句:
分頁查詢每頁3條查看第4頁的數據
select s.* from(select t.* , rownum rn from(select * from t_score )twhere rownum<=12)swhere rn>=10刪除重復的記錄
delete from t_log tl where rowid <(select max(rowid) from t_log tg where tl.logid=tg.logid and tl.logname=tg.logname andtl.logdate=tg.logdate and tl.logcount=tg.logcount and tl.typeid=tg.typeid)二叉樹
?
JDK版本特性!
Jdk1.7新特性?
1,?Switch可以支持字符串,
2,泛型自動推斷,
3,倆個char之間可以使用equals方法?
4,安全的加減乘除
5,map支持花括號傳值
Jdk1.8新特性
1,允許接口中有默認方法實現??
2,函數式接口??
3,接口里允許使用方法體
4,允許::調用方法???
5,加入全新的日期API(這些功能都放在java.time包下)提出了時間的加減乘除?
6,允許在類和接口上寫注解
JDK1.9新特性
1,簡化進程API??
2,輕量級的JSon?API??(Java.util包)
3,錢或貨幣的API(錢或貨幣之間的轉換)?
4,改善鎖爭用機制(通訊服務器開房了海量的進程,鏈接客戶端申請同一個資源)
?
接口與抽象類的區別?
1. 抽象類可以有構造方法,接口中不能有構造方法。
2. 抽象類中可以有普通成員變量,接口中沒有普通成員變量
3. 抽象類中可以包含非抽象的普通方法,接口中的所有方法必須都是抽象的,不能有非抽象的普通方法。
4. 抽象類中的抽象方法的訪問類型可以是public,protected和默認類型,但接口中的抽象方法只能是public類型的,并且默認即為public abstract類型。
5. 抽象類中可以包含靜態方法,接口中不能包含靜態方法
6. 抽象類和接口中都可以包含靜態成員變量,抽象類中的靜態成員變量的訪問類型可以任意,但接口中定義的變量只能是public static final類型,并且默認即為public static final類型。
7. 一個類可以實現多個接口,但只能繼承一個抽象類。
get和post請求的區別??
答:?
①get請求用來從服務器上獲得資源,而post是用來向服務器提交數據;?
②get將表單中數據按照name=value的形式,添加到action 所指向的URL 后面,并且兩者使用"?"連接,而各個變量之間使用"&"連接;post是將表單中的數據放在HTTP協議的請求頭或消息體中,傳遞到action所指向URL;?
③get傳輸的數據要受到URL長度限制(1024字節);而post可以傳輸大量的數據,上傳文件通常要使用post方式;?
④使用get時參數會顯示在地址欄上,如果這些數據不是敏感數據,那么可以使用get;對于敏感數據還是應用使用post;?
⑤get使用MIME類型application/x-www-form-urlencoded的URL編碼(也叫百分號編碼)文本的格式傳遞參數,保證被傳送的參數由遵循規范的文本組成,例如一個空格的編碼是"%20"。
&和&&的區別。
&和&&都可以用作邏輯與的運算符,&&為短路與,&不是短路與。
另外&可以做為整數的位運算符
?
例1:對于if(str != null&& !str.equals(“”))表達式,當str為null時,后面的表達式不會執行,所以不會出現NullPointerException如果將&&改為&,則會拋出NullPointerException異常。
例2:If(x==33 &++y>0) y會增長,if(x==33 && ++y>0)不會增長
?
備注:這道題先說兩者的共同點,再說出&&和&的特殊之處,并列舉一些經典的例子來表明自己理解透徹深入、實際經驗豐富。
"=="和equals方法的區別?
他們的區別主要存在在引用數據類型上
==為比較兩側的對象是否同一對象,是用內存地址來比較的
?
equals是方法,默認是用內存地址比較,重寫后,主要是用來比較兩側的對象的值是否相同,和equals方法中的實現有關
==可以兩側都為null,但equals左側的引用指向的對象不能空,不然有NullPointerException
?
除非需要比較兩個引用指向的對象是同一對象,一般都使用equals方法進行比較。尤其是String之類的值對象,另外,常量盡量放在比較的左側
Integer與int的區別
int是java提供的8種原始數據類型之一,意思整型,占用4字節。
Integer是java為int提供的封裝類,是引用數據類型。
int的默認值為0,而Integer的默認值為null,即Integer可以區分出未賦值和值為0的區別,int則無法表達出未賦值的情況。
例如,要想表達出沒有參加考試和考試成績為0的區別,則只能使用Integer
?
在JSP開發中,Integer的默認為null,所以用el表達式在文本框中顯示時,值為空白字符串,而int默認的默認值為0,所以用el表達式在文本框中顯示時,結果為0,所以,int不適合作為web層的表單數據的類型。
?
在Hibernate中,如果將OID定義為Integer類型,那么Hibernate就可以根據其值是否為null而判斷一個對象是否是臨時的,如果將OID定義為了int類型,還需要在hbm映射文件中設置其unsaved-value屬性為0。
?
另外,Integer提供了多個與整數相關的操作方法,例如,將一個字符串轉換成整數,Integer中還定義了表示整數的最大值和最小值的常量。
面向對象的特征有哪些方面
1. 封裝,隱藏內部實現,只暴露公共行為
2. 繼承,提高代碼的重用性
3. 多態,體現現實生活中相似對象的差異性
4. 抽象,抽取現實世界中相似對象的共同點
?
?
linux中的命令:
?
1 ?ctrl + alt 切換系統
2 開機?power on ?關機?power off
3 命令?:?跳目錄?cd ?/ 根目錄?cd.. 上一級目錄
4 ls 插卡目錄???mkdir 建文件夾??touch 建文件???cat 看文件內容?vi 編輯文件(insert模式,按esc 鍵退出?:wq 保存并退出)
5 rm -rf 刪除文件??su root 切換用戶?
ps -ef | grep :查看進程信息
vi:文件編輯命令
more:分頁查看命令
top:常用的性能分析工具,能夠實時顯示系統中各個進程的資源占用狀況
ifconfig:顯示或配置網絡設備的命令
ping:它通常用來測試與目標主機的連通性
rsync、scp:文件同步命令
Jvm相關
棧溢出,就是當遞歸調用的時候沒有臨界退出條件
批量導入大量數據或者dom4j解析大的xml文件的時候
會出堆溢出,通過分段批量提交以及sax代替dom4j
java虛擬機有一個堆,堆是運行時數據區域所有的類和數組的內存都是從堆里分配的
堆是在java虛擬機啟動的時候創建的,
兩種內存:堆和棧,堆是java開發人員使用的
棧是jvm自己使用的,內存結構分為:堆(邏輯上連續的,物理上不是連續的,存的是
類實例,和數組),虛擬機棧(基本的數據類型,引用對象),本地方法棧(jvm棧是為
java方法的執行提供服務,
而本地方法棧是為虛擬機為本地方法提供服務的),方法區(持久代)
(加載了類的基本信息,常量池的屬于方法區的一部分,string就是存在常量池中),
計算器(就是來選取要執行下一條字節碼的指令)
gc垃圾回收機制,
動態分配內存的大小,依靠垃圾回收機制來完成對分配內存空間的回收,
從而避免了內存溢出的問題,降低了程序員工作的復雜度,采用了分代回收算法,jvm將內存分為
年輕代和年老代,年輕代就是對象剛建立不久,生命周期也很短,而年老代對象創建的比較久了
而且生命周期也很長,對于年輕代??頻繁??采用復制算法??而年老代比較少采用tracing算法
jvm的內存大小和操作系統有關,
一般來說是32位處理器內存為2個g,64為的處理器就不會有有限制了
操作系統會給一個限制一般是2GB-3GB(一般來說Windows系統下為1.5G-2G,Linux系統?下為2G-3G)
java的監視和管理控制臺:是我們在運行的時候監視各種jvm資源統計信息,使用與檢測死鎖,內存遺漏,可以連接到一個本地或遠程的jvm可以用來監視線程的狀態,內存的使用情況,垃圾收集等等等
jvm的調優:
開啟server模式,增堆的大小,以及持久代的大小,提高程序的運行效率,
設置初堆大小和最大堆的大小都為一樣的值,避免了堆增長帶來額外的壓力,持久代也是一樣
jvm中類的生命周期:加載、連接、初始化,使用,卸載
連接(校驗,準備,解析)
在服務器啟動的時候報內存溢出是因為方法區太小,也就相當于持久代的內存太小。
通過-XX:PermSize以及-XX:MaxPermSize來指定其大小
,可以解決這個問題。
引導類加載器:rt.Jar包
擴展類加載器:jre目錄有一個ext下面的lib目錄
系統類加載器:classPath的里面的東西
自定義類加載器:加載自定義類
Jvm優化:
JVM 優化主要是解決java的 GC (垃圾回收)問題。
JVM 的使用過程中各代有,年輕帶主要存放,新創建對象。 年老代,年老代存放從年輕代存活的 對象。Perm(持久代)用 于存放靜態文件,如今Java類、方法等。一般持久代可以設置大一點。
GC優化的目的有兩個:
1、將轉移到老年代的對象數量降低到最小;
2、減少full GC的執行時間;
為了達到上面的目的,一般地,你需要做的事情有:??
1、減少使用全局變量和大對象;
2、調整新生代的大小到最合適;
3、設置老年代的大小為最合適;
4、選擇合適的GC收集器;
【垃圾回收(GC收集器):串行收集器、并行收集器、并發收集器。
o ??串行處理器:
?--適用情況:數據量比較小(100M左右);單處理器下并且對響應時間無要求的應用。
?--缺點:只能用于小型應用
o ??并行處理器:
--適用情況:“對吞吐量有高要求”,多CPU、對應用響應時間無要求的中、大型應用。舉例:后臺處理、科學計算。(例如 ERP 銀行系統)
?--缺點:應用響應時間可能較長
o ??并發處理器:
--適用情況:“對響應時間有高要求”,多CPU、對應用響應時間有較高要求的中、大型應用。舉例:Web服務器/應用服務器、電信交換、集成開發環境。(例如互聯網網站)】
5、設置jvm堆大小 ,32bit 1.5-2G ?,64bit 可以超過 2G ,新版的JDK 每個線程的堆大小在1M改變這個線程所占用的堆大小,可以生成更多的線程,一般項目里線程數不能超過5000個。
多線程介紹、列舉線程池和業務場景:
多線程基本介紹:http://www.cnblogs.com/yxt9322yxt/p/4804026.html
1).什么是多線程
1個進程中可以開啟多條線程,每條線程可以并行(同時)執行不同的任務
進程?->車間,線程->車間工人
多線程技術可以提高程序的執行效率
比如同時開啟3條線程分別下載3個文件
2).多線程的原理
同一時間,CPU只能處理1條線程,只有1條線程在工作(執行)
多線程并發(同時)執行,其實是CPU快速地在多條線程之間調度(切換)
如果CPU調度線程的時間足夠快,就造成了多線程并發執行的假象
思考:如果線程非常非常多,會發生什么情況?
CPU會在N多線程之間調度,CPU會累死,消耗大量的CPU資源
每條線程被調度執行的頻次會降低(線程的執行效率降低)
3)線程池:
是指在初始化一個多線程應用程序過程中創建一個線程集合,然后在需要執行新的任務時重用這些線程而不是新建一個線程。線程池中線程的數量通常完全取決于可用內存數量和應用程序的需求。然而,增加可用線程數量是可能的。線程池中的每個線程都有被分配一個任務,一旦任務已經完成了,線程回到池子中并等待下一次分配任務。
2)Java提供的四種線程池的好處在于:
a. 重用存在的線程,減少對象創建、消亡的開銷,性能佳。
b. 可有效控制最大并發線程數,提高系統資源的使用率,同時避免過多資源競爭,避免堵塞。
c. 提供定時執行、定期執行、單線程、并發數控制等功能
3)Java通過Executors提供四種線程池,分別為:
newCachedThreadPool
創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閑線程,若無可回收,則新建線程。
newFixedThreadPool
創建一個定長線程池,可控制線程最大并發數,超出的線程會在隊列中等待。
newScheduledThreadPool
創建一個定長線程池,支持定時及周期性任務執行。
newSingleThreadExecutor
創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行。
4)多線程的使用場景:http://blog.csdn.net/hll814/article/details/50816268
1、 ?常見的瀏覽器、Web服務(現在寫的web是中間件幫你完成了線程的控制),web處理請求,各種專用服務器(如游戲服務器)
2、 ?servlet多線程
3、 ?FTP下載,多線程操作文件
4、 ?數據庫用到的多線程
5、 ?分布式計算
6、 ?tomcat,tomcat內部采用多線程,上百個客戶端訪問同一個WEB應用,tomcat接入后就是把后續的處理扔給一個新的線程來處理,這個新的線程最后調用我們的servlet程序,比如doGet或者dpPost方法
7、 ?后臺任務:如定時向大量(100W以上)的用戶發送郵件;定期更新配置文件、任務調度(如quartz),一些監控用于定期信息采集
8、 ?自動作業處理:比如定期備份日志、定期備份數據庫
9、 ?異步處理:如發微博、記錄日志
10、頁面異步處理:比如大批量數據的核對工作(有10萬個手機號碼,核對哪些是已有用戶)
11、數據庫的數據分析(待分析的數據太多),數據遷移
12、多步驟的任務處理,可根據步驟特征選用不同個數和特征的線程來協作處理,多任務的分割,由一個主線程分割給多個線程完成
13、desktop應用開發,一個費時的計算開個線程,前臺加個進度條顯示
14、swing編程
jQuery的10個常用方法,常用選擇器(五大類),ajax常用的屬性
常用方法:
1,$("#ID").val(); //取value值2,$("#ID").val("xxx"); //賦值3,$("#ID").text(); //相當于取innerText4,$("#ID").text(""); //相當于賦值給innerText5,$("#ID").html(); //相當于取innerHTML6,$("#ID").html(""); //相當于賦值給innerHTML7,$("#ID").add();//將元素添加到匹配元素的集合中8,$("#ID").hide(); //隱藏9,$("#ID").show(); //顯示10,$("#ID").attr(key,value);//取得或設置匹配元素的屬性值常用選擇器:
1,id選擇器$("#myELement")選擇id值等于myElement的元素,id值不能重復在文檔中只能有一個id值是myElement所以得到的是唯一的元素
2,標簽選擇器$("div")選擇所有的div標簽元素,返回div元素數組
3.類選擇器$(".myClass")選擇使用myClass類的css的所有元素
4.通配符選擇器$("*")選擇文檔中的所有的元素
5.屬性選擇器$("[href='#']") 選取所有帶有 href 值等于 "#" 的元素。
Ajax的屬性:
1.url:?要求為String類型的參數,(默認為當前頁地址)發送請求的地址。
2.type:?要求為String類型的參數,請求方式(post或get)默認為get。注意其他http請求方法,例如put和delete也可以使用,但僅部分瀏覽器支持。
3.async:為Boolean類型的參數,默認設置為true,所有請求均為異步請求。如果需要發送同步請求,請將此選項設置為false。注意,同步請求將鎖住瀏覽器,用戶其他操作必須等待請求完成才可以執行。
4.data:前臺往后臺傳送的數據信息,可以是form表單或者單個數據信息
5.dataType:json或者text,規定請求后臺返回前臺時的數據類型
6.success:為Function類型的參數,請求成功后調用的回調函數
7.error:為Function類型的參數,請求失敗時被調用的函數
Tomcat優化
1.使用64位的tomcat和jdk
2.開啟server模式
3.通過-Xms和-Xmx設置初始堆大小和最大堆大小,通常將兩個值設置為一樣,避免堆空間不斷增大和縮小所帶來的性能損耗
4.啟用gzip壓縮
5.通過maxThreads增加tomcat的最大并發數,將其設置為500
Hibernate優化:
在處理大數據量時,會有大量的數據緩沖保存在Session的一級緩存中,這緩存大太時會嚴重顯示性能,所以在使用Hibernate處理大數 據量的,可以使用session. clear()或者session. evict(Object) ,在處理過程中,清除全部的緩存或者清除某個對象。
通過使用Hibernate的一級緩存,二級緩存,查詢緩存等來提高性能
Hibernate可以通過設置hibernate.jdbc.fetch_size,hibernate.jdbc.batch_size等屬性,對Hibernate進行優化。
????Batch Size是設定對數據庫進行批量刪除,批量更新和批量插入的時候的批次大小,Batch Size越大和數據庫交互的次數就越少,速度就越快,
但也不要無限的大下去,通常選擇一個合適的值,如100條;其次我們在進行大批量數據的導入操作時,可以結合batchsize進行分段批量提交,從而達到最優效果。
序列化和反序列化
?????序列化:序列化就是將內存中的對象持久化到本地文件的過程
為什么要序列化:通常在http網絡傳輸過程中,是不支持對象傳遞的,所以通過序列化,將對象轉換成可以被傳輸的流,方便對象信息傳遞
如何將一個對象序列化:1、類要實現 Serializable接口;2、通過ObjectOutputStream的writeObject()將對象寫到文件中
反序列化:將文件中存儲的對象信息讀取后寫到內存中
集群
Zookeeper集群
1、分別配置3個解壓好的zookeeper,在每個zookeeper文件夾下創建一個data目錄,在data文件夾下創建一個文件(myid),文件的內容就是此zookeeper的編號(1、2、3)
2、分別把3個zookeeper下conf目錄下的zoo_sample.cfg文件復制一份改名為zoo.cfg
3、分別修改3個zookeeper下的zoo.cfg的配置
?
dataDir:分別對應3個zookeeper各自新建的data路徑
clientPort:當前每個zookeeper的端口號,要保證唯一性
server.(1,2,3):3個zookeeper各自的ip地址:通訊端口:選舉端口
4、分別啟動3個zookeeper。使用dos進入每個zookeeper/bin目錄下。
啟動方式如下,必須這么啟動,雙擊zkServer.cmd啟動無效
?
到此,zookeeper集群配置完成
Solr集群
1、創建4個tomcat實例,分別修改其端口。8981-8984
2、按照之前的流程把solr.war分別部署到4個tomcat/webapps下
????????????????? 注意解壓開solr.war,然后刪除solr.war源包
? ? ? ? ? ? 注意把jar包拷貝過來(example/lib/ext/*.jar)
3、分別創建4個solrhome(1,2,3,4),把solr源包下的example\solr\*拷貝到每一個solrhome下
4、分別修改4個tomcat下solr的web.xml,分別指定其對應的那個solrhome的位置。
5、把任一個solrhome中的配置文件上傳到zookeeper集群。使用zookeeper的客戶端上傳
6、分別修改solrhome(1,2,3,4)下的solr.xml文件,指定當前實例運行的ip地址及端口號。
7、分別修改每一臺solr的tomcat 的 bin目錄下catalina.bat文件,向文件中加入-DzkHost指定zookeeper集群服務器地址
8、分別啟動4臺tomcat,訪問任意一臺tomcat
9、創建一個兩片的collection,重新訪問,刪除collection1,重新訪問
?Tomcat集群
1、復制兩個tomcat,在tomcat中將webapps中的ROOT文件夾都刪掉(注意:使用在server.xml文件中配置<Context path="" docBase="e:/ssh-login"/>,啟動tomcat時,將在webapps文件夾中生成ROOT文件夾,訪問時不加項目名)
2、修改server.xml文件中的端口號,第一個tomcat中修改端口號為8081
3、啟動tomcat
4、修改nginx-1.9.14文件夾下的conf文件夾下的nginx.conf文件(http標簽、本地服務器連接端口、請求攔截)
Mysql主從:
1、首先要安裝兩臺MySQL服務;端口號不能一致。配置主庫mastar,server-id = 1
2、指定要同步的數據庫,給主庫添加一個用戶,并指定replication權限,在主數據庫里面運行show master status;記下file和position字段對應的參數。
3、配置從庫,指定同步的數據庫,首先要先執行stop slave;命令,先停止從庫的復制功能;然后設置主從庫的一些參數,要對應主數據庫里查出來的file和position兩個參數,最后開啟從庫復制功能,start slave;
nginx熱備:
使用nginx+keepalived雙機熱備的方式來實現負載均衡調度器的高可用性,其中keepalived主要是解決了nginx的單點故障,用來檢測服務器狀態,如果一臺web服務器掛了,keepalived將檢測到,并將有故障的機器剔除掉,然后人工進行修復。
?
非專業知識:
大學情況:
學校名稱:西安外事學院(外事)
學校地址:有南北校區,都在魚化寨
??出生日期:1992年11月16日
?上小學日期:1998年9月 ??6歲 六年
?上初中日期:2003年9月 ??12歲 三年
?上高中日期:2006年9月 ??15歲 三年
?上大學日期:2009年9月 ??18歲 四年
畢業時間:2013年7月 ????22歲
入學時間:2009年9月
畢業時間:2013年7月
校長名字:陳愛民
學院:工學院
專業名稱:計算機信息與技術
專業課: 數據結構、計算機組成原理、操作系統、軟件工程、計算機程序設計、計算機網絡、計算機圖形學、多媒體技術、數據庫原理、面向對象技術、圖象處理技術、電路原理、模擬電子技術、數字邏輯技術、計算方法、編譯原理等。
院系名稱:計算機學院
學歷證書:本科
學位:學士學位
在校學生有:12000余人
有教師:1000左右人
學校的院系有:商學院、文學院、醫學院、工學院、影視藝術學院等10幾個學院,
本院專業:計算機科學與技術、物聯網工程、電氣工程及其自動化、電子信息工程、交通運輸、產品設計六個本科專業
路線:40路,外事北校區站下車
醫學院護理專業;商學院人資、會計;文學院學前教育
三、主要課程
主干課程:高級語言程序設計、UI設計(基礎/高級)、Linux操作系統、數據結構與算法、計算機網絡原理、軟件工程、數據庫原理與應用、SQLite數據庫技術、Java(基礎/高級)、Web網頁技術、Java Web開發技術、Web框架技術、Android開發(基礎/高級)、軟件分析與測試
主要實踐、創新環節:社會調查、Linux操作系統實訓、高級語言程序設計實訓、數據庫實訓、Web網頁技術實訓、專業綜合實訓、畢業論文(設計)
主要專業實驗:Linux操作系統實驗、高級語言程序設計實驗、數據庫實驗、Java程序設計實驗、靜態/動態網頁設計實驗,UI交互設計實驗、Android開發實驗、Java Web開發實驗、Web框架實驗等
上家公司:
公司簡介:北京思前軟件有限公司(簡稱就好)
公司地址:北京海淀區上地七街1號匯眾大廈2號樓106室
住址到公司地址:乘坐592路公交,從育新地鐵站上車——上地七街站下車 ?時間大概40分鐘左右,打車大概20左右
公司規模:20-99人,我們項目組9 一個項目經理,5名開發人員,2名前臺,一個運維
入職時間:2013-8
有沒有上過保險:
上個公司說是可以要折現。我就沒入
沒有上五險一金的原因:
沒有在北京買房的目的,交了五險一金還不如每個月多發一些現金比較來的實際
五險一金的名稱:
養老保險,醫療保險,失業保險,工傷保險,生育險,住房公積金
?
三個詞形容自己:
認真細致,團隊協作能力強,抗壓能力強
談談你的對軟件行業發展前景的理解:
????現在的生活越來越離不開網絡和便捷的生活方式,軟件的行業就是順應了這一特點,通過開發的軟件簡化了人們一些生活復雜度,所以在不久的將來必將成為科技的前端和人們生活的密切相關。
為什么離職:
公司最近轉型,轉向.net/php了,java這方面的項目也少了,所以想換個環境,不斷提高充實自己。我覺得咱們公司有自己的企業文化和實力(具體到時候自己網上查),能夠給我提供一個展現自己能力的價值的平臺,所以我給咱們公司投遞了簡歷。
如何看待你上家公司:
????每個公司都有自己的一個企業文化,從上一家公司我有深刻的體會,就是遇事要向內歸因,外界的給我們帶來的壓力只能是客觀因素,從本身去找解決辦法才是我們提高的一個重要標志,逐步讓我成為一個有責任心,有目標的人。和之前的同事的交流也讓我學到非常多的知識和擴展交際圈,明白更多的溝通方式。
你憑什么要這么高的薪資?
???首先我既然敢要這么多錢,那么我自信我有這樣的實力能給公司帶來同等甚至更大的經濟效益,我正值壯年,精力旺盛,能夠在高壓力下正常的工作,曾在項目上線時連續兩天通宵直到項目正常運行,在工作時,項目經理讓我研究東西,我能在較快的時間里學會并熟練應用,把這項技術教給同事,讓他們快速學會這項技術
四年漲薪:
2013年實習的時候是6500,稅后大概6000左右,轉正7500左右
到2015上半年漲了5000左右?,總12000左右
?
2016跳槽一次漲到16000 ,稅后大概15000,到今年漲到17000
?
?
跳槽的看法:?
不能頻繁跳槽,適當的跳槽是可以理解的,為了個人的一些東西。
?
你的五年規劃
如果我被貴公司錄用的話,肯定先快速的適應公司新環境.與同事處好人際關系,
然后在完成公司給的任務之后學一些新的技術,來提升自己的能力。如果貴公司晉升機制好的話,我會考慮向項目經理的方面去發展。
談談你對加班的看法:
加班其實是每個公司遇到的問題,之前我也提過我是一個能夠以大局為重的人,為了公司的利益和項目組的進度我完全可以加班來完成,但是在工作中我會規劃好自己的進度按時完成任務,即使在我的任務完成的前提下,我也會和項目組待在一起幫助他們完成項目任務。
分庫分表:
為什么分表:一張表中的數據太多了、為什么分庫:一個數據庫中的表太多了、如果不分庫分表的后果:檢索速度慢、層次不清晰。
在這工作幾年的過程中讓我明白到,當遇到困難時不去退縮勇于面對才能讓自己更快的成長,學會向內歸因,不推卸責任和錯誤,積極主動承擔責任和承認錯誤,吸取別人的優點來補足自己的缺點和不足,避免下次犯同樣的錯誤。閑暇時喜歡上一些技術類的網站:比如開源中國、CSDN,推酷、博客園等網站,關注一些前沿的技術。因為我相信,學無止境,不進則退。
最后你還想有什么了解嗎?
- 咱們公司的五險一金是怎么交的?
- 咱們公司開發的主力框架什么?
- 咱們公司的晉升制度是什么?
- 咱們公司用的什么技術框架/開發工具/數據庫?
- 咱們公司在開發什么類型的項目?
?
總結
以上是生活随笔為你收集整理的2019java后端面试集合篇最值得收藏的(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【建模算法】基于粒子群算法求解TSP问题
- 下一篇: 多元统计分析matlab,matlab与