zoukankan      html  css  js  c++  java
  • Spring 事务

    一、事务相关概念

      1.事务由四个特性:ACID

        • 原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用【要么做,要么不做
        • 一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏。【操作一致,保数据完整
        • 隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。【处理数据独立,互不干扰
        • 持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中。【数据持久保存

      2.事务传播行为:当事务方法被另一个事务方法调用时,必须指定事务应该如何传播

        • PROPAGATION_REQUIRED  支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
        • PROPAGATION_SUPPORTS    支持当前事务,如果当前没有事务,就以非事务方式执行。
        • PROPAGATION_MANDATORY     支持当前事务,如果当前没有事务,就抛出异常。
        • PROPAGATION_REQUIRES_NEW     新建事务,如果当前存在事务,把当前事务挂起。
        • PROPAGATION_NOT_SUPPORTED     以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
        • PROPAGATION_NEVER    以非事务方式执行,如果当前存在事务,则抛出异常。
        • PROPAGATION_NESTED    如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行。

      3.事务隔离级别

        • Read Uncommitted(一个事务可以读取另一个事务未提交内容)最低级别,任何情况都无法保证
        • Read Committed(一个事务只能读取另一个事务提交的内容)可避免脏读的发生。
        • Repeatable Read(对一个事务的内容可以多次重读,多次提交)可避免脏读、不可重复读的发生。
        • Serializable(可串行化,按事务顺序执行)可避免脏读、不可重复读、幻读的发生。(最高级)

      4.事务超时

            所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。  默认设置为底层事务系统的超时值,如果底层数据库事务系统没有设置超时值,那么就是none,没有超时限制。

      5.事务只读属性

             只读事务用于客户代码只读但不修改数据的情形,只读事务用于特定情景下的优化,比如使用Hibernate的时候。默认为读写事务。

    二、spring4集合Hibernate5的事务配置:

      声明式事务管理配置,的细粒度只能到方法级别,也就是一整个方法就是一个事务,方法结束后提交事务。编程式事务可以在方法局部创建事务,并提交,一般使用try/catch捕获异常并对未成功的事务进行回滚操作。一下是声明式事务的一种配置方式。

      applicationContext.xml

     1 <beans xmlns="http://www.springframework.org/schema/beans"
     2        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     3        xmlns:tx="http://www.springframework.org/schema/tx"
     4        xmlns:aop="http://www.springframework.org/schema/aop"
     5        xmlns:context="http://www.springframework.org/schema/context"
     6        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
     7        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
     8        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
     9        http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-4.3.xsd">
    10 
    11     <!-- 导入properties配置文件 -->
    12     <context:property-placeholder location="classpath*:/jdbc.properties"/>
    13 
    14     <!-- 扫描注解包 -->
    15     <context:component-scan base-package="dao.daoImpl"/>
    16     <context:component-scan base-package="service.serviceImpl" />
    17 
    18     <!-- 数据源基本配置 -->
    19     <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    20          <property name="username" value="${jdbc.username}"/>
    21          <property name="password" value="${jdbc.password}"/>
    22          <property name="url" value="${jdbc.url}"/>
    23          <property name="driverClassName" value="${jdbc.driverClassName}"/>
    24     </bean>
    25 
    26     <!-- 创建sessionFactory -->
    27     <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
    28         <property name="dataSource" ref="dataSource"/>
    29         <property name="hibernateProperties">
    30             <props>
    31                 <prop key="hibernate.show_sql">true</prop>
    32                 <prop key="hibernate.format_sql">true</prop>
    33                 <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
    34             </props>
    35         </property>
    36         <!-- 实体类映射文件 -->
    37         <property name="mappingLocations">
    38             <list>
    39                 <value>classpath*:/domain/*.hbm.xml</value>
    40             </list>
    41         </property>
    42         <property name="packagesToScan">
    43             <value>domain</value>
    44         </property>
    45         <!-- 实体类 -->
    46         <property name="annotatedClasses">
    47             <list>
    48                 <value>domain.UserEntity</value>
    49             </list>
    50         </property>
    51     </bean>
    52 
    53     <!-- 创建声明式事务管理 -->
    54     <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
    55         <property name="sessionFactory" ref="sessionFactory"/>
    56     </bean>
    57 
    58     <!-- 事务通知 -->
    59     <tx:advice id="txAdvice" transaction-manager="transactionManager">
    60         <tx:attributes>
    61             <!-- propagation配置传播行为,isolation配置隔离方式,表示在方法存在事务的时候直接使用,不存在则创建一个新事务,隔离级别为一个事务可以读取另外一个已提交事务的内容, -->
    62             <tx:method name="*" propagation="REQUIRED" isolation="READ_COMMITTED"/>
    63         </tx:attributes>
    64     </tx:advice>
    65 
    66     <!-- aop织入通知 -->
    67     <aop:config>
    68         <aop:pointcut id="serviceOption" expression="execution(* service.serviceImpl.*.*(..))"/>
    69         <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOption"/>
    70     </aop:config>
    71 
    72 
    73 </beans>

      web.xml (配置session拦截器,他将为每个请求绑定一个session,这个session是hibernateSession和,httpSession不一样,这样他可以有spring自动管理,无需手动开关)

    1 <!-- 为每个请求过程绑定一个HibernateSession,它将由spring自动管理,无需手动开启和关闭 -->
    2         <filter>
    3             <filter-name>openSessionInterceptor</filter-name>
    4             <filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
    5         </filter>
    6         <filter-mapping>
    7             <filter-name>openSessionInterceptor</filter-name>
    8             <url-pattern>/*</url-pattern>
    9         </filter-mapping>

      在未使用事务管理的时候,同一个事务内的两个数据库操作,一个成功了,就会对数据库产生影响,如果两个操作是互相对应的,比如一个是增加数值,一个是减少数值,如果两个操作只做个一个,那么数据将不完整,出现异常(当然这种异常数据是不会报错的),但是添加了事务管理之后,就可以防止这种问题,事务的原子性:一件事情要么全做要么不做,一旦有操作失败,那么事务将进行rallback()回滚,撤销之前的所有事务操作。

      如下图:

        即使执行了语句,但是后面遇到了1/0的数值计算异常,那么 事务会进行回滚,撤销操作,数据库数据还是保持原样。事务一旦commit成功,再执行rollback回滚已经没有效果了。

    测试代码:

     1 public int updateUserInfo() {
     2         Session session = sessionFactory.getCurrentSession();
     3         String hql = "update UserEntity user set user.username='改1次' where user.id=1";
     4         session.createQuery(hql).executeUpdate();
     5         hql = "update UserEntity user set user.username='改2次' where user.id=1";
     6         session.createQuery(hql).executeUpdate();
     7         List<UserEntity> usersList = session.createQuery("from UserEntity ").list();
     8         for (UserEntity u:usersList){
     9             System.out.println(u.getUsername()+" : "+u.getCreateTime());
    10         }
    11         int i = 1/0;
    12         return 0;
    13     }

      此处有一句int i=1/0;是故意制造的异常,在声明式事务中,整个方法就是一个事务,当方法执行完后提交事务,如果事务提交出现异常则回滚到提交前的状态,也就是之前执行的sql语句全部作废掉,这个方法中我们首先对同一条数据做了两次更改,然后通过查询语句查出所有数据并打印,讲道理,执行结果应该是查出来的第一条id=1的语句的username被改成了“改2次”,并且数据库中的数据也是改两次,但是执行结果如下:

      看样子好像没毛病,但是看数据库发现原来的数据并没有被修改过来,而是保持原来的样子,

      出现这种情况的原因是,声明式事务的特点是把整个方法当成事务提交,事务提交的过程中的确修改了数据库,并且查询出了修改后的数据(因为查询语句和打印语句都在事务中),然后当事务执行到int i=1/0的时候报错了(众所周知除数不能为0),产生了异常,所以整个事务的提交是有异常的,那么存在异常的事务将会被回滚,撤销原来的数据库操作,所以数据库的数据就被还原了,这也符合数据库原子性和一致性的特性。这也就出现了我们看到的查询结果明明有变,但是数据库数据却没有改变的情况。

  • 相关阅读:
    Linux下架构高可用性网络----HA+LB+lvs
    MacBook如何用Parallels Desktop安装windows7/8
    Win10如何彻底禁用小娜?彻底禁用小娜的方法
    安卓手机微信发不出去怎么办 微信不能发信息怎么办
    计算机名、主机名、用户账户名与NetBIOS名有什么区别
    安装corel x8提示你已安装了另外一个版本
    ssh整合问题总结--在添加商品模块实现图片(文件)的上传
    代理设计模式之静态代理与动态代理(超..)详解
    Java基础--反射机制的知识点梳理
    ssh整合问题总结--运行项目时报java.lang.StackOverflowError(堆栈溢出)异常
  • 原文地址:https://www.cnblogs.com/caijh/p/7724964.html
Copyright © 2011-2022 走看看