【问题标题】:Database data integrity issue数据库数据完整性问题
【发布时间】:2011-06-23 08:41:33
【问题描述】:

我需要创建一个 Windows 服务(每 5 分钟处理一次数据)

  1. 从 Table1(Queue table) (MSSQL) 中获取每条记录

  2. 将该记录插入各种 表 Table2, 3, 4, 5 (MySQL) (与 引擎 MyISAM)

  3. 插入表 1 和表 2 中的数据 进入Table3(映射表)(MSSQL)

  4. 再次从Table1中删除记录。

如何有效地做到这一点,因为 MySQL 似乎不支持事务。 我可以使用 TransactionScope 吗?或者如果下一步发生错误,我应该手动删除上一步创建的记录。我正在使用 MySQL 连接器和 Linq2SQL。任何建议都会有所帮助。谢谢。

【问题讨论】:

    标签: mysql sql-server-2008 database-connection


    【解决方案1】:

    MySQL 确实支持事务,但不支持 MyISAM,如果您需要事务,则必须使用 InnoDB 或类似的引擎。

    有一个技巧,您可以使用并仍然保留 MyISAM 并进行交易(有点)。
    以下是如何吃蛋糕和吃蛋糕的方法:-)。

    第 1 步
    创建黑洞表

    CREATE TABLE bh_insert_tables 
       t1.pk integer,
       t2field1 varchar(45),
       t2field2 integer,
       ....
       t3field1 integer,
       .... etc for all tables
       ) ENGINE = BLACKHOLE;
    

    第 2 步
    创建一个内存表将虚拟事务存储到

    CREATE TABLE my_rollback
       id unsigned integer auto_increment primary key,
       last_insert integer not null,
       tablename varchar(15) not null,
       index last_insert using hash ('last_insert'),
       index tablename using hash ('tablename') 
    ) ENGINE = MEMORY;
    
    CREATE TABLE status
      id unsigned integer auto_increment primary key,
      insert_id integer not null,
      success boolean not null,
      index insert_id using hash ('insert_id')
    ) ENGINE = MEMORY;
    

    第 3 步
    在插入时触发的黑洞表上放置一个触发器。
    此触发器还将向 MyISAM 添加事务支持(某种)。

    DELIMITER $$
    
    CREATE TRIGGER ai_bh_insert_each AFTER INSERT ON bh_insert FOR EACH ROW
    BEGIN
      DECLARE table1ID integer;
      DECLARE error boolean;
    
      DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
      BEGIN
         SET error = TRUE;
      END;
    
      SET error = FALSE;
    
      INSERT INTO table2 (field1, field2, field3) VALUES (NEW.t2field1, NEW.t2field2, NEW.t2field3);
      IF not(error) THEN BEGIN  
        INSERT INTO my_rollback (last_insert, tablename) VALUES (LAST_INSERT_ID(), 'table2');
        INSERT INTO table3 (field1,field2) VALUES (NEW.t3field1, NEW.t3field2);
      END; END IF;
      IF NOT(error) THEN BEGIN
        INSERT INTO my_rollback (last_insert, tablename) VALUES (LAST_INSERT_ID(), 'table3');
        INSERT INTO table4 .......
      END; END IF;
      IF error THEN BEGIN  /*do_rollback*/ 
        DELETE table2 FROM table2
        INNER JOIN my_rollback ON table2.id = my_rollback.last_insert
        WHERE my_rollback.tabelname = 'table2';
    
        DELETE table2 FROM table2 .......
        INSERT INTO status (insert_id, success) VALUES (NEW.pk, false);
      END; 
      ELSE BEGIN
        INSERT INTO status (insert_id, success) VALUES (NEW.pk, true);
      END; END IF;
      /*Clear my_rollback for the next insert*/
      DELETE FROM my_rollback WHERE id IS NOT NULL;
    END $$
    
    DELIMITER ;
    

    在您的插入例程中,您可以查询表 status 以查看 MSSQL 中 table1 中的哪些记录插入成功,哪些记录失败。

    链接:
    http://dev.mysql.com/doc/refman/5.0/en/blackhole-storage-engine.html
    http://dev.mysql.com/doc/refman/5.0/en/triggers.html
    http://dev.mysql.com/doc/refman/5.5/en/create-trigger.html
    http://dev.mysql.com/doc/refman/5.5/en/delete.html
    http://dev.mysql.com/doc/refman/5.5/en/declare-handler.html

    【讨论】:

    • 所有这些都是为了避免innoDB?那是,嗯,令人印象深刻!我想。
    • @Ariel,你应该一直使用 InnoDB,它比 MyISAM 还要光年,但如果你不能使用它,你需要有创意,尽管请随意投票:-)。
    【解决方案2】:

    MySQL 支持事务,只需使用 innoDB 代替 MyISAM。

    如果任一数据库发生错误,请不要忘记回滚两个数据库中的事务。

    【讨论】:

    • MySQL 数据库已投入生产。他们不允许我们对其进行任何修改。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-31
    相关资源
    最近更新 更多