通过编程写入触发器或执行操作?

问题描述:

我是新手。我正在编写一个连接到Oracle 9i数据库的Java应用程序。我需要强制执行我的应用程序像一些规则:通过编程写入触发器或执行操作?

委员会的主席必须添加/删除,成员在委员会B.

有需要被执行大约10这样的规则。我处于一个两难的境地,无论是通过编写触发器还是通过编程在我的应用程序中来实施这些规则。

我欣赏任何建议。

感谢,

我可能是错的,但你说的是像一个实际的业务规则的声音是什么(Comittee A的主席必须是B的成员,或者不能为B的成员)。国际海事组织,这应该由应用程序而不是数据库来处理。

+0

+1在代码中的业务逻辑。就我个人而言,我认为触发器对绝大多数目的都是邪恶的。 – 2009-12-08 16:09:34

+1

@戴夫Swersky:我们使用触发器来保持在一个非常重要的数据录入应用程序(因此所有数据项发生变化输入到数据库表)的审计线索,这就是它。所有这些触发器都在做,虽然,在一个表中插入记录(指示值changea和操作的类型,以及侦探小说)。我肯定不希望我的触发器改变其他表中的数据。 – peacedog 2009-12-08 16:15:34

专门解决数据完整性的规则在数据库中得到执行。规则是更合乎逻辑/业务规则,我不认为属于在数据库,因为

  • 他们是不可见的应用程序代码
  • 他们更可能是可变的,而这会带来不便如果他们被烘烤到数据库。

我更希望看到数据库强制执行的事情类型是“委员会记录名称不能为空”,即数据完整性所必需的事情。

假设这些规则与有关组织的政策相关 - 即“所有委员会主席必须是至少一个其他委员会的成员”或“没有委员会必须少于两名成员”,那么您应该可能把它们放在Java中。 Java是比SQL和RDBMS更灵活的编程环境。

说你的规则是“没有委员会主席可以成为任何其他委员会的成员”。你可能会实现这样的:

public class Committee { 

    private Person chairman; 
    private Set<Person> members; 

    public Person getChairman() { 
     return chairman; 
    } 

    public void setChairman(Person person) { 
     for (Committee other : person.getMemberships() { 
      other.removeMember(person); 
     } 
     chairman = person; 
     addMember(person); 
    } 

    public void addMember(Person person) { 
     members.add(person); 
     person.addMembership(this); 
    } 

    public void removeMember(Person person) { 
     members.remove(person); 
     person.removeMembership(this); 
    } 

    public Set<Person> getMembers() { 
     return new HashSet<Person>(members); 
    } 
} 

public class Person { 

    private Set<Committee> memberships = new HashSet<Committee>(); 

    public Set<Committee> getMemberships() { 
     return new HashSet<Committee>(memberships); // Return a copy, not the original 
    } 

    public void addMembership(Committee committee) { 
     memberships.add(committee); 
    } 

    public void removeMembership(Committee committee) { 
     memberships.remove(committee); 
    } 

} 

然后,您可以编写单元测试委员会确认为主席的规则工作,他们会跑得很快,因为他们不会需要数据库。

public class CommitteeTest { 

    @Test 
    public void testChairmanship() { 

     // Set up the initial conditions 
     Person person = new Person(); 
     Committee other = new Committee(); 
     Commiteee commitee = new Committee(); 
     other.addMember(person); 

     committee.setChairman(person); 
     assertTrue(committee.getChairman().equals(person)); 
     assertFalse(other.getMembers().contains(person)); 
    } 
} 

(您可能想使用一个模拟对象的人,因为这个单元测试应该仅测试委员会)

当您添加更多的规则,你将增加更多的单元测试,那么会继续快速运行。

+0

记住,这些“强制执行”如果有多人同时工作经常中断。例如,某人在与其他人同时向某个委员会加入人员使他们担任主席的情况下。要真正实施这些规则的唯一方法是序列化操作,以便在确定测试期间状态是否固定的情况下完成任何验证测试。 – 2009-12-10 22:19:20

我认为如果一个约束可以在数据库中执行,那么它应该是,但是应用程序应该尝试首先执行它,并且数据库应该只作为备份来使用 - 故障安全,if你喜欢。

但是在RDBMS中有一些难以实施的限制,这个例子就是其中之一。这很难,因为数据库的本地约束类型(独特的,检查,引用等)不允许你强制执行它,你将不得不恢复到触发器或物化视图等等。触发器是在强制约束可怕,因为查询的隔离级别可能会导致一些违反打滑,而且他们也无法读取或修改受影响的表(变异表的问题)。

是公平的,虽然应用程序级的约束检查从查询隔离级别,因此,使用的数据库约束作为备份同样的问题困扰。

+0

我同意。任何业务规则应该尽可能低。如果您在数据库中执行业务规则,那么当您重新编写客户端或编写额外的iPhone Widget时,业务规则仍然存在。但是,如果您发现自己在非正常的环境中跳跃以使触发器执行您的业务规则,那么不要担心它太多 - 它可能只是应用程序级别的业务规则。 – 2009-12-10 23:00:08