1Spring事务传播行为

所谓事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。Spring支持7种事务传播行为

PROPAGATION_REQUIRED(加入已有事务)

如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见也是默认的方式。

PROPAGATION_SUPPORTS(跟随环境)

支持当前事务,如果当前没有事务,就以非事务方式执行。

PROPAGATION_MANDATORY(需要事务)

使用当前的事务,如果当前没有事务,就抛出异常。

PROPAGATION_REQUIRES_NEW(独立事务)

新建事务,如果当前存在事务,把当前事务挂起。

PROPAGATION_NOT_SUPPORTED(非事务方式)

以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

PROPAGATION_NEVER(排除事务)

以非事务方式执行,如果当前存在事务,则抛出异常。

PROPAGATION_NESTED(嵌套事务)

如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

Spring默认的事务传播行为是PROPAGATION_REQUIRED,它适合于绝大多数的情况。假设ServiveX#methodX()都工作在事务环境下(即都被Spring事务增强了),假设程序中存在如下的调用链:Service1#method1()->Service2#method2()->Service3#method3(),那么这3个服务类的3个方法通过Spring的事务传播机制都工作在同一个事务中。

如果在一个ServiceA和a()方法中启动一个线程,在这个新创建的线程中执行ServiceB的事务方法b()。在相同线程中进行相互嵌套调用的事务方法工作于相同的事务中。如果这些相互嵌套调用的方法工作在不同的线程中,不同线程下的事务方法工作在独立的事务中。

2多种数据持久方法事务管理

如果你采用了一个高端ORM技术(Hibernate,JPA,JDO),同时采用一个JDBC技术(Spring JDBC,iBatis),由于前者的会话(Session)是对后者连接(Connection)的封装,Spring会“足够智能地”在同一个事务线程让前者的会话封装后者的连接。所以,我们只要直接采用前者的事务管理器就可以了。下表给出了混合数据访问技术所对应的事务管理器:

1不同持久方式的事务统一

Spring提供了一个能从当前事务上下文中获取绑定的数据连接的工具类,那就是DataSourceUtils。Spring强调必须使用DataSourceUtils工具类获取数据连接。

static Connection doGetConnection(DataSource dataSource)

首先尝试从事务上下文中获取连接,失败后再从数据源获取连接;

static Connection getConnection(DataSource dataSource)

doGetConnection方法的功能一样,实际上,它内部就是调用doGetConnection方法获取连接的;

static void  doReleaseConnection(Connection con, DataSource dataSource)

释放连接,放回到连接池中;

static void release Connection(Connection con, DataSource dataSource)

和doReleaseConnection方法的功能一样,实际上,它内部就是调用doReleaseConnection方法获取连接的;

测试demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Service
public class TestTranscationServiceImpl implements TestTranscationService {
 
    @Autowired
    private TestTranscationDao testTranscationDao;
 
    @Override
    @Transactional
    public int test(){
        testTranscationDao.update1();
        testTranscationDao.update2();       
        return 0;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Autowired
    private JdbcTemplate jdbcTemplate;
 
    @Override
    public int update1() {
        //1.获得数据库连接
        Connection con = DataSourceUtils.getConnection(jdbcTemplate.getDataSource());
        try {
            con.prepareStatement("update grade_info set grade_name='11' where grade_id=1").executeUpdate();
        catch (SQLException e) {
            throw new RuntimeException(e);
        }finally {
            //2如果当前方法没有上下文事务管理,不释放数据库连接会造成数据库连接泄露
            //如果存在上下文事务,调用或者不调用数据库连接释放都没有问题
            DataSourceUtils.releaseConnection(con, jdbcTemplate.getDataSource());
        }
        return 0;
 
    }
 
    @Override
    public int update2(){
        //3.获得数据库连接   和1的数据库连接是同一个连接
        Connection con = DataSourceUtils.getConnection(jdbcTemplate.getDataSource());
        try {
            //4.这种方法取到的数据库连接和 1,3取到的数据库连接不同
            Connection conn = jdbcTemplate.getDataSource().getConnection();
            conn.close();
        catch (SQLException e) {
            e.printStackTrace();
        }
        return jdbcTemplate.update("update grade_info set grade_name='高中三年级' where grade_id=1");
    }

Spring为每个数据访问技术框架都提供了一个获取事务上下文绑定的数据连接(或其衍生品)的工具类和数据源(或其衍生品)的代理类。

2Hibernate和JDBC混合使用注意事项

由于Hibernate一级缓存的原因,在通过save,update,delete等方法操作数据时,并没有真正向数据库发送SQL,只有调用flush()时,Hibernate才会将一级缓存中的状态变化同步到数据库中。

Hibernate的事务管理在提交事务时,会自动调用flush()操作,将一级缓存同步到数据库中,此时才会将产生并向数据库发送SQL语句。

正是因为以上原因的存在,所有在混合使用JDBC和Hibernate时,可能存在丢失更新的问题。

在混合使用Hibernate和JDBC时,JDBC的操作不会同步到Hibernate的缓存中(一级缓存及二级缓存),Hibernate缓存中的状态变更也不被JDBC感知。因此混合使用时必须特别关注这一点。

由于混合数据访问技术的方案的事务同步而缓存不同步的情况,所以最好用Hibernate完成读写操作,而用Spring JDBC完成读的操作。如用Spring JDBC进行简要列表的查询,而用Hibernate对查询出的数据进行维护。如果确实要同时使用Hibernate和Spring JDBC读写数据,则必须充分考虑到Hibernate缓存机制引发的问题:必须充分分析数据维护逻辑,根据需要,及时调用Hibernate的flush()方法,以免覆盖Spring JDBC的更改,在Spring JDBC更改数据库时,维护Hibernate的缓存。

3Spring的事务增强限制条件

由于Spring事务管理是基于接口代理或动态字节码技术,通过AOP实施事务增强的。

对于基于接口动态代理的AOP事务增强来说,由于接口的方法是public的,这就要求实现类的实现方法必须是public的(不能是protected,private等),同时不能使用static的修饰符。所以,可以实施接口动态代理的方法只能是使用“public”或“public final”修饰符的方法,其它方法不可能被动态代理,相应的也就不能实施AOP增强,也即不能进行Spring事务增强了。

基于CGLib字节码动态代理的方案是通过扩展被增强类,动态创建子类的方式进行AOP增强植入的。由于使用final,static,private修饰符的方法都不能被子类覆盖,相应的,这些方法将不能被实施的AOP增强。所以,必须特别注意这些修饰符的使用,以免不小心成为事务管理的漏网之鱼。

4Spring事务管理的异常捕捉,事务回滚

spring的事务管理器只对 unchecked exception进行异常回滚,Error和RuntimeException及其子类是unchecked exception.其他exception是checked exception.

如果在service层中,使用了try ,catch来捕捉异常,导致sevice层出现的异常被 “截留”,无法抛出给事务管理器,这就给事务管理器造成一种假象,就像程序在运行中,没有产生任何问题,因此也就不会对出现 runtimeException进行回滚操作。

Spring高级事务管理难点剖析的更多相关文章

  1. [转]Spring的事务管理难点剖析(1):DAO和事务管理的牵绊

    原文地址:http://stamen.iteye.com/blog/1441758 有些人很少使用Spring而不使用Spring事务管理器的应用,因此常常有人会问:是否用了Spring,就一定要用S ...

  2. JTA事务管理--配置剖析(二)

    Spring引用Tomcat的 JTA事务     Tomcat是Servlet容器,但它提供了JNDI的实现,因此用户可以象在Java EE应用程序服务器中一样,在Tomcat中使用JNDI查找JD ...

  3. Spring的事务管理

    事务 事务:是逻辑上一组操作,要么全都成功,要么全都失败. 事务特性(ACID) 原子性:事务不可分割 一致性:事务执行的前后,数据完整性保持一致 隔离性:一个事务执行的时候,不应该受到其他事务的打扰 ...

  4. spring笔记--事务管理之声明式事务

    事务简介: 事务管理是企业级应用开发中必不可少的技术,主要用来确保数据的完整性和一致性, 事务:就是一系列动作,它们被当作一个独立的工作单元,这些动作要么全部完成,要么全部不起作用. Spring中使 ...

  5. Spring应用——事务管理

    事务基础:请参看:http://www.cnblogs.com/solverpeng/p/5720306.html 一.Spring 事务管理 1.前提:事务管理器 在使用 Spring 声明式事务管 ...

  6. spring+mybatis事务管理

    spring+mybatis事务管理 最近在和朋友做一个项目,考虑用springmvc+mybatis来做,之前在公司工作吧,对于数据库这块的配置也有人再弄,最近因为这个项目,我就上网学习了一些关于数 ...

  7. spring,mybatis事务管理配置与@Transactional注解使用[转]

    spring,mybatis事务管理配置与@Transactional注解使用[转] spring,mybatis事务管理配置与@Transactional注解使用 概述事务管理对于企业应用来说是至关 ...

  8. CSDN上看到的一篇有关Spring JDBC事务管理的文章(内容比较全) (转)

    JDBC事务管理 Spring提供编程式的事务管理(Programmatic transaction manage- ment)与声明式的事务管理(Declarative transaction ma ...

  9. Spring之事务管理

        事务管理对于企业应用至关重要.它保证了用户的每一次操作都是可靠的,即便出现了异常的访问情况,也不至于破坏后台数据的完整性.     就像银行的自助取款机,通常都能正常为客户服务,但是也难免遇到 ...

随机推荐

  1. JS 学习笔记--5---对象和数组

    1.Object类型(引用类型) 不具备多少功能,但是对于在ECMAScript中存储和传递数据确实,确是很理想的选择. 创建方式:(1).使用new Object();方式创建对象,然后对对象进行设 ...

  2. 剑指offer-17题

    题目要求:输入一个表示整数的字符串,把该字符串转换成整数并输出.例如输入字符串"345",则输出整数345. 分析:这道题能够很好地反应出程序员的思维和编程习惯. 的确,自己编写的 ...

  3. java socket 一个服务器对应多个客户端,可以互相发送消息

    直接上代码,这是网上找的demo,然后自己根据需求做了一定的修改.代码可以直接运行 服务器端: package socket; import java.io.BufferedReader; impor ...

  4. C#中实现VB中的CreateObject方法

    经常看到有些VB的例子中直接用个CreateObject就可调用系统功能(大多是COM对象),像用户设定,网络设定等等.虽然C#中可以通过使用VB的命名空间的方法来调用CreateObject函数,但 ...

  5. UML状态图(转载)

    概述: 图表本身的名称,阐明该图的目的和其他细节.它描述了在一个系统中的一个组成部分不同的状态.状态是特定的一个系统的组件/对象. 状态图描述了一个状态机.我们阐明的状态机可以被定义为一台机器,它定义 ...

  6. 如何在帝国cms后台菜单栏中添加删除链接?

    下午测试一个网上下载经过二次开发的帝国cms系统,还原完数据进入后台ytkah发现菜单栏多出了几个链接,有点不习惯,就想着怎么把它去掉.由于自己用的win7系统,搜索时没有像xp那样可以搜索包含某字符 ...

  7. Android 添加Button事件

    protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentV ...

  8. php laravel 安装

    windows环境尝试学习一下laravel 1.因为SAE的php版本为5.3,因此最高只能支持到Laravel4.1.x.(Laravel4.2用到了php5.4的trait特性) 以4.1为主. ...

  9. UITableView局部刷新

    只刷新cell不刷新section,这问题还难住了一阵子 需要用到: - (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnima ...

  10. 相对布局RelativeLayout

      一. public class RelativeLayout extends ViewGroup java.lang.Object    ↳ android.view.View      ↳ an ...