環境資訊中心綜合外電;姜唯 編譯;林大利 審校
本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※評比前十大台北網頁設計、台北網站設計公司知名案例作品心得分享
※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選
※評比南投搬家公司費用收費行情懶人包大公開
※幫你省時又省力,新北清潔一流服務好口碑
摘錄自2019年12月9日聯合新聞網「轉角國際」報導
「島上已確定5死,但死傷數量恐不止這樣。」紐西蘭北島豐盛灣區的火山奇景名勝——白島(White Island,毛利語稱「Whakaari 」)——當地時間9日下午2時11分,突然無預警噴發。雖然噴發的時間與規模都不大,但事前全無偵測到地質活動的徵兆,因此噴發當下,島上仍有近百人的登島旅行團。目前紐西蘭總理已出面坐鎮警急應變,並派出警消海巡登島搜救,但直到傍晚為止已確認5人死亡、「20~30人仍下落不明」;已被救出的旅客則有多人遭火山碎屑集中,或遭噴發的高溫蒸氣嚴重灼傷,但由於災害海域已經入夜且仍有噴發可能,「因此救難特遣隊目前沒有辦法登島救援失聯者。」
位於紐西蘭北部沿海的「白島」,是地質景觀極為壯麗的海上火山島。其與紐西蘭北島的火山系統同為一脈,皆屬於活躍的「陶波火山帶」(TVZ)。由於過往白島的頻繁噴發,因此原住民毛利人稱其為「劇烈的火山」(Whakaari);而當英國探險家庫克船長(James Cook)於16世紀帶領歐洲艦隊航至紐西蘭後,則因Whakaari島上的灰白火山灰與噴發蒸氣,取名稱之為「白島」。
由於火山地形險峻不適人居,白島長年無人居住、鮮少開發,唯在19世紀末期曾短暫開礦採挖硫礦,但礦坑聚落卻在1914年遭山崩而下的火山泥流毀滅,白島礦業從此終止,直到1970年代才被列為保護區,並開始小額開放預約制的「登島觀光」。
本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※評比前十大台北網頁設計、台北網站設計公司知名案例作品心得分享
※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選
※評比南投搬家公司費用收費行情懶人包大公開
※幫你省時又省力,新北清潔一流服務好口碑
電動版奔馳B級是戴姆勒繼Smart ForTwo電動版之後的第二款純電動車,由戴姆勒和特斯拉聯合開發,其電動馬達由特斯拉提供,今年將先後在美國和歐洲上市。

電動版奔馳B級擁有大約200公里的續航里程,0到100km/h加速僅需時7.9秒,最高速度為160km/h。其電動馬達由特斯拉提供,規律達174馬力,同寶馬i3電動車的規律相比還高出8馬力。目前戴姆勒尚未公佈新款奔馳B級電動車的售價。
電動版奔馳B級由戴姆勒位於德國的拉施塔特(Rastatt)工廠負責生產,汽油、柴油及天然氣版本的奔馳B級也在該工廠投產。據戴姆勒一名女發言人透露,電動版奔馳B級在其整個生命週期中的產量預計將達到五位數。
本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※評比前十大台北網頁設計、台北網站設計公司知名案例作品心得分享
※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選
※評比南投搬家公司費用收費行情懶人包大公開
※幫你省時又省力,新北清潔一流服務好口碑
日前,銀河電子為拓展新能源汽車領域,以8.73億人民幣(下同)收購福建駿鵬通信科技有限公司和洛陽嘉盛電源科技有限公司。 福建駿鵬主要業務為新能源電動車和高端LED關鍵結構件的供應商,嘉盛電源主營業務定位於新能源電動汽車充電類產品。2015年前4個月兩公司的營業收入分別是6622.59萬元和2331.76萬元,實現淨利潤1146.11萬元和685.14萬元。 交易對方承諾:福建駿鵬2015年、2016年和2017年經審計的扣除非經常性損益後歸屬于母公司股東的淨利潤分別為5500萬元、7200萬元和9500萬元;嘉盛電源2015年、2016年和2017年經審計的扣除非經常性損益後歸屬于母公司股東的淨利潤分別為2000萬元、3000萬元和4000萬元。 銀河電子錶示,此次收購後將進一步擴大和提升了公司在新能源電動汽車行業的業務機會和盈利能力
本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"
※網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線
※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整
※南投搬家費用,距離,噸數怎麼算?達人教你簡易估價知識!
※教你寫出一流的銷售文案?
互聯網公司程序員,前些天項目趕進度,被強制加班。 我們公司以前也是鼓勵員工加班,但比較隱晦, 不是強制的,而這次是上司直接發話,必須要加班,否則工作無法完成的責任會扣到你頭上。
被要求強行加班,無償的,而且是喪心病狂的996,我臉上顯得很平靜,但是內心一萬頭草泥馬在奔騰。當天晚上,我就發微信給上司,我說:
“趕項目我一定不拖進度,該完成的工作按時完成,但是你別讓我加班,第一天弄的太晚,直接影響第二天工作效率,這樣得不償失”
工作只是生活的一部分,如果每天9點以後下班,就表示沒時間陪家人,沒時間娛樂活動,沒時間弄好吃的,沒有時間做自己感興趣的事情,到家直接洗洗睡,第二天醒來繼續上班,這樣的生活豈不是很無趣,加班是罪魁禍首。
寫程序是腦力勞動與體力勞動的結合,聚精會神寫一整天代碼,效率很高,但到了下班點,整個人會非常疲乏,如果繼續工作,會影響第二天狀態,所以後面所謂的加班其實是在划水,根本做不了什麼東西。當然,也可以平均分佈工作和划水,正常上班時也不用那麼認真,那麼加班的時候好像還能做點東西, 但是一整天的總工作成果沒有變化。所以,與其把工作分佈到12個小時,還不如前8個小時多做產出,后4個小時下班回家,這樣有效工作量並不會減少,還有了自由時間, 只是看起來沒那麼积極,但不用怕完不成工作而被問責。
程序員俗稱碼農,也叫IT民工,這是自黑,可在不懂技術的領導眼中就跟搬磚工沒區別,在他們眼裡,程序員多加班一小時,就會多一小時工作成果,搬磚嘛,或多或少總能搬幾塊。他們不知道,寫程序雖然不像搞藝術,非常依賴靈感,沒靈感什麼都幹不成,但在精神良好、腦子靈活的狀態下,工作效率絕對要高於無精打采、混混沌沌的狀態,有時候幾小時搞不定的問題,忽然間靈光一閃就能解決,這就不是靠加班加出來的。良好的工作狀態下產生的工作成果不是靠堆時間可以趕超的。所以很多時候在一個不開明的領導指揮下,團隊所有人看似很努力的在加班工作,其實所花的時間都是沒有意義的冤枉時間,原本這些時間可以做更有意義的事情。
還有一種加班,更加無厘頭,這種加班叫做:我也不知道為什麼要加班,別人在加, 那麼我也加一會。
這種加班,到下班時間點后員工們手上的工作停下來了,但沒人動屁股,大家看網頁的看網頁,看視頻的看視頻,打遊戲的打遊戲,下班,不存在的。因為別人都在加班,我下班了,感覺就像在犯罪,有強烈的罪惡感。這種加班比前一種加班更加可惡,沒半分實際意義, 但是偏偏就很難打破。其實每個人都在抱怨,可又沒有人敢越雷池一步。
說實話我挺佩服能不加班的人,雖然加班有很多外部因素,比如工作真的忙,比如公司文化就是這樣,在比如領導犯渾,但加班表達出來的意思其實就是工作任務完不成了,要多花時間。那麼不加班也意味着在正常的工作時間內能游刃有餘的完成工作,是能力的體現。
我也想實現這個夢想,所以我拒絕加班,領導也同意了,他說:“那你自己看着辦吧, 我不強迫你”,然而我知道,我在這家公司只能在地板上混了,連天花板都別想碰到,更別談升級,但是我覺得值,因為我想要更多的自由生活時間。
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※評比前十大台北網頁設計、台北網站設計公司知名案例作品心得分享
※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選
※評比南投搬家公司費用收費行情懶人包大公開
※幫你省時又省力,新北清潔一流服務好口碑
引用自: 《重構 改善既有代碼的設計》
重構是在不改變軟件可觀察行為的前提下改善其內部結構。當你面對一個最需要重構的遺留系統時,其規模之大、歷史之久、代碼質量之差,常會使得添加單元測試或者理解其邏輯都成為不可能的任務。此時你唯一能依靠的就是那些已經被證明是行為保持的重構手法: 用絕對安全的手法從焦油坑中整理出可測試的接口,給它添加測試,以此作為繼續重構的立足點。
因為我們部門內容平台的文章系統之前遺留了很多問題,急需解決這些具有”壞味道”的代碼。最後因為其他人手頭裡都有其他工作,最後這些任務就交給了我。以下是急需解決的問題。
內容平台新增/更新/取消/刪除文章,同步各集團下文章行為狀態,消息鏈路過長的問題。
問題導火索: 運營後台文章發布,發送消息到marketing-base
慢鏈路,鏈路過長
mysql數據同步,單條執行n次
es索引數據同步,dubbo接口調用n次
圖1 鏈路圖
//開啟同步開關的集團
List<Integer> groupList = autoSyncStatusService.getAutoSyncGroupByManageType(MANAGE_TYPE_GROUP_ARTICLE);
for (Integer groupId : syncSubjectList) {
SiteGroupInfoDTO siteGroupInfo = siteSPI.getGroupInfoById(groupId);
Set<String> groupBrandSet = carOnSaleManage.getGroupBrandSet(siteGroupInfo);
List<String> matchedBrandCodes = extractBrandCodesFromArticleLabel(article.getLabelInfos());
if (CollectionUtils.isEmpty(matchedBrandCodes) || CollectionUtils.containsAny(groupBrandSet, matchedBrandCodes)) {
ArticleGroupMaterialBO groupMaterialBO =
ArticleBeanConverter.convertMaterial2GroupMaterial(article, groupId, groupList);
// 設置對應的集團主題id
ArticleGroupSubjectBO groupSubjectBO =
articleGroupSubjectService.getGroupSubjectBySoucheId(groupId, article.getSubjectId());
if (Objects.nonNull(groupSubjectBO.getId())) {
groupMaterialBO.setSubjectId(groupSubjectBO.getId());
groupMaterialBO.setMaterialId(myArticleId);
articleGroupMaterialService.addArticleGroupMaterial(groupMaterialBO);
}
}
} else {
//查詢同步的文章數據是否存在
List<ArticleGroupMaterialBO> list = articleGroupMaterialService.getListByMaterialId(myArticleId);
for (ArticleGroupMaterialBO a : list) {
if (groupList.contains(a.getGroupId())) {
articleGroupMaterialService.changeRecommendStatus(a.getId(), a.getGroupId(), recommend, article.getLastOperatorName(), article.getLastOperatorName());
}
}
}
第4行中我們可以看到這裡有一個for循環️,假設開啟同步開關的集體有1000家,則第18行中mysql插入操作就需要執行1000次。
第24行這裏同樣有一個for循環體️,則26行內部的es數據同步則需要調用1000次。它的實現如下:
@Override
public boolean changeRecommendStatus(int id, int groupId, int recommended, String lastOperatorUserId, String lastOperatorName) {
final boolean success = articleGroupMaterialDAO.changeRecommendStatus(
id, groupId, recommended, lastOperatorUserId, lastOperatorName) > 0;
if (success) {
//更新索引,更改推薦狀態
articleSearchManage.updateArticleIndex(ArticleIndexUtil.getUpdateRecommendIndex(recommended, id, lastOperatorName));
}
return success;
}
對於第一個循環️體中,我們需要將數據批量添加到數據庫,mybatis提供了將list集合循環添加到數據庫的方法。
insertForeach(List < Fund > list) 方法,返回值是批量添加的數據條數public interface FundMapper {
int insertForeach(List<Fund> list);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.center.manager.mapper.FundMapper">
<insert id="insertForeach" parameterType="java.util.List" useGeneratedKeys="false">
insert into fund
( id,fund_name,fund_code,date_x,data_y,create_by,create_date,update_by,update_date,remarks,del_flag)
values
<foreach collection="list" item="item" index="index" separator=",">
(
#{item.id},
#{item.fundName},
#{item.fundCode},
#{item.dateX},
#{item.dataY},
#{item.createBy},
#{item.createDate},
#{item.updateBy},
#{item.updateDate},
#{item.remarks},
#{item.delFlag}
)
</foreach>
</insert>
</mapper>
com.souche.elastic.search.api.IndexService
方法:BulkUpdateResponse bulkUpdate(String index, Map<String, Object> event, String query, String origin)
參數:
index:要操作的索引
event:更新的數據,可以只包含需要更新的字段,相當於mysql的update語句中的set語句中的字段
query:query中的條件相當於mysql中的where,具體語法與下面的搜索接口中【querys:string 複雜的複合查詢 不同字段的OR 查詢】相同
origin:操作源,一般寫調用方自己的應用名,用於區分不同調用方
返回值:
BulkUpdateResponse:
{
requestId:本次操作的唯一標示
status:狀態,目前返回默認都是true
updated:成功更新的條數
failed:更新失敗的條數
message:第一條更新失敗的原因
}
調用示例:
1Map<String, Object> data = new HashMap<>();
2 data.put("id", 20);
3 data.put("title", "xue yin");
4 data.put("content", "kuang dao");
5 BulkUpdateResponse response = indexService.bulkUpdate("test_index", data, "address=bj AND contry=cn", "shenfl");
這條更新將test_index索引中所有 address是bj並且contry是cn 的數據的 title更新成‘xue yin’ content更新成‘kuang dao’,注意:address和contry兩個字段在索引中需要加索引
當前article數據表數據量:
select count(*) as 總數 from article;
結果如下:
總數
369737
@Override
public String addSharedArticle(ArticleBO articleBO) {
ArticleDO articleDO = new ArticleDO();
BeanUtils.copyProperties(articleBO, articleDO);
String shortUUID = UUIDUtil.getShortUUID();
articleDO.setUid(shortUUID);
if (articleDAO.addSharedArticle(articleDO) > 0) {
return shortUUID;
}
return StringUtil.EMPTY_STRING;
}
從上面這個業務邏輯實現類中,我們可以看到事實上我們想得到的是插入表數據的uid。但是之前的邏輯中,我們並沒有判斷該條數據是否已經存在,我們需要在上面代碼中判斷數據是否存在,已存在,查詢最後一天數據的uid返回給上層。不存在的話,執行插入操作。
article_material | CREATE TABLE `article_material` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`my_article_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '內容平台我的文章id',
`status` tinyint(3) unsigned NOT NULL COMMENT '1-待發布、2-發布、3-取消發布',
`subject_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '主題id',
`platform_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '平台id',
`source` varchar(32) NOT NULL DEFAULT '' COMMENT '版塊',
`crawler_article_id` varchar(32) NOT NULL DEFAULT '0' COMMENT '爬蟲的文章id',
`title` varchar(64) NOT NULL DEFAULT '' COMMENT '標題',
`cover_img` varchar(128) NOT NULL COMMENT '封面圖',
`summary` varchar(255) NOT NULL DEFAULT '' COMMENT '摘要',
`labels` varchar(512) NOT NULL DEFAULT '' COMMENT '標籤',
`label_infos` varchar(1024) NOT NULL DEFAULT '' COMMENT '標籤詳細信息',
`content` text NOT NULL COMMENT '內容,用戶看到的',
`content_imgs` text NOT NULL COMMENT '內容中圖片',
`content_videos` varchar(255) NOT NULL DEFAULT '' COMMENT '內容中視頻',
`content_draft` text NOT NULL COMMENT '草稿內容,編輯后保存到這裏,發布后內容會複製到content,此字段清空',
`content_imgs_draft` text NOT NULL COMMENT '草稿內容的圖片,同上',
`content_videos_draft` varchar(255) NOT NULL DEFAULT '' COMMENT '草稿內容的視頻',
`recommended` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '0-不推薦、1-推薦',
`author_user_id` varchar(64) NOT NULL DEFAULT '' COMMENT '作者userId',
`author_name` varchar(16) NOT NULL COMMENT '作者名稱',
`last_operator_user_id` varchar(64) NOT NULL DEFAULT '' COMMENT '最後操作人userId',
`last_operator_name` varchar(16) NOT NULL COMMENT '最後操作人名字',
`publish_date` datetime DEFAULT NULL COMMENT '發布時間',
`publisher_user_id` varchar(64) NOT NULL DEFAULT '' COMMENT '發布者userId',
`publisher_name` varchar(16) NOT NULL DEFAULT '' COMMENT '發布者名字',
`pv` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '流量pv',
`uv` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '流量uv',
`share_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '分享次數',
`share_people_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '分享人數',
`date_create` datetime NOT NULL,
`date_update` datetime NOT NULL,
`date_delete` datetime DEFAULT NULL,
`deleted` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '0 表示未刪除,刪除后是毫秒級時間戳',
PRIMARY KEY (`id`),
UNIQUE KEY `uniq_id` (`my_article_id`),
KEY `idx_title_label_status` (`subject_id`,`platform_id`,`title`,`label_infos`(255),`source`)
) ENGINE=InnoDB AUTO_INCREMENT=861 DEFAULT CHARSET=utf8 COMMENT='文章素材庫,給集團提供文章素材'
上表中content, content_imgs,content_videos都是text類型等大字段,對於這種類型,我們需要把這種類型的表拆分成2張表 article_metedata和article_content 兩張表。
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※評比前十大台北網頁設計、台北網站設計公司知名案例作品心得分享
※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選
※評比南投搬家公司費用收費行情懶人包大公開
※幫你省時又省力,新北清潔一流服務好口碑
文:宋瑞文(媽媽監督核電廠聯盟特約撰述)
本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※評比前十大台北網頁設計、台北網站設計公司知名案例作品心得分享
※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選
※評比南投搬家公司費用收費行情懶人包大公開
據報導,特斯拉將於3月31日發佈全新MODEL 3車型,新車將於同期開始接受預訂,最快有望於2017年晚些時候交付客戶。新車的預估售價約為35000美元(約合人民幣22.77萬元)。
發佈當日,特斯拉將同期開始接受現場預訂,訂金為1000美元(約合人民幣6506元),次日(4月1日)起接受線上預訂,而新車實際交付將會於2017年晚些時候進行。根據消息,預售價為35000美元(約合人民幣22.77萬元)的MODEL 3作為入門車型,其電池續航里程或低於定位更高的MODEL S和MODEL X車型。即將發佈的MODEL 3車型為一款三廂轎車,但未來不排除有跨界版本出現的可能。
特斯拉CEO埃隆•馬斯克曾經表示,MODEL 3未來有望在中國投產,而價格預計只有MODEL S的一半。作為特斯拉的入門車型,MODEL 3將是一款肩負走量任務的產品,適合進行當地語系化生產。未來國產後,其價格可能會下降三分之一。
本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※評比前十大台北網頁設計、台北網站設計公司知名案例作品心得分享
※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選
※評比南投搬家公司費用收費行情懶人包大公開
MySQL InnoDB支持三種行鎖定
行鎖(Record Lock):鎖直接加在索引記錄上面,鎖住的是key。
間隙鎖(Gap Lock):鎖定索引記錄間隙,確保索引記錄的間隙不變。間隙鎖是針對事務隔離級別為可重複讀或以上級別而設計的。
后碼鎖(Next-Key Lock):行鎖和間隙鎖組合起來就叫Next-Key Lock。
默認情況下,InnoDB工作在可重複讀隔離級別下,並且會以Next-Key Lock的方式對數據行進行加鎖,這樣可以有效防止幻讀的發生。Next-Key Lock是行鎖和間隙鎖的組合,當InnoDB掃描索引記錄的時候,會首先對索引記錄加上行鎖(Record Lock),再對索引記錄兩邊的間隙加上間隙鎖(Gap Lock)。加上間隙鎖之後,其他事務就不能在這個間隙修改或者插入記錄。
create table x(`id` int, `num` int, index `idx_id` (`id`));
insert into x values(1, 1), (2, 2);
-- 事務A
START TRANSACTION;
update x set id = 1 where id = 1;
-- 事務B
-- 如果事務A沒有commit,id=1的記錄拿不到X鎖,將出現等待
START TRANSACTION;
update x set id = 1 where id = 1;
-- 事務C
-- id=2的記錄可以拿到X鎖,不會出現等待
START TRANSACTION;
update x set id = 2 where id = 2;
-- 事務A
START TRANSACTION;
update x set num = 1 where num = 1;
-- 事務B
-- 由於事務A中num字段上沒有索引將產生表鎖,導致整張表的寫操作都會出現等待
START TRANSACTION;
update x set num = 1 where num = 1;
-- 事務C
-- 同理,會出現等待
START TRANSACTION;
update x set num = 2 where num = 2;
-- 事務D
-- 等待
START TRANSACTION;
insert into x values(3, 3);
在MySQL中select稱為快照讀,不需要鎖,而insert、update、delete、select for update則稱為當前讀,需要給數據加鎖,幻讀中的“讀”即是針對當前讀。
RR事務隔離級別允許存在幻讀,但InnoDB RR級別卻通過Gap鎖避免了幻讀
測試環境
MySQL,InnoDB,默認的隔離級別(RR)
數據表
CREATE TABLE `test` (
`id` int(1) NOT NULL AUTO_INCREMENT,
`name` varchar(8) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
數據
INSERT INTO `test` VALUES ('1', '小羅');
INSERT INTO `test` VALUES ('5', '小黃');
INSERT INTO `test` VALUES ('7', '小明');
INSERT INTO `test` VALUES ('11', '小紅');
以上數據,會生成隱藏間隙
(-infinity, 1]
(1, 5]
(5, 7]
(7, 11]
(11, +infinity]
/* 開啟事務1 */
BEGIN;
/* 查詢 id = 5 的數據並加記錄鎖 */
SELECT * FROM `test` WHERE `id` = 5 FOR UPDATE;
/* 延遲30秒執行,防止鎖釋放 */
SELECT SLEEP(30);
-- 注意:以下的語句不是放在一個事務中執行,而是分開多次執行,每次事務中只有一條添加語句
/* 事務2插入一條 name = '小張' 的數據 */
INSERT INTO `test` (`id`, `name`) VALUES (4, '小張'); # 正常執行
/* 事務3插入一條 name = '小張' 的數據 */
INSERT INTO `test` (`id`, `name`) VALUES (8, '小東'); # 正常執行
/* 提交事務1,釋放事務1的鎖 */
COMMIT;
以上,由於主鍵是唯一索引,而且是只使用一個索引查詢,並且只鎖定一條記錄,所以,只會對 id = 5 的數據加上記錄鎖,而不會產生間隙鎖。
/* 開啟事務1 */
BEGIN;
/* 查詢 id 在 7 - 11 範圍的數據並加記錄鎖 */
SELECT * FROM `test` WHERE `id` BETWEEN 5 AND 7 FOR UPDATE;
/* 延遲30秒執行,防止鎖釋放 */
SELECT SLEEP(30);
-- 注意:以下的語句不是放在一個事務中執行,而是分開多次執行,每次事務中只有一條添加語句
/* 事務2插入一條 id = 3,name = '小張1' 的數據 */
INSERT INTO `test` (`id`, `name`) VALUES (3, '小張1'); # 正常執行
/* 事務3插入一條 id = 4,name = '小白' 的數據 */
INSERT INTO `test` (`id`, `name`) VALUES (4, '小白'); # 正常執行
/* 事務4插入一條 id = 6,name = '小東' 的數據 */
INSERT INTO `test` (`id`, `name`) VALUES (6, '小東'); # 阻塞
/* 事務5插入一條 id = 8, name = '大羅' 的數據 */
INSERT INTO `test` (`id`, `name`) VALUES (8, '大羅'); # 阻塞
/* 事務6插入一條 id = 9, name = '大東' 的數據 */
INSERT INTO `test` (`id`, `name`) VALUES (9, '大東'); # 阻塞
/* 事務7插入一條 id = 11, name = '李西' 的數據 */
INSERT INTO `test` (`id`, `name`) VALUES (11, '李西'); # 阻塞
/* 事務8插入一條 id = 12, name = '張三' 的數據 */
INSERT INTO `test` (`id`, `name`) VALUES (12, '張三'); # 正常執行
/* 提交事務1,釋放事務1的鎖 */
COMMIT;
從上面我們可以看到,(5, 7]、(7, 11] 這兩個區間,都不可插入數據,其它區間,都可以正常插入數據。所以當我們給 (5, 7] 這個區間加鎖的時候,會鎖住 (5, 7]、(7, 11] 這兩個區間。
/* 開啟事務1 */
BEGIN;
/* 查詢 id = 3 這一條不存在的數據並加記錄鎖 */
SELECT * FROM `test` WHERE `id` = 3 FOR UPDATE;
/* 延遲30秒執行,防止鎖釋放 */
SELECT SLEEP(30);
-- 注意:以下的語句不是放在一個事務中執行,而是分開多次執行,每次事務中只有一條添加語句
/* 事務2插入一條 id = 3,name = '小張1' 的數據 */
INSERT INTO `test` (`id`, `name`) VALUES (2, '小張1'); # 阻塞
/* 事務3插入一條 id = 4,name = '小白' 的數據 */
INSERT INTO `test` (`id`, `name`) VALUES (4, '小白'); # 阻塞
/* 事務4插入一條 id = 6,name = '小東' 的數據 */
INSERT INTO `test` (`id`, `name`) VALUES (6, '小東'); # 正常執行
/* 事務5插入一條 id = 8, name = '大羅' 的數據 */
INSERT INTO `test` (`id`, `name`) VALUES (8, '大羅'); # 正常執行
/* 提交事務1,釋放事務1的鎖 */
COMMIT;
我們可以看出,指定查詢某一條記錄時,如果這條記錄不存在,會產生間隙鎖
結論
id = 5 FOR UPDATE;id BETWEEN 5 AND 7 FOR UPDATE;數據準備
創建 test1 表:
CREATE TABLE `test1` (
`id` int(1) NOT NULL AUTO_INCREMENT,
`number` int(1) NOT NULL COMMENT '数字',
PRIMARY KEY (`id`),
KEY `number` (`number`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
id 是主鍵,number上建立了一個普通索引。先加一些數據:
INSERT INTO `test1` VALUES (1, 1);
INSERT INTO `test1` VALUES (5, 3);
INSERT INTO `test1` VALUES (7, 8);
INSERT INTO `test1` VALUES (11, 12);
test1表中 number 索引存在的隱藏間隙:
(-infinity, 1]
(1, 3]
(3, 8]
(8, 12]
(12, +infinity]
/* 開啟事務1 */
BEGIN;
/* 查詢 number = 5 的數據並加記錄鎖 */
SELECT * FROM `test1` WHERE `number` = 3 FOR UPDATE;
/* 延遲30秒執行,防止鎖釋放 */
SELECT SLEEP(30);
-- 注意:以下的語句不是放在一個事務中執行,而是分開多次執行,每次事務中只有一條添加語句
/* 事務2插入一條 number = 0 的數據 */
INSERT INTO `test1` (`number`) VALUES (0); -- 正常執行
/* 事務3插入一條 number = 1 的數據 */
INSERT INTO `test1` (`number`) VALUES (1); -- 被阻塞
/* 事務4插入一條 number = 2 的數據 */
INSERT INTO `test1` (`number`) VALUES (2); -- 被阻塞
/* 事務5插入一條 number = 4 的數據 */
INSERT INTO `test1` (`number`) VALUES (4); -- 被阻塞
/* 事務6插入一條 number = 8 的數據 */
INSERT INTO `test1` (`number`) VALUES (8); -- 正常執行
/* 事務7插入一條 number = 9 的數據 */
INSERT INTO `test1` (`number`) VALUES (9); -- 正常執行
/* 事務8插入一條 number = 10 的數據 */
INSERT INTO `test1` (`number`) VALUES (10); -- 正常執行
/* 提交事務1 */
COMMIT;
這裏可以看到,number (1 – 8) 的間隙中,插入語句都被阻塞了,而不在這個範圍內的語句,正常執行,這就是因為有間隙鎖的原因。
將數據還原成初始化的那樣
/* 開啟事務1 */
BEGIN;
/* 查詢 number = 5 的數據並加記錄鎖 */
SELECT * FROM `test1` WHERE `number` = 3 FOR UPDATE;
/* 延遲30秒執行,防止鎖釋放 */
SELECT SLEEP(30);
/* 事務1插入一條 id = 2, number = 1 的數據 */
INSERT INTO `test1` (`id`, `number`) VALUES (2, 1); -- 阻塞
/* 事務2插入一條 id = 3, number = 2 的數據 */
INSERT INTO `test1` (`id`, `number`) VALUES (3, 2); -- 阻塞
/* 事務3插入一條 id = 6, number = 8 的數據 */
INSERT INTO `test1` (`id`, `number`) VALUES (6, 8); -- 阻塞
/* 事務4插入一條 id = 8, number = 8 的數據 */
INSERT INTO `test1` (`id`, `number`) VALUES (8, 8); -- 正常執行
/* 事務5插入一條 id = 9, number = 9 的數據 */
INSERT INTO `test1` (`id`, `number`) VALUES (9, 9); -- 正常執行
/* 事務6插入一條 id = 10, number = 12 的數據 */
INSERT INTO `test1` (`id`, `number`) VALUES (10, 12); -- 正常執行
/* 事務7修改 id = 11, number = 12 的數據 */
UPDATE `test1` SET `number` = 5 WHERE `id` = 11 AND `number` = 12; -- 阻塞
/* 提交事務1 */
COMMIT;
這裡有一個奇怪的現象:
事務3添加 id = 6,number = 8 的數據,給阻塞了;
事務4添加 id = 8,number = 8 的數據,正常執行了。
事務7將 id = 11,number = 12 的數據修改為 id = 11, number = 5的操作,給阻塞了;
這是為什麼呢?我們來看看下邊的圖
從圖中可以看出,當 number 相同時,會根據主鍵 id 來排序,所以:
事務3添加的 id = 6,number = 8,這條數據是在 (3, 8) 的區間裡邊,所以會被阻塞;
事務4添加的 id = 8,number = 8,這條數據則是在(8, 12)區間裡邊,所以不會被阻塞;
事務7的修改語句相當於在 (3, 8) 的區間裡邊插入一條數據,所以也被阻塞了。
后碼鎖是記錄鎖與間隙鎖的組合,它的封鎖範圍,既包含索引記錄,又包含索引區間。
注:Next-key Lock的主要目的,也是為了避免幻讀(Phantom Read)。如果把事務的隔離級別降級為RC,Next-key Lock則也會失效。
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※評比前十大台北網頁設計、台北網站設計公司知名案例作品心得分享
※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選
※評比南投搬家公司費用收費行情懶人包大公開