各位大侠帮忙看看这个事务存储过程写的有什么问题?大概意思是创建一个家庭。参数:为创建者ID,创建者名字,和家庭名称
返回:是否成功,家庭ID涉及到三个表,必须要保证都插入了才算正确,否则就要回滚!!
  SET AUTOCOMMIT = 0;
  START TRANSACTION;
--------------------
这么用可以吗?这样用的目的是为了防止多个存储过程对其进行操作。DELIMITER $$DROP PROCEDURE IF EXISTS `family_create` $$
CREATE DEFINER=`root`@`localhost` PROCEDURE `family_create`(IN nGlobalID INT, IN szCreaterName CHAR(32), IN szFamilyName CHAR(32))
    COMMENT 'create the family'
BEGIN  DECLARE ret_value INT;
  DECLARE ret_family_id INT;
  DECLARE family_count INT;  SET ret_value = 1;
  SET ret_family_id = -1;
  SET family_count = 0;  SET AUTOCOMMIT = 0;
  START TRANSACTION;  SELECT count(*) INTO family_count FROM database.family_member where MemberID = nGlobalID;
  IF family_count = 0 THEN    INSERT INTO database.family_info ...
    IF ROW_COUNT() = 1 THEN        SET ret_family_id = LAST_INSERT_ID();        INSERT INTO database.family_member ...
        IF ROW_COUNT() = 1 THEN          INSERT INTO database.family_log ...          IF ROW_COUNT() = 1 THEN
            SET ret_value = 0;
          ELSE
            SET ret_value = -1;
          END IF;        ELSE
            SET ret_value = -2;
        END IF;
    ELSE
      SET ret_value = -3;
    END IF;  ELSE
    SET ret_value = -4;
  END IF;  IF ret_value = 0 THEN
    COMMIT;
  ELSE
    ROLLBACK;
  END IF;  SELECT ret_value, ret_family_id;END $$DELIMITER ;====================================================================还有一个问题,就是写存储过程的时候,我看很多人这样
CALL t(@a)
然后再
SELECT @a
来获取返回值
为什么不直接把SELECT这个放在储存过程中呢?
这样我们直接CALL t()的时候,直接就相当于CALL t(@a) & SELECT @a。
why?====================================================================
mysql文档里面有个串行化事务,请问如何串行化?

解决方案 »

  1.   

    [code]
    DELIMITER $$DROP PROCEDURE IF EXISTS `family_create` $$
    CREATE DEFINER=`root`@`localhost` PROCEDURE `family_create`(IN nGlobalID INT, IN szCreaterName CHAR(32), IN szFamilyName CHAR(32))
      COMMENT 'create the family'
    BEGIN  DECLARE ret_value INT;
      DECLARE ret_family_id INT;
      DECLARE family_count INT;  SET ret_value = 1;
      SET ret_family_id = -1;
      SET family_count = 0;  SET AUTOCOMMIT = 0;
      START TRANSACTION;  SELECT count(*) INTO family_count FROM database.family_member where MemberID = nGlobalID;
      IF family_count = 0 THEN  INSERT INTO database.family_info ...
      IF ROW_COUNT() = 1 THEN  SET ret_family_id = LAST_INSERT_ID();  INSERT INTO database.family_member ...
      IF ROW_COUNT() = 1 THEN  INSERT INTO database.family_log ...  IF ROW_COUNT() = 1 THEN
      SET ret_value = 0;
      ELSE
      SET ret_value = -1;
      END IF;  ELSE
      SET ret_value = -2;
      END IF;
      ELSE
      SET ret_value = -3;
      END IF;  ELSE
      SET ret_value = -4;
      END IF;  IF ret_value = 0 THEN
      COMMIT;
      ELSE
      ROLLBACK;
      END IF;  SELECT ret_value, ret_family_id;END $$DELIMITER ;[/code]
      

  2.   

    不过 IF ROW_COUNT() = 1 THEN 的意义在事务中并无实际作用。如果INSERT INTO database.family_info ..失败,则整个事务会回滚。 你可以自己做个试验。
      

  3.   

    这个和编程习惯有关。 CALL t(@a)更符合模块间的松耦合性。就和设计一个程序函数一样,通过接口进行传递。
    另外在MYSQL的FUNCTION中也允许有 SELECT @a。一种编程习惯而已,就象各种变量命名规则,可以遵守,也可以不遵守。
      

  4.   

    call t(@a) 和 在存储过程里写select @a,再CALL 都一样,像狼头哥说的,个人习惯问题..
      

  5.   


    MySQL 的还没用过这个啊。
      

  6.   

    事务可以了,
    至于返回变量的问题,也可以用保存到表中的方法,为什么不直接把SELECT这个放在储存过程中呢?
    主要要取返回值
      

  7.   


    CALL t(@a) & SELECT @a  这个在存储过程逻辑操作后返回单个值的时候用。比如通过N多步骤,得到一个学校学生的人数总和,单个值。SELECT这个放在储存过程中,在返回一个记录集的时候用。比较通过N多步骤,要求得到学校学生排名的前100名的姓名,学号,班级,成绩  ,这样的情况下就不适应select @a.
      

  8.   

    一个存储过程内的事务例子:create PROCEDURE aa(SqlCMD1 varchar(8000),SqlCMD2 varchar(8000),SqlCMD3 varchar(8000))
    begin 
        declare exit handler for sqlexception rollback;
        start TRANSACTION;
        
        PREPARE stmt_name FROM SqlCMD1;
        EXECUTE stmt_name;
        DEALLOCATE stmt_name;
        PREPARE stmt_name FROM SqlCMD2;
        EXECUTE stmt_name;
        DEALLOCATE stmt_name;
        PREPARE stmt_name FROM SqlCMD3;
        EXECUTE stmt_name;
        DEALLOCATE stmt_name;
        COMMIT;
    end#drop PROCEDURE aa
      

  9.   

    SET AUTOCOMMIT = 0;
    START TRANSACTION;--------------------
    这么用可以吗?
      

  10.   

    你的意思是只有insert这种属于数据库出错才自动回滚是吗?而影响的行数为0不会自动回滚是吧?如果delete的话,我就需要判断影响的行数?
    否则就算delete影响的行数为0,我也想继续执行,是不是就得判断了。
      

  11.   

    你的这一行是不是表示出错自动回滚?
    是你的意思是只有insert这种属于数据库出错才自动回滚是吗?而影响的行数为0不会自动回滚是吧?与影响的行数没有关系,与SQL语句执行是否正常有关系
      

  12.   

    INSERT如果影响的行数为0,说明有错误发生了,数据库出错 -》 自动回滚DELETE则不一定,因为DELETE了0行也对数据库来说语句也正确执行了。