當前位置:首頁 » 數據倉庫 » 資料庫讀寫鎖
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

資料庫讀寫鎖

發布時間: 2023-02-10 12:02:18

❶ 如何使用多線程同事訪問多個sqlite資料庫

SQLite作為一款小型的嵌入式資料庫,本身沒有提供復雜的鎖定機制,無法內部管理多路並發下的數據操作同步問題,更談不上優化,所以涉及到多路並發的情況,需要外部進行讀寫鎖控制,否則SQLite會返回SQLITE_BUSY錯誤,以駁回相關請求。
返回SQLITE_BUSY主要有以下幾種情況:
1。當有寫操作時,其他讀操作會被駁回
2。當有寫操作時,其他寫操作會被駁回
3。當開啟事務時,在提交事務之前,其他寫操作會被駁回
4。當開啟事務時,在提交事務之前,其他事務請求會被駁回
5。當有讀操作時,其他寫操作會被駁回
6。讀操作之間能夠並發執行
基於以上討論,可以看出這是一個典型的讀者寫者問題,讀操作要能夠共享,寫操作要互斥,讀寫之間也要互斥

可以設計如下的方案解決並發操作資料庫被鎖定的問題,同時保證讀操作能夠保持最大並發
1。採用互斥鎖控制資料庫寫操作
2。只有擁有互斥鎖的線程才能夠操作資料庫
3。寫操作必須獨立擁有互斥鎖
4。讀操作必須能夠共享互斥鎖,即在第一次讀取的時候獲取互斥鎖,最後一次讀取的時候釋放互斥鎖

❷ spring boot動態修改es的連接地址

在項目啟動後,使用修改配置文件+restart()連接/連接池對象的方法解決。
使用讀寫鎖,給restart()、setUrl()等代碼塊加寫鎖,給資料庫操作方法加讀鎖。這樣就可以在修改資料庫連接信息時,先獲取寫鎖,保證資料庫操作方法不能執行。而在不修改連接時,資料庫操作方法之間獲取的是讀鎖,不會影響線程彼此之間的操作。

❸ Mysql到底是怎麼實現MVCC的

Mysql到底是怎麼實現MVCC的
Mysql到底是怎麼實現MVCC的?這個問題無數人都在問,但google中並無答案,本文嘗試從Mysql源碼中尋找答案。
在Mysql中MVCC是在Innodb存儲引擎中得到支持的,Innodb為每行記錄都實現了三個隱藏欄位:

6位元組的事務ID(DB_TRX_ID )
7位元組的回滾指針(DB_ROLL_PTR)
隱藏的ID
6位元組的事物ID用來標識該行所述的事務,7位元組的回滾指針需要了解下Innodb的事務模型。

1. Innodb的事務相關概念
為了支持事務,Innbodb引入了下面幾個概念:
redo log
redo log就是保存執行的SQL語句到一個指定的Log文件,當Mysql執行recovery時重新執行redo log記錄的SQL操作即可。當客戶端執行每條SQL(更新語句)時,redo log會被首先寫入log buffer;當客戶端執行COMMIT命令時,log buffer中的內容會被視情況刷新到磁碟。redo log在磁碟上作為一個獨立的文件存在,即Innodb的log文件。
undo log
與redo log相反,undo log是為回滾而用,具體內容就是事務前的資料庫內容(行)到undo buffer,在適合的時間把undo buffer中的內容刷新到磁碟。undo buffer與redo buffer一樣,也是環形緩沖,但當緩沖滿的時候,undo buffer中的內容會也會被刷新到磁碟;與redo log不同的是,磁碟上不存在單獨的undo log文件,所有的undo log均存放在主ibd數據文件中(表空間),即使客戶端設置了每表一個數據文件也是如此。
rollback segment
回滾段這個概念來自Oracle的事物模型,在Innodb中,undo log被劃分為多個段,具體某行的undo log就保存在某個段中,稱為回滾段。可以認為undo log和回滾段是同一意思。

Innodb提供了基於行的鎖,如果行的數量非常大,則在高並發下鎖的數量也可能會比較大,據Innodb文檔說,Innodb對鎖進行了空間有效優化,即使並發量高也不會導致內存耗盡。
對行的鎖有分兩種:排他鎖、共享鎖。共享鎖針對對,排他鎖針對寫,完全等同讀寫鎖的概念。如果某個事務在更新某行(排他鎖),則其他事物無論是讀還是寫本行都必須等待;如果某個事物讀某行(共享鎖),則其他讀的事物無需等待,而寫事物則需等待。通過共享鎖,保證了多讀之間的無等待性,但是鎖的應用又依賴Mysql的事務隔離級別。
隔離級別
隔離級別用來限制事務直接的交互程度,目前有幾個工業標准:
- READ_UNCOMMITTED:臟讀
- READ_COMMITTED:讀提交
- REPEATABLE_READ:重復讀
- SERIALIZABLE:串列化
Innodb對四種類型都支持,臟讀和串列化應用場景不多,讀提交、重復讀用的比較廣泛,後面會介紹其實現方式。
2. 行的更新過程
下面演示下事務對某行記錄的更新過程:
1. 初始數據行

F1~F6是某行列的名字,1~6是其對應的數據。後面三個隱含欄位分別對應該行的事務號和回滾指針,假如這條數據是剛INSERT的,可以認為ID為1,其他兩個欄位為空。
2.事務1更改該行的各欄位的值

當事務1更改該行的值時,會進行如下操作:
用排他鎖鎖定該行

❹ 我的程序,查詢資料庫很慢。請問怎麼提高查詢速度

SQL提高查詢效率

1.對查詢進行優化,應盡量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。

2.應盡量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:
select id from t where num is null
可以在num上設置默認值0,確保表中num列沒有null值,然後這樣查詢:
select id from t where num=0

3.應盡量避免在 where 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描。

4.應盡量避免在 where 子句中使用 or 來連接條件,否則將導致引擎放棄使用索引而進行全表掃描,如:
select id from t where num=10 or num=20
可以這樣查詢:
select id from t where num=10
union all
select id from t where num=20

5.in 和 not in 也要慎用,否則會導致全表掃描,如:
select id from t where num in(1,2,3)
對於連續的數值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3

6.下面的查詢也將導致全表掃描:
select id from t where name like '%abc%'
若要提高效率,可以考慮全文檢索。

7.如果在 where 子句中使用參數,也會導致全表掃描。因為SQL只有在運行時才會解析局部變數,但優化程序不能將訪問計劃的選擇推遲到運行時;它必須在編譯時進行選擇。然而,如果在編譯時建立訪問計劃,變數的值還是未知的,因而無法作為索引選擇的輸入項。如下面語句將進行全表掃描:
select id from t where num=@num
可以改為強制查詢使用索引:
select id from t with(index(索引名)) where num=@num

8.應盡量避免在 where 子句中對欄位進行表達式操作,這將導致引擎放棄使用索引而進行全表掃描。如:
select id from t where num/2=100
應改為:
select id from t where num=100*2

9.應盡量避免在where子句中對欄位進行函數操作,這將導致引擎放棄使用索引而進行全表掃描。如:
select id from t where substring(name,1,3)='abc'--name以abc開頭的id
select id from t where datediff(day,createdate,'2005-11-30')=0--『2005-11-30』生成的id
應改為:
select id from t where name like 'abc%'
select id from t where createdate>='2005-11-30' and createdate<'2005-12-1'

10.不要在 where 子句中的「=」左邊進行函數、算術運算或其他表達式運算,否則系統將可能無法正確使用索引。

11.在使用索引欄位作為條件時,如果該索引是復合索引,那麼必須使用到該索引中的第一個欄位作為條件時才能保證系統使用該索引,否則該索引將不會被使用,並且應盡可能的讓欄位順序與索引順序相一致。

12.不要寫一些沒有意義的查詢,如需要生成一個空表結構:
select col1,col2 into #t from t where 1=0
這類代碼不會返回任何結果集,但是會消耗系統資源的,應改成這樣:
create table #t(...)

13.很多時候用 exists 代替 in 是一個好的選擇:
select num from a where num in(select num from b)
用下面的語句替換:
select num from a where exists(select 1 from b where num=a.num)

14.並不是所有索引對查詢都有效,SQL是根據表中數據來進行查詢優化的,當索引列有大量數據重復時,SQL查詢可能不會去利用索引,如一表中有欄位sex,male、female幾乎各一半,那麼即使在sex上建了索引也對查詢效率起不了作用。

15.索引並不是越多越好,索引固然可以提高相應的 select 的效率,但同時也降低了 insert 及 update 的效率,因為 insert 或 update 時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有必要。

16.應盡可能的避免更新 clustered 索引數據列,因為 clustered 索引數據列的順序就是表記錄的物理存儲順序,一旦該列值改變將導致整個表記錄的順序的調整,會耗費相當大的資源。若應用系統需要頻繁更新 clustered 索引數據列,那麼需要考慮是否應將該索引建為 clustered 索引。

17.盡量使用數字型欄位,若只含數值信息的欄位盡量不要設計為字元型,這會降低查詢和連接的性能,並會增加存儲開銷。這是因為引擎在處理查詢和連接時會逐個比較字元串中每一個字元,而對於數字型而言只需要比較一次就夠了。

18.盡可能的使用 varchar/nvarchar 代替 char/nchar ,因為首先變長欄位存儲空間小,可以節省存儲空間,其次對於查詢來說,在一個相對較小的欄位內搜索效率顯然要高些。

19.任何地方都不要使用 select * from t ,用具體的欄位列表代替「*」,不要返回用不到的任何欄位。

20.盡量使用表變數來代替臨時表。如果表變數包含大量數據,請注意索引非常有限(只有主鍵索引)。

21.避免頻繁創建和刪除臨時表,以減少系統表資源的消耗。

22.臨時表並不是不可使用,適當地使用它們可以使某些常式更有效,例如,當需要重復引用大型表或常用表中的某個數據集時。但是,對於一次性事件,最好使用導出表。

23.在新建臨時表時,如果一次性插入數據量很大,那麼可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果數據量不大,為了緩和系統表的資源,應先create table,然後insert。

24.如果使用到了臨時表,在存儲過程的最後務必將所有的臨時表顯式刪除,先 truncate table ,然後 drop table ,這樣可以避免系統表的較長時間鎖定。

25.盡量避免使用游標,因為游標的效率較差,如果游標操作的數據超過1萬行,那麼就應該考慮改寫。

26.使用基於游標的方法或臨時表方法之前,應先尋找基於集的解決方案來解決問題,基於集的方法通常更有效。

27.與臨時表一樣,游標並不是不可使用。對小型數據集使用 FAST_FORWARD 游標通常要優於其他逐行處理方法,尤其是在必須引用幾個表才能獲得所需的數據時。在結果集中包括「合計」的常式通常要比使用游標執行的速度快。如果開發時間允許,基於游標的方法和基於集的方法都可以嘗試一下,看哪一種方法的效果更好。

28.在所有的存儲過程和觸發器的開始處設置 SET NOCOUNT ON ,在結束時設置 SET NOCOUNT OFF 。無需在執行存儲過程和觸發器的每個語句後向客戶端發送 DONE_IN_PROC 消息。

29.盡量避免大事務操作,提高系統並發能力。

30.盡量避免向客戶端返回大數據量,若數據量過大,應該考慮相應需求是否合理

1、避免將欄位設為「允許為空」
2、數據表設計要規范
3、深入分析數據操作所要對資料庫進行的操作
4、盡量不要使用臨時表
5、多多使用事務
6、盡量不要使用游標
7、避免死鎖
8、要注意讀寫鎖的使用
9、不要打開大的數據集
10、不要使用伺服器端游標
11、在程序編碼時使用大數據量的資料庫
12、不要給「性別」列創建索引
13、注意超時問題
14、不要使用Select *
15、在細節表中插入紀錄時,不要在主表執行Select MAX(ID)
16、盡量不要使用TEXT數據類型
17、使用參數查詢
18、不要使用Insert導入大批的數據
19、學會分析查詢
20、使用參照完整性
21、用INNER JOIN 和LEFT JOIN代替Where

提高SQL查詢效率(要點與技巧):
· 技巧一:
問題類型:ACCESS資料庫欄位中含有日文片假名或其它不明字元時查詢會提示內存溢出。
解決方法:修改查詢語句
sql="select * from tablename where column like '%"&word&"%'"
改為
sql="select * from tablename"
rs.filter = " column like '%"&word&"%'"
===========================================================
技巧二:
問題類型:如何用簡易的辦法實現類似網路的多關鍵詞查詢(多關鍵詞用空格或其它符號間隔)。
解決方法:
'//用空格分割查詢字元串
ck=split(word," ")
'//得到分割後的數量
sck=UBound(ck)
sql="select * tablename where"
在一個欄位中查詢
For i = 0 To sck
SQL = SQL & tempJoinWord & "(" & _
"column like '"&ck(i)&"%')"
tempJoinWord = " and "
Next
在二個欄位中同時查詢
For i = 0 To sck
SQL = SQL & tempJoinWord & "(" & _
"column like '"&ck(i)&"%' or " & _
"column1 like '"&ck(i)&"%')"
tempJoinWord = " and "
Next
===========================================================
技巧三:大大提高查詢效率的幾種技巧

1. 盡量不要使用 or,使用or會引起全表掃描,將大大降低查詢效率。
2. 經過實踐驗證,charindex()並不比前面加%的like更能提高查詢效率,並且charindex()會使索引失去作用(指sqlserver資料庫)
3. column like '%"&word&"%' 會使索引不起作用
column like '"&word&"%' 會使索引起作用(去掉前面的%符號)
(指sqlserver資料庫)
4. '%"&word&"%' 與'"&word&"%' 在查詢時的區別:
比如你的欄位內容為 一個容易受傷的女人
'%"&word&"%' :會通配所有字元串,不論查「受傷」還是查「一個」,都會顯示結果。
'"&word&"%' :只通配前面的字元串,例如查「受傷」是沒有結果的,只有查「一個」,才會顯示結果。
5. 欄位提取要按照「需多少、提多少」的原則,避免「select *」,盡量使用「select 欄位1,欄位2,欄位3........」。實踐證明:每少提取一個欄位,數據的提取速度就會有相應的提升。提升的速度還要看您舍棄的欄位的大小來判斷。
6. order by按聚集索引列排序效率最高。一個sqlserver數據表只能建立一個聚集索引,一般默認為ID,也可以改為其它的欄位。
7. 為你的表建立適當的索引,建立索引可以使你的查詢速度提高幾十幾百倍。(指sqlserver資料庫)
· 以下是建立索引與不建立索引的一個查詢效率分析:
Sqlserver索引與查詢效率分析。
表 News
欄位
Id:自動編號
Title:文章標題
Author:作者
Content:內容
Star:優先順序
Addtime:時間
記錄:100萬條
測試機器:P4 2.8/1G內存/IDE硬碟
=======================================================
方案1:
主鍵Id,默認為聚集索引,不建立其它非聚集索引
select * from News where Title like '%"&word&"%' or Author like '%"&word&"%' order by Id desc
從欄位Title和Author中模糊檢索,按Id排序
查詢時間:50秒
=======================================================
方案2:
主鍵Id,默認為聚集索引
在Title、Author、Star上建立非聚集索引
select * from News where Title like '"&word&"%' or Author like '"&word&"%' order by Id desc
從欄位Title和Author中模糊檢索,按Id排序
查詢時間:2 - 2.5秒
=======================================================
方案3:
主鍵Id,默認為聚集索引
在Title、Author、Star上建立非聚集索引
select * from News where Title like '"&word&"%' or Author like '"&word&"%' order by Star desc
從欄位Title和Author中模糊檢索,按Star排序
查詢時間:2 秒
=======================================================
方案4:
主鍵Id,默認為聚集索引
在Title、Author、Star上建立非聚集索引
select * from News where Title like '"&word&"%' or Author like '"&word&"%'
從欄位Title和Author中模糊檢索,不排序
查詢時間:1.8 - 2 秒
=======================================================
方案5:
主鍵Id,默認為聚集索引
在Title、Author、Star上建立非聚集索引
select * from News where Title like '"&word&"%'

select * from News where Author like '"&word&"%'
從欄位Title 或 Author中檢索,不排序
查詢時間:1秒
· 如何提高SQL語言的查詢效率?
問:請問我如何才能提高SQL語言的查詢效率呢?
答:這得從頭說起:
由於SQL是面向結果而不是面向過程的查詢語言,所以一般支持SQL語言的大型關系型資料庫都使用一個基於查詢成本的優化器,為即時查詢提供一個最佳的執行策略。對於優化器,輸入是一條查詢語句,輸出是一個執行策略。
一條SQL查詢語句可以有多種執行策略,優化器將估計出全部執行方法中所需時間最少的所謂成本最低的那一種方法。所有優化都是基於用記所使用的查詢語句中的where子句,優化器對where子句中的優化主要用搜索參數(Serach Argument)。
搜索參數的核心思想就是資料庫使用表中欄位的索引來查詢數據,而不必直接查詢記錄中的數據。
帶有 =、<、<=、>、>= 等操作符的條件語句可以直接使用索引,如下列是搜索參數:
emp_id = "10001" 或 salary > 3000 或 a =1 and c = 7
而下列則不是搜索參數:
salary = emp_salary 或 dep_id != 10 或 salary * 12 >= 3000 或 a=1 or c=7
應當盡可能提供一些冗餘的搜索參數,使優化器有更多的選擇餘地。請看以下3種方法:
第一種方法:
select employee.emp_name,department.dep_name from department,employee where (employee.dep_id = department.dep_id) and (department.dep_code="01") and (employee.dep_code="01");
它的搜索分析結果如下:
Estimate 2 I/O operations
Scan department using primary key
for rows where dep_code equals "01"
Estimate getting here 1 times
Scan employee sequentially
Estimate getting here 5 times
第二種方法:
select employee.emp_name,department.dep_name from department,employee where (employee.dep_id = department.dep_id) and (department.dep_code="01");
它的搜索分析結果如下:
Estimate 2 I/O operations
Scan department using primary key
for rows where dep_code equals "01"
Estimate getting here 1 times
Scan employee sequentially
Estimate getting here 5 times
第一種方法與第二種運行效率相同,但第一種方法最好,因為它為優化器提供了更多的選擇機會。
第三種方法:
select employee.emp_name,department.dep_name from department,employee where (employee.dep_id = department.dep_id) and (employee.dep_code="01");
這種方法最不好,因為它無法使用索引,也就是無法優化……
使用SQL語句時應注意以下幾點:
1、避免使用不兼容的數據類型。例如,Float和Integer,Char和Varchar,Binary和Long Binary不兼容的。數據類型的不兼容可能使優化器無法執行一些本可以進行的優化操作。例如:
select emp_name form employee where salary > 3000;
在此語句中若salary是Float類型的,則優化器很難對其進行優化,因為3000是個整數,我們應在編程時使用3000.0而不要等運行時讓DBMS進行轉化。
2、盡量不要使用表達式,因它在編繹時是無法得到的,所以SQL只能使用其平均密度來估計將要命中的記錄數。
3、避免對搜索參數使用其他的數學操作符。如:
select emp_name from employee where salary * 12 > 3000;
應改為:
select emp_name from employee where salary > 250;
4、避免使用 != 或 <> 等這樣的操作符,因為它會使系統無法使用索引,而只能直接搜索表中的數據。
· ORACAL中的應用
一個1600萬數據表--簡訊上行表TBL_SMS_MO
結構:
CREATE TABLE TBL_SMS_MO
(
SMS_ID NUMBER,
MO_ID VARCHAR2(50),
MOBILE VARCHAR2(11),
SPNUMBER VARCHAR2(20),
MESSAGE VARCHAR2(150),
TRADE_CODE VARCHAR2(20),
LINK_ID VARCHAR2(50),
GATEWAY_ID NUMBER,
GATEWAY_PORT NUMBER,
MO_TIME DATE DEFAULT SYSDATE
);
CREATE INDEX IDX_MO_DATE ON TBL_SMS_MO (MO_TIME)
PCTFREE 10
INITRANS 2
MAXTRANS 255
STORAGE
(
INITIAL 1M
NEXT 1M
MINEXTENTS 1
MAXEXTENTS UNLIMITED
PCTINCREASE 0
);
CREATE INDEX IDX_MO_MOBILE ON TBL_SMS_MO (MOBILE)
PCTFREE 10
INITRANS 2
MAXTRANS 255
STORAGE
(
INITIAL 64K
NEXT 1M
MINEXTENTS 1
MAXEXTENTS UNLIMITED
PCTINCREASE 0
);
問題:從表中查詢某時間段內某手機發送的短消息,如下SQL語句:
SELECT MOBILE,MESSAGE,TRADE_CODE,MO_TIME
FROM TBL_SMS_MO
WHERE MOBILE='130XXXXXXXX'
AND MO_TIME BETWEEN TO_DATE('2006-04-01','YYYY-MM-DD HH24:MI:SS') AND TO_DATE('2006-04-07','YYYY-MM-DD HH24:MI:SS')
ORDER BY MO_TIME DESC
返回結果大約需要10分鍾,應用於網頁查詢,簡直難以忍受。
分析:
在PL/SQL Developer,點擊「Explain Plan」按鈕(或F5鍵),對SQL進行分析,發現預設使用的索引是IDX_MO_DATE。問題可能出在這里,因為相對於總數量1600萬數據來說,都mobile的數據是很少的,如果使用IDX_MO_MOBILE比較容易鎖定數據。
如下優化:
SELECT /*+ index(TBL_SMS_MO IDX_MO_MOBILE) */ MOBILE,MESSAGE,TRADE_CODE,MO_TIME
FROM TBL_SMS_MO
WHERE MOBILE='130XXXXXXXX'
AND MO_TIME BETWEEN TO_DATE('2006-04-01','YYYY-MM-DD HH24:MI:SS') AND TO_DATE('2006-04-07','YYYY-MM-DD HH24:MI:SS')
ORDER BY MO_TIME DESC
測試:
按F8運行這個SQL,哇~... ... 2.360s,這就是差別。
http://www.cnblogs.com/ShaYeBlog/archive/2013/07/31/3227244.html

❺ 資料庫分區和分表的區別

分區、分表、分庫的詳細理解
一、什麼是分區、分表、分庫
分區
就是把一張表的數據分成N個區塊,在邏輯上看最終只是一張表,但底層是由N個物理區塊組成的

分表
就是把一張表按一定的規則分解成N個具有獨立存儲空間的實體表。系統讀寫時需要根據定義好的規則得到對應的字表明,然後操作它。

分庫
一旦分表,一個庫中的表會越來越多

將整個資料庫比作圖書館,一張表就是一本書。當要在一本書中查找某項內容時,如果不分章節,查找的效率將會下降。而同理,在資料庫中就是分區。

二、常用的單機資料庫的瓶頸
問題描述
單個表數據量越大,讀寫鎖,插入操作重新建立索引效率越低。
單個庫數據量太大(一個資料庫數據量到就是極限)
單個資料庫伺服器壓力過大
讀寫速度遇到瓶頸(並發量幾百)
三、分區
什麼時候考慮使用分區?
一張表的查詢速度已經慢到影響使用的時候。

sql經過優化

數據量大

表中的數據是分段的
對數據的操作往往只涉及一部分數據,而不是所有的數據

分區解決的問題
主要可以提升查詢效率

分區的實現方式(簡單)
mysql5 開始支持分區功能

四、分表
什麼時候考慮分表?
一張表的查詢速度已經慢到影響使用的時候。

sql經過優化

數據量大
當頻繁插入或者聯合查詢時,速度變慢

分表解決的問題
分表後,單表的並發能力提高了,磁碟I/O性能也提高了,寫操作效率提高了

查詢一次的時間短了
數據分布在不同的文件,磁碟I/O性能提高
讀寫鎖影響的數據量變小
插入資料庫需要重新建立索引的數據減少
分表的實現方式(復雜)
需要業務系統配合遷移升級,工作量較大

分區和分表的區別與聯系
分區和分表的目的都是減少資料庫的負擔,提高表的增刪改查效率。

分區只是一張表中的數據的存儲位置發生改變,分表是將一張表分成多張表。
當訪問量大,且表數據比較大時,兩種方式可以互相配合使用。
當訪問量不大,但表數據比較多時,可以只進行分區。

常見分區分表的規則策略(類似)
Range(范圍)
Hash(哈希)
按照時間拆分
Hash之後按照分表個數取模
在認證庫中保存資料庫配置,就是建立一個DB,這個DB單獨保存user_id到DB的映射關系

❻ mysql中innodb引擎的行鎖是通過加在什麼上完成

行鎖的等待

在介紹如何解決行鎖等待問題前,先簡單介紹下這類問題產生的原因。產生原因簡述:當多個事務同時去操作(增刪改)某一行數據的時候,MySQL 為了維護 ACID 特性,就會用鎖的形式來防止多個事務同時操作某一行數據,避免數據不一致。只有分配到行鎖的事務才有權力操作該數據行,直到該事務結束,才釋放行鎖,而其他沒有分配到行鎖的事務就會產生行鎖等待。如果等待時間超過了配置值(也就是 innodb_lock_wait_timeout 參數的值,個人習慣配置成 5s,MySQL 官方默認為 50s),則會拋出行鎖等待超時錯誤。


如上圖所示,事務 A 與事務 B 同時會去 Insert 一條主鍵值為 1 的數據,由於事務 A 首先獲取了主鍵值為 1 的行鎖,導致事務 B 因無法獲取行鎖而產生等待,等到事務 A 提交後,事務 B 才獲取該行鎖,完成提交。這里強調的是行鎖的概念,雖然事務 B 重復插入了主鍵,但是在獲取行鎖之前,事務一直是處於行鎖等待的狀態,只有獲取行鎖後,才會報主鍵沖突的錯誤。當然這種 Insert 行鎖沖突的問題比較少見,只有在大量並發插入場景下才會出現,項目上真正常見的是 update&delete 之間行鎖等待,這里只是用於示例,原理都是相同的。


根據我之前接觸到的此類問題,大致可以分為以下幾種原因:

1. 程序中非資料庫交互操作導致事務掛起將介面調用或者文件操作等這一類非資料庫交互操作嵌入在 SQL 事務代碼之中,那麼整個事務很有可能因此掛起(介面不通等待超時或是上傳下載大附件)。


2. 事務中包含性能較差的查詢 SQL事務中存在慢查詢,導致同一個事務中的其他 DML 無法及時釋放佔用的行鎖,引起行鎖等待。

3. 單個事務中包含大量 SQL通常是由於在事務代碼中加入 for 循環導致,雖然單個 SQL 運行很快,但是 SQL 數量一大,事務就會很慢。

4. 級聯更新 SQL 執行時間較久這類 SQL 容易讓人產生錯覺,例如:update A set ... where ...in (select B) 這類級聯更新,不僅會佔用 A 表上的行鎖,也會佔用 B 表上的行鎖,當 SQL 執行較久時,很容易引起 B 表上的行鎖等待。

5. 磁碟問題導致的事務掛起極少出現的情形,比如存儲突然離線,SQL 執行會卡在內核調用磁碟的步驟上,一直等待,事務無法提交。綜上可以看出,如果事務長時間未提交,且事務中包含了 DML 操作,那麼就有可能產生行鎖等待,引起報錯。

❼ java怎樣將數據保存到緩存中,之後再保存

Java中可以使用隊列來保存數據,當使用的時候,加上鎖,防止其他進程訪問,當不用的時候保存到資料庫裡面,示例如下:

packagecom.henry;
importjava.util.HashMap;
importjava.util.Map;
importjava.util.Random;
importjava.util.concurrent.locks.ReadWriteLock;
importjava.util.concurrent.locks.ReentrantReadWriteLock;

publicclassCacheDataTest{
staticMap<Integer,Object>dataMap=newHashMap<Integer,Object>();
staticReadWriteLocklock=newReentrantReadWriteLock();//創建讀寫鎖的實例
staticObjectgetData(Integerkey){
lock.readLock().lock();//讀取前先上鎖
Objectval=null;
try{
val=dataMap.get(key);
if(val==null){
//
lock.readLock().unlock();
lock.writeLock().lock();
try{
//可能已經由其他線程寫入數據
if(val==null){
//dataMap.put(key,"");//queryfromdb
val=queryDataFromDB(key);
}
}finally{
//
lock.readLock().lock();
//Unlockwrite,stillholdread
lock.writeLock().unlock();
}
}
}finally{
lock.readLock().unlock();//最後一定不要忘記釋放鎖
}
System.out.println("getdatakey="+key+">val="+val);
returnval;
}

staticObjectqueryDataFromDB(Integerkey){
Objectval=newRandom().nextInt(1000);
dataMap.put(key,val);
System.out.println("writeintodatakey="+key+">val="+val);
returnval;
}

publicstaticvoidmain(String[]args){
for(inti=0;i<10;i++){
newThread(newRunnable(){publicvoidrun(){
getData(newRandom().nextInt(5));
}}).start();
}
}
}

❽ 資料庫可以區分用戶提交數據時候的語句是否核發

資料庫可以區分用戶提交數據時候的語句會核發
資料庫隔離級別,每個級別會引發什麼問題,mysql默認是哪個級別

MySQL提供的四種隔離級別,通過設置transaction-isolation值來指定:
串列化:對於同一行記錄,寫和讀都會加鎖,當出現讀寫鎖沖突時,會等待。避免臟讀,不可重復讀和幻讀的發生。
可重復讀:一個事務執行過程中,在啟動時就會創建視圖,所以這個事務總和它啟動的時候看到的數據是一致的,核心是一致性讀,事務更新數據時,只能使用當前讀,如果當前記錄行鎖被佔用,就需要進入鎖等待。避免臟讀,不可重復讀的發生。
讀已提交:它的視圖是在每個sql語句開始執行的時候創建的,所以一個事務提交之後,他的變更才能被其他事務看到。可以避免臟讀的發生。
讀未提交:沒有視圖概念,所以一個事務還沒提交時,他的變更就能被別的事務看到。任何情況都無法保證。
MySQL默認隔離級別為可重復讀。

❾ mysql中的鎖都有哪些

MySQL 中有哪些鎖?

資料庫中鎖的設計初衷處理並發問題,作為多用戶共享資源,當出現並發訪問的時候,資料庫需要合理控制資源訪問規則。鎖就是實現這些訪問規則中的重要數據。

鎖的分類

根據加鎖范圍,MySQL 裡面的鎖可以分成 全局鎖 表級鎖 行鎖 三類。

全局鎖

全局鎖,就是對整個資料庫實例加鎖,MySQL 提供了一個加全局讀鎖的方法,命令是:

Flush tables with read lock (FTWRL)

當需要整個庫只讀狀態的時候,可以使用這個命令,之後其他線程的:數據更新語句(增刪改),數據定義語句(建表,修改表結構)和更新事務的提交語句將會被阻塞。

全局鎖的使用場景

全局鎖的定型使用場景,做 全庫邏輯備份 。也就是把整個庫每個表都 Select 出來,然後存成文本。

如何整個庫都只讀,會有什麼問題? 如果你在主庫上備份,那麼在備份期間都不能執行更想,業務就基本上停擺。 如果在從庫上備份,那麼備份期間從庫不能執行主庫同步過來的 binlog ,會導致從延遲。 既然要全庫只讀, 為什麼不使用set global readonly=true的方式呢?

readonly 方式也可以讓全庫進入只讀狀態,但我還是會建議你用FTWRL方式, 主要有兩個原因:

一是, 在有些系統中, readonly的值會被用來做其他邏輯,比如用來判斷一個庫是主庫還是備庫。因此,修改global變數的方式影響面更大, 我不建議你使用。 二是, 在異常處理機制上有差異。如果執行FTWRL命令之後由於客戶端發生異常斷開, 那麼MySQL會自動釋放這個全局鎖, 整個庫回到可以正常更新的狀態。而將整個庫設置為readonly之後, 如果客戶端發生異常, 則資料庫就會一直保持readonly狀態, 這樣會導致整個庫長時間處於不可寫狀態, 風險較高 表級別鎖

MySQL 裡面表級別的鎖有兩種:一種是表鎖,一種是元數據鎖(meta data lok, MDL)。表鎖的語法是 :

lock tables ... read/write

與 FTWRL 類似,可以使用 unlock tables 主動釋放鎖,也可以在客戶端斷開的時候自動釋放。需要注意的是,lock tables語法除了會限制別的線程的讀寫外,也限定了本線程接下來的操作對象。

MDL 表級鎖

MDL 不需要顯示使用,在訪問一個表的時候自動加上, MDL 保證讀寫的正確性,也就是說在查詢數據時,不允許有其他線程對這個表結構做變更。

什麼操作會加 MDL 鎖?

在MySQL 5.5版本中引入了MDL, 當對一個表做增刪改查操作的時候,加 MDL讀鎖 ;當要對表做結構變更操作的時候,加 MDL寫鎖

讀鎖之間不互斥,因此可以有多個線程同時對一張表增刪改查。 讀寫之間、寫鎖之間是互斥的,用來保證變更表結構操作的安全性,如果有兩個線程要同時給一個表加欄位,其中一個要等另外一個執行完才能執行。 更改表結構要注意哪些?

給一個表加欄位, 或者修改欄位, 或者加索引, 需要掃描全表的數據。在對大表操作的時候, 你肯定會特別小心, 以免對線上服務造成影響。而實際上, 即使是小表, 操作不慎也會出問題,導致整個庫的線程爆滿。

舉個例子

我們來看一下下面的操作序列, 假設表t是一個小表。

image

session A先啟動, 這時候會對表t加一個 MDL讀鎖 。由於session B需要的也是 MDL讀鎖 , 因此可以正常執行。 session C會被blocked, 是因為session A的MDL讀鎖還沒有釋放, 而session C需要MDL寫鎖, 因此只能被阻塞,讀寫鎖互斥。 如果只有session C自己被阻塞還沒什麼關系, 但是之後所有要在表t上新申請MDL讀鎖的請求也會被session C阻塞。前面我們說了,所有對表的增刪改查操作都需要先申請MDL讀鎖, 就都被鎖住, 等於這個表現在完全不可讀寫了。

如果某個表上的查詢語句頻繁, 而且客戶端有重試機制,也就是說超時後會再起一個新session 再請求的話, 這個 庫的線程很快就會爆滿 。事務中的MDL鎖, 在語句執行開始時申請, 但是語句結束後並不會馬上釋放, 而會等到整個事務提交後再釋放。

怎麼解決這個 更改表結構問題

比較理想的機制是, 在alter table語句裡面設定等待時間, 如果在這個指定的等待時間裡面能夠拿到MDL寫鎖最好, 拿不到也不要阻塞後面的業務語句, 先放棄。

ALTER TABLE tbl_name NOWAIT add column ... ALTER TABLE tbl_name WAIT N add column ...