您的位置:首页 > 编程语言 > Java开发

事务有哪些特性?spring的事务管理有几种方式实现,如何实现?spring 中常用的两种事务配置方式以及事务的传播性、隔离级别

2018-03-13 16:34 1151 查看
事务有哪些特性?
            1.原子性:一个事务中所有对数据库的操作是一个不可分割的操作序列,要么全做要么全不做            2.一致性:数据不会因为事务的执行而遭到破坏            3.隔离性:一个事物的执行,不受其他事务的干扰,即并发执行的事物之间互不干扰            4.持久性:一个事物一旦提交,它对数据库的改变就是永久的spring的事务管理有几种方式实现,如何实现?         
            事务的实现方式:实现方式共有两种:编码方式;声明式事务管理方式           基于AOP技术实现的声明式事务管理,实质就是:在方法执行前后进行拦截,然后再目标方法开始之前创建并加入事务执行完目标方法后根据执行情况提交或回滚事务.           声明式事务管理又有两种实现方式:基于xml配置文件的方式;另一个实在业务方法上进行@Transaction注解,将事务规则应用到业务逻辑中。            一种常见的事务管理配置:事务拦截器TransactionInterceptor和事务自动代理BeanNameAutoProxyCreator相结合的方式。创建事务的时机:

是否需要创建事务,是由事务传播行为控制的。读数据不需要或只为其指定只读事务,而数据的插入,修改,删除就需要事务管理了。

<!--定义Hibernate的事务管理器HibernateTransactionManager -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<!-- 依赖注入上面定义的sessionFactory -->
<property name="sessionFactory" ref="sessionFactory"/>
</bean>

<!--定义Spring的事务拦截器TransactionInterceptor -->
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<!-- 依赖注入上面定义的事务管理器transactionManager -->
<property name="transactionManager" ref="transactionManager"/>
<!-- 定义需要进行事务拦截的方法及所采用的事务控制类型 -->
<property name="transactionAttributes">
<props>
<!-- 以browse、list、load、get及is开头的所有方法采用只读型事务控制类型 -->
<prop key="browse*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="list*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="is*">PROPAGATION_REQUIRED,readOnly</prop>
<!-- 所有方法均进行事务控制,如果当前没有事务,则新建一个事务 -->
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>

<!-- 定义BeanNameAutoProxyCreatorf进行Spring的事务处理-->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<!-- 针对指定的bean自动生成业务代理 -->
<property name="beanNames">
<list>
<value>adminService</value>
<value>columnsService</value>
<value>newsService</value>
<value>crawlService</value>
<value>memberLevelService</value>
<value>memberService</value>
<value>categoryService</value>
<value>merService</value>
<value>cartService</value>
<value>ordersService</value>
<value>trafficService</value>
</list>
</property>
<!-- 这个属性为true时,表示被代理的是目标类本身而不是目标类的接口 -->
<property name="proxyTargetClass">
<value>true</value>
</property>
<!-- 依赖注入上面定义的事务拦截器transactionInterceptor -->
<property name="interceptorNames">
<list>
<value>transactionInterceptor</value>
</list>
</property>
</bean>
注解式事务
1、 事务配置实例(1)、spring+mybatis 事务配置
[html] view plain copy        <!-- 定义事务管理器 -->  
<bean id="transactionManager"  
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
    <property name="dataSource" ref="dataSource" />  
</bean>  
<!--使用注释事务 -->  
<tx:annotation-driven  transaction-manager="transactionManager" />  
(2)、spring+hibernate 事务配置
[html] view plain copy <!-- 事务管理器配置,单数据源事务 -->  
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">  
    <property name="sessionFactory" ref="sessionFactory" />  
</bean>  
  
<!-- 使用annotation定义事务 -->  
<tx:annotation-driven  transaction-manager="transactionManager"   proxy-target-class="true" />  
看到上面的这两段配置文件是不是很熟悉,对的这就是我们平时看到的事务的配置,在spring的配置中配置数据源即dataSource、事务管理器,事务管理器使用不同的orm框架事务管理器类就不同,比如这里使用的是mybatis 所以是[html] view plain copy org.springframework.jdbc.datasource.DataSourceTransactionManager  
如果使用hibernate 则事务管理器类为

[html] view plain copy org.springframework.orm.hibernate3.HibernateTransactionManager  
这是使用注解方式时要配置的,代码中的具体的注解以及事务的传播性、隔离级别一般在service 层中配置下面看看
2、@Transactional
(1)、这里说明一下,有的把这个注解放在类名称上面了,这样你配置的这个@Transactional 对这个类中的所有public方法都起作用
(2)、@Transactional 方法方法名上,只对这个方法有作用,同样必须是public的方法
比如这里就对这个方法定义了一个事务同时设置了很多属性:
[java] view plain copy @Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class,timeout=1,isolation=Isolation.DEFAULT)  
public void saveUser(Map<String, String> map) throws Exception {  
        System.out.println("方法开始");  
    for (int i = 0; i < 500000; i++) {  
            System.out.println("*");  
        }  
     System.out.println("进入保存");  
     userDao.saveUser(map);  
     System.out.println("退出保存");  
}  

3、事物配置中有哪些属性可以配置(1)、事务的传播性:@Transactional(propagation=Propagation.REQUIRED) 
      如果有事务, 那么加入事务, 没有的话新建一个(默认情况下)

(2)、事务的超时性:@Transactional(timeout=30) //默认是30秒 
      注意这里说的是事务的超时性而不是Connection的超时性,这两个是有区别的
(3)、事务的隔离级别:@Transactional(isolation = Isolation.READ_UNCOMMITTED)
      读取未提交数据(会出现脏读, 不可重复读) 基本不使用

(4)、回滚:
指定单一异常类:@Transactional(rollbackFor=RuntimeException.class)指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class})
该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。
(5)、只读:@Transactional(readOnly=true)
该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。

ok 这种注解方式实现事务的配置以及一些属性的定义,其实事务的东西还有很多要注意的事项,如果要深入学习的话要学习的东西还很多,这里只是简单记录一下
那我们要注意什么那:
1、在spring配置文件中引入<tx:>命名空间:xmlns:tx="http://www.springframework.org/schema/tx"
                                 http://www.springframework.org/schema/tx  http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
[html] view plain copy <beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
     xmlns:tx="http://www.springframework.org/schema/tx"  
    xmlns:context="http://www.springframework.org/schema/context"  
    xmlns:aop="http://www.springframework.org/schema/aop"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans   
                  http://www.springframework.org/schema/beans/spring-beans-3.2.xsd  
                  http://www.springframework.org/schema/context  
                  http://www.springframework.org/schema/context/spring-context-3.2.xsd  
                  http://www.springframework.org/schema/aop   
                  http://www.springframework.org/schema/aop/spring-aop.xsd        
                 http://www.springframework.org/schema/tx   
                 http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">  
2、@Transactional 只能被应用到public方法上, 对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能.

3、用 spring 事务管理器,由spring来负责数据库的打开,提交,回滚.默认遇到运行期例外(throw new RuntimeException("注释");)会回滚,即遇到不受检查(unchecked)的例外时回滚;而遇到需要捕获的例外(throw new Exception("注释");)不会回滚,即遇到受检查的例外(就是非运行时抛出的异常,编译器会检查到的异常叫受检查例外或说受检查异常)时,需我们指定方式来让事务回滚 要想所有异常都回滚,要加上 @Transactional( rollbackFor={Exception.class,其它异常}) .如果让unchecked例外不回滚: @Transactional(notRollbackFor=RunTimeException.class)
如下:
@Transactional(rollbackFor=Exception.class) //指定回滚,遇到异常Exception时回滚
public void methodName() {
throw new Exception("注释");

}
@Transactional(noRollbackFor=Exception.class)//指定不回滚,遇到运行期例外(throw new RuntimeException("注释");)会回滚
public ItimDaoImpl getItemDaoImpl() {
throw new RuntimeException("注释");
}4、@Transactional 注解应该只被应用到 public 可见度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错, 但是这个被注解的方法将不会展示已配置的事务设置。
5、@Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上。然而,请注意仅仅 @Transactional 注解的出现不足于开启事务行为,它仅仅 是一种元数据,能够被可以识别 @Transactional 注解和上述的配置适当的具有事务行为的beans所使用。上面的例子中,其实正是 <tx:annotation-driven/>元素的出现 开启 了事务行为。
6、Spring团队的建议是你在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。你当然可以在接口上使用 @Transactional 注解,但是这将只能当你设置了基于接口的代理时它才生效。因为注解是 不能继承 的,这就意味着如果你正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装(将被确认为严重的)。因 此,请接受Spring团队的建议并且在具体的类上使用 @Transactional 注解。二、使用AOP的方式实现事务的配置
1、这种事务使用也很多,下面我们来看看简单的例子
2、事务配置实例:
(1)、配置文件
[html] view plain copy <!-- 定义事务管理器 -->  
    <bean id="transactionManager"  
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
        <property name="dataSource" ref="dataSource" />  
    </bean>  
    <!-- 下面使用aop切面的方式来实现 -->  
    <tx:advice id="TestAdvice" transaction-manager="transactionManager">  
        <!--配置事务传播性,隔离级别以及超时回滚等问题 -->  
        <tx:attributes>  
            <tx:method name="save*" propagation="REQUIRED" />  
            <tx:method name="del*" propagation="REQUIRED" />  
            <tx:method name="update*" propagation="REQUIRED" />  
            <tx:method name="add*" propagation="REQUIRED" />  
            <tx:method name="*" rollback-for="Exception" />  
        </tx:attributes>  
    </tx:advice>  
    <aop:config>  
        <!--配置事务切点 -->  
        <aop:pointcut id="services"  
            expression="execution(* com.website.service.*.*(..))" />  
        <aop:advisor pointcut-ref="services" advice-ref="TestAdvice" />  
    </aop:config>  
上面我们看到了,简单的配置了事务,其中tx:attributes中设置了事务的传播性,隔离级别以及那种问题能进行回滚超时等这些问题,也就是你自己按照业务需求定制一个事务来满足你的业务需求。注意: 这里注意一下,在tx:method中配置了rollback_for 中配置的Exception 这个是运行时的异常才会回滚不然其他异常是不会回滚的!
[java] view plain copy @Service("userService")  
public class UserService {  
    @Autowired  
    private UserDao userDao;  
    public void saveUser(Map<String, String> map) throws Exception {  
         userDao.saveUser(map);  
         throw new RuntimeException();  
         // throw new Exception ();  
           
    }  
}  

这里我们看到了,如果抛出的是一个运行时异常则会回滚而如果抛出的不是运行时异常则会不回滚的。需要注意的地方:(1)、在spring 配置文件中引入:xmlns:aop="http://www.springframework.org/schema/aop" http://www.springframework.org/schema/aop 
                  http://www.springframework.org/schema/aop/spring-aop.xsd [html] view plain copy <beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
     xmlns:tx="http://www.springframework.org/schema/tx"  
    xmlns:context="http://www.springframework.org/schema/context"  
    xmlns:aop="http://www.springframework.org/schema/aop"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans   
                  http://www.springframework.org/schema/beans/spring-beans-3.2.xsd  
                  http://www.springframework.org/schema/context  
                  http://www.springframework.org/schema/context/spring-context-3.2.xsd  
                  http://www.springframework.org/schema/aop   
                  http://www.springframework.org/schema/aop/spring-aop.xsd        
                 http://www.springframework.org/schema/tx   
                 http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">  
(2) advice(建议)的命名:由于每个模块都会有自己的Advice,所以在命名上需要作出规范,初步的构想就是模块名+Advice(只是一种命名规范)。(3) tx:attribute标签所配置的是作为事务的方法的命名类型。         如<tx:method name="save*" propagation="REQUIRED"/>        其中*为通配符,即代表以save为开头的所有方法,即表示符合此命名规则的方法作为一个事务。        propagation="REQUIRED"代表支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。(4) aop:pointcut标签配置参与事务的类,由于是在Service中进行数据库业务操作,配的应该是包含那些作为事务的方法的Service类。       首先应该特别注意的是id的命名,同样由于每个模块都有自己事务切面,所以我觉得初步的命名规则因为 all+模块名+ServiceMethod。而且每个模块之间不同之处还在于以下一句:       expression="execution(* com.test.testAda.test.model.service.*.*(..))"       其中第一个*代表返回值,第二*代表service下子包,第三个*代表方法名,“(..)”代表方法参数。(5) aop:advisor标签就是把上面我们所配置的事务管理两部分属性整合起来作为整个事务管理。(6)注意标红的地方


ok 到这里两种配置方式简单的demo 都有了,下面我们来看看tx:method 中还有那些属性可以配置

下面来看看aop 这种方式来配置的时候我们还能配置那些属性:
<tx:advice id="advice" transaction-manager="txManager">
<tx:attributes>
<!-- tx:method的属性:
* name 是必须的,表示与事务属性关联的方法名(业务方法名),对切入点进行细化。通配符(*)可以用来指定一批关联到相同的事务属性的方法。
如:'get*'、'handle*'、'on*Event'等等.
* propagation  不是必须的 ,默认值是REQUIRED
表示事务传播行为, 包括REQUIRED,SUPPORTS,MANDATORY,REQUIRES_NEW,NOT_SUPPORTED,NEVER,NESTED
* isolation    不是必须的 默认值DEFAULT
表示事务隔离级别(数据库的隔离级别)
* timeout      不是必须的 默认值-1(永不超时)
表示事务超时的时间(以秒为单位)
* read-only    不是必须的 默认值false不是只读的 
        表示事务是否只读? 
* rollback-for 不是必须的   
        表示将被触发进行回滚的 Exception(s);以逗号分开。
        如:'com.foo.MyBusinessException,ServletException' 
* no-rollback-for 不是必须的  
表示不被触发进行回滚的 Exception(s);以逗号分开。
如:'com.foo.MyBusinessException,ServletException'
        任何 RuntimeException 将触发事务回滚,但是任何 checked Exception 将不触发事务回滚  
-->
<tx:method name="save*" propagation="REQUIRED" isolation="DEFAULT" read-only="false"/>
<tx:method name="update*" propagation="REQUIRED" isolation="DEFAULT" read-only="false"/>
<tx:method name="delete*" propagation="REQUIRED" isolation="DEFAULT" read-only="false"/>
<!-- 其他的方法之只读的 -->
<tx:method name="*" read-only="true"/>
</tx:attributes>
</tx:advice>


OK 两种配置方式我们也都简单学习了,两种配置方式有哪些属性要配置我们也了解了,但是,这里只是说了有这两种常用的方法,而没有具体说事务以及事务的配置带来的数据的安全性以及性能的影响,其实事务不是那么简单,具体深入学习希望以后有总结!

下面给大家列出spring事务的几种传播特性:
[html] view plain copy 1. PROPAGATION_REQUIRED: 如果存在一个事务,则支持当前事务。如果没有事务则开启  
2. PROPAGATION_SUPPORTS: 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行  
3. PROPAGATION_MANDATORY: 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。  
4. PROPAGATION_REQUIRES_NEW: 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。  
5. PROPAGATION_NOT_SUPPORTED: 总是非事务地执行,并挂起任何存在的事务。  
6. PROPAGATION_NEVER: 总是非事务地执行,如果存在一个活动事务,则抛出异常  
7. PROPAGATION_NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务,   
      则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行  
Spring事务的隔离级别
[html] view plain copy 1. ISOLATION_DEFAULT: 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别,另外四个与JDBC的隔离级别相对应  
2. ISOLATION_READ_UNCOMMITTED: 这是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据,这种隔离级别会产生脏读,不可重复读和幻像读。  
3. ISOLATION_READ_COMMITTED: 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据  
4. ISOLATION_REPEATABLE_READ: 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读,它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。  
5. ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行,除了防止脏读,不可重复读外,还避免了幻像读。   

事务的隔离级别和数据库中是一样的大家可以看数据库事务隔离级别就能明白了但是事务的传播性是个什么鬼貌似之前没听过那下面就来看看
拷贝文章:http://blog.sina.com.cn/s/blog_4b5bc0110100z7jr.html
我们都知道事务的概念,那么事务的传播特性是什么呢?(此处着重介绍传播特性的概念,关于传播特性的相关配置就不介绍了,可以查看spring的官方文档)在我们用SSH开发项目的时候,我们一般都是将事务设置在Service层 那么当我们调用Service层的一个方法的时候它能够保证我们的这个方法中执行的所有的对数据库的更新操作保持在一个事务中,在事务层里面调用的这些方法要么全部成功,要么全部失败。那么事务的传播特性也是从这里说起的。如果你在你的Service层的这个方法中,除了调用了Dao层的方法之外,还调用了本类的其他的Service方法,那么在调用其他的Service方法的时候,这个事务是怎么规定的呢,我必须保证我在我方法里掉用的这个方法与我本身的方法处在同一个事务中,否则如果保证事物的一致性。事务的传播特性就是解决这个问题的,“事务是会传播的”在Spring中有针对传播特性的多种配置我们大多数情况下只用其中的一种:PROPGATION_REQUIRED:这个配置项的意思是说当我调用service层的方法的时候开启一个事务(具体调用那一层的方法开始创建事务,要看你的aop的配置),那么在调用这个service层里面的其他的方法的时候,如果当前方法产生了事务就用当前方法产生的事务,否则就创建一个新的事务。这个工作使由Spring来帮助我们完成的。以前没有Spring帮助我们完成事务的时候我们必须自己手动的控制事务,例如当我们项目中仅仅使用hibernate,而没有集成进spring的时候,我们在一个service层中调用其他的业务逻辑方法,为了保证事物必须也要把当前的hibernate session传递到下一个方法中,或者采用ThreadLocal的方法,将session传递给下一个方法,其实都是一个目的。现在这个工作由spring来帮助我们完成,就可以让我们更加的专注于我们的业务逻辑。而不用去关心事务的问题。默认情况下当发生RuntimeException的情况下,事务才会回滚,所以要注意一下 如果你在程序发生错误的情况下,有自己的异常处理机制定义自己的Exception,必须从RuntimeException类继承 这样事务才会回滚!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring事务
相关文章推荐