新聞中心
在日常開發(fā)工作中,我們常常需要向數(shù)據(jù)庫中插入大量數(shù)據(jù)。對于一次只能插入一條數(shù)據(jù)的操作,手動添加顯然是個非常繁瑣的過程。此時(shí),批量插入就成為了更好的選擇。

目前創(chuàng)新互聯(lián)已為上千家的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)站空間、網(wǎng)站托管維護(hù)、企業(yè)網(wǎng)站設(shè)計(jì)、正安網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。
本文將介紹數(shù)據(jù)庫批量插入操作的基礎(chǔ)理論、使用方法以及需要注意的事項(xiàng),希望能夠?yàn)殚_發(fā)者們提供一些實(shí)用的經(jīng)驗(yàn)。
一、什么是批量插入
批量插入,顧名思義就是一次性向數(shù)據(jù)庫中插入多條數(shù)據(jù)。通常情況下,批量插入的操作速度與單次插入相比要快得多。原因在于,多條數(shù)據(jù)的集中操作可以將多個查詢請求一次性發(fā)送給數(shù)據(jù)庫,減少了連接和釋放時(shí)間。此外,批量插入還能夠減少數(shù)據(jù)庫日志記錄,避免了多余的系統(tǒng)開銷。
二、批量插入的技術(shù)實(shí)現(xiàn)
1. 數(shù)據(jù)庫支持批量插入
首先要注意的是,不是所有數(shù)據(jù)庫都支持批量插入。在使用之前,需要先確認(rèn)數(shù)據(jù)庫是否支持批量插入操作。大多數(shù)主流的數(shù)據(jù)庫如MySQL、Oracle、SQLServer等都支持此操作。
2. 使用預(yù)編譯語句
批量插入需要使用到SQL語句,這些語句需要先解析成數(shù)據(jù)庫可以執(zhí)行的二進(jìn)制碼。預(yù)編譯語句可以將SQL語句預(yù)先編譯成二進(jìn)制碼,以減少每個插入操作的解析和編譯時(shí)間。
3. 使用事務(wù)處理
批量插入操作存在著一定的風(fēng)險(xiǎn):如果某一條插入操作失敗,整個插入操作將被中斷,同時(shí)之前已經(jīng)成功插入的數(shù)據(jù)也會被回滾,導(dǎo)致數(shù)據(jù)的不連續(xù)性。使用事務(wù)處理可以有效避免這種風(fēng)險(xiǎn)。通過事務(wù)處理,我們可以將多個插入操作統(tǒng)一到一個事務(wù)中,在所有操作執(zhí)行完畢后再一起提交到數(shù)據(jù)庫中。如果某個操作失敗,那么整個事務(wù)都將被回滾,保證了數(shù)據(jù)的一致性。
三、批量插入的實(shí)現(xiàn)方法
1. JDBC批量插入
JDBC是Java數(shù)據(jù)庫連接的標(biāo)準(zhǔn),通過JDBC可以實(shí)現(xiàn)Java程序與各種關(guān)系型數(shù)據(jù)庫的連接和操作。在JDBC中,批量插入需要使用到PreparedStatement類。該類可以通過addBatch()方法插入多個參數(shù),最后一次性將參數(shù)塞入到PreparedStatement中。
示例代碼:
// 插入數(shù)據(jù)
String sql = “INSERT INTO user (name, age, sex) VALUES (?, ?, ?)”;
PreparedStatement pstmt = conn.prepareStatement(sql); // 預(yù)編譯SQL
for (User u : userList) { // 模擬用戶數(shù)據(jù)
pstmt.setString(1, u.getName());
pstmt.setInt(2, u.getAge());
pstmt.setString(3, u.getSex());
pstmt.addBatch(); // 將操作添加到預(yù)編譯語句中
}
pstmt.executeBatch(); // 一次執(zhí)行多條SQL語句
conn.commit(); // 提交事務(wù)
2. MyBatis批量插入
MyBatis是一款優(yōu)秀的Java持久化框架,可以將Java對象映射到關(guān)系型數(shù)據(jù)庫中。在MyBatis中,批量插入需要使用到BatchExecutor類。
示例代碼:
INSERT INTO user (name, age, sex) VALUES
(#{item.name}, #{item.age}, #{item.sex})
// 將數(shù)據(jù)封裝到List中
List userList = new ArrayList();
for (int i = 0; i
userList.add(new User(“test” + i, 18, “F”));
}
// 執(zhí)行批量插入
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false);
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
for (int i = 0; i
List subList = userList.subList(i * 100, (i + 1) * 100);
userMapper.batchInsert(subList);
}
sqlSession.commit(); // 提交事務(wù)
四、批量插入的注意事項(xiàng)
1. 數(shù)據(jù)庫限制
不同的數(shù)據(jù)庫對于批量插入操作的限制不同。使用之前,需要確保數(shù)據(jù)庫對于一次插入操作的數(shù)據(jù)量不會超出限制。
2. 防止數(shù)據(jù)重復(fù)插入
在批量插入操作中,可能會產(chǎn)生重復(fù)數(shù)據(jù)的情況。為了避免出現(xiàn)這種情況,需要在插入之前進(jìn)行數(shù)據(jù)去重操作。
3. 注意執(zhí)行過程中的異常處理
批量插入是一次性操作大量數(shù)據(jù)的過程,如果在此過程中出現(xiàn)異常,必須進(jìn)行及時(shí)處理以避免數(shù)據(jù)丟失或不完整的情況。
:
相關(guān)問題拓展閱讀:
- mysql 怎么用insert批量插入數(shù)據(jù)
mysql 怎么用insert批量插入數(shù)據(jù)
這就是自己實(shí)現(xiàn)一個id自增的東西。
比如的你有個公用冊襲類專門用來生成后面的數(shù)字州灶兄,所有需要用到的方法都調(diào)用這個類的一辯鉛個方法我們就叫它nextid吧,只要這個方法是線程安全的就可以了。
idutils.nextid()
int
nextid()
{
lock(this){
return
this.id++;
}
}
應(yīng)用啟動的時(shí)候從數(shù)據(jù)庫查詢一下id的更大值并設(shè)置給工具類的id,讓它接著增長就行了。
具體實(shí)現(xiàn)看你用什么語言。
請仔細(xì)閱讀別人回答的是什么意思。想想oracle的sequence的實(shí)現(xiàn),是不是類似?
一次插入多行數(shù)據(jù)
insert
into
表名
values(值列表1),(值列表2),…(值列表n);
例如:
insert
into
students(sid,sname,dob)
values
(‘001′,’張三核銀’,”),
(‘002′,’李四’,”),
(‘宴配003′,’王五’,”);
將一張表或查詢中的改祥宴數(shù)據(jù)插入到另一張表里
insert
into
表名(字段列表)
select
(字段列表)
from
源表
where
篩選表達(dá)式;
例如將表2中的記錄全部插入到表1,假設(shè)它們的結(jié)構(gòu)一樣
insert
into
表1(*)
select
*
from
表2;
加鎖情況與死鎖原因分析
為方便大家復(fù)現(xiàn),完整表結(jié)構(gòu)和數(shù)據(jù)如下:
CREATE TABLE `t3` (
`c1` int(11) NOT NULL AUTO_INCREMENT,
`c2` int(11) DEFAULT NULL,
PRIMARY KEY (`c1`),
UNIQUE KEY `c2` (`c2`)
) ENGINE=InnoDB
insert into t3 values(1,1),(15,15),(20,20);
在 session1 執(zhí)行 commit 的瞬間,我們會看到 session2、session3 的其中一個報(bào)死鎖。這個死鎖是這樣產(chǎn)生的:
1. session1 執(zhí)行 delete 會在唯一索引 c2 的 c2 = 15 這一記錄上加 X lock(也就是在MySQL 內(nèi)部觀測到的:X Lock but not gap);
2. session2 和 session3 在執(zhí)行 insert 的時(shí)候,由于唯一約束檢測發(fā)生唯一沖突,會加 S Next-Key Lock,即對 (1,15> 這個區(qū)間加鎖包括間隙,并且被 seesion1 的 X Lock 阻塞,進(jìn)入等待;
3. session1 在執(zhí)行模世 commit 后,會釋放 X Lock,session2 和 session3 都獲得 S Next-Key Lock;
4. session2 和 session3 繼續(xù)執(zhí)行插入操作,這個時(shí)候 INSERT INTENTION LOCK(插入意向鎖)出現(xiàn)了,并且由于插入意向鎖會被 gap 鎖阻塞,所以 session2 和 session3 互相等待,造成死鎖。
死鎖日志如下:
INSERT INTENTION LOCK
在之前的死鎖分析第四點(diǎn),如果不分析插入意向鎖,也是會造成死鎖的,因?yàn)椴迦胱罱K還是要對記錄加 X Lock 的,session2 和 session3 還是會互相阻塞互相等待。
但是插入意向鎖是客觀存在的,我們可以在官方手冊中查到,不可忽略:
Prior to inserting the row, a type of gap lock called an insert intention gap lock is set. This lock signals the intent to insert in such a way that multiple transactions inserting into the same index gap need not wait for each other if they are not inserting at the same position within the gap.
插入意向鎖其實(shí)是一種特殊的 gap lock,但是它不會阻塞其他鎖。假設(shè)存在值為 4 和 7 的索引記錄,嘗試插入值 5 和 6 的兩個事務(wù)在獲取插入行上的排它鎖之前使用插入意向鎖鎖定間隙,即在(4,7)上加 gap lock,但是這兩個事務(wù)不會互相沖突等待。
當(dāng)插入一條記錄時(shí),會去檢查當(dāng)前插入位置的下一條記錄上是否存在鎖對象,如果下一條記錄上存在鎖對象,就需要判斷該鎖對象是否鎖住了 gap。如果 gap 被鎖住了,則插入意向鎖與之沖突,進(jìn)入等待狀態(tài)(插入意向鎖之間并不互斥)。總結(jié)一下這把鎖的屬性:
1. 它不會阻塞其他任何鎖;
2. 它本身僅會被 gap lock 阻塞。
在學(xué)習(xí) MySQL 過程中,一般只有在它被阻塞的時(shí)候才能觀察到,所以這也是它常常被忽略的原因吧…
GAP LOCK
在此例中,另外一個重要的點(diǎn)就是 gap lock,通常情況下我們說到 gap lock 都只會聯(lián)想到 REPEATABLE-READ 隔離級別利用其解決幻讀。但實(shí)際上在 READ-COMMITTED 隔離級別,也會存在 gap lock ,只發(fā)生在:唯一約束檢查到有唯一沖突的時(shí)候,會加 S Next-key Lock,即對記錄以及與和上一條記錄之間的間隙加共享鎖。
通過下面這個例子就能驗(yàn)證:
這余碼橋里 session1 插入數(shù)據(jù)遇到唯一沖突,雖然報(bào)錯,但是對 (15,20> 加的 S Next-Key Lock 并不會馬上釋放,所以豎猛 session2 被阻塞。另外一種情況就是本文開始的例子,當(dāng) session2 插入遇到唯一沖突但是因?yàn)楸?X Lock 阻塞,并不會立刻報(bào)錯 “Duplicate key”,但是依然要等待獲取 S Next-Key Lock 。
有個困惑很久的疑問:出現(xiàn)唯一沖突需要加 S Next-Key Lock 是事實(shí),但是加鎖的意義是什么?還是說是通過 S Next-Key Lock 來實(shí)現(xiàn)的唯一約束檢查,但是這樣意味著在插入沒有遇到唯一沖突的時(shí)候,這個鎖會立刻釋放,這不符合二階段鎖原則。這點(diǎn)希望能與大家一起討論得到好的解釋。
如果是在 REPEATABLE-READ,除以上所說的唯一約束沖突外,gap lock 的存在是這樣的:
普通索引(非唯一索引)的S/X Lock,都帶 gap 屬性,會鎖住記錄以及前1條記錄到后1條記錄的左閉右開區(qū)間,比如有記錄,delete 6,則會鎖住
對于 gap lock,相信 DBA 們的心情是一樣一樣的,所以我的建議是:
1. 在絕大部分的業(yè)務(wù)場景下,都可以把 MySQL 的隔離界別設(shè)置為 READ-COMMITTED;
2. 在業(yè)務(wù)方便控制字段值唯一的情況下,盡量減少表中唯一索引的數(shù)量。
鎖沖突矩陣
關(guān)于數(shù)據(jù)庫批量插入怎么做的介紹到此就結(jié)束了,不知道你從中找到你需要的信息了嗎 ?如果你還想了解更多這方面的信息,記得收藏關(guān)注本站。
香港服務(wù)器選創(chuàng)新互聯(lián),2H2G首月10元開通。
創(chuàng)新互聯(lián)(www.cdcxhl.com)互聯(lián)網(wǎng)服務(wù)提供商,擁有超過10年的服務(wù)器租用、服務(wù)器托管、云服務(wù)器、虛擬主機(jī)、網(wǎng)站系統(tǒng)開發(fā)經(jīng)驗(yàn)。專業(yè)提供云主機(jī)、虛擬主機(jī)、域名注冊、VPS主機(jī)、云服務(wù)器、香港云服務(wù)器、免備案服務(wù)器等。
文章名稱:數(shù)據(jù)庫批量插入操作指南(數(shù)據(jù)庫批量插入怎么做)
鏈接地址:http://m.fisionsoft.com.cn/article/djhpdci.html


咨詢
建站咨詢
