对于现在的大多数场景下,面向数据库编程对于实现功能来说是十分方便的,门槛比较低。主要三把斧,建表,orm框架生成dao方法,然后service层对dao进行复杂操作。最后可以封装接口提供给下游服务使用。但是对于一个复杂的场景来说,对于每张表进行各自的增删改查,这样的模型是松散的。以下介绍一个订单的简单例子。对于订单,在订单上下文中属于聚合根,根据领域驱动设计的命令事件法,命令是下订单,返回的事件是订单已生成。因此,我们此文通过对订单这个聚合根的讲解,来突出聚合对于整个业务逻辑的好处。
一般我们在电商网站下单,需要付钱,需要填写地址等。因此,订单肯定有订单号、费用以及用户的收件地址,对于事件来说会存在一个状态。比如下单后会存在待付款、已付款、运送中等多个状态。对于一个订单我们可能会买多个物品,因此在订单中有多个条目。存在一对多的关系,因此item(条目)可以单独成表,与订单表是多对一的关系。至于订单聚合根中地址状态可以与订单同一个状态,也可以分开。与订单形成一对一的关系。本文中讲解的例子是分开。以下是本文讲解订单案例的数据库ER图。
上述数据库关联的sql语句如下:
use order_s;
create table order_table(
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键id',
`order_name` varchar(64) NULL DEFAULT NULL COMMENT '订单名称' ,
primary key(`id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
create table order_item (
`product_id` varchar(64) NULL DEFAULT NULL COMMENT '产品id' ,
`qty` int(11) NULL DEFAULT 0 COMMENT "金额" ,
`order_table` int(11) NULL DEFAULT 0 COMMENT '订单id' ,
`order_table_key` int NOT NULL AUTO_INCREMENT COMMENT '主键id',
primary key(`order_table_key`),
CONSTRAINT `order_item_ibfk` FOREIGN KEY(`order_table`) REFERENCES `order_table` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
create table address (
`street` varchar(64) NULL DEFAULT NULL COMMENT '街道',
`zip` varchar(64) NULL DEFAULT NULL COMMENT '位置' ,
`order_table` int(11) NULL DEFAULT 0 COMMENT '订单id' ,
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键id',
PRIMARY KEY (`id`),
CONSTRAINT `address_ibfk` FOREIGN KEY(`order_table`) REFERENCES `order_table` (`id`) ON DELETE CASCADE ON UPDATE CASCADE)ENGINE=InnoDB DEFAULT CHARSET=utf8;
create table order_status (
`state` int(11) NULL DEFAULT 0 COMMENT '状态' ,
`order_table` int(11) NULL DEFAULT 0 COMMENT '订单id' ,
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键id',
PRIMARY KEY (`id`),
CONSTRAINT `status_ibfk` FOREIGN KEY(`order_table`) REFERENCES `order_table` (`id`) ON DELETE CASCADE ON UPDATE CASCADE)ENGINE=InnoDB DEFAULT CHARSET=utf8;
根据数据库模型给出demo。
order类代码:
根据Order类可以看出Order这个聚合根与OrderItem是一对多的关系,与Address和OrderStatus都是一对一的关系。除了通过@OneToOne和@OneToMany注释建立关联。同时需要在被关联对象中建立与维护端的关系,如下列代码中的代码片段在address赋值之后,同时需要将当前order对象赋值给Address对象中关联的order属性。这样两者便相互建立了关系。
private Order(Address address, Collection<OrderItem> items,String name) {
this.m_Address = address;
this.m_OrderStatus = new Placed();
this.name = name;
//需要与维持方建立关系,这里订单与地址一对一的关系,地址需要与订单建立关系
m_Address.setOrder(this);
this.items = items.stream().map(r->{
r.setOrder(this);
return r;}).collect(Collectors.toList());
m_OrderStatus.setOrder(this);
* ClassName Order
* @author carson
* @description
* @Version V1.0
* @createTime
@Table(name = "order_table")
@Entity
@Proxy(lazy = false)
public class Order {
@OneToOne(mappedBy = "order",fetch=FetchType.LAZY,cascade = CascadeType.ALL)
//@JsonBackReference
private Address m_Address;
@OneToOne(mappedBy = "order",fetch=FetchType.LAZY,cascade = CascadeType.ALL)
private OrderStatus m_OrderStatus;
@OneToMany(mappedBy = "order",cascade = CascadeType.ALL,fetch = FetchType.LAZY)
//@JsonBackReference
private Collection<OrderItem> items;
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name = "order_name")
private String name;
public Order() {
items = new ArrayList<>();
m_OrderStatus = new Placed();
public int getId() {
return id;
public void setId(int id) {
this.id = id;
public void addItem(OrderItem item) {
items.add(item);
public Collection<OrderItem> getItems() {
return items;
public void setItems(Collection<OrderItem> items) {
this.items = items;
public Address getM_Address() {
return m_Address;
public void setM_Address(Address m_Address) {
this.m_Address = m_Address;
public OrderStatus getM_OrderStatus() {
return m_OrderStatus;
public String getName() {
return name;
public void setName(String name) {
this.name = name;
public boolean setM_OrderStatus(OrderStatus m_OrderStatus) {
if(m_OrderStatus==null){
return false;
OrderStatus status = getM_OrderStatus();
if(status==null){
return false;
OrderStatus orderStatusN = status.next();
if (orderStatusN.getState() == m_OrderStatus.getState()) {
this.m_OrderStatus = orderStatusN;
return true;
} else
return false;
private Order(Address address, Collection<OrderItem> items,String name) {
this.m_Address = address;
this.m_OrderStatus = new Placed();
this.name = name;
//需要与维持方建立关系,这里订单与地址一对一的关系,地址需要与订单建立关系
m_Address.setOrder(this);
this.items = items.stream().map(r->{
r.setOrder(this);
return r;}).collect(Collectors.toList());
m_OrderStatus.setOrder(this);
public static OrderVOBuilder builder() {
return new OrderVOBuilder();
public static class OrderVOBuilder{
private Address address;
private Collection<OrderItem> items;
private String name;
public OrderVOBuilder withAddress(Address address) {
this.address = address;
return this;
public OrderVOBuilder withItems(Collection<OrderItem> items) {
this.items = items;
return this;
public OrderVOBuilder withName(String name){
this.name = name;
return this;
public Order build() {
return new Order(address, items,name);
OrderItem:
* ClassName OrderItem
* @author carson
* @description
* @Version V1.0
* @createTime
@Entity
@Table(name = "order_item")
@Proxy(lazy = false)
public class OrderItem {
@Column(name = "product_id")
private String productId;
private int qty;
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "order_table_key")
private int order_table_key;
//JoinColumn中name是表中的外键名,referencedColumnName代表关联表的字段
@ManyToOne
@JoinColumn(name = "order_table",referencedColumnName = "id")
@JsonBackReference
private Order order;
public void setOrder_table_key(int order_table_key) {
this.order_table_key = order_table_key;
public Order getOrder() {
return order;
public void setOrder(Order order) {
this.order = order;
Address:
JPA自带的注释@OneToOne,同时@JoinColumn注释来将外键与关联表的主键关联起来。
* ClassName Address
* @author carson
* @description
* @Version V1.0
* @createTime
@Table(name = "address")
@Entity
@Proxy(lazy = false)
public class Address {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name = "street")
private String street;
@Column(name = "zip")
private String zip;
@OneToOne(targetEntity = Order.class)
@JoinColumn(name = "order_table",referencedColumnName = "id")
@JsonBackReference
private Order order;
public Order getOrder() {
return order;
public void setOrder(Order order) {
this.order = order;
public Address() {
public int getId() {
return id;
public void setId(int id) {
this.id = id;
public String getStreet() {
return street;
public void setStreet(String street) {
this.street = street;
public String getZip() {
return zip;
public void setZip(String zip) {
this.zip = zip;
OrderStatus:
* ClassName OrderStatus
* @author carson
* @description
* @Version V1.0
* @createTime
@Table(name = "order_status")
@Entity
@Proxy(lazy = false)
@ToString
public class OrderStatus {
protected int state = -1;
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@OneToOne(targetEntity = Order.class)
@JoinColumn(name = "order_table",referencedColumnName = "id")
@JsonBackReference
private Order order;
public OrderStatus(){
public int getId() {
return id;
public void setId(int id) {
this.id = id;
public Order getOrder() {
return order;
public void setOrder(Order order) {
this.order = order;
public OrderStatus(int state) {
this.state = state;
public int getState() {
return state;
public void setState(int state) {
this.state = state;
//切换的时候记得把其他的都要copy过来,仅有状态发生改变
public OrderStatus next() {
OrderStatus orderStatus = null;
if (state == 0) {
state = state+1;
else if (state == 1) {
state = state+1;
} else {
state = -1;
return this;
OrderStatus有三个子类
Payment:
* ClassName Payment
* @author carson
* @description
* @Version V1.0
* @createTime
public class Payment extends OrderStatus {
public Payment() {
super(1);//表示已支付
public OrderStatus next() {
return new Delivery();
Placed:
* ClassName Placed
* @author carson
* @description
* @Version V1.0
* @createTime
public class Placed extends OrderStatus {
public Placed() {
super(0);
@Override
public OrderStatus next() {
return new Payment();
Delivery:
* ClassName Delivery
* @author carson
* @description
* @Version V1.0
* @createTime
public class Delivery extends OrderStatus {
public Delivery() {
super(2);//已发货
@Override
public OrderStatus next() {
return null;
* ClassName OrderRepository
* @author carson
* @description
* @Version V1.0
* @createTime
public interface OrderRepository extends CrudRepository<Order,Integer> {
* ClassName OrderController
* @author carson
* @description
* @Version V1.0
* @createTime
@RestController
@Transactional(rollbackFor = Exception.class)
public class OrderController {
@Resource
private OrderRepository orderRepo;
@PostMapping("/orders")
public Order placeOrder(@RequestBody OrderItem orderItem,
@RequestParam String name,
@RequestParam String street,
@RequestParam String zip) {
Collection<OrderItem> orderItems = new ArrayList<>();
((ArrayList<OrderItem>) orderItems).add(orderItem);
Order order = Order.builder().withName(name).withAddress(createAddress(street,zip)).withItems(orderItems).build();
System.out.println("order:"+order);
return orderRepo.save(order);
@PutMapping("/orders/updateAddress")
public Order updateAddress(@RequestParam String street,@RequestParam Integer orderId,@RequestParam String zip){
Order order = orderRepo.findById(orderId).orElse(new Order());
Address address = order.getM_Address();
if(Objects.isNull(address)){
address = createAddress(street, zip);
}else {
address.setZip(zip);
address.setStreet(street);
order.setM_Address(address);
return orderRepo.save(order);
@PostMapping("/orders/payment")
public Order payment(@RequestParam Integer orderId) {
Order orderSaved2 = orderRepo.findById(orderId).orElse(new Order());
if (orderSaved2.setM_OrderStatus(new Payment()))
orderRepo.save(orderSaved2);
return orderSaved2;
@PostMapping("/orders/delivery")
public Order delivery(@RequestParam Integer orderId) {
Order orderSaved2 = orderRepo.findById(orderId).orElse(new Order());
if (orderSaved2.setM_OrderStatus(new Delivery()))
orderRepo.save(orderSaved2);
return orderSaved2;
1.一对多和一对一都需要在被维护端的实例中建立与维护端的相互关系
2.注意@Id注释不要引错包,org.springframework.data.annotation.Id;会带来实体转换的错误,切记要引用javax.persistence.Id;
具体代码可以在github上下载,地址:https://github.com/carson0408/order
5.1 简介
在上一章中,我们已经说明了状态管理的多版本方法,其中突变被分成两个不同的阶段:只处理计算的计算阶段和向前移动状态引用的提交阶段。
通常,在生产系统中,突变同时发生。像我们在上一章中所做的那样天真地推进状态是不合适的。在本章中,我们将学习如何处理并发突变。
在DO中,只有提交阶段的代码是有状态的,这一事实允许我们利用不涉及任何锁定机制的乐观并发控制策略。因此,读写吞吐量很高。
对代码的修改不是微不足道的,因为我们必须实现一个协调并发突变之间的算法。但是修改只
通过将代码与数据分离来降低系统复杂性
2.1简介
正如我们在第0章中提到的,面向数据编程(DO)的最大洞察力在于,我们可以通过将代码与数据分开来降低系统的复杂性。事实上,当代码与数据分离时,我们的系统由两个可以分开考虑的主要部分组成:数据实体和代码模块。
本章深入探讨了面向数据编程的第一个原则:
NOTE 原则#1:以代码驻留在函数中的方式将代码与数据分开,这些函数的行为不依赖于以某种方式封装在函数上下文中的数据。
我们在第1章介绍的图书馆管理系统的上下文中说明了代码和数据的分离,并揭示了这
使用成本低。开源的,且提供免费版本。
容易使用。与其他大型数据库的设置和管理相比,其复杂程度较低,易于使用。
可移植性强。能够运用于多种系统平台上。【Windows、Linux、UNIX】等。
适用更多用户。支持最常用的数据管理功能,适用于中小型企业甚至大型网站应用。
命令行方式操作MySQL数据库
数据库类型
系统数据库:
information
面向对象:建立解决问题所需的各个模型(类)。
面向数据:考虑数据的存取及布局(数据)。
值得一说的是,面向过程和面向对象都是解决问题的一种方法,而面向数据只是一种优化的设计思想,而非解决问题的方法。
冷数据/热数据分割
我们希望CPU缓存存储的是经常使用的数据,而不是那些少用的数据。这就引入了冷数据/热数据分割的概念了。
热数据:经常要操作使用的数据,我们一般可
数据库编程 面向对象版2018,学生考务管理系统 某学院需要一个简易选课系统,学生可以选修多门课程;每门课程可以有多个学生选修,并限定选课人数上限。
系统功能如下:
需具有选课、登记成绩等基本功能;
每学期末学院可查看各学生平均成绩、各课程平均成绩、不及格学生名单及门数
能自动统计某门课程的考试人数、最高分、最低分、平均分、100-90分段百分比、90-80分段百分比、80-70分段百分比、70-60分段百分比、60-0分段百分比
能自动统计某学生每学期平均成绩的变化曲线
对成绩修改进行严格管理,每次调高成绩都应有记录
在我们JavaWeb开发过程中,或多或少会有些只是几行sql语句的service方法或是http请求,总是要反复写Controller层、service层、dao层。于是,我做了一个大胆的尝试,对于此类方法,封装出一个公共方法,不需要写java代码,写几行sql语句就能出各种接口及方法。
description
creator
creattime
updateti...
1.2.1 什么是O/R Mapping如果我们采用面向对象的思想进行系统的分析设计,那么数据库采用关系型数据库就会存在对象模型和关系模型两者之间“不匹配”这个不容忽视的问题。面向对象设计和关系型数据库设计存在很大的不同。对象模型基于软件工程的一些原理,面向对象设计的理论包括封装、关联、聚合、继承、多态,而关系模型主要针对数据的存储。我们希望通过面向对象的设计方式来完成业务流程,这一点可以实现