事務(wù)
事務(wù)及數(shù)據(jù)庫事務(wù),是數(shù)據(jù)庫管理系統(tǒng)執(zhí)行過程中的一個(gè)邏輯單位,由一個(gè)有限的數(shù)據(jù)庫操作序列構(gòu)成。
ACID特性
數(shù)據(jù)庫事務(wù)擁有四個(gè)特性,稱之為ACID特性。
- 原子性(
Atomicity
):事務(wù)作為一個(gè)整體被執(zhí)行,事務(wù)中的所有操作要么全部完成,要么全部不完成。事務(wù)在執(zhí)行過程中發(fā)生錯(cuò)誤,會被回滾(Rollback)到事務(wù)開始前的狀態(tài)。 - 一致性(
Consistency
):事務(wù)應(yīng)確保數(shù)據(jù)庫的狀態(tài)從一個(gè)一致狀態(tài)轉(zhuǎn)變?yōu)榱硪粋€(gè)一致狀態(tài)。在事務(wù)開始之前和事務(wù)結(jié)束以后,數(shù)據(jù)庫的完整性沒有被破壞。 - 隔離性(
Isolation
):當(dāng)兩個(gè)或者多個(gè)事務(wù)并發(fā)訪問數(shù)據(jù)庫的同一數(shù)據(jù)時(shí)所表現(xiàn)出的相互關(guān)系。事務(wù)隔離分為不同級別,包括讀未提交(Read uncommitted)、讀提交(read commited
)、可重復(fù)讀(repeatable read) 和串行化(Serializable) - 持久性(Durability):在事務(wù)完成以后,該事務(wù)對數(shù)據(jù)庫所作的更改便持久的保存在數(shù)據(jù)庫中,并且是完全的。
事務(wù)并發(fā)問題
分布式系統(tǒng)中,通常會有多個(gè)線程連接到數(shù)據(jù)庫中同時(shí)對一個(gè)表進(jìn)行操作,這種情況下如果會話的事務(wù)設(shè)置不當(dāng),就會導(dǎo)致數(shù)據(jù)混亂,經(jīng)常會出現(xiàn)以下三種情況
- 臟讀(Dirty Read)
- 不可重復(fù)讀(Unrepeatable Read)
- 換讀(Phantom Read)
事務(wù)隔離級別
針對事務(wù)的隔離性,分為四個(gè)隔離級別
- 串行化(Serializable):可避免臟讀、不可重復(fù)讀、幻讀情況發(fā)生
- 可重復(fù)讀(repeatable read): 可避免臟讀、不可重復(fù)讀情況發(fā)生
- 讀提交(read commited): 可避免臟讀情況發(fā)生
- 讀未提交(Read uncommitted):級別最低,上面三種情況都無法保證
Spring 事務(wù)管理
spring 事務(wù)屬性
在Spring中,事務(wù)是通過 TransactionDefinition
接口來定義的,包含了與事務(wù)屬性相關(guān)的方法。
public interface TransactionDefinition{
int getIsolationLevel(); // 返回事務(wù)的傳播行為
int getPropagationBehavior(); // 返回事務(wù)的隔離級別
int getTimeout(); // 返回事務(wù)在超時(shí)前能運(yùn)行多久
boolean isReadOnly(); // 返回事務(wù)是否只讀
}
事務(wù)隔離級別
TransactionDefinition
中還定義了五個(gè)表示隔離級別的常量:
-
ISOLATION_DEFAULT
: 默認(rèn)值,表示使用底層數(shù)據(jù)庫的默認(rèn)隔離級別。其他四個(gè)與JDBC的隔離級別相對應(yīng) -
ISOLATION_READ_UNCOMMITTED
: 表示一個(gè)事務(wù)可以看到另一事物修改但還沒有提交的數(shù)據(jù)。這種隔離級別會產(chǎn)生臟讀,不可重復(fù)讀和幻讀,因此很少使用該級別。 -
ISOLATION_READ_COMMITTED
:表示一個(gè)事務(wù)只能讀取另一個(gè)事務(wù)已經(jīng)提交的數(shù)據(jù)。可以防止臟讀。 -
ISOLATION_REPEATABLE_READ
:表示一個(gè)事務(wù)在整個(gè)過程中可以多次重復(fù)執(zhí)行某個(gè)查詢,并且返回的記錄相同。即使在多次在多次查詢之間有新增的數(shù)據(jù)滿足該查詢,這些新增的記錄也會被忽略。該級別可以防止臟讀和不可重復(fù)讀。 -
ISOLATION_SERIALIZABLE
: 級別最高,所有事務(wù)依次順序執(zhí)行,可以防止臟讀、不可重復(fù)讀以及幻讀。但是開銷太大影響程序性能,通常不會用該級別。
事務(wù)傳播行為
事務(wù)傳播行為是指,開始當(dāng)前事務(wù)之前,一個(gè)事務(wù)上下文已經(jīng)存在,此時(shí)有若干選項(xiàng)可以指定當(dāng)前事務(wù)的行為。TransactionDefinition
接口中定義了七個(gè)事務(wù)傳播行為。
-
PROPAGATION_REQUIRED
:如果當(dāng)前存在事務(wù),則加入當(dāng)前事務(wù);不存在這新建一個(gè)事務(wù) -
PROPAGATION_SUPPORTS
:如果當(dāng)前存在事務(wù),則加入當(dāng)前事務(wù);不存在則以非事務(wù)(non-transactionally
)方式執(zhí)行 -
PROPAGATION_MANDATORY
:如果當(dāng)前存在事務(wù),則加入當(dāng)前事務(wù);不存在則拋出異常 -
PROPAGATION_REQUIRES_NEW
:如果當(dāng)前存在事務(wù),則將當(dāng)前事務(wù)掛起;新創(chuàng)建一個(gè)事務(wù) -
PROPAGATION_NOT_SUPPORTED
:以非事務(wù)(non-transactionally
)方式運(yùn)行,如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起 -
PROPAGATION_NEVER
:以非事務(wù)(non-transactionally
)方式運(yùn)行,如果當(dāng)前存在事務(wù),則拋出異常 -
PROPAGATION_NESTED
:如果當(dāng)前存在事務(wù),則創(chuàng)建一個(gè)事務(wù)作為當(dāng)前事務(wù)的嵌套事務(wù)執(zhí)行,如果當(dāng)前沒有事務(wù),則等價(jià)于PROPAGATION_REQUIRED
//新開一個(gè)輔助線程,用于定時(shí)向ZK服務(wù)器匯報(bào)心路
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
String heartBeat = robotIdValue + DateUtil.formatDate(new Date()) + "#" + servletContext.getServerInfo();
logger.debug(uuid + " => " + heartBeat); // /robot/{env}/{robotId}/uuid
String heartBeatNode = TargetNodes.APP_ROOT_NODE + "/" + env + "/" + appId + "/" + uuid;
if (!zkClient.exists(heartBeatNode)) {
zkClient.createEphemeral(heartBeatNode);
}
zkClient.writeData(heartBeatNode, heartBeat);
try {
Thread.sleep(10000);//10秒鐘報(bào)告一次心跳
} catch (InterruptedException e)
{
logger.error(appId + " 發(fā)送心跳出錯(cuò)!", e);
}
}
}}).start();