例:    现有两个类Cla_A和Cla_B,Cla_B是一个父类,里面封装的是操作DB的方法,即别的类中要操作DB,如Insert、Updata、Delete或Select,只需调用Cla_B中相关类,传入相关参数就可以。我现在在Cla_A中有一个方法,其需要进行多个表的Insert操作,现在在Cla_A的方法中加入一个事务,在事务中间调用Cla_B中的相关方法,如果我最后一个Insert有问题,那个这事务会进行回滚操作,现在我想问的是:那在这个Insert之前的Insert会回滚吗?我现在遇到的问题是出现上述情况,那事务回滚是有问题的,事务没有起到其应有的作用。PS:我听说事务不能进行跨类或方法的,即操作出了事务所在方法就不会被纳入到事务中来,就像上面例中的情形一样。不知这种说法对不对?有没有办法实现上述例中的操作模式,并且事务也能起作用。在线等,万分感谢!!!

解决方案 »

  1.   

    事务transaction和类,方法的范围无关,它的范围取决于定义。
    lz先需要说明是用什么做事务的管理,EJB还是Spring Transaction Manager,或者Hibernate Transaction?
      

  2.   


    我们没有用Spring和Hibernate,用的是JDBC进行操作的,因为这是与手机端程序相关的,所以速度要求比较高。
      

  3.   

    LZ,如果你的Cla_B里的CRUD方法大约是这样的:Connection con = DB.getCon();
    ......
    con.close; //做完事马上关闭connection那么显然,Cla_A在调用这些方法的时候是没有机会控制事务的。如果Cla_B的CRUD方法是这样:Connection con = DB.getCurrentCon();
    ...... //只管取得已经打开的connection,把打开/关闭connection的责任交给调用方这样你的Cla_A才“有可能”具备管理事务的权限。涉及到具体的事务机制就得根据实际情况来说了,目前比较常见的事利用ThreadLocal来持有当前线程的connection。
      

  4.   

    把同一个session传来传去,就可以了,只要session不提交,都在事务控制范围内。可能你的类结构得改改,session的管理(开、关、提交、回滚)不要放在一个类里面,发起事务的代码控制
      

  5.   

    只要是在一个事务中,可以的。
    可以使用ThreadLocal,在当前线程中使用同一个连接
      

  6.   

    如4楼所言,共用一个物理连接就可以共享事务,B 方法本身比较全面地处理 DB 访问,现在你想加一个方法 A 做一部分事再调用 B 方法同时希望共享事务,那么只有让 A 来控制事务,因为 A 作为调用方在外面,它先得到连接相关的情况,如果当初 B 方法的连接是自己获取的而不是作为参数传进来的那么这时可能需要作为参数传进来,对于 Web 程序你也可以考虑像他们说的那样用 ThreadLocal 来获取连接,但要记得他们用 Web 时的另外一个约定:我们在 Servlet Filter 里面来处理连接申请和关闭的。或许作为参数传进来也不错的。楼主所言,事务在方法之外就不能被纳入事务范围我猜想可能有些人告诉你有些框架是这样的,但一般他们可能忘记了告诉那个框架有什么约定。比如 Web/EJB 我们配置一个资源引用时我们可以指定事务的边界是 method 还是 active session, 当我们指定了 method 时,在一个方法里面打开一个连接然后再调用另一个方法又打开另一个连接,这样的代码经常会得到应用服务器的一个警告,因为它怀疑你没有正确设置事务边界,而当我把外面的方法打开的连接作为参数传进被调用的方法时应用服务器就没有警告我了。当我们把事务边界设置为 Active Session 时就表示整个调用链都被纳入事务范围不管谁调用了谁,自我们进入激活事务的方法这道门开始直到从这道门出去。
      

  7.   


    我的操作是这样的:在Cla_A的方法中从连接池中获Connection,并在该方法中开启和提交(回滚)事务,在这中间调用Cla_B的CRUD方法。这样中间的操作会被纳入到事务中去吗?
      

  8.   

    部分代码如下:
    Cla_A中:....
    con = dbPool.getSqlConn();
    con.setAutoCommit(false);
    ....
    sql = (String) SimpleProperties.getStaticProperties().get("INSERT_ORDER_HEADERS");
    insertDatasToDB_Code(sql, insertOrderHeadTemp_);
    ....
    con.commit();
    Cla_B:....
    public String insertDatasToDB_Code(String sql, String[] parameter) throws SQLException {
    String code = "-1";
    PreparedStatement ps = null;
    String l_sql = SqlTransform.transSql(sql, parameter); try {
    if (con != null) {
    con.close();
    con = null;
    }
    con = dbPool.getSqlConn();

    ps = con.prepareStatement(l_sql);
    ps.executeUpdate();
    code = "-1";
    } catch (SQLException ex) {
    // 2627为违反主键约束错误代码
    // ex.printStackTrace();
    code = "" + ex.getErrorCode();
    log.info("操作数据库异常代码:" + code);
    log.error("insertDatasToDB_Code Error: " + ex.getMessage());
    log.error("SQL: " + l_sql);
    } catch (Exception ex) {
    ex.printStackTrace();
    log.error(ex.getMessage());
    log.error("SQL: " + l_sql);
    } finally {
    if (ps != null) {
    ps.close();
    ps = null;
    }
    if (con != null) {
    con.close();
    con = null;
    }
    }
    return code;
    }
    ....
      

  9.   

    谢谢各位大大,事务已经解决了,但有一个新的问题,那就是SQL是表锁定的,事务有没有地办法用行级锁?