代码之家  ›  专栏  ›  技术社区  ›  Robbie

是否可以在数据库级别强制“子组”上的“自动增量”?

  •  0
  • Robbie  · 技术社区  · 14 年前

    在Rails中,我有以下内容

    class Token < ActiveRecord
      belongs_to :grid
      attr_accessible :turn_order
    end
    

    当您插入一个新的令牌时,turn-order应该自动递增。但是,对于属于同一网格的令牌,它应该只自动递增。

    因此,以4个令牌为例:
    标记_1属于格线_1,插入时转动顺序应为1。
    标记_2属于网格_2,插入时旋转顺序应为1。

    如果我将代币_3插入到网格_1中,则在插入时的转动顺序应为2。
    如果我将代币_4插入到网格_2中,则在插入时,旋转顺序应为2。

    还有一个额外的约束,假设我执行 @Token_3.turn_order = 1 现在 @Token_1 必须自动将其转向顺序设置为2,因为在这些“子组”中不能有转向顺序冲突。

    我知道mysql有auto-increment,我想知道是否有任何逻辑可以在db级别应用来强制这样的约束。基本上,在查询的子组中自动递增,这些子组基于一个外键。

    这是可以在数据库级别处理的,还是我应该努力在应用程序层实现坚如磐石的约束?

    3 回复  |  直到 14 年前
        1
  •  1
  •   Community Dan Abramov    7 年前

    如果我正确理解了您的问题,那么您可以使用以下两种方法之一(innodb与myisam)。就我个人而言,我会选择InnoDB道路,因为我喜欢Myisam不支持的聚集索引,我更喜欢性能而不是需要键入多少行代码,但这是你的决定……

    http://dev.mysql.com/doc/refman/5.0/en/innodb-table-and-index.html

    Rewriting mysql select to reduce time and writing tmp to disk

    完整的SQL脚本: http://pastie.org/1259734

    InnoDB实现(推荐)

    -- TABLES
    
    drop table if exists grid;
    create table grid
    (
    grid_id int unsigned not null auto_increment primary key,
    name varchar(255) not null,
    next_token_id int unsigned not null default 0
    )
    engine = innodb;
    
    drop table if exists grid_token;
    create table grid_token
    (
    grid_id int unsigned not null,
    token_id int unsigned not null,
    name varchar(255) not null,
    primary key (grid_id, token_id) -- note clustered PK order (innodb only)
    )
    engine = innodb;
    
    -- TRIGGERS
    
    delimiter #
    
    create trigger grid_token_before_ins_trig before insert on grid_token
    for each row
    begin
    
    declare tid int unsigned default 0;
    
      select next_token_id + 1 into tid from grid where grid_id = new.grid_id;
    
      set new.token_id = tid;
    
      update grid set next_token_id = tid where grid_id = new.grid_id;
    
    end#
    
    delimiter ;
    
    -- TEST DATA
    
    insert into grid (name) values ('g1'),('g2'),('g3');
    
    insert into grid_token (grid_id, name) values
    (1,'g1 t1'),(1,'g1 t2'),(1,'g1 t3'),
    (2,'g2 t1'),
    (3,'g3 t1'),(3,'g3 t2');
    
    select * from grid;
    select * from grid_token;
    

    myisam实施(不推荐)

    -- TABLES
    
    drop table if exists grid;
    create table grid
    (
    grid_id int unsigned not null auto_increment primary key,
    name varchar(255) not null
    )
    engine = myisam;
    
    drop table if exists grid_token;
    create table grid_token
    (
    grid_id int unsigned not null,
    token_id int unsigned not null auto_increment,
    name varchar(255) not null,
    primary key (grid_id, token_id) -- non clustered PK 
    )
    engine = myisam;
    
    -- TEST DATA
    
    insert into grid (name) values ('g1'),('g2'),('g3');
    
    insert into grid_token (grid_id, name) values
    (1,'g1 t1'),(1,'g1 t2'),(1,'g1 t3'),
    (2,'g2 t1'),
    (3,'g3 t1'),(3,'g3 t2');
    
    select * from grid;
    select * from grid_token;
    
        2
  •  1
  •   Steve Ross    14 年前

    我的观点是:在应用程序层面上有坚实的约束。你可以让它在SQL中工作——我看到一些人做了一些非常了不起的事情。过去很多SQL逻辑都被存放在触发器中,但最近我没有看到太多这样的情况。

    这闻起来更像业务逻辑,你完全可以用Ruby来完成它,而不用把自己裹在树上。还有…人们将能够看到测试并阅读代码。

        3
  •  0
  •   heavysixer    14 年前

    对我来说,这听起来像是您希望在after-save方法或观察者中处理的事情。如果模型本身不需要知道什么时候或者如何增加,那么我将把业务逻辑坚持在观察者中。这种方法将使递增逻辑对其他开发人员和数据库不可知论者更有表现力。