1. 程式人生 > >樂觀鎖版本機制+100個併發讀取資料修改資料

樂觀鎖版本機制+100個併發讀取資料修改資料

package com.lock;


import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.concurrent.CountDownLatch;

public class LostUpdateOccDiscard implements Runnable{
    private CountDownLatch countDown;
    public LostUpdateOccDiscard(CountDownLatch countDown){
        this.countDown = countDown;
    }
    
    @Override
    public void run() {
        Connection conn=null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager
                    .getConnection(
                            "jdbc:mysql://192.168.1.191:3306/fangwifi_new?useUnicode=true&characterEncoding=UTF-8",
                            "root", "kw2014_!)");
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }
        
        try {
            conn.setAutoCommit(false);
            //讀的時候一併讀出version
            PreparedStatement ps =conn.prepareStatement("select * from LostUpdate where id =1");
            ResultSet rs=ps.executeQuery();
            int count = 0;
            int version = 0;
            while(rs.next()){
                count= rs.getInt("count");
                version= rs.getInt("version");
            }
            
            count++;
            
            //更新操作,用cas原子操作來更新
            ps =conn.prepareStatement("update LostUpdate set count=?, version=version+1 where id =1 and version=?");
            ps.setInt(1, count);
            ps.setInt(2, version);
            int result = ps.executeUpdate();
            
            //檢查有無因衝突導致執行失敗
            //成功,則commit,完成任務
            if(result>0) {    
                conn.commit();
            }
            //失敗,回滾,拋異常提醒呼叫者出現衝突。
            else{
                conn.rollback();
                throw new Exception("更新count出現衝突");
            }            
        } catch (SQLException e) {
            try {
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        }
        catch (Exception e) {
            System.out.println(e.getMessage());
        }
        //表示一次任務完成
        countDown.countDown();
    }

}

package com.lock;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestLockOcc {
     public static void main(String[] args) throws InterruptedException {
            //建立執行緒池,裡面有10個執行緒,共執行100次+1操作
            final int THREAD_COUNT=10;
            final int RUN_TIME=100;
           
            ExecutorService threadPool=Executors.newFixedThreadPool(THREAD_COUNT);
            //用CountDownLatch保證主執行緒等待所有任務完成
            CountDownLatch count=new CountDownLatch(RUN_TIME);
           
            for(int i=0;i<RUN_TIME;i++)
                threadPool.execute(new LostUpdateOccDiscard(count));
           
            threadPool.shutdown();
            count.await();
            //提示所有任務執行完
            System.out.println("finish");
        }
}

package com.lock;


import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.concurrent.CountDownLatch;

public class LostUpdateOccDiscard implements Runnable{
    private CountDownLatch countDown;
    public LostUpdateOccDiscard(CountDownLatch countDown){
        this.countDown = countDown;
    }
    
    @Override
    public void run() {
        Connection conn=null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager
                    .getConnection(
                            "jdbc:mysql://192.168.1.191:3306/fangwifi_new?useUnicode=true&characterEncoding=UTF-8",
                            "root", "kw2014_!)");
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }
        
        try {
            conn.setAutoCommit(false);
            //讀的時候一併讀出version
            PreparedStatement ps =conn.prepareStatement("select * from LostUpdate where id =1");
            ResultSet rs=ps.executeQuery();
            int count = 0;
            int version = 0;
            while(rs.next()){
                count= rs.getInt("count");
                version= rs.getInt("version");
            }
            
            count++;
            
            //更新操作,用cas原子操作來更新
            ps =conn.prepareStatement("update LostUpdate set count=?, version=version+1 where id =1 and version=?");
            ps.setInt(1, count);
            ps.setInt(2, version);
            int result = ps.executeUpdate();
            
            //檢查有無因衝突導致執行失敗
            //成功,則commit,完成任務
            if(result>0) {    
                conn.commit();
            }
            //失敗,回滾,拋異常提醒呼叫者出現衝突。
            else{
                conn.rollback();
                throw new Exception("更新count出現衝突");
            }            
        } catch (SQLException e) {
            try {
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        }
        catch (Exception e) {
            System.out.println(e.getMessage());
        }
        //表示一次任務完成
        countDown.countDown();
    }
}
轉載至https://www.cnblogs.com/deliver/p/5730616.html