背景
-
同一個事務中,MySQL數據庫隔離級別爲可重複讀、讀提交、讀未提交、串行化。對需要插入的一條數據進行很多其他操作,會出現怎樣的情況呢?
-
同一個事務中,研究事務隔離級別是沒有任何意義的。可重複讀,讀提交,讀未提交,串行化都可以對同一條數據反覆地進行操作。
-
起兩個事務,在數據庫中事務隔離級別是:可重複讀,讀未提交,讀提交,又是怎樣的表現形式呢?
過程
Spring使用@Transactional且是同一個事務中
-
可重複讀
在數據庫中執行如下:select @@transaction_isolation ;
得到數據庫的隔離級別是:REPEATABLE-READ
java代碼
@Service
@Transactional(readOnly = true)
public class StudentServiceImpl implements StudentService {
@Autowired
private StudentMapper studentMapper;
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void insert(Student student) {
studentMapper.insert(student);
}
@Transactional(propagation = Propagation.REQUIRED)
@Override
public Student selectByName(String name) {
return studentMapper.selectByName(name);
}
@Transactional(propagation = Propagation.REQUIRED)
@Override
public Student selectById(Integer id) {
return studentMapper.selectById(id);
}
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void update(Student sara) {
studentMapper.update(sara);
}
}
測試代碼:
@Test
public void test1() {
Student sara = Student.builder()
.name("Test1")
.age(22)
.createTime(new Date())
.status(1).build();
studentService.insert(sara);
Student student1 = studentService.selectByName(sara.getName());
System.out.println("name: " + student1.getName());
student1.setName("Test2");
studentService.update(student1);
Student student2 = studentService.selectByName("Test2");
System.out.println("name: " + student2.getName());
}
測試結果:
過程分析:
Spring類上的@Transactional註解是隻讀的,方法上的註解不是隻讀的,但是要求必須在事務中執行。此時沒有任何異常出現,因此也不需要什麼回滾操作。
當代碼執行insert的時候,會啓動一個事務,後續的方法selectByName, update, selectByName都不會另啓一個事務。這四個方法都在同一個事務中執行。
測試證明:在同一個事務中,對同一條數據進行先插入,後查詢,再更新,再查詢,都是可行的。
Spring使用@Transactional且是不同事務中
-
可重複讀 數據事務隔離級別是可重複讀
一個事務A代碼:在打印語句處,點上debug
@Transactional(propagation = Propagation.REQUIRED) @Override public void insert(Student student) { studentMapper.insert(student); System.out.println("aaaaa"); }
測試代碼:
@Test public void test2() { Student sara = Student.builder() .name("Test1") .age(22) .createTime(new Date()) .status(1).build(); studentService.insert(sara); }
另一個事務B代碼: 根據姓名爲Test1進行查詢
@Transactional(propagation = Propagation.REQUIRED) @Override public Student selectByName(String name) { return studentMapper.selectByName(name); }
測試代碼:
@Test public void test3() { Student student1 = studentService.selectByName("Test1"); System.out.println("name: " + student1.getName()); }
測試結果:
事務A啓動,由於在事務方法內中打上debug,此方法未執行完成,因此事務是不會提交的。
事務B啓動,去查詢事務A插入的數據,結果是查詢爲空。 -
讀未提交(數據庫的事務隔離級別),又是怎樣的表現形式呢?
在數據庫中執行如下:
– 設置read uncommitted級別:
set session transaction isolation level read uncommitted;
set global transaction isolation level read uncommitted;測試過程與上面一樣:
因爲是讀未提交,當事務A代碼卡在打印語句處,查詢數據庫就已經有數據了。
因此,此時執行查詢事務操作,能夠查詢到此數據。 -
讀提交(數據庫的事務隔離級別),又是怎樣的表現形式呢?
– 設置read committed級別:
set session transaction isolation level read committed;
set global transaction isolation level read committed;測試過程與上面一樣:
因爲是讀提交,當事務A代碼卡在打印語句處。
此時執行查詢事務B操作,不能查詢到此數據。
小結
-
查詢 MySQL實例隔離級別指令 select @@transaction_isolation, @@tx_isolation;
-
記錄MySQL設置隔離級別指令
– 設置read uncommitted級別:
set session transaction isolation level read uncommitted;
set global transaction isolation level read uncommitted;– 設置read committed級別:
set session transaction isolation level read committed;
set global transaction isolation level read committed;– 設置repeatable read級別:
set session transaction isolation level repeatable read;
set global transaction isolation level repeatable read;– 設置serializable級別:
set session transaction isolation level serializable;
set global transaction isolation level serializable; -
記錄Spring的註解@Transactional在不同的數據庫事務隔離級別的表現形式。
-
加深理解,事務隔離級別研究的是事務之間的關係。而同一個事務中的代碼執行邏輯是沒有所謂的事務隔離級別的。