Spring 和 JDBC 整合開發(fā):(2)
通過JDBC模板類 處理 異常
處理 事務(wù)的傳播特性
處理事務(wù)的隔離性
@Transactional(noRollbackFor=RuntimeException.class)
public void save(User user) throws Exception{
// TODO Auto-generated method stub
this.template.update("insert into user values(?,?)",
new Object[]{new Integer(user.getId()),user.getName()},
new int[]{java.sql.Types.INTEGER,java.sql.Types.VARCHAR});
System.out.println("插入成功....");
throw new RuntimeException();
}
我們制定了參數(shù):noRollbackFor 所以 即使 遇到了運(yùn)行期異常(nocheck異常)的時(shí)候 仍然不會(huì)回滾
Spring默認(rèn)的是 只是 運(yùn)行期異常才會(huì)回滾但是 我們這里可以認(rèn)為的指定哪些類 需要回滾事務(wù)
@Transactional(rollbackFor=Exception.class)
public void save(User user) throws Exception{
// TODO Auto-generated method stub
this.template.update("insert into user values(?,?)",
new Object[]{new Integer(user.getId()),user.getName()},
new int[]{java.sql.Types.INTEGER,java.sql.Types.VARCHAR});
System.out.println("插入成功....");
throw new Exception();
}
此時(shí) 我們指定Exception異常要回滾 所以 執(zhí)行結(jié)果是事務(wù)回滾了
下面是 事務(wù)傳播特性的 第一個(gè)例子:Required nerver給出代碼:
@Transactional(propagation=Propagation.REQUIRED)
public void save(User user) {
// TODO Auto-generated method stub
this.template.update("insert into user values(?,?)",
new Object[]{new Integer(user.getId()),user.getName()},
new int[]{java.sql.Types.INTEGER,java.sql.Types.VARCHAR});
System.out.println("插入成功....");
userdao_1.save(null);
}
代碼二:
@Transactional(propagation=Propagation.NEVER)
public void save(User user){
// TODO Auto-generated method stub
this.getTemplate().update("insert into user values(21,'fasd')");
System.out.println("插入成功....???????????????///");
}
代碼一 需要事務(wù) 當(dāng)執(zhí)行到dao層是 檢測(cè)到?jīng)]有事務(wù) 所以 就 給分配了事務(wù):但是 嵌套了一個(gè)方法,代碼二中的方法不需要事務(wù)PROPAGATION.NEVER但是 它運(yùn)行在了事務(wù)環(huán)境中 所以 拋出異常
因?yàn)?代碼二:運(yùn)行在代碼一的事務(wù)環(huán)境中,出現(xiàn)了異常(此異常是RuntimeExcpetion的一個(gè)子類) 所以 全部回滾 一條數(shù)據(jù) 都沒有插入進(jìn);
強(qiáng)制:代碼一:
@Transactional(propagation=Propagation.NEVER)
public void save(User user) {
// TODO Auto-generated method stub
this.template.update("insert into user values(?,?)",
new Object[]{new Integer(user.getId()),user.getName()},
new int[]{java.sql.Types.INTEGER,java.sql.Types.VARCHAR});
System.out.println("插入成功....");
userdao_1.save(null);
}
代碼二:
@Transactional(propagation=Propagation.MANDATORY)
public void save(User user){
// TODO Auto-generated method stub
this.getTemplate().update("insert into user values(21,'fasd')");
System.out.println("插入成功....???????????????///");
}
運(yùn)行結(jié)果拋出異常:但是 代碼一不需要事務(wù) 運(yùn)行完SQL 就對(duì)數(shù)據(jù)庫(kù) 修改了,但是代碼二需要事務(wù) 但是運(yùn)行在沒有事務(wù)的環(huán)境下所以跑出了異常
支持:
@Test
public void save() throws Exception {
BeanFactory bf = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDAO dao =(UserDAO) bf.getBean("userdao");
User user = new User();
user.setId(11);
user.setName("劉強(qiáng)");
dao.save(user);
}
代碼一:
@Transactional(propagation=Propagation.NEVER)
public void save(User user) {
// TODO Auto-generated method stub
this.template.update("insert into user values(?,?)",
new Object[]{new Integer(user.getId()),user.getName()},
new int[]{java.sql.Types.INTEGER,java.sql.Types.VARCHAR});
System.out.println("插入成功....");
userdao_1.save(null);
} 代碼二:
@Transactional(propagation=Propagation.SUPPORTS)
public void save(User user){
// TODO Auto-generated method stub
this.getTemplate().update("insert into user values(22,'fasd')");
System.out.println("插入成功....???????????????///");
}
第一個(gè) 不支持事務(wù) 因?yàn)樗沁\(yùn)行在無事務(wù)的環(huán)境中所以 可以運(yùn)行成功,代碼二 是suppoert 當(dāng)沒有事務(wù)的時(shí)候就 在沒有事務(wù)的環(huán)境下運(yùn)行
新的這個(gè)就不多說了,每次都分配一個(gè)新的事務(wù)嵌套傳播
@Transactional(propagation=Propagation.REQUIRED)
public void save(User user) {
// TODO Auto-generated method stub
this.template.update("insert into user values(?,?)",
new Object[]{new Integer(user.getId()),user.getName()},
new int[]{java.sql.Types.INTEGER,java.sql.Types.VARCHAR});
System.out.println("插入成功....");
try {
userdao_1.save(null);
} catch (RuntimeException e) {
// TODO Auto-generated catch block
this.template.update("insert into user values(500,'fsd')");
}
}
代碼二:
@Transactional(propagation=Propagation.NESTED)
public void save(User user){
// TODO Auto-generated method stub
this.getTemplate().update("insert into user values('fasd')");
System.out.println("插入成功....???????????????///");
}
這里 是下面類似:
*************************************************************************
在這篇文章里,他用兩個(gè)嵌套的例子輔助分析,我這里直接引用了。********************sample***********************
ServiceA {
/**
* 事務(wù)屬性配置為 PROPAGATION_REQUIRED
*/
void methodA() {
ServiceB.methodB();
}
}
ServiceB {
/**
* 事務(wù)屬性配置為 PROPAGATION_REQUIRED
*/
void methodB() {
}
} *************************************************
我看這個(gè)還不太理解,覺得如果你都用try catch 給把異常捕獲了,就肯定不會(huì)拋異常事務(wù)就肯定可以完成這樣不覺得有什么多神秘的區(qū)別
事務(wù)的隔離級(jí)別:四種隔離級(jí)別:第一種:代碼一:COMMITTED
@Transactional(isolation=Isolation.READ_COMMITTED)
public User query(Integer integer) {
// TODO Auto-generated method stub
return (User)this.getTemplate().queryForObject("select * from user where id=?",
new Object[]{integer},new RowMapper(){
@Override
public Object mapRow(ResultSet resultset, int i)
throws SQLException {
// TODO Auto-generated method stub
User user = new User();
user.setId(resultset.getInt("id"));
user.setName(resultset.getString("name"));
return user;
}
});
}
代碼二:
public void save(User user) {
// TODO Auto-generated method stub
this.template.update("insert into user values(?,?)",
new Object[]{new Integer(user.getId()),user.getName()},
new int[]{java.sql.Types.INTEGER,java.sql.Types.VARCHAR});
System.out.println("插入成功....");
}
這種類型是只可以讀取 提交了事務(wù)的數(shù)據(jù) 這里如果 代碼二打一個(gè)斷點(diǎn) 保存ID為3的用戶,當(dāng)運(yùn)行在方法結(jié)束 停止,然后 運(yùn)行取ID為3的數(shù)據(jù)的操作 ,結(jié)果 失敗了 因?yàn)?事務(wù)沒有提交 查詢不到ID 為三的用戶
第二種UNCOMMITTED代碼和上面的一樣 ,把隔離級(jí)別換了就可以,…… 結(jié)果可以取得數(shù)據(jù)出現(xiàn)了所謂的“ 臟讀”
第三種REPEATABLE_READ可以重復(fù)讀
具體看下面的了
1. 臟讀(事務(wù)沒提交,提前讀?。号K讀就是指當(dāng)一個(gè)事務(wù)正在訪問數(shù)據(jù),并且對(duì)數(shù)據(jù)進(jìn)行了修改,而這種修改還沒有提交到數(shù)據(jù)庫(kù)中,這時(shí),另外一個(gè)事務(wù)也訪問這個(gè)數(shù)據(jù),然后使用了這個(gè)數(shù)據(jù)。
2. 不可重復(fù)讀(兩次讀的不一致) :是指在一個(gè)事務(wù)內(nèi),多次讀同一數(shù)據(jù)。在這個(gè)事務(wù)還沒有結(jié)束時(shí),另外一個(gè)事務(wù)也訪問該同一數(shù)據(jù)。那么,在第一個(gè)事務(wù)中的兩次讀數(shù)據(jù)之間,由于第二個(gè)事務(wù)的修改,那么第一個(gè)事務(wù)兩次讀到的的數(shù)據(jù)可能是不一樣的。這樣就發(fā)生了在一個(gè)事務(wù)內(nèi)兩次讀到的數(shù)據(jù)是不一樣的,因此稱為是不可重復(fù)讀。例如,一個(gè)編輯人員兩次讀取同一文檔,但在兩次讀取之間,作者重寫了該文檔。當(dāng)編輯人員第二次讀取文檔時(shí),文檔已更改。原始讀取不可重復(fù)。如果只有在作者全部完成編寫后編輯人員才可以讀取文檔,則可以避免該問題。
3.幻讀 :是指當(dāng)事務(wù)不是獨(dú)立執(zhí)行時(shí)發(fā)生的一種現(xiàn)象,例如第一個(gè)事務(wù)對(duì)一個(gè)表中的數(shù)據(jù)進(jìn)行了修改,這種修改涉及到表中的全部數(shù)據(jù)行。同時(shí),第二個(gè)事務(wù)也修改這個(gè)表中的數(shù)據(jù),這種修改是向表中插入一行新數(shù)據(jù)。那么,以后就會(huì)發(fā)生操作第一個(gè)事務(wù)的用戶發(fā)現(xiàn)表中還有沒有修改的數(shù)據(jù)行,就好象發(fā)生了幻覺一樣。例如,一個(gè)編輯人員更改作者提交的文檔,但當(dāng)生產(chǎn)部門將其更改內(nèi)容合并到該文檔的主復(fù)本時(shí),發(fā)現(xiàn)作者已將未編輯的新材料添加到該文檔中。如果在編輯人員和生產(chǎn)部門完成對(duì)原始文檔的處理之前,任何人都不能將新材料添加到文檔中,則可以避免該問題。
4.第一類更新丟失(回滾丟失):當(dāng)2個(gè)事務(wù)更新相同的數(shù)據(jù)源,如果第一個(gè)事務(wù)被提交,而另外一個(gè)事務(wù)卻被撤銷,那么會(huì)連同第一個(gè)事務(wù)所做的跟新也被撤銷。也就是說第一個(gè)事務(wù)做的跟新丟失了。
5.第二類更新丟失(覆蓋丟失):第二類更新丟失實(shí)在實(shí)際應(yīng)用中經(jīng)常遇到的并發(fā)問題,他和不可重復(fù)讀本質(zhì)上是同一類并發(fā)問題,通常他被看做不可重復(fù)讀的特例:當(dāng)2個(gè)或這個(gè)多個(gè)事務(wù)查詢同樣的記錄然后各自基于最初的查詢結(jié)果更新該行時(shí),會(huì)造成第二類丟失更新。因?yàn)槊總€(gè)事務(wù)都不知道不知道其他事務(wù)的存在,最后一個(gè)事務(wù)對(duì)記錄做的修改將覆蓋其他事務(wù)對(duì)該記錄做的已提交的跟新……
補(bǔ)充 : 基于元數(shù)據(jù)的 Spring 聲明性事務(wù) :
Isolation 屬性一共支持五種事務(wù)設(shè)置,具體介紹如下:
DEFAULT 使用數(shù)據(jù)庫(kù)設(shè)置的隔離級(jí)別 ( 默認(rèn) ) ,由 DBA 默認(rèn)的設(shè)置來決定隔離級(jí)別 .
READ_UNCOMMITTED 會(huì)出現(xiàn)臟讀、不可重復(fù)讀、幻讀 ( 隔離級(jí)別最低,并發(fā)性能高 )
READ_COMMITTED 會(huì)出現(xiàn)不可重復(fù)讀、幻讀問題(鎖定正在讀取的行)
REPEATABLE_READ 會(huì)出幻讀(鎖定所讀取的所有行)
SERIALIZABLE 保證所有的情況不會(huì)發(fā)生(鎖表)
不可重復(fù)讀的重點(diǎn)是修改 :
同樣的條件 , 你讀取過的數(shù)據(jù) , 再次讀取出來發(fā)現(xiàn)值不一樣了
幻讀的重點(diǎn)在于新增或者刪除
同樣的條件 , 第 1 次和第 2 次讀出來的記錄數(shù)不一樣
通過JDBC模板類 處理 異常
處理 事務(wù)的傳播特性
處理事務(wù)的隔離性
@Transactional(noRollbackFor=RuntimeException.class)
public void save(User user) throws Exception{
// TODO Auto-generated method stub
this.template.update("insert into user values(?,?)",
new Object[]{new Integer(user.getId()),user.getName()},
new int[]{java.sql.Types.INTEGER,java.sql.Types.VARCHAR});
System.out.println("插入成功....");
throw new RuntimeException();
}
我們制定了參數(shù):noRollbackFor 所以 即使 遇到了運(yùn)行期異常(nocheck異常)的時(shí)候 仍然不會(huì)回滾
Spring默認(rèn)的是 只是 運(yùn)行期異常才會(huì)回滾但是 我們這里可以認(rèn)為的指定哪些類 需要回滾事務(wù)
@Transactional(rollbackFor=Exception.class)
public void save(User user) throws Exception{
// TODO Auto-generated method stub
this.template.update("insert into user values(?,?)",
new Object[]{new Integer(user.getId()),user.getName()},
new int[]{java.sql.Types.INTEGER,java.sql.Types.VARCHAR});
System.out.println("插入成功....");
throw new Exception();
}
此時(shí) 我們指定Exception異常要回滾 所以 執(zhí)行結(jié)果是事務(wù)回滾了
下面是 事務(wù)傳播特性的 第一個(gè)例子:Required nerver給出代碼:
@Transactional(propagation=Propagation.REQUIRED)
public void save(User user) {
// TODO Auto-generated method stub
this.template.update("insert into user values(?,?)",
new Object[]{new Integer(user.getId()),user.getName()},
new int[]{java.sql.Types.INTEGER,java.sql.Types.VARCHAR});
System.out.println("插入成功....");
userdao_1.save(null);
}
代碼二:
@Transactional(propagation=Propagation.NEVER)
public void save(User user){
// TODO Auto-generated method stub
this.getTemplate().update("insert into user values(21,'fasd')");
System.out.println("插入成功....???????????????///");
}
代碼一 需要事務(wù) 當(dāng)執(zhí)行到dao層是 檢測(cè)到?jīng)]有事務(wù) 所以 就 給分配了事務(wù):但是 嵌套了一個(gè)方法,代碼二中的方法不需要事務(wù)PROPAGATION.NEVER但是 它運(yùn)行在了事務(wù)環(huán)境中 所以 拋出異常
因?yàn)?代碼二:運(yùn)行在代碼一的事務(wù)環(huán)境中,出現(xiàn)了異常(此異常是RuntimeExcpetion的一個(gè)子類) 所以 全部回滾 一條數(shù)據(jù) 都沒有插入進(jìn);
強(qiáng)制:代碼一:
@Transactional(propagation=Propagation.NEVER)
public void save(User user) {
// TODO Auto-generated method stub
this.template.update("insert into user values(?,?)",
new Object[]{new Integer(user.getId()),user.getName()},
new int[]{java.sql.Types.INTEGER,java.sql.Types.VARCHAR});
System.out.println("插入成功....");
userdao_1.save(null);
}
代碼二:
@Transactional(propagation=Propagation.MANDATORY)
public void save(User user){
// TODO Auto-generated method stub
this.getTemplate().update("insert into user values(21,'fasd')");
System.out.println("插入成功....???????????????///");
}
運(yùn)行結(jié)果拋出異常:但是 代碼一不需要事務(wù) 運(yùn)行完SQL 就對(duì)數(shù)據(jù)庫(kù) 修改了,但是代碼二需要事務(wù) 但是運(yùn)行在沒有事務(wù)的環(huán)境下所以跑出了異常
支持:
@Test
public void save() throws Exception {
BeanFactory bf = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDAO dao =(UserDAO) bf.getBean("userdao");
User user = new User();
user.setId(11);
user.setName("劉強(qiáng)");
dao.save(user);
}
代碼一:
@Transactional(propagation=Propagation.NEVER)
public void save(User user) {
// TODO Auto-generated method stub
this.template.update("insert into user values(?,?)",
new Object[]{new Integer(user.getId()),user.getName()},
new int[]{java.sql.Types.INTEGER,java.sql.Types.VARCHAR});
System.out.println("插入成功....");
userdao_1.save(null);
} 代碼二:
@Transactional(propagation=Propagation.SUPPORTS)
public void save(User user){
// TODO Auto-generated method stub
this.getTemplate().update("insert into user values(22,'fasd')");
System.out.println("插入成功....???????????????///");
}
第一個(gè) 不支持事務(wù) 因?yàn)樗沁\(yùn)行在無事務(wù)的環(huán)境中所以 可以運(yùn)行成功,代碼二 是suppoert 當(dāng)沒有事務(wù)的時(shí)候就 在沒有事務(wù)的環(huán)境下運(yùn)行
新的這個(gè)就不多說了,每次都分配一個(gè)新的事務(wù)嵌套傳播
@Transactional(propagation=Propagation.REQUIRED)
public void save(User user) {
// TODO Auto-generated method stub
this.template.update("insert into user values(?,?)",
new Object[]{new Integer(user.getId()),user.getName()},
new int[]{java.sql.Types.INTEGER,java.sql.Types.VARCHAR});
System.out.println("插入成功....");
try {
userdao_1.save(null);
} catch (RuntimeException e) {
// TODO Auto-generated catch block
this.template.update("insert into user values(500,'fsd')");
}
}
代碼二:
@Transactional(propagation=Propagation.NESTED)
public void save(User user){
// TODO Auto-generated method stub
this.getTemplate().update("insert into user values('fasd')");
System.out.println("插入成功....???????????????///");
}
這里 是下面類似:
*************************************************************************
在這篇文章里,他用兩個(gè)嵌套的例子輔助分析,我這里直接引用了。********************sample***********************
ServiceA {
/**
* 事務(wù)屬性配置為 PROPAGATION_REQUIRED
*/
void methodA() {
ServiceB.methodB();
}
}
ServiceB {
/**
* 事務(wù)屬性配置為 PROPAGATION_REQUIRED
*/
void methodB() {
}
} *************************************************
我看這個(gè)還不太理解,覺得如果你都用try catch 給把異常捕獲了,就肯定不會(huì)拋異常事務(wù)就肯定可以完成這樣不覺得有什么多神秘的區(qū)別
事務(wù)的隔離級(jí)別:四種隔離級(jí)別:第一種:代碼一:COMMITTED
@Transactional(isolation=Isolation.READ_COMMITTED)
public User query(Integer integer) {
// TODO Auto-generated method stub
return (User)this.getTemplate().queryForObject("select * from user where id=?",
new Object[]{integer},new RowMapper(){
@Override
public Object mapRow(ResultSet resultset, int i)
throws SQLException {
// TODO Auto-generated method stub
User user = new User();
user.setId(resultset.getInt("id"));
user.setName(resultset.getString("name"));
return user;
}
});
}
代碼二:
public void save(User user) {
// TODO Auto-generated method stub
this.template.update("insert into user values(?,?)",
new Object[]{new Integer(user.getId()),user.getName()},
new int[]{java.sql.Types.INTEGER,java.sql.Types.VARCHAR});
System.out.println("插入成功....");
}
這種類型是只可以讀取 提交了事務(wù)的數(shù)據(jù) 這里如果 代碼二打一個(gè)斷點(diǎn) 保存ID為3的用戶,當(dāng)運(yùn)行在方法結(jié)束 停止,然后 運(yùn)行取ID為3的數(shù)據(jù)的操作 ,結(jié)果 失敗了 因?yàn)?事務(wù)沒有提交 查詢不到ID 為三的用戶
第二種UNCOMMITTED代碼和上面的一樣 ,把隔離級(jí)別換了就可以,…… 結(jié)果可以取得數(shù)據(jù)出現(xiàn)了所謂的“ 臟讀”
第三種REPEATABLE_READ可以重復(fù)讀
具體看下面的了
1. 臟讀(事務(wù)沒提交,提前讀?。号K讀就是指當(dāng)一個(gè)事務(wù)正在訪問數(shù)據(jù),并且對(duì)數(shù)據(jù)進(jìn)行了修改,而這種修改還沒有提交到數(shù)據(jù)庫(kù)中,這時(shí),另外一個(gè)事務(wù)也訪問這個(gè)數(shù)據(jù),然后使用了這個(gè)數(shù)據(jù)。
2. 不可重復(fù)讀(兩次讀的不一致) :是指在一個(gè)事務(wù)內(nèi),多次讀同一數(shù)據(jù)。在這個(gè)事務(wù)還沒有結(jié)束時(shí),另外一個(gè)事務(wù)也訪問該同一數(shù)據(jù)。那么,在第一個(gè)事務(wù)中的兩次讀數(shù)據(jù)之間,由于第二個(gè)事務(wù)的修改,那么第一個(gè)事務(wù)兩次讀到的的數(shù)據(jù)可能是不一樣的。這樣就發(fā)生了在一個(gè)事務(wù)內(nèi)兩次讀到的數(shù)據(jù)是不一樣的,因此稱為是不可重復(fù)讀。例如,一個(gè)編輯人員兩次讀取同一文檔,但在兩次讀取之間,作者重寫了該文檔。當(dāng)編輯人員第二次讀取文檔時(shí),文檔已更改。原始讀取不可重復(fù)。如果只有在作者全部完成編寫后編輯人員才可以讀取文檔,則可以避免該問題。
3.幻讀 :是指當(dāng)事務(wù)不是獨(dú)立執(zhí)行時(shí)發(fā)生的一種現(xiàn)象,例如第一個(gè)事務(wù)對(duì)一個(gè)表中的數(shù)據(jù)進(jìn)行了修改,這種修改涉及到表中的全部數(shù)據(jù)行。同時(shí),第二個(gè)事務(wù)也修改這個(gè)表中的數(shù)據(jù),這種修改是向表中插入一行新數(shù)據(jù)。那么,以后就會(huì)發(fā)生操作第一個(gè)事務(wù)的用戶發(fā)現(xiàn)表中還有沒有修改的數(shù)據(jù)行,就好象發(fā)生了幻覺一樣。例如,一個(gè)編輯人員更改作者提交的文檔,但當(dāng)生產(chǎn)部門將其更改內(nèi)容合并到該文檔的主復(fù)本時(shí),發(fā)現(xiàn)作者已將未編輯的新材料添加到該文檔中。如果在編輯人員和生產(chǎn)部門完成對(duì)原始文檔的處理之前,任何人都不能將新材料添加到文檔中,則可以避免該問題。
4.第一類更新丟失(回滾丟失):當(dāng)2個(gè)事務(wù)更新相同的數(shù)據(jù)源,如果第一個(gè)事務(wù)被提交,而另外一個(gè)事務(wù)卻被撤銷,那么會(huì)連同第一個(gè)事務(wù)所做的跟新也被撤銷。也就是說第一個(gè)事務(wù)做的跟新丟失了。
5.第二類更新丟失(覆蓋丟失):第二類更新丟失實(shí)在實(shí)際應(yīng)用中經(jīng)常遇到的并發(fā)問題,他和不可重復(fù)讀本質(zhì)上是同一類并發(fā)問題,通常他被看做不可重復(fù)讀的特例:當(dāng)2個(gè)或這個(gè)多個(gè)事務(wù)查詢同樣的記錄然后各自基于最初的查詢結(jié)果更新該行時(shí),會(huì)造成第二類丟失更新。因?yàn)槊總€(gè)事務(wù)都不知道不知道其他事務(wù)的存在,最后一個(gè)事務(wù)對(duì)記錄做的修改將覆蓋其他事務(wù)對(duì)該記錄做的已提交的跟新……
補(bǔ)充 : 基于元數(shù)據(jù)的 Spring 聲明性事務(wù) :
Isolation 屬性一共支持五種事務(wù)設(shè)置,具體介紹如下:
DEFAULT 使用數(shù)據(jù)庫(kù)設(shè)置的隔離級(jí)別 ( 默認(rèn) ) ,由 DBA 默認(rèn)的設(shè)置來決定隔離級(jí)別 .
READ_UNCOMMITTED 會(huì)出現(xiàn)臟讀、不可重復(fù)讀、幻讀 ( 隔離級(jí)別最低,并發(fā)性能高 )
READ_COMMITTED 會(huì)出現(xiàn)不可重復(fù)讀、幻讀問題(鎖定正在讀取的行)
REPEATABLE_READ 會(huì)出幻讀(鎖定所讀取的所有行)
SERIALIZABLE 保證所有的情況不會(huì)發(fā)生(鎖表)
不可重復(fù)讀的重點(diǎn)是修改 :
同樣的條件 , 你讀取過的數(shù)據(jù) , 再次讀取出來發(fā)現(xiàn)值不一樣了
幻讀的重點(diǎn)在于新增或者刪除
同樣的條件 , 第 1 次和第 2 次讀出來的記錄數(shù)不一樣

