SQL標准定義了4類隔離級別,包括了一些具體規則,用來限定事務內外的哪些改變是可見的,哪些是不可見的。低級別的隔離級一般支持更高的並發處理,並擁有更低的系統開銷。
Read Uncommitted(讀取未提交內容)
在該隔離級別,所有事務都可以看到其他未提交事務的執行結果。本隔離級別很少用於實際應用,因為它的性能也不比其他級別好多少。讀取未提交的數據,也被稱之為臟讀(Dirty Read)。
Read Committed(讀取提交內容)
這是大多數數據庫系統的默認隔離級別(但不是MySQL默認的)。它滿足了隔離的簡單定義:一個事務只能看見已經提交事務所做的改變。這種隔離級別 也支持所謂的不可重復讀(Nonrepeatable Read),因為同一事務的其他實例在該實例處理其間可能會有新的commit,所以同一select可能返回不同結果。
Repeatable Read(可重讀)
這是MySQL的默認事務隔離級別,它確保同一事務的多個實例在並發讀取數據時,會看到同樣的數據行。不過理論上,這會導致另一個棘手的問題:幻讀 (Phantom Read)。簡單的說,幻讀指當用戶讀取某一范圍的數據行時,另一個事務又在該范圍內插入了新行,當用戶再讀取該范圍的數據行時,會發現有新的“幻影” 行。InnoDB和Falcon存儲引擎通過多版本並發控制(MVCC,Multiversion Concurrency Control)機制解決了該問題。
Serializable(可串行化)
這是最高的隔離級別,它通過強制事務排序,使之不可能相互沖突,從而解決幻讀問題。簡言之,它是在每個讀的數據行上加上共享鎖。在這個級別,可能導致大量的超時現象和鎖競爭。
臟讀(Drity Read):某個事務已更新一份數據,另一個事務在此時讀取了同一份數據,由於某些原因,前一個RollBack了操作,則后一個事務所讀取的數據就會是不正確的。
不可重復讀(Non-repeatable read):在一個事務的兩次查詢之中數據不一致,這可能是兩次查詢過程中間插入了一個事務更新的原有的數據。
幻讀(Phantom Read):在一個事務的兩次查詢中數據行數不一致,例如有一個事務查詢了幾列行Row)數據,而另一個事務卻在此時插入了新的幾行數據,先前的事務在接下來的查詢中,就會發現有幾行數據是它先前所沒有的。
Spring事務:
先導入jar包
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.29</version>
</dependency>
實體類:
public class Stock {
private Integer sid;
private String sname;
private Integer count;
public Integer getSid() {
return sid;
}
public void setSid(Integer sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
}
ublic class Accounta {
private Integer aid;
private String aname;
private Integer balance;
public Integer getAid() {
return aid;
}
public void setAid(Integer aid) {
this.aid = aid;
}
public String getAname() {
return aname;
}
public void setAname(String aname) {
this.aname = aname;
}
public Integer getBalance() {
return balance;
}
public void setBalance(Integer balance) {
this.balance = balance;
}
}
dao層:
public interface StockDAO {
public boolean updateStock(int sid,int quantity,boolean isBuy);
}
public class StockDAOimpl extends JdbcDaoSupport implements StockDAO{
//quantity 交易的數量
public boolean updateStock(int sid, int quantity, boolean isBuy) {
boolean b=false;
String sql=null;
if(isBuy){
sql="update stock set count=count+? where sid=?";
}else{
sql="update stock set count=count-? where sid=?";
}
int update = this.getJdbcTemplate().update(sql,quantity,sid);
if (update>0){
b=true;
}
return b;
}
}
public interface AccountaDAO {
//isBuy 判斷股票的交易方式
public boolean updateAccounta(int aid,int amoney,boolean isBuy);
}
public class AccountaDAOimpl extends JdbcDaoSupport implements AccountaDAO {
//amoney 花費的金額
public boolean updateAccounta(int aid, int amoney,boolean isBuy) {
boolean a=true;
String sql="";
if(isBuy){
sql="update accounta set balance=balance-? where aid=?";
}else{
sql="update accounta set balance=balance+? where aid=?";
}
int update = this.getJdbcTemplate().update(sql,amoney,aid);
if (update>0){
a=false;
}
return a;
}
}
service層:
public interface Stock {
public boolean by(int aid,int amoney,int sid,int quantity) throws StockException;
}
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,rollbackFor = SocketException.class)
public class Stockserviceimpl implements Stock {
private AccountaDAO accountaDAO;
private StockDAO stockDAO;
public AccountaDAO getAccountaDAO() {
return accountaDAO;
}
public void setAccountaDAO(AccountaDAO accountaDAO) {
this.accountaDAO = accountaDAO;
}
public StockDAO getStockDAO() {
return stockDAO;
}
public void setStockDAO(StockDAO stockDAO) {
this.stockDAO = stockDAO;
}
public boolean by(int aid, int amoney, int sid, int quantity) throws StockException {
boolean isBuy=true;
accountaDAO.updateAccounta(aid,amoney,isBuy);
//int result=5/0;
if(1==1) {
// throw new SecurityException("fgh");
throw new StockException("錯啦");
}
stockDAO.updateStock(sid,quantity,isBuy);
return false;
}
}
配置文件:
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql:///smbms"></property>
<property name="username" value="root"></property>
<property name="password" value=""></property>
</bean>
<!--2.識別到jdbc.properties文件-->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:jdbc.properties"></property>
</bean>
<!--3.StockDAO-->
<bean id="stockDAO" class="dao.daoimpl.StockDAOimpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--4.AccountaDAO-->
<bean id="accountDAO" class="dao.daoimpl.AccountaDAOimpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--5.service id-->
<bean id="stockService" class="service.serviceimpl.Stockserviceimpl">
<property name="stockDAO" ref="stockDAO"></property>
<property name="accountaDAO" ref="accountDAO"></property>
</bean>
<!--事務:事務管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--方式三:AspectJ AOP 配置事務-->
<!-- <tx:advice id="stockAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="by" isolation="DEFAULT" propagation="REQUIRED" rollback-for="StockException"/>
<!– <tx:method name="select*" isolation="DEFAULT" propagation="REQUIRED" read-only="true"/>–>
</tx:attributes>
</tx:advice>
<aop:config>
<!–1.切點–>
<aop:pointcut id="mypointcut" expression="execution(* *..serviceimpl.*.*(..))"></aop:pointcut>
<!–3.顧問–>
<aop:advisor advice-ref="stockAdvice" pointcut-ref="mypointcut"></aop:advisor>
<!–2.切面–>
</aop:config>-->
<!--方式二:事務注解驅動-->
<tx:annotation-driven transaction-manager="transactionManager" />
<!--事務控制 事務代理工廠Bean 方式一: TransactionProxyFactoryBean -->
<!--<bean id="stockServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager"></property>
<property name="target" ref="stockService"></property>
<!– <!–事務屬性–>–>
<property name="transactionAttributes">
<props>
<prop key="buyStock">ISOLATION_DEFAULT,PROPAGATION_REQUIRED,-StockException</prop>
</props>
</property>
</bean>-->
測試類:
public class Text {
@Test
public void test01(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext22tx.xml");
Stock service=(Stock) context.getBean("stockService");
try{
service.by(3,100,1,5);
}catch (Exception ex){
ex.printStackTrace();
}
}
}