MySQL的事件溯源Event Sourcing表結構
-- EVENT STORE事件儲存表 CREATE TABLE events ( sequence BIGINT UNSIGNED PRIMARY KEY, event_type VARCHAR(32) NOT NULL, aggregate_type VARCHAR(32) NOT NULL, aggregate_id CHAR(36) NULL, payload JSON NOT NULL, recorded_at DATETIME NOT NULL, KEY idx_event_type (event_type), KEY idx_aggregate_id (aggregate_id), KEY idx_aggregate_type (aggregate_type) ) // -- EVENT STORE TRIGGERS觸發器 -- Before Insert CREATE TRIGGER events_before_insert BEFORE INSERT ON events FOR EACH ROW BEGIN DECLARE next_sequence BIGINT DEFAULT 0; SELECT COALESCE(new.sequence, COALESCE(MAX(sequence), 0) + 1) FROM events INTO next_sequence; SET new.sequence = next_sequence; SET new.recorded_at = COALESCE(new.recorded_at, NOW()); END // -- Before Update CREATE TRIGGER events_before_update BEFORE UPDATE ON events FOR EACH ROW BEGIN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '[E001] The event store is immutable (append only), updating events is not allowed.'; END // -- Before Delete CREATE TRIGGER events_before_delete BEFORE DELETE ON events FOR EACH ROW BEGIN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '[E001] The event store is immutable (append only), deleting events is not allowed.'; END // -- EVENT STORE RECORDING MECHANISM CREATE PROCEDURE record_event (IN event_type VARCHAR(32), IN aggregate_type VARCHAR(32), IN aggregate_id CHAR(36), IN payload JSON) BEGIN DECLARE recorded_at DATETIME DEFAULT NOW(); DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN ROLLBACK; RESIGNAL; END; START TRANSACTION; INSERT INTO events (event_type, aggregate_type, aggregate_id, payload, recorded_at) VALUES (event_type, aggregate_type, aggregate_id, payload, recorded_at); CALL process_event(event_type, aggregate_id, payload, recorded_at); COMMIT; END // -- EVENT HANDLING CREATE PROCEDURE process_event (IN event_type VARCHAR(32), IN aggregate_id CHAR(36), IN payload JSON, IN recorded_at DATETIME) BEGIN DECLARE handler_name VARCHAR(38) DEFAULT CONCAT('handle', event_type); DECLARE EXIT HANDLER FOR 1305 BEGIN END; -- Procedure does not exist, which is okay. SET @handler_sql = CONCAT('CALL ', handler_name, '(?,?,?)'); PREPARE prepared_statement FROM @handler_sql; SET @aggregate_id = aggregate_id; SET @payload = payload; SET @recorded_at = recorded_at; EXECUTE prepared_statement USING @aggregate_id, @payload, @recorded_at; END // -- HELPERS CREATE PROCEDURE map_error (errors JSON) BEGIN GET DIAGNOSTICS CONDITION 1 @error_number = MYSQL_ERRNO, @error_message = MESSAGE_TEXT; SET @error_message = JSON_UNQUOTE(COALESCE(JSON_EXTRACT(errors, CONCAT('$.e', @error_number)), @error_message)); SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = @error_message; END // -- SAMPLE IMPLEMENTATION CREATE TABLE customer ( customer_id CHAR(36) PRIMARY KEY, first_name VARCHAR(64) NOT NULL, last_name VARCHAR(64) NOT NULL, phone_number VARCHAR(15) NOT NULL, email VARCHAR(255) NOT NULL, password CHAR(98) NOT NULL, registered DATETIME NOT NULL, UNIQUE KEY idx_email (email) ) // -- This is the signature all handlers should implement: (IN aggregate_id CHAR(36), IN payload JSON, IN recorded_at DATETIME) CREATE PROCEDURE handleUserRegistered (IN aggregate_id CHAR(36), IN payload JSON, IN recorded_at DATETIME) BEGIN DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN CALL map_error(JSON_OBJECT( -- map e{error_code} to a more domain specific message 'e1062', 'A customer with this e-mail address already exists' )); END; INSERT INTO customer (customer_id, first_name, last_name, phone_number, email, password, registered) VALUES ( aggregate_id, payload->>"$.firstName", payload->>"$.lastName", payload->>"$.phoneNumber", payload->>"$.email", payload->>"$.passwordHash", recorded_at ); END // DELIMITER ; -- This yields an entry in the customer table CALL record_event ('UserRegistered', 'User', '5d1e0bcd-6cfb-47af-b4f8-8159f390163a', '{"firstName": "John", "lastName": "Doe", "phoneNumber": "+31612345678", "email": "john@doe.com", "passwordHash": "[xxx]"}'); -- Trying to create this customer again results in an error with the following message 'A customer with this e-mail address already exists' CALL record_event ('UserRegistered', 'User', '5d1e0bcd-6cfb-47af-b4f8-8159f390163a', '{"firstName": "John", "lastName": "Doe", "phoneNumber": "+31612345678", "email": "john@doe.com", "passwordHash": "[xxx]"}'); |
相關文章
- mysql 事件 eventMySql事件
- Event Sourcing落地與意義
- 說服您的CTO使用事件溯源 -Event Store Blog事件
- MySQL入門--EVENT(事件)MySql事件
- GitHub - knative/eventing-contrib: 基於knative的Event Sources事件溯源Github事件
- MySQL中的事件排程器EVENTMySql事件
- .NET的事件溯源構建庫:Eventuous事件
- Apache Kafka不適用於Event Sourcing!ApacheKafka
- 用資料結構解釋事件溯源 – {4Comprehension}資料結構事件
- .NET遵循CQRS-ES架構的EventFlow的DDD + CQRS + Event-sourcing原始碼架構原始碼
- 事件溯源與流水賬的結賬模式事件模式
- akka-typed(10) - event-sourcing, CQRS實戰
- WIX是如何從CRUD轉換到Event Sourcing?
- 事件流與事件溯源事件
- 事件協作和事件溯源事件
- PHP 事件溯源PHP事件
- mysql中複製表結構的方法小結MySql
- (譯)使用Spring Boot和Axon實現CQRS&Event SourcingSpring Boot
- C#總結(二)事件Event 介紹總結C#事件
- Rust中的事件溯源 - ariseyhunRust事件
- 剖玄析微聚合 - 事件溯源事件
- 基於事件溯源與CDC的事件驅動微服務架構案例原始碼事件微服務架構原始碼
- freeswitch的event事件處理事件
- Chronicle事件溯源的最佳實踐事件
- Python的事件溯源開源庫Python事件
- MySQL修改表結構到底會不會鎖表?MySql
- Tkinter (44) 事件 Event事件
- JS中event事件JS事件
- Laravel使用event事件Laravel事件
- 無伺服器與事件溯源結合的演示案例:將事件溯源作為Azure函式的資料持久化機制的庫伺服器事件函式持久化
- 事件溯源全指南 - Arkwrite事件
- 事件消費者之 Saga - 事件溯源事件
- 事件消費者之 Reactor - 事件溯源事件React
- 事件消費者之 Projector - 事件溯源事件Project
- mysql表結構自動生成golang structMySqlGolangStruct
- mysql複製表結構和資料MySql
- mysql表結構同步工具SchemaSync使用初探MySql
- MySQL千萬級大表線上變更表結構MySql