From 3fa50e79f12fe2b66ebd5d643ed597c6a121b198 Mon Sep 17 00:00:00 2001
From: muqiuhan Prisma ORM 在设计上就考虑了 N+1 问题,并提供了一种既方便开发者又高效的解决方案。当使用 Prisma Client 查询数据并需要包含关联模型时,Prisma 会自动优化查询,避免产生 N+1 查询,主要通过关系查询(Relation Queries)中的 假设想获取所有用户及其发布的帖子,使用 Prisma Client,可以这样写: 当执行上述查询时,Prisma 不会 生成 N+1 个 SQL 查询。而是首先会分析请求,并将其转化为数量非常有限的高效 SQL 查询。对于上面这个一对多关系的 baby is an OCaml library that offers several implementations of balanced binary search trees. [ANN] Preview of Stripe client and mock server - DkStdRestApis. [ANN] CAISAR release 2.0, a platform for characterizing AI safety and robustness. llama: A library for building software-defined modular synthesizers in a declarative style. baby is an OCaml library that offers several implementations of balanced binary search trees. [ANN] Preview of Stripe client and mock server - DkStdRestApis. [ANN] CAISAR release 2.0, a platform for characterizing AI safety and robustness. 一对一的 self-relation 需要两个端点,即使这两个端点是同一条数据。 而在关系型数据库中,一对一的 self-relation 可以用如下 SQL 描述: 可以通过将 用 SQL 描述 User model: 在关系型数据库中,可以用如下 SQL 描述: 以上这些就是对业务中的实体的 Repository 抽象,这样就隔离开了业务和存储逻辑,例如使用 MongoDB,可以实现一个 然后实现一个 Sunday, March 30, 2025 7:58 PM: TDD 和 DDD 并不冲突,实际上它们可以互补。TDD 可以帮助确保代码的正确性和可靠性,而 DDD 可以确保系统与业务需求紧密结合。在进行 TDD 时,可以使用 DDD 的领域模型和 Ubiquitous Language 来编写测试用例,确保测试覆盖了业务需求。在进行 DDD 时,可以使用 TDD 来驱动实现,确保每个领域模型的实现。 It’s hard to miss things when you don’t know different things exist The first problem is, and personally, I believe it’s the biggest JavaScript problem ever: we don’t know what can throw an error. From a JavaScript error perspective, it’s the same as the following: JavaScript doesn’t know; JavaScript doesn’t care. You should know. Second thing, this is perfectly viable code: No errors, no linters, even though this can break your app. Right now, in my head, I can hear, “What’s the problem, just use try/catch everywhere.” Here comes the third problem: we don’t know which one is thrown. Of course, we can somehow guess by the error message, but what about bigger services/functions with many places where errors can happen? Are you sure you are handling all of them properly with one try/catch? The most verbose of the three shown here and, ironically, the best one. So, first of all, Rust handles the errors using its amazing enums (they are not the same as TypeScript enums!). Without going into detail, what is important here is that it uses an enum called The summary here is that Rust always know where there might be an error. And it force you to deal with it right where it appears (mostly). No hidden ones, no guessing, no breaking app with a surprise face. And this approach is just better. By A MILE. We cannot make TypeScript errors work like the Rust. The limiting factor here is the language itself; it doesn’t have the proper tools to do that. But what we can do is try to make it similar. And make it simple: we do need a few try/catches. The good thing is we only need about two, not 100,000: This is just a wrapper with our New solution is longer, but it performs better because of the following reasons: 本快速入门文档参照 Turborepo 2.x 官方文档: https://turbo.build/repo/docs It’s hard to miss things when you don’t know different things exist The first problem is, and personally, I believe it’s the biggest JavaScript problem ever: we don’t know what can throw an error. From a JavaScript error perspective, it’s the same as the following: JavaScript doesn’t know; JavaScript doesn’t care. You should know. Second thing, this is perfectly viable code: No errors, no linters, even though this can break your app. Right now, in my head, I can hear, “What’s the problem, just use try/catch everywhere.” Here comes the third problem: we don’t know which one is thrown. Of course, we can somehow guess by the error message, but what about bigger services/functions with many places where errors can happen? Are you sure you are handling all of them properly with one try/catch? The most verbose of the three shown here and, ironically, the best one. So, first of all, Rust handles the errors using its amazing enums (they are not the same as TypeScript enums!). Without going into detail, what is important here is that it uses an enum called The summary here is that Rust always know where there might be an error. And it force you to deal with it right where it appears (mostly). No hidden ones, no guessing, no breaking app with a surprise face. And this approach is just better. By A MILE. We cannot make TypeScript errors work like the Rust. The limiting factor here is the language itself; it doesn’t have the proper tools to do that. But what we can do is try to make it similar. And make it simple: we do need a few try/catches. The good thing is we only need about two, not 100,000: This is just a wrapper with our New solution is longer, but it performs better because of the following reasons:include 选项或嵌套读取(nested reads)来实现这一点:import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
async function getUsersWithPosts() {
const usersWithPosts = await prisma.user.findMany({
include: {
posts: true, // 指示 Prisma 加载关联的 posts
},
})
// usersWithPosts 包含了用户列表,每个用户对象中都有一个 posts 数组
console.log(usersWithPosts)
}
getUsersWithPosts()
.catch((e) => {
throw e
})
.finally(async () => {
await prisma.$disconnect()
})import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
async function getUsersWithPosts() {
const usersWithPosts = await prisma.user.findMany({
include: {
posts: true, // 指示 Prisma 加载关联的 posts
},
})
// usersWithPosts 包含了用户列表,每个用户对象中都有一个 posts 数组
console.log(usersWithPosts)
}
getUsersWithPosts()
.catch((e) => {
throw e
})
.finally(async () => {
await prisma.$disconnect()
})include 查询,Prisma 通常会执行以下两步(类似于批量加载策略):
@@ -1133,67 +1133,6 @@
-
-新消息
-
-有价值的文章
-
-dune build.有趣的项目
-
]]>
+
+新消息
+
+有价值的文章
+
+dune build.有趣的项目
+
]]>CREATE TABLE "User" (
id SERIAL PRIMARY KEY,
"name" TEXT,
"successorId" INTEGER
);
ALTER TABLE "User" ADD CONSTRAINT fk_successor_user FOREIGN KEY ("successorId") REFERENCES "User" (id);
ALTER TABLE "User" ADD CONSTRAINT successor_unique UNIQUE ("successorId");CREATE TABLE "User" (
id SERIAL PRIMARY KEY,
"name" TEXT,
"successorId" INTEGER
);
ALTER TABLE "User" ADD CONSTRAINT fk_successor_user FOREIGN KEY ("successorId") REFERENCES "User" (id);
ALTER TABLE "User" ADD CONSTRAINT successor_unique UNIQUE ("successorId");一对多
model User {
id Int @id @default(autoincrement())
name String?
teacherId Int?
teacher User? @relation("TeacherStudents", fields: [teacherId], references: [id])
students User[] @relation("TeacherStudents")
}teacher 字段设为 required 来要求每个 User 都有一名 teacher。CREATE TABLE "User" (
id SERIAL PRIMARY KEY,
"name" TEXT,
"teacherId" INTEGER
);
ALTER TABLE "User" ADD CONSTRAINT fk_teacherid_user FOREIGN KEY ("teacherId") REFERENCES "User" (id);CREATE TABLE "User" (
id SERIAL PRIMARY KEY,
"name" TEXT,
"teacherId" INTEGER
);
ALTER TABLE "User" ADD CONSTRAINT fk_teacherid_user FOREIGN KEY ("teacherId") REFERENCES "User" (id);teacherId 没有使用 UNIQUE 约束,这代表着多个 students 可以有同一个 teacher多对多
model User {
id Int @id @default(autoincrement())
name String?
followedBy User[] @relation("UserFollows")
following User[] @relation("UserFollows")
}model User {
id Int @id @default(autoincrement())
name String?
followedBy Follows[] @relation("followedBy")
following Follows[] @relation("following")
}
model Follows {
followedBy User @relation("followedBy", fields: [followedById], references: [id])
followedById Int
following User @relation("following", fields: [followingId], references: [id])
followingId Int
@@id([followingId, followedById])
}CREATE TABLE "User" (
id integer DEFAULT nextval('"User_id_seq"'::regclass) PRIMARY KEY,
name text
);
CREATE TABLE "_UserFollows" (
"A" integer NOT NULL REFERENCES "User"(id) ON DELETE CASCADE ON UPDATE CASCADE,
"B" integer NOT NULL REFERENCES "User"(id) ON DELETE CASCADE ON UPDATE CASCADE
);CREATE TABLE "User" (
id integer DEFAULT nextval('"User_id_seq"'::regclass) PRIMARY KEY,
name text
);
CREATE TABLE "_UserFollows" (
"A" integer NOT NULL REFERENCES "User"(id) ON DELETE CASCADE ON UPDATE CASCADE,
"B" integer NOT NULL REFERENCES "User"(id) ON DELETE CASCADE ON UPDATE CASCADE
);在同一模型上建立多个 self-relations
model User {
id Int @id @default(autoincrement())
name String?
teacherId Int?
teacher User? @relation("TeacherStudents", fields: [teacherId], references: [id])
students User[] @relation("TeacherStudents")
followedBy User[] @relation("UserFollows")
following User[] @relation("UserFollows")
}IGenericRepository 中定义的函数是每个 Repository 公开的通用存储函数。MongoGenericRepository:import { Model } from 'mongoose';
import { IGenericRepository } from '../../../core';
export class MongoGenericRepository<T> implements IGenericRepository<T> {
private _repository: Model<T>;
private _populateOnFind: string[];
constructor(repository: Model<T>, populateOnFind: string[] = []) {
this._repository = repository;
this._populateOnFind = populateOnFind;
}
getAll(): Promise<T[]> {
return this._repository.find().populate(this._populateOnFind).exec();
}
get(id: any): Promise<T> {
return this._repository.findById(id).populate(this._populateOnFind).exec();
}
create(item: T): Promise<T> {
return this._repository.create(item);
}
update(id: string, item: T) {
return this._repository.findByIdAndUpdate(id, item);
}
}import { Model } from 'mongoose';
import { IGenericRepository } from '../../../core';
export class MongoGenericRepository<T> implements IGenericRepository<T> {
private _repository: Model<T>;
private _populateOnFind: string[];
constructor(repository: Model<T>, populateOnFind: string[] = []) {
this._repository = repository;
this._populateOnFind = populateOnFind;
}
getAll(): Promise<T[]> {
return this._repository.find().populate(this._populateOnFind).exec();
}
get(id: any): Promise<T> {
return this._repository.findById(id).populate(this._populateOnFind).exec();
}
create(item: T): Promise<T> {
return this._repository.create(item);
}
update(id: string, item: T) {
return this._repository.findByIdAndUpdate(id, item);
}
}MongoDataServices:import { Injectable, OnApplicationBootstrap } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { IDataServices } from '../../../core';
import { MongoGenericRepository } from './mongo-generic-repository';
import {
Author,
AuthorDocument,
Book,
BookDocument,
Genre,
GenreDocument,
} from './model';
()
export class MongoDataServices
implements IDataServices, OnApplicationBootstrap
{
authors: MongoGenericRepository<Author>;
books: MongoGenericRepository<Book>;
genres: MongoGenericRepository<Genre>;
constructor(
(Author.name)
private AuthorRepository: Model<AuthorDocument>,
(Book.name)
private BookRepository: Model<BookDocument>,
(Genre.name)
private GenreRepository: Model<GenreDocument>,
) {}
onApplicationBootstrap() {
this.authors = new MongoGenericRepository<Author>(this.AuthorRepository);
this.books = new MongoGenericRepository<Book>(this.BookRepository, [
'author',
'genre',
]);
this.genres = new MongoGenericRepository<Genre>(this.GenreRepository);
}
}import { Injectable, OnApplicationBootstrap } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { IDataServices } from '../../../core';
import { MongoGenericRepository } from './mongo-generic-repository';
import {
Author,
AuthorDocument,
Book,
BookDocument,
Genre,
GenreDocument,
} from './model';
()
export class MongoDataServices
implements IDataServices, OnApplicationBootstrap
{
authors: MongoGenericRepository<Author>;
books: MongoGenericRepository<Book>;
genres: MongoGenericRepository<Genre>;
constructor(
(Author.name)
private AuthorRepository: Model<AuthorDocument>,
(Book.name)
private BookRepository: Model<BookDocument>,
(Genre.name)
private GenreRepository: Model<GenreDocument>,
) {}
onApplicationBootstrap() {
this.authors = new MongoGenericRepository<Author>(this.AuthorRepository);
this.books = new MongoGenericRepository<Book>(this.BookRepository, [
'author',
'genre',
]);
this.genres = new MongoGenericRepository<Genre>(this.GenreRepository);
}
}
try {
let data = “Hello”;
} catch (err) {
console.error(err);
}const request = { name: “test”, value: 2n };
const body = JSON.stringify(request);
const response = await fetch("https://example.com", {
method: “POST”,
body,
});
if (!response.ok) {
return;
}
-let greeting_file_result = File::open(“hello.txt”);
let greeting_file = match greeting_file_result {
Ok(file) => file,
Err(error) => panic!("Problem opening the file: {:?}", error),
};Result with two variants: Ok and Err. As you might guess, Ok holds a value and Err holds…surprise, an error :D.export type Safe<T> =
| {
success: true;
data: T;
}
| {
success: false;
error: string;
};export function safe<T>(promise: Promise<T>, err?: string): Promise<Safe<T>>;
export function safe<T>(func: () => T, err?: string): Safe<T>;
export function safe<T>(
promiseOrFunc: Promise<T> | (() => T),
err?: string,
): Promise<Safe<T>> | Safe<T> {
if (promiseOrFunc instanceof Promise) {
return safeAsync(promiseOrFunc, err);
}
return safeSync(promiseOrFunc, err);
}
async function safeAsync<T>(
promise: Promise<T>,
err?: string
): Promise<Safe<T>> {
try {
const data = await promise;
return { data, success: true };
} catch (e) {
console.error(e);
if (err !== undefined) {
return { success: false, error: err };
}
if (e instanceof Error) {
return { success: false, error: e.message };
}
return { success: false, error: "Something went wrong" };
}
}
function safeSync<T>(
func: () => T,
err?: string
): Safe<T> {
try {
const data = func();
return { data, success: true };
} catch (e) {
console.error(e);
if (err !== undefined) {
return { success: false, error: err };
}
if (e instanceof Error) {
return { success: false, error: e.message };
}
return { success: false, error: "Something went wrong" };
}
}Safe type as the return one. But sometimes simple things are all you need. Let’s combine them with the example from above.const request = { name: “test”, value: 2n };
const body = safe(
() => JSON.stringify(request),
“Failed to serialize request”,
);
if (!body.success) {
// handle error (body.error)
return;
}
const response = await safe(
fetch("https://example.com", {
method: “POST”,
body: body.data,
}),
);
if (!response.success) {
// handle error (response.error)
return;
}
if (!response.data.ok) {
// handle network error
return;
}
// handle response (body.data)
-
]]>
+]]>
+
最后一次编辑:二〇二四年九月二十七日下午六点〇七分try {
let data = “Hello”;
} catch (err) {
console.error(err);
}const request = { name: “test”, value: 2n };
const body = JSON.stringify(request);
const response = await fetch("https://example.com", {
method: “POST”,
body,
});
if (!response.ok) {
return;
}
+let greeting_file_result = File::open(“hello.txt”);
let greeting_file = match greeting_file_result {
Ok(file) => file,
Err(error) => panic!("Problem opening the file: {:?}", error),
};Result with two variants: Ok and Err. As you might guess, Ok holds a value and Err holds…surprise, an error :D.export type Safe<T> =
| {
success: true;
data: T;
}
| {
success: false;
error: string;
};export function safe<T>(promise: Promise<T>, err?: string): Promise<Safe<T>>;
export function safe<T>(func: () => T, err?: string): Safe<T>;
export function safe<T>(
promiseOrFunc: Promise<T> | (() => T),
err?: string,
): Promise<Safe<T>> | Safe<T> {
if (promiseOrFunc instanceof Promise) {
return safeAsync(promiseOrFunc, err);
}
return safeSync(promiseOrFunc, err);
}
async function safeAsync<T>(
promise: Promise<T>,
err?: string
): Promise<Safe<T>> {
try {
const data = await promise;
return { data, success: true };
} catch (e) {
console.error(e);
if (err !== undefined) {
return { success: false, error: err };
}
if (e instanceof Error) {
return { success: false, error: e.message };
}
return { success: false, error: "Something went wrong" };
}
}
function safeSync<T>(
func: () => T,
err?: string
): Safe<T> {
try {
const data = func();
return { data, success: true };
} catch (e) {
console.error(e);
if (err !== undefined) {
return { success: false, error: err };
}
if (e instanceof Error) {
return { success: false, error: e.message };
}
return { success: false, error: "Something went wrong" };
}
}Safe type as the return one. But sometimes simple things are all you need. Let’s combine them with the example from above.const request = { name: “test”, value: 2n };
const body = safe(
() => JSON.stringify(request),
“Failed to serialize request”,
);
if (!body.success) {
// handle error (body.error)
return;
}
const response = await safe(
fetch("https://example.com", {
method: “POST”,
body: body.data,
}),
);
if (!response.success) {
// handle error (response.error)
return;
}
if (!response.data.ok) {
// handle network error
return;
}
// handle response (body.data)
+
]]>
我使用 Pop!_OS,此发行版使用 EFI 启动,故而可以在 /boot/efi/loader/loader.conf 中加上:
options quiet splash amdgpu.dcdebugmask=0x10 amdgpu.sg_display=0 |
对于其他使用 EFI 或 GRUB 启动的发行版也可以添加类似的参数尝试尝试。
+]]> +/* The tick thread: posts a SIGPREEMPTION signal periodically */ |
这是因为Multicore OCaml的GC目前需要一个进程(或一个Domain)中的所有线程一起参与以避免并发访问。如果一个线程在system call上被阻塞,那么整个Domain就会被卡住,直到该线程可以参与当前的垃圾收集。为了避免这个问题,tick 线程可以代替被阻塞的线程执行垃圾收集操作。
+]]> +一、 聚集索引(Clustered Index)的插入机制
+在 InnoDB 中,聚集索引的叶子节点同时存储了行数据,且按照索引键(主键)顺序物理排序。
+当新记录的主键完全随机(如 UUID v4)时,每次插入都会随机落在 B-Tree 的不同叶子页,导致频繁的页分裂和指针重排,而页分裂和随机 I/O 会带来大量的磁盘写放大和缓存抖动(cache churn),削弱吞吐并拉高延迟。
+二、UUID v7 的时间排序特性
+UUID v7 在高位(前 48 位)嵌入了以毫秒级精度的 Unix 时间戳,剩下的位用于随机数或序列号,这样生成的 ID 保持全局唯一性的同时,随着时间自然递增(即“近似单调递增”),新插入的记录几乎总是追加到 B-Tree 的最右端叶子节点。
+参见 dbaplus.cn 的分析:
+++“UUID v7 的创新之处在于其时间排序特性,它在前 48 位中嵌入了以毫秒为单位的 Unix 时间戳……可能在插入和查询操作上提供更好的性能”【1】。
+
三、降低页分裂与碎片化
+顺序或近似顺序的主键能使叶子节点连续增长,极少触发页分裂,并且更少的页分裂意味着更低的写放大(write amplification)和更稳定的插入延迟,同时,减少了空洞和链表重排,提高了磁盘和内存缓存的命中率。
+四、提升查询局部性与缓存命中
+因为数据物理上是按时间顺序紧凑写入,时间范围查询(如 “最近 1 小时的日志”)可以快速定位连续的叶子页,I/O 更聚集,内存缓冲池(buffer pool)或操作系统页缓存能更有效地缓存最近热数据,进一步加速查询。
+Rimon Tawadrous 在其 GitHub repo 中的测试,对比 100 万条逐条插入实验,UUID v7 相较 UUID v4 在单线程插入上速度快约 3.24%,多线程下更可观【1】。
+参考链接
[1] “为什么 UUID 7 比 UUID 4 更适合作为 RDBMS 的聚集索引?” dbaplus.cn
https://dbaplus.cn/news-160-6313-1.html
[2] “PostgreSQL and UUID as primary key” maciejwalkowiak
https://maciejwalkowiak.com/blog/postgres-uuid-primary-key/
[3] “Optimised UUIDs in mysql” stitcher
https://stitcher.io/blog/optimised-uuids-in-mysql
[3] “Storing UUID Values in MySQL” percona
https://www.percona.com/blog/store-uuid-optimized-way/
这世上也不是所有事都算得准的。
云仰望着太阳,羡慕他的炙热,或许太阳也在仰望着云,渴求他的停留。
地球距离太阳1.5亿公里,如无意外,两者此生不会相遇,但从此以后,我与世间美好再也不会分离。
-]]> -天空泛起一丝鱼肚白,那是每年夏至,凌晨四点多就会早起的日出。
-而身后那栋为我而建的世界上独一无二的小屋子,正通宵达旦地亮着灯火,里面是我的痕迹,我的热爱,我的温暖和祝福。
-身前,我的山林和小狗,正笨拙地试图从自然的馈赠里找到那份属于它们的礼物。
-它们那样爱着我,那样忠诚于我。
-那一刻,我突然就想起了曾经在书上看过的一句很喜欢的话——“世界先爱了我,我不能不爱他.”
-曾经在冬季日出的时候,我见过海岸线浮满碎冰的模样,那是连太阳都会显得寂寥和落寞的冷清。
-可是太阳始终当着太阳,守着一个恒星的职责,不知疲倦地用自己炽热的温度和光芒试图唤醒沉睡的冬日。
-直到终于有一天,有人在冬夜里复苏,爱上了那个比夏天更炽烈的温度,然后海浪成了新娘白色的花环,我成了太阳一生的爱人。
-所以我始终愿意相信,是这个世界先温柔地爱了我。
-哪怕世界给予我的这份爱,在最初的时候,来得并不那么明显,也并不那么浓烈,我也曾因此孤独过,无助过,迷茫过,放弃过。
-可是那份爱最终还是随着冰雪消融,春暖花开,随着夏天剧烈摇晃过后的气泡水,滋滋地冒了出来,连盖上盖子,也没有办法捂住。
-所以我拥有了世界上最好的义无反顾的爱。
-看着前方,轻轻叫了一声:“毛毛”
-狗狗立马回了头,和乍出的日光,和突然转动的风力发电机,和突然被风吹动的山林,同步发生。好像只要我一声令下,这个世界就愿意为我而生动。
-可这世间哪里会在乎茫茫人海中这不值一提的爱
-我们都只不过是平凡世界里平凡生活着的人们,如果非要说有什么不同,那就是我只爱着这个世界而已。
-于是我看着那只大笨狗,看着并没有被虚化成背景的世界,温柔地弯起了唇角:“有句话今天我一直忘记告诉你了。”
-狗狗叼起一根树枝,歪头不解地看着我。
-然后我就在山峰浮现出第一缕阳光时,笑着对这个世界说:“我爱你,会永远爱你,永远最爱你。”
-我爱这个因为有我而变得温柔的世界。
-这将是我与周遭的一切,热爱一生,共度一生的地方。
]]>还是广袤宇宙中的一颗有名有姓的星星,
宇宙、银河、太阳,都不重要。
热爱这个世界,是我成长里最美妙的勇敢事迹。
+]]> +天空泛起一丝鱼肚白,那是每年夏至,凌晨四点多就会早起的日出。
+而身后那栋为我而建的世界上独一无二的小屋子,正通宵达旦地亮着灯火,里面是我的痕迹,我的热爱,我的温暖和祝福。
+身前,我的山林和小狗,正笨拙地试图从自然的馈赠里找到那份属于它们的礼物。
+它们那样爱着我,那样忠诚于我。
+那一刻,我突然就想起了曾经在书上看过的一句很喜欢的话——“世界先爱了我,我不能不爱他.”
+曾经在冬季日出的时候,我见过海岸线浮满碎冰的模样,那是连太阳都会显得寂寥和落寞的冷清。
+可是太阳始终当着太阳,守着一个恒星的职责,不知疲倦地用自己炽热的温度和光芒试图唤醒沉睡的冬日。
+直到终于有一天,有人在冬夜里复苏,爱上了那个比夏天更炽烈的温度,然后海浪成了新娘白色的花环,我成了太阳一生的爱人。
+所以我始终愿意相信,是这个世界先温柔地爱了我。
+哪怕世界给予我的这份爱,在最初的时候,来得并不那么明显,也并不那么浓烈,我也曾因此孤独过,无助过,迷茫过,放弃过。
+可是那份爱最终还是随着冰雪消融,春暖花开,随着夏天剧烈摇晃过后的气泡水,滋滋地冒了出来,连盖上盖子,也没有办法捂住。
+所以我拥有了世界上最好的义无反顾的爱。
+看着前方,轻轻叫了一声:“毛毛”
+狗狗立马回了头,和乍出的日光,和突然转动的风力发电机,和突然被风吹动的山林,同步发生。好像只要我一声令下,这个世界就愿意为我而生动。
+可这世间哪里会在乎茫茫人海中这不值一提的爱
+我们都只不过是平凡世界里平凡生活着的人们,如果非要说有什么不同,那就是我只爱着这个世界而已。
+于是我看着那只大笨狗,看着并没有被虚化成背景的世界,温柔地弯起了唇角:“有句话今天我一直忘记告诉你了。”
+狗狗叼起一根树枝,歪头不解地看着我。
+然后我就在山峰浮现出第一缕阳光时,笑着对这个世界说:“我爱你,会永远爱你,永远最爱你。”
+我爱这个因为有我而变得温柔的世界。
+这将是我与周遭的一切,热爱一生,共度一生的地方。
]]>