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();
}
}
}