本窍门技巧从问题简单描述开始:定义组合数据库键这个键组合了多列唯地定义个数据库表行有时组合键也称为自然键 或业务键某些时候使用组合键原因是所选键在某些方面和最终用户业务领域相关联要定义组合键只需从该领域中选择些属性并将其组合在起提供所需行唯性程度组合键缺点是设计和编码略有难度此外组合键倾向于将您数据库和 ORM 设计绑定到原始领域后者可能会成为严重问题
实体代码
清单 1 展示了个名为 BillingAddress Java 类该类建模名个人或个组织账单邮寄地址账单本身和另个名为 PurchaseOrder Java 类关联这里并没有什么出人意料的处 — 下置购买订单接下来进行账单邮寄流程
清单 1. BillingAddress 类
import javax.persistence.*;
import java.io.Serializable;
@Embeddable
public BillingAddress implements Serializable {
private String street;
private String city;
BillingAddress {}
public BillingAddress(String street, String city) {
this.street = street;
this.city = city;
}
public String getStreet {
street;
}
private void Street(String street) {
this.street = street;
}
public String getCity {
city;
}
private void City(String city) {
this.city = city;
}
}
这里有必要介绍说明个要点该类实现了 Java Serializable 接口另外还要注意带有注释 @Embeddable 行此注释是组合键拼图中第块带有 @Embeddable 注释 Java 类本身可作为其他类子组件这听起来似乎有点复杂而实际并非如此作为演示清单 2 展示了 PurchaseOrder 类它使用清单 1 中 BillingAddress 类
清单 2. PurchaseOrder 类
import javax.persistence.*;
@Entity
@Table(name = "PURCHASE_ORDERS")
@IdClass(BillingAddress.)
public PurchaseOrder {
PurchaseOrder {}
PurchaseOrder(BillingAddress billingAddress) {
street = billingAddress.getStreet;
city = billingAddress.getCity;
}
@Id
@AttributeOverrides({
@AttributeOverride(name = "street",
column = @Column(name="STREET")),
@AttributeOverride(name = "city",
column = @Column(name="CITY"))
})
private String street;
private String city;
private String itemName;
public String getItemName {
itemName;
}
public void ItemName(String itemName) {
this.itemName = itemName;
}
}
注释总是有些难以理解清单 2 也不例外因此我会将其拆分成便于管理块第个注释是 @Entity指明该类是个数据库实体(也就是说它将构成 ORM 解决方案部分)通常看到 @Entity 注释就等于看到了对应数据库表后者由清单 2 中名为 @Table 相应注释表明我发现以这种方式拆分更容易理解
清单 2 中下个注释是 @IdClass它定义组合键类引用您可能已经注意到了该类引用清单 1 中 BillingAddress 类跳过清单 2 中构造思路方法注意 @Id 注释组合键就是在这里使用嵌套 @AttributeOverrides 注释定义这些注释用于定义组合键列:分别是 “STREET” 和 “CITY”
就在清单 2 注释的后您是否看到了来自清单 1 两行重复代码?当然重复代码是表示街道和城市两个私有数据成员这样重复是创建组合键所必需
数据库模式
至此讨论内容都是技术层面上现在我们将以更加具体方式表述此窍门技巧我们将生成个数据库模式清单 3 展示了来自这个非常简单 ORM 数据库设计模式
清单 3. 数据库模式
drop table PURCHASE_ORDERS exists;
create table PURCHASE_ORDERS (
street varchar(255) not null,
city varchar(255) not null,
itemName varchar(255),
primary key (street, city)
);
可以看到主键实际上是由 street 和 city 字段组合而成在真实数据库中 — 例如带有图形用户界面(GUI)工具数据库中这将得到怎样效果?在给出答案的前我编写了段简单客户端代码用于将个或两个实体保持到数据库中
清单 4 展示了段代码摘录例子化上文所定义类对象
清单 4. ORM 客户端代码摘录
// Start EntityManagerFactory
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("helloworld");
// First unit of work
EntityManager em = emf.createEntityManager;
EntityTransaction tx = em.getTransaction;
tx.begin;
PurchaseOrder purchaseOrder =
PurchaseOrder( BillingAddress("Broad Street", "Boston"));
purchaseOrder.ItemName("My computer");
em.persist(purchaseOrder);
tx.commit;
em.close;
清单 4 中代码展示了从 PurchaseOrder 对象例子化和设置直到此对象在数据库中持久化这个完整过程这实实在在地体现了 ORM 魔力让我们来看看发生了什么
首先创建个 EntityManagerFactory 例子随后使用此例子创建 EntityManager 个名为 em 例子后者随后用于将 PurchaseOrder 对象例子写入数据库保持到数据库中实际过程是在事务中完成
事务就是组原子操作可能全部成功完成或在出现时回滚如清单 4 所示EntityManager 对象用于创建 EntityTransaction 个名为 tx 例子后面这个对象将工作单元打包到事务中
请注意对 persist 和 commit 必须牢记除非同时出现这两个否则不能更改数据库这是 Java 持久 API(JPA)简单模式
为了完成 ORM 的旅图 1 展示了运行清单 4 中代码的后数据库状态代码是使用称为 HSQLDB 内存数据库测试这种产品包含个简单 GUI 工具图 1 显示了 HSQLDB 数据库状态可以看到我对 PURCHASE_ORDERS 表运行了 SQL 查询该表是通过模式创建模式本身是使用本文前面给出清单创建
图 1. 填充后数据库
在图 1 中可以看到清单 4 中这行代码产生效果:purchaseOrder.ItemName("My computer")对 ter 代码使用 String 数据 “My computer” 填充了数据库行中相关列就工作流而言可认为整个都是在创建新计算机购买订单时运行随后就是发票邮寄过程工作流中所有步骤都隐式地存储在数据库中
结束语
清单 1 和清单 2 中定义组合键允许您将多个列绑定在起列组合能提供所需唯性使您数据库表中能拥有任意数量行我们已经介绍了如何实现这目标现在您需要大致了解为什么要选择这种有些奇特数据库设计思路方法
使用组合键最常见原因或许就是为了向后兼容换句话说在您需要将新数据库代码整合到遗留环境中时候我认为如今故意以这样种方式设计数据库做法并不常见您只需要在符合惯例场合创建组合键
在这种情况下我认为对于这种思路方法讨论都是毫无意义如果组合键是标准那么就不可能很快发生变化在很多时候都有大量现有数据是使用这种思路方法构造因而如果组合键被数字键所取代那么遗留数据就必须进行迁移此外也有许多业务流程是对应组合键数据所有这些原因结合在起使组合键成为种必不可少技术
最新评论