數據庫基礎知識: http://blog.csdn.net/luyaran/article/details/53502917
死鎖:如果需要“修改”一條數據,首先數據庫管理系統會在上面加鎖,以保證在同一時間只有一個事務能進行修改操作。鎖定(Locking)發生在當一個事務獲得對某一資源的“鎖”時,這時,其他的事務就不能更改這個資源了,這種機制的存在是爲了保證數據一致性。
錯誤: Causedby:java.sql.BatchUpdateException: Deadlock found when trying to get lock;tryrestarting transaction
產生死鎖的兩個必要條件:
1.使用事物
2.where 條件後面 一個是索引,一個不是索引
場景一:
sparkStreaming 在foreachportion(相當於多線程) 裏批量執行下面語句
updatebi_publish_back_cost set main_man='' where pkg_code='204022' andperformance_time='2017-05-22'
解決方法:
1.刪掉其中的一個索引就可以了
2.把兩個單獨索引改爲一個整體索引 (最終解決方法)
3.不使用事物
其他錯誤的嘗試:dobatch時,每 100 條execute一次,還是鎖住
場景二:
sparkStreaming 在foreachportion(相當於多線程) 裏批量執行下面語句
INSERT INTObi_gamepublic_base_day_kpi(parent_game_id,child_game_id,medium_channel,ad_site_channel,pkg_code,publish_date,new_regi_device_num)VALUES (?,?,?,?,?,?,?) ON DUPLICATE KEY updateos=?,group_id=?,medium_account=?,promotion_channel=?,promotion_mode=?,head_people=?,new_regi_device_num=new_regi_device_num+ VALUES(new_regi_device_num)
產生死鎖的原因: child_game_id,medium_channel,ad_site_channel,pkg_code中 child_game_id 和 pkg_code 爲 unique key ,執行這樣的語句,更新的時候 unique key 就相當於where,後續原因如場景一
解決方法:
1.把5個字段設置爲一個整體索引
2.不使用事物插入(最終解決方法)
死鎖解決方法總結:
1.多線程 批量更新數據庫的時候,where後面的限制條件要麼是同一索引,要不都不是索引,不要一般是索引,一半不是索引
2.不要使用 多線程事物插入
===多線程死鎖
public class DeadLocker { public static void main(String[] args) { DeadLock t1 = new DeadLock(); t1.setName("線程1"); DeadLock t2 = new DeadLock(); t2.setName("線程2"); t1.flag = true; t2.flag = false; t1.start(); t2.start(); } }
class DeadLock extends Thread {
public boolean flag = true; static Object o1 = new Object();// 定義兩個公共資源 static Object o2 = new Object();
@Override public void run() { // TODO Auto-generated method stub if (flag) { System.out.println(Thread.currentThread().getName() + "等待o1"); synchronized (o1) { System.out.println(Thread.currentThread().getName() + "佔用o1,等待o2"); synchronized (o2) { System.out.println(Thread.currentThread().getName() + "佔用o2"); } System.out.println(Thread.currentThread().getName() + "釋放o2"); } System.out.println(Thread.currentThread().getName() + "釋放o1"); } else { System.out.println(Thread.currentThread().getName() + "等待o2"); synchronized (o2) { System.out.println(Thread.currentThread().getName() + "佔用o2,等待o1"); synchronized (o1) { System.out.println(Thread.currentThread().getName() + "佔用o1"); } System.out.println(Thread.currentThread().getName() + "釋放o1"); } System.out.println(Thread.currentThread().getName() + "釋放o2"); } } }
|