如何在 Python 中使用 MongoDB 与 MongoEngine

一、介绍

MongoDB是一个免费的开源NoSQL数据库程序。它将数据存储在文档集合中,其中文档类似于传统关系数据库系统中的一行。它没有用于在集合中存储数据的固定架构;您可以将数据存储在键值对中,就像 Python 字典一样。灵活的数据模型和对水平扩展的支持等功能允许您在需求更改时进行更改或缩放数据库。

MongoEngine是一个对象文档映射器(ODM),它允许你的Python应用程序与MongoDB数据库进行交互。它提供了一个声明性 API,您可以在其中使用 Python 类和对象与数据库中的文档进行交互。这个抽象层使开发人员更容易与MongoDB数据库进行交互,有助于减少开发时间,并使数据库逻辑不易出错。

本文介绍 MongoEngine ODM 的安装和配置,定义文档架构、执行创建、读取、更新和删除 (CRUD) 操作以及从数据库中查询筛选数据的步骤。它还介绍了文档引用、迁移和元选项的基础知识。

二、准备工作

  • 在 Vultr 部署 Ubuntu 20.04 实例。
  • 创建具有 sudo 权限的非 root 用户。
  • 以非根用户身份登录您的实例。
  • 在实例上安装 MongoDB 数据库服务器。

三、设置环境

安装 MongoEngine 库。

$ pip install mongoengine

设置新的项目目录。

$ mkdir ~/mongoengine_demo

切换到项目目录。

$ cd ~/mongoengine_demo

 四、连接到数据库

您可以使用 MongoEngine 模块中的函数与 MongoDB 服务器建立连接。必须将主机名、端口、数据库等值作为参数传递。connect()

使用文本编辑器创建一个名为 的新 Python 文件。app.py

$ nano app.py

将以下内容添加到文件中,并使用 + 然后保存文件。CTRLXENTER

from mongoengine import *

client = connect('mongoengine_demo')

上面的代码使用默认主机和端口与MongoDB服务器建立连接。作为参数传递的字符串引用数据库的名称。如果数据库不存在,它会尝试使用传递给函数的名称创建新数据库。127.0.0.127017connect()

以下示例演示如何使用非默认值连接到 MongoDB 服务器。

connect('database_name', username='username', password='password', authentication_source='admin')

还可以使用该参数与多个数据库或数据库服务器建立连接。有关详细信息,请参阅 MongoEngine 文档中的多个数据库部分。alias

五、定义文档架构

存储在MongoDB数据库中的文档没有任何固定的模式。但是,定义文档架构可确保数据结构和验证,从而使数据库逻辑不易出错。

MongoEngine ODM允许您创建固定或动态文档架构。您可以从 MongoEngine 模块继承 or 类以创建新的文档类并使用字段对象定义每个字段,请参阅 MongoEngine 文档中的字段部分以查找所有可用的字段类型。DocumentDynamicDocument

编辑在上一节中创建的 Python 文件。

$ nano app.py

将以下内容添加到文件中,并使用 + 然后保存文件。CTRLXENTER

class User(Document):
    name = StringField(required=True)
    email = EmailField(required=True)
    age = IntField(required=True)

    def __repr__(self):
        return f'<User name="{self.name}">'

上面的代码创建了一个名为继承自 MongoEngine 模块中的类的文档类。它将 Python 类映射到数据库中的集合。默认情况下,它使用转换为蛇大小写的 Python 类名作为集合名称。此文档类使用固定架构,其中对象只能包含名称、电子邮件和期限。UserDocument

六、执行 CRUD 操作

MongoEngine 将每个文档类映射到数据库中的集合。创建文档类的新实例以在集合中创建新文档。本节介绍如何使用上一节中创建的文档类执行 CRUD 操作。

进入Python控制台。

$ python

导入所需的模块。

>>> from app import User

上面的命令从您在上一节中创建的 Python 文件中导入类。User

创建新条目。

>>> user1 = User(name='Example User', email=f'user@example.com', age=21)
>>> user1.save()

上面的命令从类创建一个新对象并调用该方法,该方法启动集合并在数据库中创建新文档。Usersave()

阅读第一个条目。

>>> User.objects.first()

上面的命令返回一个字典,其中包含存储在集合中的第一个文档的值。user

更新条目。

>>> user1.age = 22
>>> user1.save()

上面的命令更改对象中 age 属性的值并调用该方法,该方法将更新数据库中的文档。user1save()

验证更改。

>>> User.objects.first().age

删除条目。

>>> user1.delete()

验证更改。

>>> User.objects

退出 Python 控制台。

>>> exit()

 七、查询筛选后的数据

文档类具有允许访问存储在集合中的对象的属性。该属性是一个接受条件并返回包含筛选的文档对象的对象。本节介绍使用文档类查询筛选数据的基础知识。objectsobjectsQuerySetManagerQuerySet

进入Python控制台。

$ python

导入所需的模块。

>>> from app import User

填充数据库。

>>> user_objects = [User(name=f'Person {i}', email=f'person{i}@example.com', age=i+18) for i in range(10)]
>>> User.objects.insert(user_objects)

上述命令使用枚举值创建 10 个不同对象的列表,并将其插入到数据库中。User

使用单个条件查询文档。

>>> User.objects(age__gt=20)

上面的命令返回年龄超过 20 的文档列表。

输出

[<User name="Person 3">, <User name="Person 4">, <User name="Person 5">, <User name="Person 6">, <User name="Person 7">, <User name="Person 8">, <User name="Person 9">]

使用多个条件查询文档。

>>> User.objects(age__gt=20, age__lt=25)

上面的命令返回年龄大于 20 且小于 25 的文档列表。

输出

[<User name="Person 3">, <User name="Person 4">, <User name="Person 5">, <User name="Person 6">]

获取单个文档。

>>> User.objects(age__=19).first()

上面的命令返回一个生存期为 19 的文档对象。该方法返回单个文档对象,而不是包含文档对象的列表。first()

输出

<User name="Person 1">

退出 Python 控制台。

>>> exit()

请参阅 MongoEngine 文档中的查询数据库,以查找 中的所有可用过滤选项。QuerySetManager

 八、文档参考

MongoEngine ODM允许链接到文档架构中的其他文档。它使您能够在文档之间创建关系;与传统的关系数据库系统一样,它们将链接行的主键存储为外键。

您可以使用文档架构中的字段对象链接到其他文档。MongoEngine ODM 还支持 和 字段对象的组合以形成多对一关系。ReferenceFieldListFieldReferenceField

本节介绍如何使用文档类中的字段对象链接到不同的文档。ReferenceField

编辑 Python 文件。

$ nano app.py

将以下内容添加到 User 文档类上方的文件中,并使用 + 然后保存文件。CTRLXENTER

class Video(Document):
    title = StringField(required=True)

    def __repr__(self):
        return f'<Video title="{self.title}">'

class Course(Document):
    name = StringField(required=True)
    price = IntField(required=True)
    videos = ListField(ReferenceField(Video))

    def __repr__(self):
        return f'<Course name="{self.name}">'

上面的代码创建 Python 类,并从在数据库中创建两个新集合的类继承。文档类使用 and 字段对象在 videos 属性中存储视频对象引用的列表。VideoCourseDocumentCourseReferenceFieldListField

进入 Python 控制台。

$ python

导入所需的模块。

>>> from app import Course, Video

上面的命令从文件中导入 and 类。CourseVideoapp.py

视频集合中创建新条目。

>>> video1 = Video(title='Example Video 1').save()
>>> video2 = Video(title='Example Video 2').save()

上述命令创建文档类的两个新实例,该实例在数据库中启动并创建两个新文档。Video

课程集合中创建新条目。

>>> course1 = Course(name='Example Course 1', price=100, videos=[video1, video2]).save()

上面的命令创建文档类的新实例,该实例初始化并在数据库中创建新文档。它将文档与视频集合中的其他两个文档链接。Course

验证更改。

>>> Course.objects.first().videos
>>> Course.objects.first().videos[0].title
>>> Course.objects.first().videos[1].title

退出 Python 控制台。

>>> exit()

 九、文档迁移

NoSQL 数据库的灵活性使您可以轻松地进行文档架构更改。本节介绍如何在文档架构中进行结构更改。

编辑 Python 文件

$ nano app.py

将以下内容添加到文件中,并使用 + 然后保存文件。CTRLXENTER

class User(Document):
    name = StringField(required=True)
    email = EmailField(required=True)
    age = IntField(required=True)
    enrolled_courses = ListField(ReferenceField(Course))

    def __repr__(self):
        return f'<User name="{self.name}">'

上面的代码修改在用户集合中添加了一个名为 enrolled_courses 的新属性。和字段对象的组合允许用户文档引用多个课程文档。ListFieldReferenceField

进入Python控制台。

$ python

导入所需的模块。

>>> from app import User, Course

上面的命令从文件中导入 and 类。UserCourseapp.py

获取文档对象。

>>> user1 = User.objects.first()
>>> course1 = Course.objects.first()

上述命令从用户课程集合中获取第一个文档对象。

更新用户文档对象。

>>> user1.enrolled_courses = [course1]
>>> user1.save()

上述命令将 enrolled_courses 属性的值设置为包含文档引用对象的 Python 列表。Course

验证更改。

>>> User.objects.first().enrolled_courses
>>> User.objects.first().enrolled_courses[0].name

退出 Python 控制台。

>>> exit()

文档架构中的更改不会影响现有文档。如果要将更改应用于所有文档,则必须对集合使用该方法。有关更多信息,请参阅 MongoEngine 文档中的文档迁移部分。update_many()

十、文档元选项

文档类中的字典允许您向集合添加元数据,例如集合名称、文档索引列表、默认排序和继承选项、分片键等。本节介绍字典在文档类中的用法。metameta

编辑 Python 文件

$ nano app.py

将以下内容添加到 User 文档类下面的文件中,并使用 + then 保存文件。CTRLXENTER

class MetaExample(Document):
    age = IntField()

    meta = {
        'collection': 'example_collection',
        'indexes': ['age']
    }

    def __repr__(self):
        return f'<MetaExample age={self.age}>'

上面的代码创建了一个名为从该类继承的新 Python 类。它会创建一个名为 example_collection 的新集合,并在集合索引中添加年龄字段。MetaExampleDocument

索引是一种特殊的数据结构,它存储存储在数据库中的数据子集,使数据更易于以编程方式横向。如果没有索引,服务器必须执行完全集合扫描。如果查询存在适当的索引,则服务器可以限制必须扫描的文档数。

进入Python控制台。

$ python

导入所需的模块。

>>> from app import client, MetaExample

上面的命令从文件中导入对象和类。clientMetaExampleapp.py

初始化集合。

>>> MetaExample(age=999).save()

验证自定义集合名称。

>>> client.get_database('mongoengine_demo').list_collection_names()

验证集合索引。

>>> MetaExample.list_indexes()

退出 Python 控制台。

>>> exit()

请参阅 MongoEngine 文档中的文档集合部分,以查找可用元选项的完整列表。

十一、结论

您安装了 MongoEngine 库,与 MongoDB 数据库服务器建立了连接,定义了文档架构,执行了 CRUD 操作,并从数据库中查询了过滤的数据。您还探索了文档引用、迁移和元选项的基础知识。

在 Ubuntu 20.04 上使用 Golang 和 MongoDB 创建 CRUD 应用程序

1.介绍

MongoDB是最好的基于文档的开源数据库管理系统之一。由于其灵活的设计模式,您可以在各种业务系统中使用该应用程序,这是传统 SQL 数据库无法满足的。

凭借其强大的数据库模式,MongoDB平台适用于设置用于管理产品数据,创建内容管理系统(CMS)的系统,以及在大多数情况下存储和查询大数据的系统。

另一方面,Golang 是一种快速、可扩展且易于学习的现代编程语言,用于编码高级软件应用程序。由于MongoDB为Golang语言提供了全面的API,因此您可以将这两个应用程序一起使用,为金融,电子商务,研究等提供解决方案。

在本指南中,您将使用 MongoDB 设置一个数据库,并从自定义 Golang 应用程序与其通信,以在 Ubuntu 20.04 服务器上执行基本的创建、读取、更新和删除 (CRUD) 操作。

2.准备工作

要继续执行本指南,请确保您已获得以下各项:

  • Ubuntu 20.04 服务器。
  • 具有 sudo 权限的非 root 用户。
  • 使用用户帐户和密码配置的 MongoDB 数据库。
  • 一个戈朗包。

3. 创建 MongoDB 数据库

数据驱动应用程序必须能够存储、检索、更新和删除记录。只有在为软件设置数据库后,才能执行所有这些操作。通过 SSH 连接到您的服务器,然后按照以下步骤初始化 MongoDB 数据库。

  1. 登录到您的MongoDB数据库。替换为数据库的管理员帐户。mongo_db_admin
    $ mongosh -u mongo_db_admin -p --authenticationDatabase admin
  2. 出现提示时,输入MongoDB帐户的密码,然后按继续。接下来,运行下面的语句以创建数据库。ENTERshop_db
    test> use shop_db
  3. 确认已切换到新数据库。shop_db
    switched to db shop_db
  4. 接下来,使用 MongoDB 函数在新集合中插入三个文档。productsinsertMany()
    shop_db> db.products.insertMany([
    
                {"product_id" : 1,
    
                 "product_name" : "LEATHER BELT",
    
                 "retail_price" : 24.35   
    
                },
    
                {"product_id" : 2,
    
                 "product_name" : "WINTER JACKET",
    
                 "retail_price" : 99.95    
    
                },
    
                {"product_id" : 3,
    
                 "product_name" : "WOOLEN SWEATER",
    
                 "retail_price" : 43.20
    
                }  
    
               ]);
  5. 通过确认下面的输出来确保命令已成功。
    {
    
      acknowledged: true,
    
      insertedIds: {
    
        '0': ObjectId("62188b2358979df39bbcf178"),
    
        '1': ObjectId("62188b2358979df39bbcf179"),
    
        '2': ObjectId("62188b2358979df39bbcf17a")
    
      }
    
    }
  6. 接下来,使用以下语句查询集合以确保数据已到位。products
    shop_db> db.products.find()
  7. 您应该获得所有产品的列表以及相关的产品,如下所示。_ids
    [
    
      {
    
        _id: ObjectId("62188b2358979df39bbcf178"),
    
        product_id: 1,
    
        product_name: 'LEATHER BELT',
    
        retail_price: 24.35
    
      },
    
      {
    
        _id: ObjectId("62188b2358979df39bbcf179"),
    
        product_id: 2,
    
        product_name: 'WINTER JACKET',
    
        retail_price: 99.95
    
      },
    
      {
    
        _id: ObjectId("62188b2358979df39bbcf17a"),
    
        product_id: 3,
    
        product_name: 'WOOLEN SWEATER',
    
        retail_price: 43.2
    
      }
    
    ]
  8. 从 MongoDB 服务器注销。
    shop_db> quit
  9. 现在,您已经设置了数据库集合和示例文档。在接下来的步骤中,您将使用 Golang 语言创建一些脚本来操作您的 MongoDB 集合。shop_dbproducts

4. 创建文件main.go

该文件将保存应用程序的函数。这是执行应用程序时触发的主要方法。main.gomain()

  1. 在创建文件的源代码之前,请创建一个目录以将源代码与其余 Linux 文件分开。main.goproject
    $ mkdir project
  2. 然后,切换到新目录。project
    $ cd project
  3. 接下来,使用文本编辑器打开一个新文件以进行编辑。nanomain.go
    $ nano main.go
  4. 打开文件后,在文件中输入以下信息。将 替换为 MongoDB 用户帐户的正确值。main.gomongo_db_adminEXAMPLE_PASSWORD
    package main
    
    
    
    import (
    
        "context"
    
        "net/http"
    
        "encoding/json" 
    
        _"log" 
    
        "fmt" 
    
        "go.mongodb.org/mongo-driver/mongo" 
    
    "go.mongodb.org/mongo-driver/mongo/options"         
    
    )
    
    
    
    const (  
    
        dbUser = "mongo_db_admin"
    
        dbPass = "EXAMPLE_PASSWORD"
    
        dbName = "shop_db"
    
    )
    
    
    
    func main() {
    
         http.HandleFunc("/api/v1/products", requestHandler)
    
         http.ListenAndServe(":8080", nil)
    
    }
    
    
    
    func requestHandler(w http.ResponseWriter, req *http.Request) {
    
    
    
        w.Header().Set("Content-Type", "application/json")
    
    
    
        response := map[string]interface{}{}
    
    
    
        ctx := context.Background()
    
    
    
        client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://" + dbUser + ":" + dbPass + "@localhost:27017"))
    
    
    
        if err != nil { 
    
            fmt.Println(err.Error())
    
        } 
    
    
    
        collection := client.Database(dbName).Collection("products")  
    
    
    
        data := map[string]interface{}{} 
    
    
    
        err = json.NewDecoder(req.Body).Decode(&data)
    
    
    
        if err != nil { 
    
            fmt.Println(err.Error())
    
        }
    
    
    
        switch req.Method {
    
            case "POST":
    
                response, err = createRecord(collection, ctx, data)
    
            case "GET":
    
                response, err = getRecords(collection, ctx)
    
            case "PUT":
    
                response, err = updateRecord(collection, ctx, data)
    
            case "DELETE":
    
                response, err = deleteRecord(collection, ctx, data)
    
        }
    
    
    
        if err != nil { 
    
            response = map[string]interface{}{"error": err.Error(),}  
    
        } 
    
    
    
        enc := json.NewEncoder(w)
    
        enc.SetIndent("", "  ")
    
    
    
        if err := enc.Encode(response); err != nil {
    
            fmt.Println(err.Error())
    
        }   
    
    }
  5. 完成编辑后保存并关闭文件。
  6. 在上面的文件中,您将创建一个 Web 服务器,该服务器使用语句和 .8080http.HandleFunc("/api/v1/products", requestHandler)http.ListenAndServe(":8080", nil)
  7. 在该函数下,您将连接到之前创建的 MongoDB 实例。接下来,使用 Golang 语句通过传递集合引用将 HTTP 请求路由到相应的 CRUD 函数。最后,您将使用 JSON 函数以人类可读的格式格式化和输出数据。requestHandler()switchproducts
  8. 创建文件后,现在将在不同的文件上设置单独的函数,以处理应用程序的所有 CRUD 操作。main.go

5. 设置新文件create_record.go

要为 CRUD 操作设置的第一个文件是该文件。此文件包含用于将文档插入集合的功能。create_record.goproducts

  1. 运行以下命令以设置文件。create_record.go
    $ nano create_record.go
  2. 接下来,在文件中输入以下信息。
    package main
    
    
    
    import (
    
        "context"      
    
        "go.mongodb.org/mongo-driver/mongo"       
    
    )
    
    
    
    func createRecord(collection *mongo.Collection, ctx context.Context, data map[string]interface{})(map[string]interface{}, error){     
    
    
    
        req, err := collection.InsertOne(ctx, data)
    
    
    
        if err != nil { 
    
            return nil, err                    
    
        }
    
    
    
        insertedId := req.InsertedID
    
    
    
        res := map[string]interface{}{
    
                   "data" : map[string]interface{}{                            
    
                        "insertedId": insertedId,
    
                    },
    
               } 
    
    
    
        return res, nil
    
    }
  3. 保存并关闭文件。
  4. 上面文件中的主要功能是将BSON有效负载从请求HTTP客户端保存到MongoDB数据库。在上述文件下,如果语句执行没有任何错误,则返回新文档的 。collection.InsertOne(ctx, data)insertedId
  5. 接下来,您将设置一个函数来从 MongoDB 集合中删除文档。

6. 创建文件delete_record.go

与任何其他应用程序一样,如果不再需要记录,则必须提供从集合中删除记录的功能。products

  1. 使用 打开一个新文件 。delete_record.gonano
    $ nano delete_record.go
  2. 接下来,在文件中输入以下信息。delete_record.go
    package main
    
    
    
    import (
    
        "context"          
    
        "go.mongodb.org/mongo-driver/mongo"     
    
        "go.mongodb.org/mongo-driver/bson"
    
    )
    
    
    
    func deleteRecord(collection *mongo.Collection, ctx context.Context, data map[string]interface{})(map[string]interface{}, error){
    
    
    
        _, err := collection.DeleteOne(ctx, bson.M{"product_id": data["product_id"]})
    
    
    
        if err != nil { 
    
            return nil, err                    
    
        }     
    
    
    
        res := map[string]interface{}{
    
                   "data" : "Document deleted successfully.",   
    
               } 
    
    
    
        return res, nil
    
    }
  3. 保存并关闭文件。
  4. 在上面的文件中,您正在使用该函数从MongoDB数据库中删除文档。为了确保删除正确的文档,请使用语句检索要删除的项目。换句话说,在向应用程序提交请求时,您应该在 HTTP 有效负载中传递 a。collection.DeleteOne(...)product_idbson.M{"product_id": data["product_id"]}product_idDELETE
  5. 接下来,您将设置一个函数来更新文档。

7. 创建一个新文件update_record.go

您将使用该文件对文档进行更改。此文件下的 function() 依赖于包含要更新的字段的有效负载以及文档的唯一性。update_record.goupdateRecord()product_id

  1. 用于打开新文件。nanoupdate_record.go
    $ nano update_record.go
  2. 接下来,在文件中输入以下信息。update_record.go
    package main
    
    
    
    import (
    
        "context"
    
        "go.mongodb.org/mongo-driver/bson"     
    
        "go.mongodb.org/mongo-driver/mongo" 
    
    )
    
    
    
    func updateRecord(collection *mongo.Collection, ctx context.Context, data map[string]interface{})(map[string]interface{}, error){            
    
    
    
        filter := bson.M{"product_id": data["product_id"]}
    
        fields := bson.M{"$set": data}
    
    
    
        _, err := collection.UpdateOne(ctx, filter, fields)
    
    
    
        if err != nil { 
    
            return nil, err                    
    
        }
    
    
    
        res := map[string]interface{}{
    
                   "data" : "Document updated successfully.",   
    
               } 
    
    
    
        return res, nil
    
    }
  3. 在上面的文件中,您首先使用语句为要更新的文档提供一个参数。然后,您将使用语句提交新的文档值。此处的值来自请求客户端提交的 HTTP 有效负载。filterfilter := bson.M{"product_id": data["product_id"]}fields := bson.M{"$set": data}data
  4. 接下来,使用该函数向集合提交更新请求。在下一步中,您将创建一个函数,用于从 MongoDB 集合中检索记录。collection.UpdateOne(ctx, filter, fields)

8. 创建一个新文件get_records.go

MongoDB API for Golang具有非常直观的功能,用于以地图的形式从数据库中检索文档。您将使用这些函数查询数据库集合并将文档返回到之前创建的文件。main.go

  1. 用于创建新文件。nanoget_records.go
    $ nano get_records.go
  2. 然后,在文件中输入以下信息。get_records.go
    package main
    
    
    
    import (
    
        "context"          
    
        "go.mongodb.org/mongo-driver/bson"
    
        "go.mongodb.org/mongo-driver/mongo" 
    
    )
    
    
    
    func getRecords(collection *mongo.Collection, ctx context.Context)(map[string]interface{}, error){ 
    
    
    
        cur, err := collection.Find(ctx, bson.D{})
    
    
    
        if err != nil { 
    
            return nil, err
    
        }
    
    
    
        defer cur.Close(ctx) 
    
    
    
        var products []bson.M           
    
    
    
        for cur.Next(ctx) {
    
    
    
            var product bson.M
    
    
    
            if err = cur.Decode(&product); err != nil {
    
                return nil, err
    
            }
    
    
    
            products = append(products, product)
    
    
    
        }
    
    
    
        res := map[string]interface{}{}
    
    
    
        res = map[string]interface{}{
    
                  "data" : products,   
    
              }             
    
    
    
        return res, nil
    
    }
  3. 保存并关闭文件。
  4. 在上面的文件中,您将使用该函数返回已保存在集合中的文档的光标。然后,您将使用循环循环访问稍后附加到数组的文档。cur, err := collection.Find(ctx, bson.D{})productsfor cur.Next(ctx) {...}products []bson.M
  5. 最后,您将数据作为映射返回到调用函数。现在,你已为应用设置了所有 CRUD 函数。在下一步中,您将测试应用程序以确保一切按预期工作。[string]interface{}

9. 测试 Golang 应用程序

在此步骤中,你将测试应用程序,以确保它可以处理所有 CRUD 操作,而不会出现任何错误。

  1. 导入 Golang 应用程序的 MongoDB 驱动程序。
    $ go get go.mongodb.org/mongo-driver/mongo
  2. 接下来,执行以下命令以运行应用程序。以下命令允许应用程序启动 Web 服务器并侦听端口上的传入 HTTP 连接,并具有阻止功能。不要在此 SSH 终端窗口上运行任何其他命令。8080
    $ go run ./
  3. 接下来,在单独的终端窗口中建立与服务器的新 SSH 会话。
  4. 尝试通过运行以下命令创建新文档。curl
    $ curl -X POST localhost:8080/api/v1/products -H "Content-Type: application/json" -d '{"product_id": 4, "product_name": "WIRELESS KEYBOARD",  "retail_price": 45.30}'
  5. 您应该获得新记录,如下所示。insertedId
    {
    
      "data": {
    
        "insertedId": "621c9acf3f4e8882c3eeabef"
    
      }
    
    }
  6. 接下来,使用以下命令从集合中检索所有文档。products
    $ curl -X GET localhost:8080/api/v1/products
  7. 现在,您应该会看到四个文档的列表。前三个是首次初始化数据库时设置的文档,最后一个 record() 是您刚刚使用该命令插入的文档。WIRELESS KEYBOARDcurl
    {
    
      "data": [
    
        {
    
          "_id": "621c9aaf35ece941bcc5b80d",
    
          "product_id": 1,
    
          "product_name": "LEATHER BELT",
    
          "retail_price": 24.35
    
        },
    
        {
    
          "_id": "621c9aaf35ece941bcc5b80e",
    
          "product_id": 2,
    
          "product_name": "WINTER JACKET",
    
          "retail_price": 99.95
    
        },
    
        {
    
          "_id": "621c9aaf35ece941bcc5b80f",
    
          "product_id": 3,
    
          "product_name": "WOOLEN SWEATER",
    
          "retail_price": 43.2
    
        },
    
        {
    
          "_id": "621c9acf3f4e8882c3eeabef",
    
          "product_id": 4,
    
          "product_name": "WIRELESS KEYBOARD",
    
          "retail_price": 45.3
    
        }
    
      ]
    
    }
  8. 接下来,运行以下命令以使用 of 更新文档并将其 from 更改为 。product_id1product_nameLEATHER BELTMETAL BUCKLE LEATHER BELT
    $ curl -X PUT localhost:8080/api/v1/products -H "Content-Type: application/json" -d '{"product_id": 1, "product_name": "METAL BUCKLE LEATHER BELT",  "retail_price": 45.30}'
  9. 以下输出确认你已成功更新产品详细信息。
    {
    
      "data": "Document updated successfully."
    
    }
  10. 通过运行以下命令删除带有 of () 的文档。product_id4WIRELESS KEYBOARD
    $ curl -X DELETE localhost:8080/api/v1/products -H "Content-Type: application/json" -d '{"product_id": 4}'
  11. 您应该会收到以下确认消息。
    {
    
      "data": "Document deleted successfully."
    
    }
  12. 接下来,再次检索记录,以确保已在集合中执行 和 操作。UPDATEDELETEproducts
    $ curl -X GET localhost:8080/api/v1/products
  13. 从下面的输出中可以看到,您已经删除了带有 of 的文档,并且您还成功地将文档的值更新为 of 到 。product_id4product_id1METAL BUCKLE LEATHER BELT
    {
    
      "data": [
    
        {
    
          "_id": "621c9aaf35ece941bcc5b80d",
    
          "product_id": 1,
    
          "product_name": "METAL BUCKLE LEATHER BELT",
    
          "retail_price": 45.3
    
        },
    
        {
    
          "_id": "621c9aaf35ece941bcc5b80e",
    
          "product_id": 2,
    
          "product_name": "WINTER JACKET",
    
          "retail_price": 99.95
    
        },
    
        {
    
          "_id": "621c9aaf35ece941bcc5b80f",
    
          "product_id": 3,
    
          "product_name": "WOOLEN SWEATER",
    
          "retail_price": 43.2
    
        }
    
      ]        
    
    }
  14. 您的代码现在按预期工作,并且能够处理所有 CRUD 操作。

10.结论

在本指南中,您使用Golang编程语言在Ubuntu 20.04服务器上连接和操作MongoDB集合中的数据。使用 Golang 设计下一个数据驱动的 MongoDB 应用程序时,请使用本指南中的函数。

如何在 Debian 11 上安装 MongoDB

一、介绍

MongoDB是一个NoSQL数据库应用程序,用于将数据作为类似JSON的文档存储在服务器上。MongoDB拥有现代化的基础设施,具有各种服务,同时具有延展性和友好性,为开发人员及其代码提供了自由。

  • 跨平台
  • 可选架构
  • 各种安全和加密功能
  • 易于实施

本指南将解释如何在 Debian 11 实例上安装和配置 MongoDB 基础知识。

二、准备工作

  • 部署 Debian 11 实例。
  • 使用 sudo 用户登录到实例。

三、安装 MongoDB

安装用于安装 MongoDB 的其他软件包。

$ sudo apt install gnupg2 wget

添加 MongoDB 公共 GPG 密钥。

$ wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | sudo apt-key add -

将 MongoDB 的存储库添加到您的实例中。

$ echo "deb http://repo.mongodb.org/apt/debian buster/mongodb-org/5.0 main" | sudo tee /etc/apt/sources.list.d/mongodb-org-5.0.list

更新您的实例。

$ sudo apt update

安装 MongoDB。

$ sudo apt install mongodb-org

验证 MongoDB 是否已成功安装。

$ mongod --version



db version v5.0.6

    Build Info: {

        "version": "5.0.6",

        "gitVersion": "212a8dbb47f07427dae194a9c75baec1d81d9259",

        "openSSLVersion": "OpenSSL 1.1.1k  25 Mar 2021",

        "modules": [],

        "allocator": "tcmalloc",

        "environment": {

        "distmod": "debian10",

        "distarch": "x86_64",

        "target_arch": "x86_64"

    }

}

启动 MongoDB 服务。

$ sudo systemctl start mongod

启用 MongoDB 以在实例启动时启动。

$ sudo systemctl enable mongod

 四、创建新用户

在MongoDB的环境中创建用户对于在特定数据库中授权自己和访问MongoDB中的功能非常简单有用。

输入MongoDB的shell,Mongosh。您可以连接到MongoDB部署。但是,在本指南中,我们将连接到在本地主机上运行的MongoDB实例。

$ sudo mongosh

默认情况下,您将使用测试数据库。您可以通过输入Mongosh来显示您正在使用的数据库。让我们将数据库切换到管理数据库。db

$ use admin

要创建新用户,请在 Mongosh 中输入此代码块。您可以添加自己唯一的用户名和密码

db.createUser(

    {

        user: "Vultr",

        pwd:  "topSecret1",

        roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]

    }

)

成功创建新用户后,Mongosh 会提示以下输出。

{ ok: 1 }

显示数据库上的可用用户。

> show users

[

    {

        _id: 'admin.Vultr',

        userId: UUID("697f43de-6542-4a3c-b846-fbb3ad9f766b"),

        user: 'Vultr',

        db: 'admin',

        roles: [ { role: 'userAdminAnyDatabase', db: 'admin' } ],

        mechanisms: [ 'SCRAM-SHA-1', 'SCRAM-SHA-256' ]

    }

 ]

您可以通过按 + 两次、+ 或输入 Mongosh 来退出 Mongosh。CTRLCCTRLD.exit

五、启用数据库身份验证

MongoDB的标准是在使用数据库时禁用身份验证。为了保护您的数据库,在MongoDB中启用用户身份验证至关重要。

使用所需的文本编辑器输入MongoDB配置文件。

$ sudo nano /etc/mongod.conf

将此代码块粘贴到 MongoDB 配置文件中以启用身份验证。

security:

 authorization: enabled

保存并退出配置文件,然后重新启动MongoDB。

$ sudo systemctl restart mongod

输入Mongosh与您的用户名和密码。

$ sudo mongosh -u Vultr -p topSecret1

成功进行身份验证后,Mongosh 会提示以下输出。

Current Mongosh Log ID: 61fff39bf56ab6dd6b893038

Connecting to: mongodb://127.0.0.1:27017/directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+1.1.9

Using MongoDB:          5.0.6

Using Mongosh:          1.1.9



For mongosh info see: https://docs.mongodb.com/mongodb-shell/



> 

在 Linux 服务器上使用 Golang 和 MySQL 实现 Redis 事务和锁

一、介绍

在 Redis 中,事务是由必须以原子方式提交的多个命令组成的单个工作单元。也就是说,要么执行所有命令,要么不执行任何命令。Redis 使用 、、 和 函数来实现此功能。MULTIEXECDISCARDWATCH

要通过该工具创建事务,您只需先运行命令,然后运行其他后续命令。最后,应执行命令来处理事务或命令刷新排队的命令。redis-cliMULTIEXECDISCARD

该命令允许您在事务的生存期内实现锁定机制,如果您的密钥被另一个会话修改,该命令应无法避免将 Redis 数据库置于不一致状态。WATCHWATCHedEXEC

在本指南中,您将使用 Redis 事务函数在 Linux 服务器上使用 Golang 和 MySQL 创建抢票应用程序。

二、准备工作

若要继续本教程,请确保具有以下各项:

  • 一个 Linux 服务器。
  • 具有 sudo 权限的非 root 用户。
  • 一个MySQL服务器。
  • 一个 Redis 服务器。
  • 一个戈朗包。

三、 创建 MySQL 数据库、用户帐户和表

Redis 是一个内存数据库,虽然它可以将数据持久保存到磁盘,但它不是为此目的而设计的,可能无法以最佳方式执行。因此,在本指南中,您将使用 MySQL 数据库在 Redis 服务器生成票证信息后将其永久存储到 MySQL 表中。

通过 SSH 连接到您的服务器,然后按照以下步骤创建数据库。

    1. 以 身份登录到 MySQL 服务器。root
      $ sudo mysql -uroot -p
    2. 出现提示时输入您的 MySQL 密码,然后按继续。然后,执行以下命令以创建数据库和帐户。替换为强值。rootENTERbookingsbookings_userEXAMPLE_PASSWORD
      mysql> CREATE DATABASE bookings DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
      
             CREATE USER 'bookings_user'@'localhost' IDENTIFIED WITH mysql_native_password BY 'EXAMPLE_PASSWORD';
      
             GRANT ALL PRIVILEGES ON bookings.* TO 'bookings_user'@'localhost';
      
             FLUSH PRIVILEGES;
    3. 切换到新数据库。
      mysql> USE bookings;
    4. 接下来,创建一个表。在此示例应用程序中,您将使用 Redis 服务器从可用座位池中抓取乘客的座位。然后,您将在表中永久存储分配的信息和信息。ticketsseat_no'sticket_id'stickets
      mysql> CREATE TABLE tickets (
      
                 ticket_id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
      
                 seat_no BIGINT    
      
             ) ENGINE = InnoDB;
    5. 您的数据库、用户帐户和表现已就位。从 MySQL 服务器注销。
      mysql> QUIT;

      在下一步中,您将创建一个 Golang 脚本来接受通过 HTTPS 传入的工单请求。

四、创建文件main.go

要将此应用程序与其他 Linux 文件分开,您需要一个单独的源代码目录。

  1. 创建目录.project
    $ mkdir project
  2. 然后,切换到新目录.project
    $ cd project
  3. 接下来,用于创建文件。此文件包含运行应用程序时触发的主脚本.nanomain.go
    $ nano main.go
  4. With the file opened, paste the following information into the file.main.go
    package main
    
    
    
    import (
    
    "encoding/json"
    
    "fmt"
    
    "net/http"
    
    "strconv"
    
    )
    
    
    
    func main() {
    
        http.HandleFunc("/tickets", httpHandler)            
    
        http.ListenAndServe(":8080", nil)
    
    }
    
    
    
    func httpHandler(w http.ResponseWriter, req *http.Request) { 
    
    
    
        var err error
    
        resp := map[string]interface{}{}
    
    
    
        resp, err = newTicket() 
    
    
    
        enc := json.NewEncoder(w)
    
        enc.SetIndent("", "  ") 
    
    
    
        if err != nil {
    
            resp = map[string]interface{}{"error": err.Error(),}     
    
        }
    
    
    
        if err := enc.Encode(resp); err != nil {
    
            fmt.Println(err.Error())
    
        }
    
    
    
    }
    
    
    
    func newTicket() (map[string]interface{}, error) {
    
    
    
        seatNo, err := createTicket("test")
    
    
    
        if err != nil {
    
            return nil, err
    
        }
    
    
    
        resp := map[string]interface{}{"Response" : "Seat # " + strconv.FormatInt(seatNo, 10) + " booked successfully.",}
    
    
    
        return resp, nil          
    
    
    
    }
  5. Save and close the file when you’re through with editing.
  6. 在上面的文件中,你将导入包,该包允许你格式化 JSON 数据。接下来,你已包含用于格式化和输出字符串的包。该包允许您将其他数据类型转换为字符串格式,同时库提供 HTTP 实现。main.goencoding/jsonfmtstrconvnet/http
  7. 在 main 函数 () 下,您正在侦听 URL 中端口上的传入 HTTP 请求。然后,您将 HTTP 请求重定向到函数,该函数又使用该语句调用该函数。func main() {...}8080/ticketsfunc httpHandler(){...}newTicket()resp, err = newTicket()
  8. 在该函数下,您将使用该语句调用该函数,以从 Redis 服务器获取乘客的座位号。在下一步中,您将在新文件中创建函数。func newTicket(){}createTicket(...)seatNo, err := createTicket("test")createTicket(...)tickets.go

五、 创建文件tickets.go

在此步骤中,您将创建一个连接到 Redis 服务器的 Golang 脚本。首先,脚本将读取一个键,用于检查可供预订的座位总数。然后,如果剩余席位数大于或等于 1,则脚本将保留一个席位号,将剩余席位数减 1 并返回分配给调用脚本的席位。testseat_no

  1. 用于创建文件。nanotickets.go
    $ nano tickets.go
  2. 然后,在文件中输入以下信息。tickets.go
    package main
    
    
    
    import (
    
    "context"
    
    "errors"
    
    "strconv"
    
    "github.com/go-redis/redis"
    
    )
    
    
    
    func createTicket(key string) (int64, error) {
    
    
    
        ctx := context.Background()
    
    
    
        redisClient := redis.NewClient(&redis.Options{
    
            Addr: "localhost:6379",
    
            Password: "",
    
            DB: 0,
    
        })
    
    
    
        var seatNo int64
    
    
    
        err := redisClient.Watch(ctx, func(tx *redis.Tx) error {
    
    
    
            val, err := tx.Get(ctx, key).Int64()
    
    
    
            if err != nil && err != redis.Nil {
    
                return err
    
            }
    
    
    
            seatNo = val
    
    
    
            if (seatNo - 1) < 0 {
    
                return errors.New("Unable to secure a seat.\r\n")
    
            }
    
    
    
            _, err = tx.Pipelined(ctx, func(pipe redis.Pipeliner) error {
    
    
    
                pipe.Set(ctx, key, strconv.FormatInt(seatNo - 1, 10), 0)    
    
    
    
                return nil
    
            })
    
    
    
            if err == nil {
    
                insertRecord(seatNo)
    
            }
    
    
    
    return err
    
    
    
    }, key)
    
    
    
        if err == redis.TxFailedErr {               
    
            return createTicket(key)
    
    }
    
    
    
    return seatNo, err
    
    }
  3. 保存并关闭文件。
  4. 在上面的文件中,您已导入包,以使用语句为 Redis 调用提供不受限制的截止时间。然后,使用包将自定义错误返回到调用函数。该软件包允许您在 Golang 脚本中实现 Redis 函数。contextctx := context.Background()errorsgithub.com/go-redis/redis
  5. 在 中,您接受 1 个参数。这是您用于在应用程序中保留可用席位的名称。在本教程中,你将用作键名称。在生产环境中,您可以考虑使用更有意义/更具描述性的名称,例如 。func createTicket(key string) (int64, error){}keytestavailable_seats
  6. 该语句允许您连接并创建新的 Redis 客户端实例。然后,您使用语句初始化一个空变量。脚本分配座位号后,您将填充此变量。redisClient := redis.NewClient(...)seatNovar seatNo int64
  7. 接下来,您将使用 Redis 函数,该语句在事务的生存期内监视密钥。如果另一个会话以任何方式修改了密钥,则整个事务应中止,并且您已对脚本进行了编码,以便使用语句重试脚本。请记住,在生产环境中,客户可以从不同的应用程序(例如移动应用程序、API、桌面应用程序、门户等)购买票证。这里的想法是一次发行一张票以避免超额预订。WATCHerr := redisClient.Watch(ctx, func()...{...}, key)testtestif err == redis.TxFailedErr { return createTicket(key) }
  8. 在函数内部,您可以使用语句检索剩余席位的值。如果没有剩余席位,您将使用 语句 抛出自定义错误。WATCHval, err := tx.Get(ctx, key).Int64()if (seatNo - 1) < 0 { return errors.New("Unable to secure a seat.\r\n") }
  9. 接下来,预订座位后,您将使用语句减少可用座位数。Redis 管道允许您在一次网络调用中将多个命令传输到 Redis 服务器。在本教程中仅执行一个命令时,应始终使用管道模型,以便在应用程序逻辑发生更改时更轻松地进行修改。pipe.Set(ctx, key, strconv.FormatInt(seatNo - 1, 10), 0)
  10. 然后,您调用该函数以将票证信息保存到 MySQL 数据库,以防使用该语句执行流水线命令时没有错误。一旦整个函数运行,它应该返回文件或任何错误,以防遇到任何错误。insertRecord()if err == nil { insertRecord(seatNo) }createTicket()seatNomain.go
  11. 在下一步中,您将在不同的文件中创建要在此调用的函数。insertRecord()tickets.godatabase.go

六、创建文件database.go

您将为此抢票应用程序创建的最后一个脚本是文件。此文件包含将票证信息永久存储到 MySQL 数据库的逻辑。database.go

  1. 使用 Nano 创建文件。database.go
    $ nano database.go
  2. 然后,在文件中输入以下信息。database.go
    package main
    
    
    
    import (
    
        "database/sql"
    
        _ "github.com/go-sql-driver/mysql"      
    
    )
    
    
    
    func insertRecord(seatNo int64) error {
    
    
    
        dbUser     := "bookings_user"
    
        dbPassword := "EXAMPLE_PASSWORD"
    
        dbName     := "bookings"
    
    
    
        db, err := sql.Open("mysql", dbUser + ":" + dbPassword + "@tcp(127.0.0.1:3306)/" + dbName) 
    
    
    
        if err != nil {
    
            return err
    
        }
    
    
    
        defer db.Close()
    
    
    
        queryString := "insert into tickets (seat_no) values (?)"
    
    
    
        stmt, err   := db.Prepare(queryString) 
    
    
    
        if err != nil {
    
            return err       
    
        }
    
    
    
        defer stmt.Close()     
    
    
    
        _, err = stmt.Exec(seatNo) 
    
    
    
        if err != nil {
    
            return err
    
        }
    
    
    
        return nil
    
    }
  3. 保存并关闭文件。
  4. 在上面的文件中,你正在使用 and 包来实现 Golang 中的 SQL 和 MySQL 功能。在该函数下,你将使用之前创建的凭据连接到 MySQL 数据库。然后,您将工单信息保存到表中。database/sqlgithub.com/go-sql-driver/mysqlfunc insertRecord(...) error {...}tickets
  5. 现在,您已经编写了使用 MySQL 和 Golang 运行 Redis 事务的所有脚本。在下一步中,您将测试一切是否按预期工作。

七、 测试 Redis 事务应用程序

您的 Golang 事务应用程序现在已经准备好进行测试了。

  1. 在执行应用程序之前,请导入已在应用程序中实现的所有包。
    $ go get github.com/go-redis/redis
    
    $ go get github.com/go-sql-driver/mysql
  2. 接下来,打开 Redis 命令行界面。
    $ redis-cli
  3. 通过将键的值设置为 .10test10
    $ SET test 10
  4. 从 Redis 服务器注销。
    $ QUIT
  5. 确保您仍在目录下,然后执行以下命令以运行 Golang 应用程序。project
    $ go run ./
  6. 上面的命令有一个阻塞功能,可以在端口下旋转 Web 服务器。不要在此终端窗口上运行任何其他命令。8080
  7. 接下来,在新的终端窗口中通过 SSH 连接到您的服务器并安装 Apache Bench () 软件包。你将使用此工具向应用程序发送并行票证请求命令,以查看它是否可以处理事务,而不会出现任何超额预订或争用情况。ab
    $ sudo apt install -y apache2-utils
  8. 接下来,向应用程序发送并行票证请求。请记住,您只在 Redis 服务器中使用了席位。因此,只有事务应该成功,其余事务应该失败。此外,由于您已使用该函数实现了 Redis 锁,因此不应出现不同会话具有相同情况的情况。201010seat_noWATCH
    $ ab -v 2 -n 20 -c 20 http://localhost:8080/tickets
  9. 您应该会收到以下响应。
    ...
    
    {
    
      "Response": "Seat # n booked successfully."
    
    }
    
    
    
    ...
    
    
    
    {
    
      "error": "Unable to secure a seat.\r\n"
    
    }
    
    
    
    ...
  10. 接下来,在仍然登录到第二个终端窗口的同时,登录到MySQL数据库以确认新的更改。root
    $ sudo mysql -u root -p
  11. 输入 MySQL 服务器的密码,然后按继续。然后,切换到数据库。rootENTERbooking
    mysql> USE bookings;
  12. 对表运行语句。SELECTtickets
    mysql> SELECT
    
               ticket_id,
    
               seat_no
    
           FROM tickets;
  13. 您现在应该看到以下票证和关联的 .从以下输出中可以看出,没有超额预订的情况。此外,该脚本已成功消除了任何竞争条件的机会,因为没有两张票具有相同的。seat_no'sseat_no
    +-----------+---------+
    
    | ticket_id | seat_no |
    
    +-----------+---------+
    
    |         1 |      10 |
    
    |         2 |       9 |
    
    |         3 |       7 |
    
    |         4 |       8 |
    
    |         5 |       6 |
    
    |         6 |       5 |
    
    |         7 |       3 |
    
    |         8 |       4 |
    
    |         9 |       1 |
    
    |        10 |       2 |
    
    +-----------+---------+
    
    10 rows in set (0.00 sec)
  14. 您的脚本现在按预期工作。

八、结论

在本指南中,您已经在 Linux 服务器中实现了 Redis 事务并使用 Golang 和 MySQL 数据库锁定,以创建抢票应用程序。使用本指南中的逻辑可避免在创建多用户应用程序时出现争用条件和数据库不一致。

如何在 Ubuntu 20.04 上安装 Supabase

一、介绍

在本教程中,您将学习如何在 Ubuntu 20.04 上安装和配置 Supabase。您还将学习如何使用安全密钥和反向代理保护您的 Supabase 实例。

Supabase 是 Firebase 的替代方案,通过 Web 界面提供 PostgreSQL 数据库,用户身份验证,存储和实时 API。Supabase 还具有开源 API 库,可以与其他应用程序轻松交互。

二、准备工作

在开始之前,您应该:

  • 部署至少具有 2 GB RAM 的 Ubuntu 20.04 服务器。
  • 创建具有 sudo 权限的非 root 用户。
  • 以非 root 用户身份登录到您的服务器。
  • 确保服务器已完全更新。
  • 在 Vultr 防火墙或 ufw 上打开端口 433(如果适用)。

您还需要一个指向您的服务器的域名。这是因为SSL证书生成器Certbot/Let’s Encrypt)不提供IP地址的SSL证书。您需要创建一个指向您的服务器的域名。也可以改用 HTTP,但不建议这样做。

三、安装

3.1、Nginx、Certbot 和 Git

  1. 安装 Nginx 和 Git。
    $ sudo apt install nginx git
  2. 卸载任何旧版本的 Certbot 和 Docker。
    $ sudo apt remove certbot docker docker.io containerd runc
  3. 更新快照安装程序。
    $ sudo snap install core; sudo snap refresh core
  4. 使用 安装 Certbot。snap
    $ sudo snap install --classic certbot
  5. 运行 Certbot 并按照提示输入您的域名并将所有流量重定向到 HTTPS。
    $ sudo certbot certonly --standalone
  6. 记下提供的证书和私钥路径。根据所使用的域,它会有所不同。
    Certificate Path: /etc/letsencrypt/live/example.com/fullchain.pem
    
    Private Key Path: /etc/letsencrypt/live/example.com/privkey.pem

如果您使用了其他 SSL 提供程序,请确保证书和私钥文件存储在系统上的某个位置,并且您知道它们的完整文件路径。

3.2、Docker

  1. 使用 安装 Docker 。snap
    $ sudo snap install docker
  2. 克隆 Supabase 存储库。
    $ git clone --depth 1 https://github.com/supabase/supabase.git
  3. 打开文件夹。docker
    $ cd supabase/docker
  4. 将文件复制到 。.env.example.env
    $ cp .env.example .env
  5. 在文本编辑器中打开文件。.env
    $ nano .env
  6. 在浏览器中打开一个强密码生成器,如Bitwarden,并生成一个新密码。它应包含超过 25 个字符。
    https://bitwarden.com/password-generator/
  7. 将文件中的值替换为生成的密码。POSTGRES_PASSWORD.env
    POSTGRES_PASSWORD=<password>
  8. 生成另一个密码,其中包含超过 32 个字符且没有特殊字符。将文件中的值替换为新生成的密码。JWT_SECRET.env
    JWT_SECRET=<new password>
  9. 使用您的在Supabase网站上生成一个。复制并粘贴您的 ,将“预配置有效负载”类型切换为 ,按“生成 JWT”,然后将“生成的令牌”结果复制到文件中的值中。JWT_SECRETANON_KEYJWT_SECRETANON_KEYANON_KEY.env
    https://supabase.com/docs/guides/hosting/overview#api-keys
    
    
    
    ANON_KEY=<generated key>
  10. 在使用相同的 .将其粘贴为文件中的值。SERVICE_KEYJWT_SECRETSERVICE_ROLE_KEY.env
    SERVICE_ROLE_KEY=<generated key>
  11. 关闭文本编辑器并保存更改,方法是使用 + ,然后使用 ,后跟 。CTRLXYENTER
  12. 导航到该文件夹并在文本编辑器中打开。volumes/apikong.yml
    $ cd volumes/api
    
    $ nano kong.yml
  13. 在 下,将用户的替换为文件中的值。consumersanonkeyANON_KEY.env
    consumers:
    
    - username: anon
    
      keyauth_credentials:
    
      - key: [anon key]
  14. 将用户的替换为文件中的值。service_rolekeySERVICE_ROLE_KEY.env
    consumers:
    
    - username: anon
    
      keyauth_credentials:
    
      - key: [anon key]
    
    - username: service_role
    
      keyauth_credentials:
    
      - key: [service_role key]
  15. Close your text editor again by using + , then , followed by .CTRLXYENTER
  16. Run Supabase by using in detached mode. This may take 10-15 minutes.docker-compose
    $ sudo docker-compose up -d
  17. Check that Supabase is running by using . The status should be .dockerUp
    $ sudo docker ps
    
    
    
    STATUS
    
    Up x seconds/minutes

您现在已成功安装 Supabase 并获得签名的 SSL 证书。

四、使用 Nginx 反向代理保护 Supabase

您现在可以使用SSL证书和Nginx来保护Supabase安装。确保替换为您选择的域名或 IP 地址。example.com

  1. 删除 Nginx 默认配置文件。
    $ sudo rm /etc/nginx/sites-enabled/default
  2. 在文本编辑器的 Nginx 目录中创建并打开新的配置文件。sites-available
    $ sudo nano /etc/nginx/sites-available/supabase
  3. 将以下内容粘贴到文件中,并替换为您的域名或 IP 地址。确保 和 行指向您的 SSL 证书。example.comssl_certificatessl_certificate_key
    upstream supabase {
    
      server localhost:3000;
    
    }
    
    
    
    server {
    
      listen 443 ssl http2;
    
      server_name example.com;
    
    
    
      gzip on;
    
    
    
      ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    
      ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    
      ssl_session_cache builtin:1000 shared:SSL:10m; 
    
      ssl_session_cache shared:MySSL:10m;
    
      ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    
      ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
    
      ssl_prefer_server_ciphers on;
    
    
    
    # REST API
    
    location ~ ^/rest/v1/(.*)$ {
    
        proxy_set_header Host $host;
    
        proxy_pass http://kong:8000;
    
        proxy_redirect off;
    
      }
    
    
    
    # Authentication
    
    location ~ ^/auth/v1/(.*)$ {
    
        proxy_set_header Host $host;
    
        proxy_pass http://kong:8000;
    
        proxy_redirect off;
    
      }
    
    
    
    # Realtime
    
    location ~ ^/realtime/v1/(.*)$ {
    
        proxy_redirect off;
    
        proxy_pass http://kong:8000;
    
        proxy_http_version 1.1;
    
        proxy_set_header Upgrade $http_upgrade;
    
        proxy_set_header Connection $connection_upgrade;
    
        proxy_set_header Host $host;
    
      }
    
    }

    此 Nginx 配置将在端口 443 上为 Supabase 提供服务,并将使用您之前生成的 SSL 证书和私钥。它还会将 和 路由指向 Kong API 服务器。/rest/v1//auth/v1//realtime/v1/

  4. 退出文本编辑器并保存更改,方法是按 + ,然后按 ,然后按 。CTRLXYENTER
  5. 在 Nginx 的目录中创建一个指向新配置文件的链接。sites-enabled
    $ sudo ln -s /etc/nginx/sites-available/supabase /etc/nginx/sites-enabled/supabase.conf
  6. 测试配置文件。如果测试成功,您将看到 和消息。syntax is oktest is successful
    $ sudo nginx -t
    
    nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
    
    nginx: configuration file /etc/nginx/nginx.conf test is successful
  7. 重新加载 Nginx 以应用您的更改。
    $ sudo /etc/init.d/nginx reload

 五、整理步骤

您现在应该导航到您的 Supabase 安装。

https://example.com

从那里,您可以配置数据库、身份验证和文件存储。

恭喜,您已成功安装 Supabase 并使用 SSL 证书和 Nginx 反向代理对其进行保护。

如何在 TensorFlow 中使用 BERT 问答与 Python

一、介绍

Tensorflow 是一个开源的端到端平台,用于构建机器学习驱动的应用程序。它包含一组丰富的工具和库,用于各种任务,但主要侧重于神经网络的训练和推理。Tensorflow用于多种应用,包括:

  • 搜索引擎 – 用于部署深度神经网络进行搜索排名,如谷歌的RankBrain。
  • 汽车 – 构建专为自动驾驶设计的神经网络。
  • 教育 – 设计模型来过滤课堂上的有毒聊天消息。
  • Medicare – 用于构建神经网络以从患者数据中检测潜在的健康并发症。
  • 文本摘要和情感分析。

来自变压器的双向编码器表示 (BERT) 是一种自然语言模型,它使用基于转换器的机器学习技术来完成多种常见语言功能,包括:

  • 情感分析 – 情感推断,例如确定电影评论的极性。
  • 自然语言推理 – 确定假设是否在逻辑上遵循前提。
  • 命名实体识别 – 将非结构化文本中的信息提取到预定义的类别中,例如人员名称、位置和数量。
  • 问答 – 构建对话问题和回答系统,如聊天机器人。
  • 文本生成 – 生成与人类编写的文本无法区分的文本。
  • 文本联想查询 – 预测性文字建议,例如撰写电子邮件时 Gmail 的暗示性文字。
  • 文本摘要。

BERT经过了来自维基百科的25亿个单词和来自谷歌书语料库的8亿个单词的预训练。

本指南介绍了如何使用Python在TensorFlow中实现BERT的问答。

二、准备工作

  • Python 的工作知识。
  • 正确安装和配置的 python 工具链,包括 pip(Python 版本 >= 3.7)。

三、设置项目虚拟环境

为应用程序创建隔离的虚拟环境:

  1. 安装python软件包:virtualenv
    $ pip install virtualenv
  2. 创建项目目录:
    $ mkdir bert_QA
  3. 导航到新目录:
    $ cd bert_QA
  4. 创建虚拟环境:
    $ python3 -m venv env

    这将创建一个名为包含脚本的新文件夹,以控制虚拟环境,包括程序库。env

  5. 激活虚拟环境:
    $ source env/bin/activate

 四、安装 TensorFlow

要安装 TensorFlow,请输入以下命令:

$ pip install tensorflow

 五、Tflite 模型制造商

Tflite 模型制作器是一个库,可简化使用自定义数据集训练 Tensorflow Lite 模型的过程。它使用迁移学习来减少所需的训练数据和时间。

tflite 模型制作器库降低了在部署设备上 ML 应用程序时将 Tensorflow 神经网络模型转换为特定输入数据的复杂性。这些型号可以进行微调,以便在内存和 CPU 受限的设备(如智能手机)上运行,而不会牺牲在这些低功耗设备上运行时的精度。

本指南使用 tflite 模型制作器库来微调 BERT 模型以进行问答。

 六、安装Tflite模型制作工具

要安装 tflite 模型制作工具库,请执行以下操作:

  1. 克隆存储库:
    git clone https://github.com/tensorflow/examples
  2. 安装要求:
    pip install -r examples/tensorflow_examples/lite/model_maker/requirements.txt
  3. 安装软件包:
    pip install -e examples/tensorflow_examples/lite/model_maker/pip_package/

 七、构建精简模型

要创建负责问答的微调精简模型,请在工作目录中创建 afile:lite_model_gen.py

touch lite_model_gen.py

 7.1、导入库

通过将以下行添加到lite_model_gen.py文件来导入所需的库:

import tensorflow as tf

from tflite_model_maker import model_spec

from tflite_model_maker import question_answer

from tflite_model_maker.question_answer import DataLoader

从 tflit 模型制作者库中导入的类具有以下功能:

  • model_spec:用于选择表示模型的模型规范。
  • question_answer:用于数据加载和问答的模型训练。
  • DataLoader:提供用于在模型重新训练期间加载自定义数据的通用实用程序。

 7.2、选择型号规格

tflite模型制作器库支持BERT-Base和MobileBERT模型进行问答:

  • BERT-Base- 这是广泛用于NLP任务的标准BERT模型。
  • MobileBERT– 是 BERT-Base 的紧凑型版本,体积小约 4 倍,速度快近 6 倍。MobileBERT尽管比BERT-Base小,但仍能实现有竞争力的结果,并且更适合智能手机等功率受限的设备中的设备端用例。
  • MobileBERT-SQuAD- 该模型使用与MobileBERT相同的架构,但初始模型已经在斯坦福问答数据集(SQuAD)1.1上重新训练。SQuAD是一个阅读理解数据集,由众包工作者在一组维基百科文章中提出的问答对组成。SQuAD 1.1 包含 100,000+ 篇文章的 500+ 问答对。

要使用 MobileBERT-SQuAD 规范,请添加以下行:

# Model specification representing the model

spec = model_spec.get('mobilebert_qa_squad')

model_spec有一个方法 -,该方法将模型规范的名称作为参数。对于使用 BERT 的问答任务,它可以采用三个字符串中的任何一个作为参数:get

  • mobilebert_qa_squad:指定 MobileBERT-SQuAD。
  • mobilebert_qa:指定移动伯特。
  • bert_qa:指定 BERT-Base。

 7.3、获取训练数据

本指南使用 TriviaQA 数据集进行模型训练。TriviaQA 是一个用于阅读理解和问答的大规模数据集,包含超过650k个问答证据三元组。

若要加载数据集进行训练,应使用 TriviaQA 转换 python 脚本将其转换为 SQuAD1.1 格式。本指南将使用预转换的数据集进行训练和验证。

要下载转换后的数据集,请添加以下行:

# Download archived version of already converted datasets

train_data_path = tf.keras.utils.get_file(

      fname='triviaqa-web-train-8000.json',

      origin='https://storage.googleapis.com/download.tensorflow.org/models/tflite/dataset/triviaqa-web-train-8000.json')



validation_data_path = tf.keras.utils.get_file(

      fname='triviaqa-verified-web-dev.json',

      origin='https://storage.googleapis.com/download.tensorflow.org/models/tflite/dataset/triviaqa-verified-web-dev.json')

该函数用于从给定 URL 下载文件(如果缓存中尚不存在)。fname指定文件名,指定文件的原始 URL。这将下载数据集并返回下载文件的路径。tf.keras.utils.get_file

 7.4、加载数据集

通过添加以下行加载数据集:

# Fetch the training and validation data

train_data = DataLoader.from_squad(train_data_path, spec, is_training=True)

validation_data = DataLoader.from_squad(validation_data_path, spec, is_training=False)

DataLoader.from_squad以 SQuAD 格式加载传递的数据集,并根据给定model_spec对文本进行预处理。此方法将文件名和model_spec作为参数,可选参数包括 – 表示数据是否用于训练的布尔值。is_training

 7.5、创建模型

要创建 Tflite 模型,请执行以下操作:

# Create the model

model = question_answer.create(train_data, model_spec=spec)

类方法加载数据并训练模型以进行问答。它需要两个参数 – 训练数据和模型的规范。它还需要可选参数:question_answer.create

  • batch_size=None:用于训练的批量大小。
  • epochs=2:训练的周期数。
  • steps_per_epoch=None:在宣布一个纪元完成并开始下一个纪元之前,批次的样本。它默认为运行,直到输入数据集用尽。
  • shuffle=False:采用布尔值来确定是否应随机播放输入数据。

此方法返回问答的模型实例。

 7.6、评估模型

要使用验证数据集评估模型,请执行以下操作:

# Evaluate the model

model.evaluate(validation_data)

在模型对象上调用该方法会返回指标字典,包括分数和。evaluatef1exact_match

7.7、导出模型

要导出 tflite 模型以用于设备上的问答,请执行以下操作:

# Export the model

model.export(export_dir='.')

这会以默认格式将模型导出到当前工作目录。其他导出格式包括和。TFLITEVOCABSAVED_MODEL

7.8、模型生成代码

最终代码:lite_model_gen.py

import tensorflow as tf

from tflite_model_maker import model_spec

from tflite_model_maker import question_answer

from tflite_model_maker.question_answer import DataLoader



# Model specification representing the model

spec = model_spec.get('mobilebert_qa_squad')



# Download archived version of already converted datasets

train_data_path = tf.keras.utils.get_file(

fname='triviaqa-web-train-8000.json', origin='https://storage.googleapis.com/download.tensorflow.org/models/tflite/dataset/triviaqa-web-train-8000.json')



validation_data_path = tf.keras.utils.get_file(

fname='triviaqa-verified-web-dev.json',

origin='https://storage.googleapis.com/download.tensorflow.org/models/tflite/dataset/triviaqa-verified-web-dev.json')



# Fetch the training and validation data

train_data = DataLoader.from_squad(train_data_path, spec, is_training=True)

validation_data = DataLoader.from_squad(validation_data_path, spec, is_training=False)



# Create the model

model = question_answer.create(train_data, model_spec=spec)



# Evaluate the model

model.evaluate(validation_data)



# Export the model

model.export(export_dir='.')

 八、运行代码

运行代码:

$ python3 lite_model_gen.py

注意:代码运行时介于一小时到几小时之间,具体取决于 CPU 性能或是否存在 GPU。

输出如下所示:

…

….

Downloading data from https://storage.googleapis.com/download.tensorflow.org/models/tflite/dataset/triviaqa-web-train-8000.json

32571392/32570663 [==============================] - 0s 0us/step

32579584/32570663 [==============================] - 0s 0us/step

Downloading data from https://storage.googleapis.com/download.tensorflow.org/models/tflite/dataset/triviaqa-verified-web-dev.json

1171456/1167744 [==============================] - 0s 0us/step

1179648/1167744 [==============================] - 0s 0us/step



INFO:tensorflow:Retraining the models...

INFO:tensorflow:Retraining the models...

Epoch 1/2

1067/1067 [==============================] - 70867s 66s/step - loss: 1.1337 - start_positions_loss: 1.1310 - end_positions_loss: 1.1363

Epoch 2/2

1067/1067 [==============================] - 70983s 67s/step - loss: 0.7942 - start_positions_loss: 0.7934 - end_positions_loss: 0.7949



INFO:tensorflow:Made predictions for 200 records.

INFO:tensorflow:Made predictions for 200 records.

…

…

{'exact_match': 0.5986394557823129, 'final_f1': 0.6728435963129841}

…

…

INFO:tensorflow:TensorFlow Lite model exported successfully: ./model.tflite

成功运行后,精简模型将导出到当前项目目录。

 九、建筑问答

为了集成导出的模型以进行问答,本指南使用 TFlite 支持工具包。该工具包附带强大的库,可将TFLite模型集成到不同的平台上。

要安装:

$ pip install tflite-support

现在,创建问答脚本:

$ touch question_answer.py

9.1、导入库

导入类:BertQuestionAnswerer

from tflite_support.task.text import BertQuestionAnswerer

BertQuestionAnswerer类对文本执行问答。

9.2、创建 BertQuestionAnswerer 对象

从导出的精简模型创建BertQuestionAnswerer对象:

# Create the BertQuestionAnswerer object from a TensorFlow lite model

question_answerer = BertQuestionAnswerer.create_from_file("./model.tflite")

这将返回从模型文件创建的BertQuestionAnswerer对象。

9.3、创建问答上下文

问答需要一个上下文。这个上下文可以是提出问题的段落或句子。以下关于亚历山大大帝的文字来自维基百科。这将用作问答的上下文:

# Create context for question answering

context = "Alexander the Great was a king of the ancient Greek kingdom of Macedon. He succeeded his father Philip II to the throne in 336 BC at the age of 20, and spent most of his ruling years conducting a lengthy military campaign throughout Western Asia and Egypt. By the age of thirty, he had created one of the largest empires in history, stretching from Greece to northwestern India. He was undefeated in battle and is widely considered to be one of history's greatest and most successful military commanders. Until the age of 16, Alexander was tutored by Aristotle. In 335 BC, shortly after his assumption of kingship over Macedon, he campaigned in the Balkans and reasserted control over Thrace and Illyria before marching on the city of Thebes, which was subsequently destroyed in battle. Alexander then led the League of Corinth, and used his authority to launch the pan-Hellenic project envisaged by his father, assuming leadership over all Greeks in their conquest of Persia."

9.4、创建问题

根据上述上下文创建一个字典来保存问答对:

# Create questions

questions = {

    "Who is Alexander the Great": None,

    "Until the age of 16, who tutored Alexander": None,

}

9.5、回答问题

要回答字典中的问题:

# Answer questions

for question in questions.keys():

   answer = question_answerer.answer(context, question)

   questions[question] = answer



print(questions)

该方法有两个参数,一个上下文和一个问题。它根据上下文回答问题并返回 a.QuestionAnswererResult 是由 BertQuestionAnswerer生成的可能答案列表。answerQuestionAnswererResult

十、最终问答代码

完整的 question_answer.py 代码:

from tflite_support.task.text import BertQuestionAnswerer



# Create the BertQuestionAnswerer object from a TensorFlow lite model

question_answerer = BertQuestionAnswerer.create_from_file("./model.tflite")



# Create context for question answering

context = "Alexander the Great was a king of the ancient Greek kingdom of Macedon. He succeeded his father Philip II to the throne in 336 BC at the age of 20, and spent most of his ruling years conducting a lengthy military campaign throughout Western Asia and Egypt. By the age of thirty, he had created one of the largest empires in history, stretching from Greece to northwestern India. He was undefeated in battle and is widely considered to be one of history's greatest and most successful military commanders. Until the age of 16, Alexander was tutored by Aristotle. In 335 BC, shortly after his assumption of kingship over Macedon, he campaigned in the Balkans and reasserted control over Thrace and Illyria before marching on the city of Thebes, which was subsequently destroyed in battle. Alexander then led the League of Corinth, and used his authority to launch the pan-Hellenic project envisaged by his father, assuming leadership over all Greeks in their conquest of Persia."



# Create questions

questions = {

    "Who is Alexander the Great": None,

    "Until the age of 16, who tutored Alexander": None,

}



# Answer questions

for question in questions.keys():

   answer = question_answerer.answer(context, question)

   questions[question] = answer



print(questions)

 十一、运行代码

运行上面的代码:

$ python3 question_answer.py

这将产生以下结果:

{

  'Who is Alexander the Great': QuestionAnswererResult(answers=[

      QaAnswer(pos=Pos(start=12, end=20, logit=-1.621170163154602), text='king of the ancient Greek kingdom of Macedon.'), 

      QaAnswer(pos=Pos(start=12, end=27, logit=-2.1207242012023926), text='king of the ancient Greek kingdom of Macedon. He succeeded his father Philip II'),

      QaAnswer(pos=Pos(start=19, end=20, logit=-3.1698760986328125), text='Macedon.'), 

      QaAnswer(pos=Pos(start=26, end=27, logit=-3.3418025970458984), text='Philip II'),

      QaAnswer(pos=Pos(start=12, end=12, logit=-3.3852314949035645), text='king')]), 



  'Until the age of 16, who tutored Alexander': QuestionAnswererResult(answers=[

      QaAnswer(pos=Pos(start=121, end=121, logit=7.933090686798096), text='Aristotle.'), 

      QaAnswer(pos=Pos(start=118, end=121, logit=1.3499608039855957), text='tutored by Aristotle.'), 

      QaAnswer(pos=Pos(start=121, end=122, logit=1.0493016242980957), text='Aristotle.'), 

      QaAnswer(pos=Pos(start=110, end=121, logit=0.37497782707214355), text='Until the age of 16, Alexander was tutored by Aristotle.'), 

      QaAnswer(pos=Pos(start=118, end=119, logit=-5.260964870452881), text='tutored')])

}

返回的QuestionAnswererResult对象包含一个列表,这些列表表示所提出问题的可能答案。标记答案在上下文中的相对位置,同时表示答案文本。QaAnswerpostext

在第一个问题中,返回了五个可能的答案,其中两个是正确的,而在第二个问题中 – 5 个可能答案中有 4 个是正确的。

十二、结论

本指南介绍了如何在TensorFlow中使用BERT,方法是构建一个精简的问答模型,并使用Tflite支持库在上下文中回答问题。

教程:在 Python 中实现购物车,使用 Vultr 托管数据库进行 Redis

一、介绍

Redis 服务器是使用最广泛的开源数据库解决方案之一。Redis 将所有数据存储在内存中,以实现低延迟和高吞吐量。这些优势使 Redis 适用于存储繁忙网站的购物车数据,尤其是在旺季。

从电子商务网站下订单时,客户通常会从购物清单中选择商品,然后将商品添加到购物车。在后台,购物车驻留在数据库中。虽然使用关系数据库来处理购物车数据是可行的,但此类数据库可能无法在大量用户的情况下以最佳方式执行,并且它们的缓慢可能会对用户体验产生负面影响。

Redis 具有多种功能,您可以使用它们来加快在网站上添加、删除和显示购物车数据的过程。您可以将 Redis,,, 和命令与 Redis 哈希(字段值对的集合)结合使用,以实现所有购物车功能。hsethincrbyhdelhget

本指南向您展示如何在 Ubuntu 20.04 服务器上使用 Python 和托管 Redis 数据库实现购物车应用程序。

二、准备工作

要遵循本指南:

  • 部署 Ubuntu 20.04 服务器。
  • 创建一个非根sudo用户。
  • 配置托管的 Vultr Redis 数据库。然后,导航到您的 Redis 数据库实例并单击概述选项卡以检索您的数据库连接详细信息。本指南使用以下示例连接详细信息:
    • 用户名default
    • 密码EXAMPLE_PASSWORD
    • 主持人SAMPLE_DB_HOST_STRING.vultrdb.com
    • 端口16752

三、创建中央 Redis 类

在设计 Python 应用程序时,通常为基本函数设置单独的类,以促进代码重用并减少重复。本指南使用一个中央 Redis 类,该类处理从 Redis 服务器添加、删除、删除和列出购物车项目的不同功能。按照以下步骤创建类:

  1. 首先创建一个目录,将你的 Python 源代码与其他 Linux 文件分开。project
    $ mkdir project
  2. 切换到新目录。project
    $ cd project
  3. 在文本编辑器中打开一个新文件。redis_gateway.py
    $ nano redis_gateway.py
  4. 在文件中输入以下信息。将 、 和值替换为托管 Redis 数据库中的正确数据库信息。redis_gateway.pydb_hostdb_portdb_pass
    import redis
    
    
    
    class RedisGateway:
    
    
    
        def __init__(self):
    
    
    
            db_host = 'SAMPLE_DB_HOST_STRING.vultrdb.com'
    
            db_port = 16752
    
            db_pass = 'EXAMPLE_PASSWORD'   
    
    
    
            self.redisClient = redis.Redis(host = db_host, port = db_port, password = db_pass, ssl = 'true')
    
    
    
        def add_to_cart(self, json_payload):
    
    
    
            cart_id = json_payload["cart_id"]
    
            product_name = json_payload["product_name"]
    
            quantity = json_payload["quantity"]
    
    
    
            if self.redisClient.hexists(cart_id , product_name):
    
    
    
                self.redisClient.hincrby(cart_id , product_name, quantity)
    
    
    
            else:   
    
    
    
                self.redisClient.hset(cart_id, product_name, quantity)                   
    
    
    
            return "Item added to cart successfully."
    
    
    
        def remove_from_cart(self, json_payload):
    
    
    
            cart_id = json_payload["cart_id"]
    
            product_name = json_payload["product_name"]
    
    
    
    
    
            if self.redisClient.hexists(cart_id, product_name):
    
    
    
                self.redisClient.hdel(cart_id, product_name)
    
    
    
                return "Item removed from cart."
    
    
    
            else:   
    
    
    
                return "Item not found from cart."
    
    
    
        def get_cart(self, cart_id):
    
    
    
            result = self.redisClient.hgetall(cart_id)        
    
    
    
            return result
  5. 保存并关闭文件。redis_gateway.py

3.1、redis_gateway.py文件解释

  • 该文件有一个类。redis_gateway.pyRedisGateway
  • 该类有四种方法。RedisGateway
    1. 该函数在首次导入和初始化类时触发。__init__()
    2. 该函数包含您要添加到购物车的、该和该。在函数下,您首先通过运行函数来检查 Redis 服务器中是否存在购物车。如果购物车存在,则使用命令将新数量添加到购物车。否则,如果具有定义的购物车不存在,则从头开始创建它。然后,您将使用该命令添加新的产品名称和数量。add_to_cart(..., json_payload)json_payloadcart_idproduct_namequantityadd_to_cart()self.redisClient.hexistsself.redisClient.hincrby...cart_idself.redisClient.hset(cart_id, product_name, quantity)
    3. 该函数接受具有要从购物车中删除的产品名称的 JSON 有效负载。在发出命令之前,您使用逻辑语句检查产品是否存在于 Redis 服务器中。remove_from_cart(self, json_payload)if self.redisClient.hexists(cart_id, product_name):self.redisClient.hdel(cart_id, product_name)
    4. 该函数采用并查询 Redis 服务器以使用命令列出购物车中的所有项目。get_cart(..., cart_id)cart_idself.redisClient.hgetall(cart_id)
  • 现在准备好了。您可以在其他源代码文件中引用它,并使用以下语法使用其方法:RedisGateway
    import redis_gateway  
    
    rg = redis_gateway.RedisGateway()
    
    
    
    resp = rg.add_to_cart(json_payload);
    
    resp = rg.remove_from_cart(json_payload);
    
    resp = rg.get_cart(cart_id);

准备好中央 Redis 网关后,按照下一步为您的应用程序创建主文件。

四、 创建主 Python 文件

每个 Python 应用程序都必须有一个在启动应用程序时触发的主文件。本指南使用文件作为起点。按照以下步骤创建文件:main.py

  1. 在文本编辑器中打开一个新文件。main.py
    $ nano main.py
  2. 在文件中输入以下信息。main.py
    import http.server
    
    from http import HTTPStatus
    
    from urllib.parse import urlparse, parse_qs
    
    
    
    import socketserver
    
    import json
    
    
    
    import redis_gateway        
    
    
    
    class httpHandler(http.server.SimpleHTTPRequestHandler):
    
    
    
        def do_POST(self):
    
    
    
            content_length = int(self.headers['Content-Length'])
    
            post_data = self.rfile.read(content_length)
    
    
    
            json_payload = json.loads(post_data) 
    
    
    
            self.send_response(HTTPStatus.OK)
    
            self.end_headers()
    
    
    
            rg = redis_gateway.RedisGateway()
    
    
    
            resp = rg.add_to_cart(json_payload);                
    
    
    
            self.wfile.write(bytes(resp + '\r\n', "utf8"))
    
    
    
        def do_DELETE(self):
    
    
    
            content_length = int(self.headers['Content-Length'])
    
            post_data = self.rfile.read(content_length)
    
    
    
            json_payload = json.loads(post_data) 
    
    
    
            self.send_response(HTTPStatus.OK)
    
            self.end_headers()
    
    
    
            rg = redis_gateway.RedisGateway()
    
    
    
            resp = rg.remove_from_cart(json_payload);                
    
    
    
            self.wfile.write(bytes(resp + '\r\n', "utf8"))
    
    
    
        def do_GET(self):
    
    
    
            self.send_response(HTTPStatus.OK)
    
            self.end_headers()
    
    
    
            parsed_url = urlparse(self.path)
    
            params = parse_qs(parsed_url.query)
    
    
    
            cart_id = params['cart_id'][0]
    
    
    
            rg = redis_gateway.RedisGateway()  
    
    
    
            cart = rg.get_cart(cart_id)
    
    
    
            data = { y.decode('ascii'): cart.get(y).decode('ascii') for y in cart.keys() }
    
    
    
            resp = json.dumps(data, indent = 4, separators = (',', ': '))    
    
    
    
            self.wfile.write(bytes(resp + "\r\n", "utf8"))
    
    
    
    httpServer = socketserver.TCPServer(('', 8080), httpHandler)
    
    
    
    print("HTTP server started at port 8080...")
    
    
    
    try:
    
    
    
        httpServer.serve_forever()
    
    
    
    except KeyboardInterrupt:
    
    
    
        httpServer.server_close()
    
        print("The server is stopped.")
  3. 保存并关闭文件。main.py

4.1、main.py 文件解释

  • 该部分允许您导入应用程序所需的所有必要的 Python 模块。,,,, 和模块为应用程序提供 HTTP 功能。该模块允许您在标准 JSON 响应中格式化响应。然后,要连接到 Redis 服务器,您需要导入自定义模块。import ...http.serverHTTPStatusurlparseparse_qssocketserverjsonredis_gateway
  • 该类处理所有 HTTP 方法。这些是,,,和。这些方法与以下购物车功能匹配。httpHandlerPOSTDELETEGET
    • POST:.将商品添加到购物车。rg.add_to_cart(...)
    • DELETE:.从购物车中删除商品。rg.remove_from_cart(...)
    • GET:.列出购物车中的所有商品。rg.get_cart(...)
  • 该语句在端口上启动 HTTP 服务器并声明为处理程序类。httpServer = socketserver.TCPServer(('', 8080), httpHandler)8080httpHandler

您的应用程序现已准备就绪。按照下一步测试应用程序。

五、 测试 Redis 购物车应用程序

最后一步是安装应用程序所需的第三方 Python 模块,并运行一些测试以确保一切正常。

  1. 安装 Python 包。这是一个用于下载和安装Python模块的工具。pip
    $ sudo apt update
    
    $ sudo apt install -y python3-pip
  2. 使用软件包来安装 Python 模块。pipredis
    $ pip install redis
  3. 使用命令运行应用程序,然后使用启动文件。python3main.py
    $ python3 main.py

    输出。

    HTTP server started at port 8080...
  4. 与服务器建立另一个 SSH 连接,并使用 Linux命令向应用程序发送以下请求。curl
    • 将三个项目添加到购物车使用。abccart_id
      $ curl -X POST http://localhost:8080/ -H 'Content-Type: application/json' -d '{"cart_id": "abc", "product_name": "SMART WATCH", "quantity": "4"}'
      
      
      
      $ curl -X POST http://localhost:8080/ -H 'Content-Type: application/json' -d '{"cart_id": "abc", "product_name": "4G WIRELESS ROUTER", "quantity": "7"}'
      
      
      
      $ curl -X POST http://localhost:8080/ -H 'Content-Type: application/json' -d '{"cart_id": "abc", "product_name": "500W JUICER", "quantity": "2"}'

      输出。

      ...
      
      Item added to cart successfully.
    • 从购物车中检索商品。
      $ curl -X GET 'http://localhost:8080?cart_id=abc'

      输出。

      {
      
          "SMART WATCH": "4",
      
          "4G WIRELESS ROUTER": "7",
      
          "500W JUICER": "2"
      
      }
    • 从购物车中取出一件商品。
      $ curl -X DELETE http://localhost:8080/ -H 'Content-Type: application/json' -d '{"cart_id": "abc", "product_name": "SMART WATCH"}'

      输出。

      Item removed from cart.

 六、结论

本指南在 Ubuntu 20.04 服务器上使用 Python 和来自 Vultr 的托管 Redis 数据库实现了购物车解决方案。在创建下一个购物车应用程序时,请使用本指南中的示例源代码。Redis 购物车实现允许您的应用程序在高峰期处理许多订单,从而增强用户体验。

教程:如何在 Go、NodeJS、PHP、Python 和 redis-cli 中使用 TLS/SSL 安全连接到 Redis

一、介绍

Vultr 的托管 Redis 数据库需要源代码或 CLI 中的 TLS/SSL 连接。本文包含的代码示例演示了如何使用流行的编程语言安全地使用 TLS/SSL 进行连接。redis-cli

1.1、如何查找您的 TLS/SSL 连接网址

要找到您的 Redis 连接 URL,请导航到托管 Redis 数据库的“概述”部分,然后单击“复制 Redis URL”,这会将其放在剪贴板上。

Connection String

  • URL 由用户名、密码、主机和端口值组合而成。
  • 本文中的所有代码都使用此示例 URL,您应该将其替换为真实的 URL:
    rediss://USERNAME:YOUR_PASSWORD@YOUR_HOST:PORT_NUMBER

重要:请注意协议中的双精度,这表明连接使用 TLS/SSL 加密。ssrediss://

二、连接 Go

首先,获取图书馆。go-redis/redis

$ go get github.com/go-redis/redis/v8

接下来,打开一个名为的文件并粘贴以下内容。将示例 Redis URL 替换为您的 URL。main.go

package main



import (

    "context"

    "fmt"



    "github.com/go-redis/redis/v8"

)



var ctx = context.Background()



func main() {

    redisURL := "rediss://USERNAME:YOUR_PASSWORD@YOUR_HOST:PORT_NUMBER"



    addr, err := redis.ParseURL(redisURL)

    if err != nil {

        panic(err)

    }



    rdb := redis.NewClient(addr)



    err = rdb.Set(ctx, "key", "Hello Vultr!", 0).Err()

    if err != nil {

        panic(err)

    }



    val, err := rdb.Get(ctx, "key").Result()

    if err != nil {

        panic(err)

    }

    fmt.Println("Value is:", val)

}

这将创建一个名为 value 的键。然后,它检索密钥并打印其值。keyHello Vultr!

要运行此示例,请执行以下操作:

$ go run main.go

 三、与 NodeJS 连接

首先,安装库。ioredis

$ npm install --save ioredis

接下来,打开一个名为的文件并粘贴以下内容。将示例 Redis URL 替换为您的 URL。index.php

const Redis = require("ioredis");

const redisUrl = "rediss://USERNAME:YOUR_PASSWORD@YOUR_HOST:PORT_NUMBER"

const redis = new Redis(redisUrl);



redis.set("key", "Hello Vultr!");



redis.get("key").then(function (result) {

    console.log(`Value is: ${result}`);

    redis.disconnect();

});

这将创建一个名为 value 的键。然后,它检索密钥并打印其值。keyHello Vultr!

要运行此示例,请执行以下操作:

$ node index.js

 四、与 PHP 连接

首先,安装库。predis

$ composer require predis/predis

接下来,打开一个名为的文件并粘贴以下内容。将示例 Redis URL 替换为您的 URL。index.php

<?php



require 'vendor/autoload.php';

Predis\Autoloader::register();



$redis_url = 'rediss://USERNAME:YOUR_PASSWORD@YOUR_HOST:PORT_NUMBER';



$client = new Predis\Client($redis_url);



$client->set('key', 'Hello Vultr!');

$value = $client->get('key');



echo "Value is: {$value}";

这将创建一个名为 value 的键。然后,它检索密钥并打印其值。keyHello Vultr!

要运行此示例,请执行以下操作:

$ php index.php

 五、与 Python 连接

首先,安装 redis-py 库。

$ pip install redis

接下来,打开一个名为的文件并粘贴以下内容。将示例 Redis URL 替换为您的 URL。main.py

import redis



def main():

    redis_url = 'rediss://USERNAME:YOUR_PASSWORD@YOUR_HOST:PORT_NUMBER'

    redis_client = redis.from_url(redis_url)



    redis_client.set('key', 'Hello Vultr!')

    key = redis_client.get('key').decode('utf-8')



    print('Value is:', key)



if __name__ == '__main__':

    main()

这将创建一个名为 value 的键。然后,它检索密钥并打印其值。keyHello Vultr!

要运行此示例,请执行以下操作:

$ python main.py

 六、连接redis-cli

首先,您需要安装。redis-cli

  • 选项 1:作为操作系统的Redis 包的一部分进行安装。redis-cli
  • 选项 2:安装NodeJS 独立版本。redis-cli

接下来,从终端窗口执行以下操作。将示例 Redis URL 替换为您的 URL。

$ redis-cli -u rediss://USERNAME:YOUR_PASSWORD@YOUR_HOST:PORT_NUMBER

要检查连接,请运行命令,该命令返回所有 Redis 参数。INFO

INFO

使用 uWSGI 在 Nginx 上部署 Flask 网站

创建 Flask 应用程序后,您会发现包含的 Web 服务器最适合开发。在本指南中,您将学习如何使用 Nginx Web 服务器、Certbot for SSL 和 uWSGI 应用服务器在 Debian 10 云服务器实例上托管您的 Flask 应用程序。

 

一、准备工作

  • 完全更新的 Debian 10 服务器
  • 服务器的根权限
  • 注册域名是可选的,但建议使用。

您可以在 Nginx 配置步骤中使用 localhost 来学习本教程,而无需域名。您将无法安装有效的 SSL 证书,因此请跳过 Certbot说明。

二、 安装云

  1. 安装 Nginx 软件包。
    # apt install nginx
  2. 通过在浏览器中导航到服务器的IP地址来测试Nginx。验证是否显示 Nginx 网页。
  3. 如果您有已注册的域,请为服务器设置 DNS 条目。本教程使用以下值:
    • IPv4地址:192.0.2.123
    • 服务器名称:example.com&www.example.com

三、 设置 Flask 和 uWSGI

  1. 安装 uWSGI 和 Flask。
    # apt install python3-pip python-dev
    
    # pip3 install uwsgi flask
  2. 创建网站主目录。
    # mkdir /var/www/example
  3. 如果要部署 Flask 应用程序,请将其移动到 /var/www/example目录。或者,您可以创建一个简单的 Flask 应用程序来测试本指南。
    # nano /var/www/example/main.py

    粘贴到:

    from flask import Flask
    
    app = Flask(__name__)
    
    
    
    @app.route("/")
    
    def index():
    
    return "Hello World!"
    
    
    
    if __name__ == "__main__":
    
    app.run(host="0.0.0.0")
  4. Createconfig-uwsgi.ini for uWSGI.
    # nano /var/www/example/config-uwsgi.ini

    粘贴到:

    [uwsgi]
    
    
    
    app = main
    
    module = %(app)
    
    callable = app
    
    
    
    socket = /var/www/example/example.sock
    
    chdir = /var/www/example
    
    chmod-socket = 666
    
    
    
    processes = 4
    
    die-on-term = true

    对于较大的服务器,可以将进程行设置得更高。

四、 设置 Nginx

  1. 删除默认的 Nginx 配置。
    # rm /etc/nginx/sites-enabled/default
  2. 创建一个新的 Nginx 配置文件。
    # nano /var/www/example/config-nginx.conf

    粘贴以下内容。如果您没有注册域名,请使用localhost进行server_name代替 example.com 和 www.example.com。

    server {
    
    
    
        listen 80;
    
        listen [::]:80;
    
    
    
        server_name example.com www.example.com;
    
    
    
        location / {
    
            include uwsgi_params;
    
            uwsgi_pass unix:/var/www/example/example.sock;
    
        }
    
    }
  3. 创建一个从 Nginx 配置到目录的符号链接。conf.d
    # ln -s /var/www/example/config-nginx.conf /etc/nginx/conf.d/
  4. 重新启动 Nginx。
    # systemctl restart nginx

五、运行 uWSGI

  1. Nginx被配置为将流量代理到uWSGI,但该服务尚未运行。用nohup启动uWSGI。
    # nohup uwsgi /var/www/example/config-uwsgi.ini &
  2. 按 + 发送 SIGINT 信号,并查看进程是否仍在后台运行。对于生产用途,我们建议在 systemd 下启动时运行 uWSGICTRLC
  3. 在 Web 浏览器中导航到您的网站,并验证您看到的是“Hello World!”消息。

六、安装 SSL 证书

如果您有公共域名,请使用 Certbot 使用免费的 Let’s Encrypt 证书为 HTTPS 配置 Web 服务器。

  1. 安装Certbot。
    # apt install certbot python-certbot-nginx
  2. 请求 SSL 证书。
    # certbot --nginx
  3. 在 Certbot 提示时回答问题并同意服务条款。
  4. Certbot将询问哪些域名应该支持SSL,按以选择所有名称。ENTER
  5. 出现提示时,选择将 HTTP 流量重定向到 HTTPS。

七、结论

遵循此初学者教程后,您的 Nginx Web 服务器在 uWSGI 上运行 Flask 应用程序,并使用 Certbot 进行保护。对于完全的生产使用,您还应该在启动时以具有有限权限的普通用户身份运行 uWSGI。

WordPress插件更新“需要FTP账户权限”

要执行请求的操作,WordPress需要访问您网页服务器的权限。 请输入您的FTP登录凭据以继续。 如果您忘记了您的登录凭据(如用户名、密码),请联系您的网站托管商。

其实这是一个网站目录文件的权限问题,可以临时改成755权限,升级完成后再改回去就行了。

或者将网站目录文件的用户改成www权限,其实很多程序都需要www的权限。

网站根目录权限遵循:
文件644 文件夹755 ,权限用户和用户组www,其余文档777权限是不正常的
如出现文件权限问题时,请执行下面3条命令:

chown -R www.www /你的网站目录/
find /你的网站目录所在/ -type d -exec chmod 755 {} \;
find /你的网站目录所在/ -type f -exec chmod 644 {} \;