1. 程式人生 > >多執行緒模擬高併發情況redis 與資料庫快取不一致

多執行緒模擬高併發情況redis 與資料庫快取不一致

import com.mysql.jdbc.Connection;
import entity.User;
import org.junit.Test;
import redis.clients.jedis.Jedis;

import java.sql.*;
import java.util.LinkedList;

/**
 * @描述  佇列解決高併發,redis,快取與資料庫不一致問題
 * @引數 $
 * @返回值 $
 * @建立人 [email protected]
 * @建立時間 $
 * @修改人和其它資訊
 */



public class TestQueueSolution {


    //獲得mysqlconnection
    public Connection getMysqlConn() {
        String driver = "com.mysql.jdbc.Driver";
        String url = "jdbc:mysql://localhost:3306/redistest?useSSL=false";
        String username = "root";
        String password = "root";
        Connection conn = null;
        try {
            Class.forName(driver); //classLoader,載入對應驅動
            conn = (Connection) DriverManager.getConnection(url, username, password);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }

    public User execQuerySql(Connection connection,String sqlStr, LinkedList parms) throws SQLException {
        PreparedStatement pstmt = null;
        ResultSet resultSet = null;
        pstmt = connection.prepareStatement(sqlStr);
        for (int i = 1 ; i <= parms.size() ; i++ ){
            ///記得 後面跟的是 i-1
            pstmt.setObject(i,parms.get(i-1));
        }
        resultSet = pstmt.executeQuery();
        User user = null;
        while (resultSet.next()){
            user = new User();
            System.out.println("----------------");
            user.setId(resultSet.getInt("id"));
            user.setAge(resultSet.getInt("age"));
            user.setBirthday(resultSet.getDate("birthday"));
            user.setName(resultSet.getString("name"));
        }
        return user;

    }


    //執行sql 以及引數
    public Integer exeuUpdateTheSqlWithParms(Connection connection,String sql,LinkedList parms) throws SQLException {
        PreparedStatement pstmt = null;
        ResultSet resultSet = null;
        pstmt = connection.prepareStatement(sql);
        //設定引數
        for (int i = 1 ; i <= parms.size(); i++){
            pstmt.setObject(i,parms.get(i-1));
        }
        Integer count = pstmt.executeUpdate();
        return  count;
    }



        //刪除redis並延遲更新資料的執行緒
        class UpdateRedisDataBaseThread implements Runnable{
            public String redisKey;
             //每個執行緒獲取自己的connection
            public Connection connection;
            //資料庫 名字
            public String parmName;
            //設定資料年齡
            public Integer age;

            public UpdateRedisDataBaseThread(String redisKey, String parmName, Integer age) {
                this.redisKey = redisKey;
                this.parmName = parmName;
                this.age = age;
            }

            @Override
            public void run() {
                //每個執行緒自己 的 redis 客戶端
                Jedis jedis  =  new Jedis("127.0.0.1",6379);
                //如果存在則進行刪除
                if ( jedis.exists(this.redisKey) ){
                    System.out.println("del a value from redis :" + this.redisKey);
                    jedis.del(this.redisKey);
                }
                //模擬延遲更新資料庫
                //設定引數
                this.connection = getMysqlConn();
                String sqlStr = "update t_user set age = ? where name = ?";
                LinkedList parm_link = new LinkedList();
                parm_link.add(age);
                parm_link.add(parmName);
                try {
                    //休眠一秒
                    System.out.println("UpdateRedisDataBaseThread sleep 3s");
                    Thread.sleep(3000);
                    Integer count  =   exeuUpdateTheSqlWithParms(connection,sqlStr,parm_link);
                    System.out.println("UpdateRedisDataBaseThread update database count:"+count);

                } catch (SQLException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        //直接更改資料庫的執行緒
        class SelectThread implements  Runnable{
            //每個執行緒獲取自己的connection
            public Connection connection;
            //查詢引數
            public String parmName;
            //查詢結果
            public String queryResult;

            public SelectThread(String parmName) {
                this.parmName = parmName;
            }

            @Override
            public void run() {
                //每個執行緒自己 的 redis 客戶端
                Jedis jedis  =  new Jedis("127.0.0.1",6379);
                //如果redis存在則直接得到值
                if (jedis.exists(parmName)){
                    System.out.println("SelectThread can not get value parm:" + this.parmName);
                    this.queryResult = jedis.get(parmName);
                }else {
                    //快取沒有則到資料庫查詢
                    this.connection = getMysqlConn();
                    String sqlStr = "select * from t_user where name = ?";
                    LinkedList parm_link = new LinkedList();
                    parm_link.add(parmName);
                    try {
                        User user  =   execQuerySql(connection,sqlStr,parm_link);
                        if ( user != null ){
                            this.queryResult  = user.toString();
                            //--將結果寫到redis
                            System.out.println(Thread.class.getName()+" parm " + this.parmName  +" set a vlaue to redis!");
                            jedis.set(this.parmName,this.queryResult);
                        }

                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }

        }



        @Test
        public void test() throws InterruptedException {
            //衝突的記錄
            String cfkName = "liming01";
            //第一條請求-執行更新操作的執行緒
            UpdateRedisDataBaseThread drud = new UpdateRedisDataBaseThread(cfkName,"liming01",66);
            //併發第二條請求 - 執行查詢操作的執行緒
            SelectThread udbt = new SelectThread(cfkName);
            new Thread(drud).start();
            //休眠一秒-模擬其它操作
            Thread.sleep(2000);
            //第二個執行緒開始查詢
            new Thread(udbt).start();
            //主執行緒休眠10s
            Thread.sleep(10000);//休眠20s

        }



}

相關推薦

執行模擬併發情況redis 資料庫快取一致

import com.mysql.jdbc.Connection; import entity.User; import org.junit.Test; import redis.clients.jedis.Jedis; import java.sql.*; import

執行併發情況下操作redis當中的資料,如何加鎖?

多個執行緒同時去操作Redis當中的資料,假如不加鎖的情況下,會出現資料重複的問題。假如需要每次都只有一條執行緒去操作Redis當中的資料,需要給操作加上鎖。     但是去網上一搜,網上給Redis加鎖的機制都是利用Redis的setnx自身的方法去加鎖,但是這樣

同步、非同步、執行併發不再混淆!

高併發:“短時間內遇到大量操作請求”的情況。 多執行緒:多執行緒就是指一個程序中同時有多個執行緒正在執行。其目的就是當某個執行緒很耗時的時候使用多執行緒,可以在將耗時任務放在後臺繼續執行的同時,同時執行其他操作,達到提升效率,優化使用者體驗的效果。 多執行緒是完成高併發任

Java執行:解決併發環境下資料插入重複問題

1.背景描述 應用框架:Spring + SpringMVC + Hibernate  資料庫:Oracle11g 一家文學網站向我係統推多執行緒低併發推送資料,我這邊觀察日誌和資料庫,發現有

執行WEB併發壓力測試軟體JMeter

一、 Apache JMeter工具   1)簡介   JMeter——一個100%的純java桌面應用,它是 Apache組織的開放原始碼專案,它是功能和效能測試的工具。JMeter可以用於測試靜態或者動態資源的效能(檔案、Servlets、Perl指令碼、java物

執行併發

執行緒與程序 執行緒是CPU排程和分配的基本單位,程序是資源分配和排程的基本單位 一個程序中可以包括多個執行緒,執行緒共享整個程序的資源(暫存器、堆疊、上下文),執行緒間要進行同步和互斥 區別

JUC執行併發

一、請你談談對volatile的理解 ​ Package java.util.concurrent---> A

JUC執行併發面試題

JUC多執行緒及高併發 [TOC] 一、請你談談對volatile的理解 ​ Package java.util.concurre

JAVA執行(四) Executor併發框架向RabbitMQ推送訊息

github程式碼地址:https://github.com/showkawa/springBoot_2017/tree/master/spb-demo  假設一個需求使用者點選某個頁面,我們後臺需要向MQ推送信資訊 1,模擬的MQ服務,我這邊使用RabbitMQ (關於MQ 傳送和監聽訊息可以

執行(十): 併發中集合ConcurrentHashMap

public class HashTest { static Map<String, String> map = new HashMap<>(); public static void main(String[] args) {

java:Map集合模擬鬥地主,執行模擬搶地主 例項

 原始碼如下: package selfpractice.day4; import java.util.*; //多執行緒模擬搶地,重點程式碼位於loot()方法內 public class Practice_Poker { public static void main(S

執行模擬實現生產者/消費者模型

多執行緒模擬實現生產者/消費者模型 package com.chow.queue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; import java

Java執行(二)Java併發工具包concurrent例項簡述

傳統的多執行緒並沒有提供高階特性,例如:訊號量、執行緒池和執行管理器等,而這些特性恰恰有助於建立強大的併發程式。新的Fork/Join框架針對當前的多核系統,也提供了並行程式設計的可能。這塊的內容是java多執行緒資訊量最大的一部分內容,本篇部落格循序漸進的,首

Nodejs探祕:深入理解單執行實現併發原理

前言 從Node.js進入我們的視野時,我們所知道的它就由這些關鍵字組成 事件驅動、非阻塞I/O、高效、輕量,它在官網中也是這麼描述自己的: Node.js® is a JavaScript runtime built on Chrome’s V8 JavaScript e

執行模擬搶紅包

今天有朋友問我一道面試題,有5個人搶5個紅包,可重複搶,用多執行緒程式實現,實現方式有多種,分享一下我的思路:應用了阻塞佇列的特性 /** * Created by zhanglinqiang on 2016/6/23. */ public class MyTest

JMeter壓力測試(流程骨架/搶紅包舉例實戰/場景執行組混合併發/HTTPS請求)

效能測試裡面包含三個測試:基準測試、負載測試、壓力測試。基準測試就是用一個虛擬使用者(UV)進行一個對被測系統/物件的操作負載測試就是慢慢不斷地加UV壓力測試就是長時間連續執行系統給系統性能造成的影響,一直到測出問題為止一、JMeter進行HTTP協議介面的壓力測試1.新增執

關於執行處理資料併發問題處理

資料量多時需要要多執行緒處理,尤其在叢集環境下很可能發生資源競爭的情況,此時就需要謹慎的對資料加鎖,如果加鎖出了問題,也是個麻煩事。 為安全考慮,一般處理這種問題有幾個步驟: 為此個業務加開關,如果出現問題,將開關關閉。但是遇到一些緊急問題,開關關閉會影響業務,這時就需要走

JAVA學習之路(執行)---模擬售票(細解)

首先看題目描述: 假設有火車票100張,建立4個執行緒模擬4個售票點,每100ms售出一張,打印出售票過程,格式如下: 視窗3:賣出第100張票 視窗4:賣出第99張票  ............ ............ 簡單的思路就是建立一個類,首先肯定要去繼承Thread。開啟執行

執行基礎 Java併發1

目錄   執行緒和程序概念 同步和非同步概念 多執行緒建立方式 繼承Thread類(不推薦) 實現runnable介面,重寫run方法 使用匿名內部類 多執行緒的執行狀態 守護執行緒、非守護執行緒 join方法() 優先順序 執行緒安全