樹莓派開發筆記(十七):樹莓派4B+上Qt多用戶連接操作Mysql數據庫同步(單條數據悲觀鎖)

前言

  安裝了mysq數據庫,最終時爲了實現在一個樹莓派上實現多用戶多進程操作的同步問題,避免數據併發出現一些錯誤,本篇安裝了遠程服務並且講述了使用Qt進行悲觀鎖for update操作,命令行進行同步查詢的示例。

 

其他操作

  這裏只是稍微提一下,具體參照博主的樹莓派系列博客,非常詳細。
  遠程登陸界面

sudo apt-get install tightvncserver
sudo apt-get install xrdp
sudo service xrdp restart
sudo ufw allow 3389
sudo service ufw restart

  然後可以使用window遠程桌面登陸了:
  默認用戶名:pi
  默認密碼:raspberry
  在這裏插入圖片描述
  在這裏插入圖片描述

安裝qt5

sudo apt-get install qt5-default
sudo apt-get install qtcreator

  安裝好後,遠程桌面的程序裏面就多了個qtcreator了:
  在這裏插入圖片描述
  在這裏插入圖片描述
  創建一個界面工程,然後運行:
  (編譯速度比幾年前的3B+快一些,後續開發過程中測試一下,是否可以忽略3B+的交叉編譯)
  在這裏插入圖片描述
  檢查數據庫驅動:
  在這裏插入圖片描述
  沒有mysql的數據庫驅動。

sudo apt-get install libqt5sql5-mysql

  在這裏插入圖片描述

 

Qt操作mariadb數據庫

QSqlDatabase db;
db = QSqlDatabase::addDatabase("QMYSQL");
db.setHostName("127.0.0.1");
db.setPort(3306);
db.setDatabaseName("data");
db.setUserName("root");
db.setPassword("a1234567");

if(db.open())
{
    LOG << "Succeed to open db";
}else{
    LOG << "Failed to open db:" << db.lastError().text();
    return;
}

QString cmd = "select * from student;";
QSqlQuery query = db.exec(cmd);
while(query.next())
{
    LOG << query.value(0).toString()
        << query.value(1).toString()
        << query.value(2).toString()
        << query.value(3).toString();
}

  在這裏插入圖片描述

 

多用戶操作

  本意是爲了多用戶操作,那麼讀的時候需要加讀鎖,寫的時候需要加寫鎖。
  兩個用戶同時讀取了數據庫中的一條記錄,此時用戶A對其中一個字段的值進行了修改操作並進行了提交,後來用戶B也對這個字段進行了修改,用戶B的提交將會覆蓋用戶A提交的值。
  在這裏插入圖片描述

鎖類型

悲觀鎖

  每次去取數據,很悲觀,都覺得會被別人修改,所以在拿數據的時候都會上鎖。簡言之,共享資源每次都只給一個線程使用,其他線程阻塞,等第一個線程用完後再把資源轉讓給其他線程。synchronized和ReentranLock等都是悲觀鎖思想的體現。

樂觀鎖

  每次去取數據,都很樂觀,覺得不會被被人修改。因此每次都不上鎖,但是在更新的時候,就會看別人有沒有在這期間去更新這個數據,如果有更新就重新獲取,再進行判斷,一直循環,直到拿到沒有被修改過的數據。(mysql需要自己實現樂觀鎖)。

for update使用場景(悲觀鎖)

  for update 可以爲數據庫中的一行數據加上一個排它鎖。當一個事務的操作未完成時候,其他事務可以讀取但是不能寫入或更新。
  如果項目對某個數據準確性有要求,並且項目存在併發(不一定高併發),則需要使用 for update。
  比如:用戶A使用餘額購買商品,此時用戶B向用戶A發起轉賬,如果恰好處在同一時間,則可能造成用戶A最終餘額錯誤。此時需要使用 for update 進行數據加鎖防止出錯。
  這種情況下,即使併發很小,但是也會有一定的概率會碰到,而餘額的錯誤即使差一分錢也是不能容忍的,所以這種特定的場景,即使不是高併發,也應該使用 for update 規避問題。

for update 用法

begin;
select * from XXX where XXX for update;
...
commit;

  for update 必須在事務中才生效。

 

Qt測試

使用127.0.0.1的ip進行連接(本地連接)

QSqlDatabase db;
db = QSqlDatabase::addDatabase("QMYSQL");
db.setHostName("127.0.0.1");
db.setPort(3306);
db.setDatabaseName("data");
db.setUserName("root");
db.setPassword("a1234567");

if(db.open())
{
    LOG << "Succeed to open db";
}else{
    LOG << "Failed to open db:" << db.lastError().text();
    return;
}

if(db.transaction())
{
    QString cmd = "select * from student for update;";
    QSqlQuery query = db.exec(cmd);
    while(query.next())
    {
        LOG << query.value(0).toString()
            << query.value(1).toString()
            << query.value(2).toString()
            << query.value(3).toString();
    }
    for(int index = 0; index < 10; index++)
    {
        QThread::sleep(1);
        LOG << "sleep:" << index;
    }
    if(!db.commit())
    {
        LOG << "Failed to commit";
    }
}

   在這裏插入圖片描述
  至此,我們的鎖加入成功,說清楚原理可以方便大家着手開始開發多用戶進程操作數據庫的同步開發了。

使用局域網的ip進行連接(遠程連接)

QSqlDatabase db;
db = QSqlDatabase::addDatabase("QMYSQL");
db.setHostName("192.168.0.103");
db.setPort(3306);
db.setDatabaseName("data");
db.setUserName("root");
db.setPassword("a1234567");

if(db.open())
{
    LOG << "Succeed to open db";
}else{
    LOG << "Failed to open db:" << db.lastError().text();
    return;
}

if(db.transaction())
{
    QString cmd = "select * from student for update;";
    QSqlQuery query = db.exec(cmd);
    while(query.next())
    {
        LOG << query.value(0).toString()
            << query.value(1).toString()
            << query.value(2).toString()
            << query.value(3).toString();
    }
    for(int index = 0; index < 10; index++)
    {
        QThread::sleep(1);
        LOG << "sleep:" << index;
    }
    if(!db.commit())
    {
        LOG << "Failed to commit";
    }
}

  連接不上:
  在這裏插入圖片描述
  這個時候需要修改下配置:

sudo vi /etc/mysql/mariadb.conf.d/50-server.cnf

  在這裏插入圖片描述

  重啓服務:

systemctl restart mysql.service

  在這裏插入圖片描述
  繼續測試,下面是用樹莓派使用局域網ip(之前也不能連接127.0.0.1):
  在這裏插入圖片描述
  連接成功,然後在局域網pc上連接,但是不能打開事務:
  在這裏插入圖片描述
  修改一下:
  在這裏插入圖片描述

  這個其實是跟mysql驅動有關係,因爲筆者是幾年前弄得libmysql.dll和libmysqld.dll,這個不深究了,已經可以遠程操作了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章