Spring事务总结---事务概述及Spring事务的基本使用(完整)

 一、事务概述

   这一节内容纯粹是为了写而写的,权当温习数据库知识和熟悉下怎么写博客了,谁让自己菜呢。:)

   看了许多别的博客和资料,事务两个字都快不认识了,那么其实事务的概念很简单,可以理解为一件事情,在计算机里,它就是一个操作序列。

   它相比于普通的事情不同的是,它必须服从ISO/IEC指定的ACID原则。

   A(Aotomicity)原子性,简单的说就是要么全部一起做完,要么都不做,即事务的不可分割性,若非使用特殊手段,如catch某些子事务的exception,否则当其中一个子事务失败,其他事务都将一起回滚。

   C(Consistency)一致性,即其保证是从一个正确的状态,转换成另一种正确的状态,即操作后数据不会被破坏,如转账时不会出现一方扣了钱而另一方却收不到的状况。

   I(Isolation)隔离性,在事务提交之前,它可能的结果不应该显示给其他事务。举个例子,如果一个事务为一个银行需要存入100元后存入200元,那当然不可以在存入100元后,就实例化到数据库被别的事务读取了存入100元后的结果,如果在存入200元时发生回滚不就出大事了嘛。所谓的隔离,就是需要保证各个事务之间是没有相互干扰的。

   D(Durability)持久性,其结果将正确的永久保存在数据库中,其他事务的失败不会对其造成影响。



    以上四个特性,经常受到讨论和争辩的莫过于一致性和隔离性了。所谓鱼与熊掌不可兼得,当我们需要兼顾所有的特性,可想而知,当安全性越高,其操作的顾忌和检查越多,性能也就越差。所以对于一致性和隔离性,又有着不同的规范等级。(垃圾文字功底)

    权衡之下可能出现的问题

    1、脏读,即读到不干净的数据。

     例子:(例子原址)

    1)Mary的原工资为1000, 财务人员将Mary的工资改为了8000(但未提交事务) 
    2)Mary读取自己的工资 ,发现自己的工资变为了8000,欢天喜地! 
    3)而财务发现操作有误,回滚了事务,Mary的工资又变为了1000, 像这样,Mary记取的工资数8000是一个脏数据。

    2、不可重复读,即在同一个事务中,重复读取却有不同的结果。

    例子:(例子原址)

    1)在事务A中,Mary 读取了自己的工资为1000,操作并没有完成 
    2)在事务B中,这时财务人员修改了Mary的工资为2000,并提交了事务. 
    3)在事务A中,Mary 再次读取自己的工资时,工资变为了2000 

    3、幻读,即在同一事务中,可读取到其他事务提交后的结果,造成疑惑。

    例子:(例子原址)

    1)A把所有的“黑色”改为“白色”

    2)B把所有的“红色”改为“黑色”

    3)A再查询黑色,却发现还有一批。



    隔离性的四个级别

    1、READ_UNCOMMITED(未授权读取),即可以读到未提交的数据。

    附上一个别人写的生动的例子

    公司发工资了,领导把5000元打到singo的账号上,但是该事务并未提交,而singo正好去查看账户,发现工资已经到账,是5000元整,非常高 兴。可是不幸的是,领导发现发给singo的工资金额不对,是2000元,于是迅速回滚了事务,修改金额后,将事务提交,最后singo实际的工资只有 2000元,singo空欢喜一场。(原址)

    2、READ_COMMITED(授权读取),即其保证不会读到未提交的事务,但会造成不可重复读。

    附上一个别人写的生动的例子

    singo拿着工资卡去消费,系统读取到卡里确实有2000元,而此时她的老婆也正好在网上转账,把singo工资卡的2000元转到另一账户,并在 singo之前提交了事务,当singo扣款时,系统检查到singo的工资卡已经没有钱,扣款失败,singo十分纳闷,明明卡里有钱,为 何......

    出现上述情况,即我们所说的不可重复读 ,两个并发的事务,“事务A:singo消费”、“事务B:singo的老婆网上转账”,事务A事先读取了数据,事务B紧接了更新了数据,并提交了事务,而事务A再次读取该数据时,数据已经发生了改变。(原址)
    3、REPEATABLE_READ(可重复读),即当读取时,不能进行更新。

     附上一个别人写的生动的例子

    当singo拿着工资卡去消费时,一旦系统开始读取工资卡信息(即事务开始),singo的老婆就不可能对该记录进行修改,也就是singo的老婆不能在此时转账。

    虽然Repeatable read避免了不可重复读,但还有可能出现幻读。

    singo的老婆工作在银行部门,她时常通过银行内部系统查看singo的信用卡消费记录。有一天,她正在查询到singo当月信用卡的总消费金额(select sum(amount) from transaction where month = 本月)为80元,而singo此时正好在外面胡吃海塞后在收银台买单,消费1000元,即新增了一条1000元的消费记录(insert transaction ... ),并提交了事务,随后singo的老婆将singo当月信用卡消费的明细打印到A4纸上,却发现消费总额为1080元,singo的老婆很诧异,以为出现了幻觉,幻读就这样产生了。

    注:Mysql的默认隔离级别就是Repeatable read。(原址)

    4、SERIALIZABLE(序列化),最高级别,在该级别下,事务顺序执行,那也就不会出现上面的问题了。

    这四个规范,从上至下安全性越高,性能越差。

    附一张哪都能看到的表

事务隔离级别 脏读 不可重复读 幻读
READ_UNCOMMITED Y Y Y
READ_COMMITED N Y Y
REPEATABLE_READ N N Y
SERIALIZABLE N N N




二、Spring事务用法

1、xml配置(搬运总结自开涛大神)


      class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    



    
    
        
    <:attributes>
<:advice>


    
    
    
    

    个人觉得xml配置的方式有点过于粗暴,在有事务嵌套的情况下有点难以处理(对我这种比较懒的人)。

2、Annotation声明



    其具有三个属性

transaction-manager:指定事务管理器名字,默认为transactionManager

proxy-target-class:默认为false,false使用jdk动态代理,若为true则使用cglibs代理。设置为JDK代理和CGLIBS代理的主要区别是,使用JDK代理,@Transactional注释可以作用在接口和类及其方法上,而CGLIBS只能只用在类上,为了避免疏忽,建议就写在类上而不是接口上,而且,写在接口上事务是不支持继承的。

order:定义事务通知顺序,默认将顺序决定权交给AOP处理。

    在配置文件中开启注解事务管理后我们就可以使用@Transcational注释用于事务管理了。

@Transcational
public class SuperServiceImpl implements SuperService{

    public void add();

}


@Transactional
public class SubServiceImpl extends SuperServiceImpl implements SubService{

    public void update();
}
    以上是最常用的用法:

    1、将@Transactional注释作用在类上,默认该类所有方法都加入事务

     2、将@Transactional注释作用在父类上,其可以被子类集成。

   @Transactional注释有许多自定义的属性使他的功能更加丰富。

value:指定事务管理器,用于支持多事务管理器环境

isolation:指定事务隔离级别,默认『DEFAULT』

readOnly:事务是否只读,默认false。(即该事务开始后,其他事务所提交的数据,对该事务来说不可见,常用于多条查询语句在同一事务的情况)

timeout:事务超时时间,单位:秒。默认-1,表示超时将依赖于底层事务系统。

rollbackFor:指定一组异常类,遇到该异常将进行回滚,如若没有指定,那么将只会对unchecked异常进行回滚,而checked异常将不会回滚。

rollbackForClassname:作用同上。

noRollbackFor:指定某异常类,遇到该异常不回滚事务。

noRollbackForClassname:作用同上。

    注意事项:

    1、@Transactional注释只能作用于public方法上,其他修饰将被忽略。

    2、如果在接口,类,和方法上都指定了@Transactional注释,则优先级为方法->类->接口

    3、建议只在类上加@Transactional注释,而不是接口上。

    4、默认只会对unchecked异常进行回滚,最常见的为RuntimeException及其各种子类。

    那么Spring事务基本的使用方法就酱了 : ),目测已经可以满足百分之八九十需求了。 























另一篇 

继承类的@Transactional

@Transactional这个事务注解对父类继承过来的方法无效
只对当前类和子类有效,如果想要使其对父类方法有效,则可以将@Transactional写在父类上。
继承类的@Transactional:org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here 

假设有以下类: 

@Transactional 
public class SubClass extends SuperClass { 


public void loadDb(){ 
//数据库操作 






public class SuperClass { 


public void savedb() { 
//数据库操作 






savedb是父类的方法,loadDb是子类的方法。如果有以下调用: 


@Test 
public void test(){ 
SubClass o = new SubClass(); 
o.savedb();//将会报没有Session的错误 
o.loadDb();//正常 



可以看到在调父类方法时Hibernate报没有Session的错误(org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here),子类没有问题。 


解决办法一:在子类中重载父类方法: 


@Transactional 
public class SubClass extends SuperClass { 


public void loadDb(){ 





@Override 
public void savedb() { 
super.savedb(); 




这样显然繁琐了,子类savedb没有任何新操作。 


解决方法二:在父类中标注@Transactional(父类是抽象类也可以): 


@Transactional 
public class SuperClass { 


public void savedb() { 








这需要父类的修改权限。 


--- http://www.cnblogs.com/xiefeifeihu/archive/2010/07/27/1785958.html


你可能感兴趣的:(Spring事务总结---事务概述及Spring事务的基本使用(完整))