java事务和分布式事务详解

目录

 

事务问题

1 Java事务的类型 

2 spring事务实现源码分析 


事务问题

面试经常会问到分布式锁、分布式事务、SOA 服务化、分布式系统等业务、架构的问题和解决方案,工作中接触的业务方面事关金融,也需要解决一些类似的业务问题,所以总结了一篇浅谈分享,后面实战篇正在准备,这几周会发布。       

      分布式事务就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。简单的说,就是一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务器上,且属于不同的应用,分布式事务需要保证这些小操作要么全部成功,要么全部失败。本质上来说,分布式事务就是为了保证不同数据库的数据一致性

1 3.3 JPA中UserTransaction与entityManager的关系

 private UserTransaction utx = entityManager.getTransaction();

PA中的事务管理

在JPA中,JPA本身没有提供任何类型的声明式事务管理,所以,为了更好的进行一系列的事务操作和管理,常用的事务管理有容器管理和人为管理。人为管理需要代码实现。 
在JPA中一种实现方式就是调用entityManager的UserTransaction。即:

EntityManagerFactory  emf = Persistence.createEntityManagerFactory("PersonUnit");

EntityManager  em = emf.createEntityManager();

UserTransaction utx = entityManager.getTransaction();

utx .begin();

em.getTransaction().commit();

e.printStackTrace();

//上述UserTransaction接口由entityManager对象实现,例如:

            // 实例化对象

            UserTransaction utx = entityManager.getTransaction();

            // 开启事务

            utx.begin();

            // 提交事务

            utx.commit();

public class PersonController {

    //定义全局变量

    EntityManagerFactory emf = null;

    EntityManager em = null;



    //引入UserTransaction

    private UserTransaction utx;

    private Person newPerson = new Person();

    // newPerson的getter和setter方法

    public Person getNewPerson() {
        return newPerson;
    }


    public void setNewPerson(Person newPerson) {

        this.newPerson = newPerson;

    }



    // login方法

    public void addPerson() throws IllegalStateException, SecurityException, HeuristicMixedException,

            HeuristicRollbackException, RollbackException, SystemException {

        try {

            //utx.begin();
             //该参数必须与persistence-unit的name相一致
            emf = Persistence.createEntityManagerFactory("PersonUnit");
            em = emf.createEntityManager();
            // 断点测试
            System.out.println("打印输出newPerson:   " + newPerson.toString());
            System.out.println("打印输出em:  " + em.toString());// 测试结果,EntityManager注入失败

            em.getTransaction().begin();// 至关重要的一步:开启事务

            em.persist(newPerson);

            em.getTransaction().commit();

        } catch (Exception e) {

            e.printStackTrace();

        } finally {

            em.close();

            emf.close();

            //utx.commit();

            System.out.println("存入成功!");
        }
    }
}

 

1 Java事务的类型 

    Java事务的类型有三种:JDBC事务、JTA(Java Transaction API)事务、容器事务。

    1、JDBC事务

    JDBC 事务是用 Connection 对象控制的。JDBC Connection 接口( java.sql.Connection )提供了两种事务模式:自动提交和手工提交。 java.sql.Connection 提供了以下控制事务的方法:

public void setAutoCommit(boolean)
public boolean getAutoCommit()
public void commit()
public void rollback()
    使用 JDBC 事务界定时,您可以将多个 SQL 语句结合到一个事务中。JDBC 事务的一个缺点是事务的范围局限于一个数据库连接。一个 JDBC 事务不能跨越多个数据库。

    2、JTA(Java Transaction API)事务

    JTA是一种高层的,与实现无关的,与协议无关的API,应用程序和应用服务器可以使用JTA来访问事务。

    JTA允许应用程序执行分布式事务处理——在两个或多个网络计算机资源上访问并且更新数据,这些数据可以分布在多个数据库上。JDBC驱动程序的JTA支持极大地增强了数据访问能力。

    如果计划用 JTA 界定事务,那么就需要有一个实现 javax.sql.XADataSource 、 javax.sql.XAConnection 和 javax.sql.XAResource 接口的 JDBC 驱动程序。一个实现了这些接口的驱动程序将可以参与 JTA 事务。一个 XADataSource 对象就是一个 XAConnection 对象的工厂。 XAConnection s 是参与 JTA 事务的 JDBC 连接。

    您将需要用应用服务器的管理工具设置 XADataSource .从应用服务器和 JDBC 驱动程序的文档中可以了解到相关的指导。

     J2EE应用程序用 JNDI 查询数据源。一旦应用程序找到了数据源对象,它就调用 javax.sql.DataSource.getConnection() 以获得到数据库的连接。

    XA 连接与非 XA 连接不同。一定要记住 XA 连接参与了 JTA 事务。这意味着 XA 连接不支持 JDBC 的自动提交功能。同时,应用程序一定不要对 XA 连接调用 java.sql.Connection.commit() 或者 java.sql.Connection.rollback() .

    相反,应用程序应该使用 UserTransaction.begin()、 UserTransaction.commit() 和 serTransaction.rollback() .

 

    3、容器事务

    容器事务主要是J2EE应用服务器提供的,容器事务大多是基于JTA完成,这是一个基于JNDI的,相当复杂的API实现。相对编码实现JTA事务管理, 我们可以通过EJB容器提供的容器事务管理机制(CMT)完成同一个功能,这项功能由J2EE应用服务器提供。这使得我们可以简单的指定将哪个方法加入事 务,一旦指定,容器将负责事务管理任务。这是我们土建的解决方式,因为通过这种方式我们可以将事务代码排除在逻辑编码之外,同时将所有困难交给J2EE容 器去解决。使用EJB CMT的另外一个好处就是程序员无需关心JTA API的编码,不过,理论上我们必须使用EJB.

    4、三种Java事务差异

    JDBC事务控制的局限性在一个数据库连接内,但是其使用简单。

    JTA事务的功能强大,事务可以跨越多个数据库或多个DAO,使用也比较复杂。

      容器事务,主要指的是J2EE应用服务器提供的事务管理,局限于EJB应用使用。

    5、应用场景

    Java事务控制是构建J2EE应用不可缺少的一部分,合理选择应用何种事务对整个应用系统来说至关重要。一般说来,在单个JDBC 连接连接的情况下可以选择JDBC事务,在跨多个连接或者数据库情况下,需要选择使用JTA事务,如果用到了EJB,则可以考虑使用EJB容器事务 

 

2 spring事务实现源码分析 

3.1 dao模块

dao模块定义了数据库层的各种异常,其中异常的结构已经在spring-jdbc模块中介绍过了,在这里主要是dao的支持和异常的转译,其数据库支持和转译结构如下所示:

java事务和分布式事务详解_第1张图片

dao 支持
提供了对hibernate、jdbc,cci的支持。我们都想到熟悉,对cci可能有些陌生,下面的章节会讲到。

dao异常转译
  PersistenceExceptionTranslationPostProcessor:自动将标示为@repository的bean的持久化异常进行转译。它增加一个PersistenceExceptionTranslationAdvisor来代理相应的已经存在的aop代理或者实现了目标接口的新产生的代理。它将本地资源异常转换为spring的DataAccessException及其子类上。

  PersistenceExceptionTranslationAdvisor是一个spring aop的异常转译类,它应用到respository层或者dao层。它基于给定的PersistenceExceptionTranslator来将本地持久化异常转换为spring的DataAccessException族。

PersistenceExceptionTranslationInterceptor:一个aop 方法拦截器(MethodInterceptor).提供基于PersistenceExceptionTranslator的异常转换,它是PersistenceExceptionTranslator的代理,将运行时抛出的异常转换为spring 的DataAccessException族。

  PersistenceExceptionTranslator spring集成其它数据获取技术(如jpa、toplink、jdo、hibernate等)抛出运行时异常的接口。

jca模块

   1. cci模块

   

java事务和分布式事务详解_第2张图片 类图

J2EE提供JCA(Java Connector Architecture)规范来标准化对EIS(Enterprise Information System)的访问。这个规范被分为几个不同的部分: 

SPI(Service provider interfaces)是连接器提供者(connector provider)必须实现的接口。 这些接口组成了一个能被部署在J2EE应用服务器上的资源适配器(resource adapter)。 在这种情况下,由服务器来管理连接池(connection pooling)、事务和安全(托管模式(managed mode))。 应用服务器还负责管理客户端应用程序之外所拥有的配置。连接器(connector)同样能在脱离应用服务器的情况下使用;在这种情况下,应用程序必须直接对它进行配置(非托管模式(non-managed mode))。 

CCI (Common Client Interface)是应用程序用来与连接器交互并与EIS通信的接口。同样还为本地事务划界提供了API。 

Spring对CCI的支持,目的是为了提供以典型的Spring方式来访问CCI连接器的类,并有效地使用Spring的通用资源和事务管理工具。 

注意: 
连接器的客户端不必总是使用CCI。 某些连接器暴露它们自己的API,只提供JCA资源适配器(resource adapter) 以使用J2EE容器的某些系统契约(system contracts)(连接池(connection pooling),全局事务(global transactions),安全(security))。 Spring并没有为这类连接器特有(connector-specific)的API提供特殊的支持。

 2. context模块
    ResourceAdapterApplicationContext:一个jca ResourceAdapter的applicationContext实现,需要于jca的bootstrapContext一同初始化,最后传递到实现了BootstrapContextAware的spring 受管理bean。

@Override
    protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

        beanFactory.addBeanPostProcessor(new BootstrapContextAwareProcessor(this.bootstrapContext));

        beanFactory.ignoreDependencyInterface(BootstrapContextAware.class);

        beanFactory.registerResolvableDependency(BootstrapContext.class, this.bootstrapContext);



        // JCA WorkManager resolved lazily - may not be available.

        beanFactory.registerResolvableDependency(WorkManager.class, new ObjectFactory() {

            @Override

            public WorkManager getObject() {

                return bootstrapContext.getWorkManager();

            }

        });

    }

BootstrapContextAwareProcessor:传递BootstrapContext到实现了BootStrapContextAware接口的spring bean。它在内部bean factory中自动注册。

BootstrapContextAware:需要通知BootStrapContext的实现类。

BootstrapContext:提供一种机制,这种机制将一个Bootstrap的上下文传递到一个资源适配器实例。

3.endpoint模块
  AbstractMessageEndpointFactory:实现了jca 1.5、1.6、1.7版本的javax.resource.spi.endpoint.MessageEndpointFactory接口,它提供了事务管理能力。
  GenericMessageEndpointFactory实现了抽象方法,对任意类型的消息监听对象(javax.jms.MessageListener)或者javax.resource.cci.MessageListener对象提供了事务管理的能力。
  GenericMessageEndpointManager管理类,对上述方法进行管理。
 4.support模块
   LocalConnectionFactoryBean:创建一个本地JCA连接工厂。
   ResourceAdapterFactoryBean :使用BootStrapContext启动一个jca 1.5指定的ResouceAdapter。
 5. work模块
   结构如下:
java事务和分布式事务详解_第3张图片
WorkManager提供了提交Work(Work继承了Runnable)可执行实例的便利类。

你可能感兴趣的:(02-java基础知识)