當前位置:
首頁 > 知識 > 在Mybatis中使用手動加鎖的方式操作資料庫

在Mybatis中使用手動加鎖的方式操作資料庫

在使用Spring整合Mybatis進行資料庫操作時,我們可以通過Spring的註解@Transactional來實現事務,同時可以在註解中對資料庫設置隔離級別來進行並發操作資料庫時候的控制。

但是對於某些情況,僅僅使用資料庫隔離級別無法達到最優的效果,比如兩個事務同時對一張表進行操作,其中一個事務對錶進行讀取,而另一個事務對錶進行插入操作,在PostgreSQL,Orecal以及SQL Server中,由於採用的是讀已提交的隔離級別,所以當讀事務的鎖和寫事務的鎖是不衝突的,這就會導致這兩種事務可能會並發交替執行,最終的結果是如果讀事務在事務的生命周期中對錶進行了多次讀取的話,前後兩次可能讀取到不同的值,因為寫事務對資料庫的操作只要是經過Commit,就會對讀事務可見。將資料庫隔離級別設置為串列化可以解決這個問題,但是串列化會導致資料庫的並發能力降低。

我們都知道資料庫會提供一些加鎖的語句來人為對資料庫表進行加鎖,接下來就嘗試在Mybatis中動態對資料庫的表進行加鎖操作。

首先我們需要設置資料庫可以同時執行多條語句,即在配置文件中的資料庫url的後面加上allowMultiQueries=true,這樣我們就可以在Mybatis的mapper.xml的標籤中寫入多行SQL語句來執行。

"jdbc:mysql://localhost:3306/xxx?allowMultiQueries=true"

1

接著我們隨意找一個Mybatis的xml文件,在任意一句標籤中的SQL前面多加一句「LOCK TABLE users READ」。

<mapper namespace="hello.UserMapper">

<select id="getUser" parameterType="int" resultType="hello.User">

LOCK TABLE users READ;

select * from users where id=#{id};

</select>

</mapper>

1

2

3

4

5

6

然後在Console中打開資料庫,找到users表,依次執行如下命令

START TRANSACTION;

LOCK TABLES users WRITE;

1

2

在這裡我們開啟了一個事務,在這個事務中首先是獲取users表的寫鎖,只要我們不執行commit或則rollback,這個事務將會一直持有這個鎖。

接著回到程序,在程序中我們執行如下代碼

InputStream is = Main.class.getClassLoader().getResourceAsStream(resource);

SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);

SqlSession session = sessionFactory.openSession();

String statement = "hello.UserMapper.getUser";

User user = session.selectOne(statement, 1);

System.out.println(user);

1

2

3

4

5

6

觀察程序的輸出,此時我們可以看到控制台沒有輸出,同時程序也沒有結束,而是處於阻塞狀態,此時再回到資料庫控制台,輸入

COMMIT;

1

這時可以看到Mybatis程序的控制台輸出了結果,因為當持有鎖的事務結束之後就會釋放鎖,這時嘗試獲取讀鎖的Mybatis程序就會獲取到被釋放的鎖,於是就可以往下繼續執行並最終回去查詢到的結果。

通過使用人工加鎖的方式可以很好地避免改變資料庫隔離級別來防止並發錯誤,同時大部分資料庫都提供了比表鎖更加精細的行鎖,可以大大提高並發的效率,這些鎖都是不能通過簡單使用Spring的註解來實現的,同時由於很多資料庫的設計思想是寫事務和讀事務是可以並發執行的,如果想要實現串列化的讀寫也可以嘗試使用人工加鎖的方式。

在Mybatis中使用手動加鎖的方式操作資料庫

打開今日頭條,查看更多精彩圖片

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 程序員小新人學習 的精彩文章:

高並發「搶紅包案例」:SSM環境搭建及復現紅包超發問題
Eclipse編輯Spring配置文件xml時自動提示類class包名

TAG:程序員小新人學習 |