zoukankan      html  css  js  c++  java
  • 什么叫事务?Java如何处理事务呢?

    什么叫事务?这些就是数据库特有的术语了。懒虫在这里口头解释:就是把多件事情当做一件事情来处理。也就是大家同在一条船上,要活一起活,要over一起over !

       我为什么要使用事务? 俺这里再举个很俗很俗的例子:

         俺到银行存钱,于是有这么几个步骤:
           1、把钱交给工作人员;2、工作人员填单;3、将单子给我签字;4、工作人员确认并输入电脑。

       要是,要是我把钱交给工作人员之后,进行到3我签字了。那哥们突然心脏病发作,over掉了,那,我的钱还没有输入电脑,但我却交了钱又签字确认了,而并没有其他任何记录。我岂不是要亏死了???我的血汗钱啊!赶紧退给我!!

       于是,在数据库里产生了这么一个术语:事务(Transaction),也就是要么成功,要么失败,并恢复原状。
      
       还是写程序把:

       Create Proc sp我去存款(@M Money , @iOperator Int)
       As
       Begin
        Declare @i int

        Begin Tran           --激活事务
         Exec @i=sp交钱 @m,@iOperator
         if @i<>0           --这里一般用系统错误号 @@Error。我这里为了举例子没有用到。需要根据实际情况。
         begin
          Rollback Tran                   --回滚事务
          RaisError ('银行的窗口太少了,我懒得排队,不交了!:( ', 16, 1) with Log --记录日志
          Return -1                     --返回错误号
         end

         Exec @i=sp填单 @m,@iOperator
         if @i<>0
         begin
          Rollback Tran                   --回滚事务
          RaisError ('银行的哥们打印机出了点毛病,打印不出单子来,把钱退回来给我吧??', 16, 1) with Log
          Return -2                     
         end

         Exec @i=sp签字 @m
         if @i<>0
         begin
          Rollback Tran                   --回滚事务
          RaisError ('我靠?什么烂银行,换了3支笔都写不出水来!!老子不存了!!不签!', 16, 1) with Log 
          Return -3                     
         end

         Exec @i=sp输入电脑 @m,@iOperator
         if @i<>0
         begin
          Rollback Tran                   --回滚事务
          RaisError ('什么意思?磁盘空间已满?好了好了,把钱给我,我到旁边的这家银行!', 16, 1) with Log 
          Return -4                     
         end
     
        Commit Tran        --提交事务
        Return 0
      End
     

           ----------------------------------------------------------------------
           以上是伪代码,模拟我去存款的过程。

     
     
    Java如何处理事务呢?
    简单事务的概念


      例如我们有一个订单库存管理系统,每一次生成订单的同时我们都要消减库存。通常来说订单和库存在数据库里是分两张表来保存的:订单表,库存表。每一次我们追加一个订单实际上需要两步操作:在订单表中插入一条数据,同时修改库存的数据。

      这样问题来了,例如我们需要一个单位为10的订单,库存中有30件,理想的操作是我们在订单表中插入了一条单位为10的订单,之后将库存表中的数据修改为20。但是有些时候事情并不是总是按照你的想法发生,例如:在你修改库存的时候,数据库突然由于莫名其妙的原因无法连接上了。也就是说库存更新失败了。但是订单已经产生了,那么怎么办呢?没办法,只有手动的修改。所以最好的方式是将订单插入的操作和库存修改的操作绑定在一起,必须同时成功或者什么都不做。这就是事务。

      Java如何处理事务呢?

      我们从java.sql.Connection说起,Connection表示了一个和数据库的链接,可以通过Connection来对数据库操作。在通常情况是Connection的属性是自动提交的,也就是说每次的操作真的更新了数据库,真的无法回退了。针对上述的例子,一旦库存更新失败了,订单无法回退,因为订单真的插入到了数据库中。这并不是我们希望的。

      我们希望的是:看起来成功了,但是没有真的操作数据库,知道我想让他真的发生。可以通过Connection的setAutoCommit(false)让Connection不自动提交你的数据,除非你真的想提交。那么如何让操作真的发生呢?可以使用Connection的commit方法。如何让操作回退呢?使用rollback方法。

      例如:

      try{

      Connection conn = getConnection(); // 不管如何我们得到了链接

      conn.setAutoCommit(false);

      // 插入订单

      // 修改库存

      conn.commit(); // 成功的情况下,提交更新。

      } catch(SQLException ex) {

      conn.rollback(); // 失败的情况下,回滚所有的操作

      } finally {

      conn.close();

      }

      这里有一点非常重要,事务是基于数据库链接的。所以在但数据库的情况下,事务操作很简单。

      那么如果表分布在两个不同的数据库中呢?

      例如订单表在订单库中,库存表在库存库中,那么我们如何处理这样的事务呢?

      需要注意,提交也可以遇到错误呀!

      try{

      Connection conn1 = getConnection1();

      Connection conn2 = getConnection2();

      // 基于conn1做插入操作

      // 基于conn2做更新操作

      try{

      conn1.commit()

      } catch(SQLExcetion ) {

      conn1.rollback();

      }

      try {

      conn2.commit();

      } catch(SQLException ) {

      conn2.rollbakc();

      // 保证肯定删除刚才插入的订单。

      }

      } catch(SQLException ex) {

      // 如果插入失败,conn1.rollback

      // 如果更新失败,conn1.rollback && conn2.rollback

      } finally {

      conn1.close();

      conn2.close();

      }

      看看上述的代码就知道,其实操作非常的复杂,甚至:保证肯定删除刚才插入的订单根本无法保证。

      在上述情况下的事务可以称之为分布式事务,通过上述的代码中事务同时提交处理的部分我们可以得出,要想处理分布式事务,必须有独立于数据库的第三方的事务处理组件。

      幸运的是通常情况下,JavaEE兼容的应用服务器,例如:Weblogic,Websphere,JBoss,Glassfish等都有这种分布式事务处理的组件。

      如何使用应用服务器的分布式事务管理器处理分布式事务?

      以galssfish为例

      1 建立对应两个数据库的XA(javax.sql.XADataSource)类型的数据源。

      2 使用UserTransaction来保证分布式事务。

      try{

      Connection conn1 = datasource1.getConnection();

      Connection conn2 = datasource2.getConnection();

      UserTransaction ut = getUserTransaction();

      ut.begin();

      // 插入订单

      // 修改库存

      ut.commit(); // 成功的情况下,提交更新。

      } catch(SQLException ex) {

      ut.rollback(); // 失败的情况下,回滚所有的操作

      } finally {

      conn.close();

      }

      如何获取UserTransaction呢?可以使用如下方法

      UserTransaction tx = (UserTransaction)

      ctx.lookup("jndi/UserTransaction");

  • 相关阅读:
    Linux 安装 jdk 后 jps 出现问题/usr/jdk1.8.0_151/bin/jps: /lib/ld-linux.so.2: bad ELF interpreter: No such
    Jackson 注解
    Git 右键添加Git Bash
    No validator could be found for constraint
    rror querying database. Cause: java.sql.SQLException: null, message from server: "Host '192.168.30.1' is not allowed to connect to this MySQL server"
    Linux 安装 Mysql-5.7.23-linux-glibc2
    Promise
    PAT(B) 1094 谷歌的招聘(Java)
    PAT(B) 1074 宇宙无敌加法器(Java)
    PAT(B) 1078 字符串压缩与解压(Java)
  • 原文地址:https://www.cnblogs.com/winkey4986/p/2362793.html
Copyright © 2011-2022 走看看