golang grpc进阶

news2024/10/3 13:29:51

protobuf

官方文档
基本数据类型

.proto TypeNotesGo Type
doublefloat64
floatfloat32
int32使用变长编码,对于负值的效率很低,如果你的域有可能有负值,请使用sint64替代int32
uint32使用变长编码uint32
uint64使用变长编码uint64
sint32使用变长编码,这些编码在负值时比int32高效的多int32
sint64使用变长编码,有符号的整型值。编码时比通常的int64高效。int64
fixed32总是4个字节,如果数值总是比总是比228大的话,这个类型会比uint32高效。uint32
fixed64总是8个字节,如果数值总是比总是比256大的话,这个类型会比uint64高效。uint64
sfixed32总是4个字节int32
sfixed64总是8个字节int64
boolbool
string一个字符串必须是UTF-8编码或者7-bit ASCII编码的文本。string
bytes可能包含任意顺序的字节数据。[]byte
  1. 在java中,无符号32位和64位整型被表示成他们的整型对应形似,最高位被储存在标志位中。
  2. 对于所有的情况,设定值会执行类型检查以确保此值是有效。
  3. 64位或者无符号32位整型在解码时被表示成为ilong,但是在设置时可以使用int型值设定,在所有的情况下,值必须符合其设置其类型的要求。
  4. python中string被表示成在解码时表示成unicode。但是一个ASCIIstring可以被表示成str类型。
  5. Integer在64位的机器上使用,string在32位机器上使用
    当一个消息被解析的时候,如果被编码的信息不包含一个特定的singular元素,被解析的对象锁对应的域被设置位一个默认值,对于不同类型指定如下:
    ● 对于strings,默认是一个空string
    ● 对于bytes,默认是一个空的bytes
    ● 对于bools,默认是false
    ● 对于数值类型,默认是0
    ● 对于枚举,默认是第一个定义的枚举值,必须为0;
    ● 对于消息类型(message),域没有被设置,确切的消息是根据语言确定的,详见generated code guide
    对于可重复域的默认值是空(通常情况下是对应语言中空列表)。
    注:对于标量消息域,一旦消息被解析,就无法判断域释放被设置为默认值(例如,例如boolean值是否被设置为false)还是根本没有被设置。你应该在定义你的消息类型时非常注意。例如,比如你不应该定义boolean的默认值false作为任何行为的触发方式。也应该注意如果一个标量消息域被设置为标志位,这个值不应该被序列化传输。
    查看generated code guide选择你的语言的默认值的工作细节。

proto文件中引入另一个proto文件

1.被引用的proto要先转成go代码
2.使用protobuf提供的proto引用格式与自定义的proto引用格式不同
base.proto

syntax = "proto3";
// 生成proto文件所在包路径
package protos;
// 影响go文件生成位置和包名
//.是当前文件夹
option go_package = ".;proto";
message Empty{}
message Pong{
    string id=1;
}

转成go代码

protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative base.proto 

hello.proto

syntax = "proto3";
// 生成proto文件所在包路径
package protos;
// 影响go文件生成位置和包名
//.是当前文件夹
option go_package = ".;proto";
import "base.proto";
import "google/protobuf/empty.proto";
service Greeter{
    rpc SayHello(HelloRquest)returns(HelloReply);//hello接口
    rpc Ping(google.protobuf.Empty)returns (Pong);
}
message HelloRquest{
    string name=1;//1是编号不是值
    string url=2;
}
message HelloReply{
    string message=1;
}

转成go代码

protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative hello.proto

message嵌套

目录结构
在这里插入图片描述

hello.proto

syntax = "proto3";
// 生成proto文件所在包路径
package protos;
// 影响go文件生成位置和包名
//.是当前文件夹
option go_package = ".;proto";
import "base.proto";
import "google/protobuf/empty.proto";
service Greeter{
    rpc SayHello(HelloRquest)returns(HelloReply);//hello接口
    rpc Ping(google.protobuf.Empty)returns (Pong);
}
message HelloRquest{
    string name=1;//1是编号不是值
    string url=2;
}

message HelloReply{
    string message=1;
    repeated Result data=2;
    message Result{
        string name=1;
        string url=2;
    }
}

转换

protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative hello.proto

使用

package main

import "GolangStudy/Introduction/grpc/example4/proto"

func main() {
	_ = proto.HelloReply_Result{}
}

枚举类型

目录结构

在这里插入图片描述
hello2.proto

syntax = "proto3";

// 生成proto文件所在包路径
package protos;
// 影响go文件生成位置和包名
//.是当前文件夹
option go_package = ".;proto1";
service Greeter{
    rpc SayHello(HelloRquest)returns(HelloReply);//hello接口
}
enum Gender{
    MALE=0;
    FEMALE=1;
}
message HelloRquest{
    string name=1;//1是编号不是值
    Gender g=3;
}
message HelloReply{
    string message=1;
}

转换

protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative hello2.proto

调用

package main

import (
	_ "GolangStudy/Introduction/grpc/example4/proto"
	"GolangStudy/Introduction/grpc/example4/proto1"
	"context"
	"fmt"

	"google.golang.org/grpc"
)

func main() {
	// _ = proto.HelloReply_Result{}
	conn, err := grpc.Dial("127.0.0.1:8080", grpc.WithInsecure())
	if err != nil {
		panic(err)
	}
	defer conn.Close()
	c := proto1.NewGreeterClient(conn)
	r, err := c.SayHello(context.Background(), &proto1.HelloRquest{
		Name: "bobby",
		G:    proto1.Gender_FEMALE,
	})
	if err != nil {
		panic(err)
	}
	fmt.Println(r.Message)
}

map类型

hello2.proto

syntax = "proto3";

// 生成proto文件所在包路径
package protos;
// 影响go文件生成位置和包名
//.是当前文件夹
option go_package = ".;proto1";
service Greeter{
    rpc SayHello(HelloRquest)returns(HelloReply);//hello接口
}
enum Gender{
    MALE=0;
    FEMALE=1;
}
message HelloRquest{
    string name=1;//1是编号不是值
    Gender g=2;
    map<string,string> mp=3;
}
message HelloReply{
    string message=1;
}

转换

protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative hello2.proto

使用

package main

import (
	_ "GolangStudy/Introduction/grpc/example4/proto"
	"GolangStudy/Introduction/grpc/example4/proto1"
	"context"
	"fmt"

	"google.golang.org/grpc"
)

func main() {
	// _ = proto.HelloReply_Result{}
	conn, err := grpc.Dial("127.0.0.1:8080", grpc.WithInsecure())
	if err != nil {
		panic(err)
	}
	defer conn.Close()
	c := proto1.NewGreeterClient(conn)
	r, err := c.SayHello(context.Background(), &proto1.HelloRquest{
		Name: "bobby",
		G:    proto1.Gender_FEMALE,
		Mp: map[string]string{
			"name":    "bobby",
			"company": "mooc",
		},
	})
	if err != nil {
		panic(err)
	}
	fmt.Println(r.Message)
}

timestamp类型

hello2.proto

syntax = "proto3";

// 生成proto文件所在包路径
package protos;
// 影响go文件生成位置和包名
//.是当前文件夹
option go_package = ".;proto1";
import "google/protobuf/timestamp.proto";
service Greeter{
    rpc SayHello(HelloRquest)returns(HelloReply);//hello接口
}
enum Gender{
    MALE=0;
    FEMALE=1;
}
message HelloRquest{
    string name=1;//1是编号不是值
    Gender g=2;
    map<string,string> mp=3;
    google.protobuf.Timestamp addTime=4;
}
message HelloReply{
    string message=1;
}

转换

protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative hello2.proto

使用

package main

import (
	_ "GolangStudy/Introduction/grpc/example4/proto"
	"GolangStudy/Introduction/grpc/example4/proto1"
	"context"
	"fmt"
	"time"

	"google.golang.org/grpc"
	"google.golang.org/protobuf/types/known/timestamppb"
)

func main() {
	// _ = proto.HelloReply_Result{}
	conn, err := grpc.Dial("127.0.0.1:8080", grpc.WithInsecure())
	if err != nil {
		panic(err)
	}
	defer conn.Close()
	c := proto1.NewGreeterClient(conn)
	r, err := c.SayHello(context.Background(), &proto1.HelloRquest{
		Name: "bobby",
		G:    proto1.Gender_FEMALE,
		Mp: map[string]string{
			"name":    "bobby",
			"company": "mooc",
		},
		AddTime: timestamppb.New(time.Now()),
	})
	if err != nil {
		panic(err)
	}
	fmt.Println(r.Message)
}

grpc

metadata

grpc让我们可以像本地调用一样实现远程调用,对于每一次的RPC调用中,都可能会有一些有用的数据,而这些数据就可以通过metadata来传递。metadata是以key-value的形式存储数据的,其中key是string类型,而value是[]string,即一个字符串数组类型。metadata使得client和server能够为对方提供关于本次调用的一些信息,就像一次http请求的RequestHeader和ResponseHeader一样。http中header的生命周周期是一次http请求,那么metadata的生命周期就是一次rpc调用。
实例化

//第一种方式
md := metadata.New(map[string]string{"key1": "val1", "key2": "val2"})
//第二种方式 key不区分大小写,会被统一转成小写。
md := metadata.Pairs(
    "key1", "val1",
    "key1", "val1-2", // "key1" will have map value []string{"val1", "val1-2"}
    "key2", "val2",
)

使用

//发送

md := metadata.Pairs("key", "val")

// 新建一个有 metadata 的 context
ctx := metadata.NewOutgoingContext(context.Background(), md)

// 单向 RPC
response, err := client.SomeRPC(ctx, someRequest)
//接收
func (s *server) SomeRPC(ctx context.Context, in *pb.SomeRequest) (*pb.SomeResponse, err) {
    md, ok := metadata.FromIncomingContext(ctx)
    // do something with metadata
}

使用例子

拦截器

grpc Go支持“拦截器”,即在将请求传递到用户的应用程序逻辑之前在 grpc服务器上执行的中间件,或者在用户调用时在 grpc 客户端上执行的中间件。它是实现常见模式的完美方式:身份验证、日志记录、跟踪、指标、验证、重试、速率限制等,它们可以成为出色的通用构建块,让您轻松构建多个微服务。
实例
目录结构
在这里插入图片描述
hello.proto

syntax = "proto3";
option go_package = ".;proto";
service Greeter {
    rpc SayHello (HelloRequest) returns (HelloReply);
}
//将 sessionid放入 放入cookie中 http协议
message HelloRequest {
    string name = 1;
}

message HelloReply {
    string message = 1;
}

生成

protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative hello2.proto

server

package main

import (
	"context"
	"fmt"
	"net"

	"google.golang.org/grpc"

	"GolangStudy/Introduction/grpc/interpretor/proto"
)

type Server struct{}

func (s *Server) SayHello(ctx context.Context, request *proto.HelloRequest) (*proto.HelloReply,
	error) {
	return &proto.HelloReply{
		Message: "hello " + request.Name,
	}, nil
}

func main() {
	var interceptor grpc.UnaryServerInterceptor
	interceptor = func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
		// 继续处理请求
		fmt.Println("接收到新请求")
		res, err := handler(ctx, req)
		fmt.Println("请求处理完成")
		return res, err
	}
	var opts []grpc.ServerOption
	opts = append(opts, grpc.UnaryInterceptor(interceptor))

	g := grpc.NewServer(opts...)
	proto.RegisterGreeterServer(g, &Server{})
	lis, err := net.Listen("tcp", "0.0.0.0:50051")
	if err != nil {
		panic("failed to listen:" + err.Error())
	}
	err = g.Serve(lis)
	if err != nil {
		panic("failed to start grpc:" + err.Error())
	}
}

client

package main

import (
	"context"
	"fmt"
	"time"

	"google.golang.org/grpc"

	"GolangStudy/Introduction/grpc/interpretor/proto"
)

func interceptor(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
	start := time.Now()
	err := invoker(ctx, method, req, reply, cc, opts...)
	fmt.Printf("method=%s req=%v rep=%v duration=%s error=%v\n", method, req, reply, time.Since(start), err)
	return err
}

func main() {
	//stream
	var opts []grpc.DialOption

	opts = append(opts, grpc.WithInsecure())
	// 指定客户端interceptor
	opts = append(opts, grpc.WithUnaryInterceptor(interceptor))

	conn, err := grpc.Dial("localhost:50051", opts...)
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	c := proto.NewGreeterClient(conn)
	r, err := c.SayHello(context.Background(), &proto.HelloRequest{Name: "bobby"})
	if err != nil {
		panic(err)
	}
	fmt.Println(r.Message)
}

拦截器框架

auth认证

hello.proto

syntax = "proto3";
option go_package = ".;proto";
service Greeter {
    rpc SayHello (HelloRequest) returns (HelloReply);
}

message HelloRequest {
    string name = 1;
}

message HelloReply {
    string message = 1;
}

生成

protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative hello2.proto

server

package main

import (
	"context"
	"fmt"
	"net"

	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/metadata"
	"google.golang.org/grpc/status"

	"GolangStudy/Introduction/grpc/token_auth/proto"
)

type Server struct{}

func (s *Server) SayHello(ctx context.Context, request *proto.HelloRequest) (*proto.HelloReply,
	error) {
	return &proto.HelloReply{
		Message: "hello " + request.Name,
	}, nil
}

func main() {
	var interceptor grpc.UnaryServerInterceptor
	interceptor = func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
		// 继续处理请求
		fmt.Println("接收到新请求")
		md, ok := metadata.FromIncomingContext(ctx)
		if !ok {
			return resp, status.Error(codes.Unauthenticated, "无token认证信息")
		}
		var (
			appid  string
			appkey string
		)
		if va1, ok := md["appid"]; ok {
			appid = va1[0]
		}
		if va1, ok := md["appkey"]; ok {
			appkey = va1[0]
		}
		fmt.Println(appid, appkey)
		if appid != "101010" || appkey != "i am key" {
			return resp, status.Error(codes.Unauthenticated, "无token认证信息")
		}
		res, err := handler(ctx, req)
		fmt.Println("请求处理完成")
		return res, err
	}
	var opts []grpc.ServerOption
	opts = append(opts, grpc.UnaryInterceptor(interceptor))

	g := grpc.NewServer(opts...)
	proto.RegisterGreeterServer(g, &Server{})
	lis, err := net.Listen("tcp", "0.0.0.0:50051")
	if err != nil {
		panic("failed to listen:" + err.Error())
	}
	err = g.Serve(lis)
	if err != nil {
		panic("failed to start grpc:" + err.Error())
	}
}

client

package main

import (
	"context"
	"fmt"

	"GolangStudy/Introduction/grpc/token_auth/proto"

	"google.golang.org/grpc"
)

type customCredential struct{}

func (cc *customCredential) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
	return map[string]string{
		"appid":  "101010",
		"appkey": "i am key",
	}, nil
}

// RequireTransportSecurity indicates whether the credentials requires
// transport security.
func (cc *customCredential) RequireTransportSecurity() bool {
	return false
}
func main() {
	// interceptor := func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
	// 	start := time.Now()
	// 	md := metadata.New(map[string]string{
	// 		"appid":  "101010",
	// 		"appkey": "i am key",
	// 	})
	// 	ctx = metadata.NewOutgoingContext(context.Background(), md)
	// 	err := invoker(ctx, method, req, reply, cc, opts...)
	// 	fmt.Printf("method=%s req=%v rep=%v duration=%s error=%v\n", method, req, reply, time.Since(start), err)
	// 	return err
	// }
	//stream
	var opts []grpc.DialOption

	opts = append(opts, grpc.WithInsecure())
	// 指定客户端interceptor
	opts = append(opts, grpc.WithPerRPCCredentials(&customCredential{}))

	conn, err := grpc.Dial("127.0.0.1:50051", opts...)
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	c := proto.NewGreeterClient(conn)
	r, err := c.SayHello(context.Background(), &proto.HelloRequest{Name: "bobby"})
	if err != nil {
		panic(err)
	}
	fmt.Println(r.Message)
}

验证器

实例
Protocol Buffer Validation
使用的mac电脑,使用官网的第二种第三种都试过了不可以,第二种在$GOPATH:bin找不到protoc-gen-validate文件,第三种能找到但是将proto转换成go文件时会一直报如下错误,最后使用了第一种才成功。

protoc-gen-validate: program not found or is not executable
Please specify a program using absolute path or make sure the program is available in your PATH system variable
--validate_out: protoc-gen-validate: Plugin failed with status code 1.
//第一种
go install github.com/envoyproxy/protoc-gen-validate@latest

//第二种
go get -d github.com/envoyproxy/protoc-gen-validate

//第三种
git clone https://github.com/bufbuild/protoc-gen-validate.git
cd $GOPATH/bin
cd protoc-gen-validate 
make build

hello.proto

syntax = "proto3";

option go_package=".;proto";
import "validate.proto";

service Greeter {
    rpc SayHello (Person) returns (Person);
}

message Person {
    uint64 id    = 1 [(validate.rules).uint64.gt    = 999];

    string email = 2 [(validate.rules).string.email = true];
    string mobile  = 3 [(validate.rules).string = {
                      pattern:  "^1[3456789]\\d{9}$"}];

}

转换

protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative  --validate_out="lang=go:." hello.proto

client

package main

import (
	"GolangStudy/Introduction/grpc/validate/proto"
	"context"
	"fmt"

	"google.golang.org/grpc"
)

type customCredential struct{}

func main() {
	var opts []grpc.DialOption

	//opts = append(opts, grpc.WithUnaryInterceptor(interceptor))
	opts = append(opts, grpc.WithInsecure())

	conn, err := grpc.Dial("localhost:50051", opts...)
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	c := proto.NewGreeterClient(conn)
	//rsp, _ := c.Search(context.Background(), &empty.Empty{})
	rsp, err := c.SayHello(context.Background(), &proto.Person{
		Id:     9999,
		Email:  "bobby@qq.com",
		Mobile: "19999999999",
	})
	if err != nil {
		panic(err)
	}
	fmt.Println(rsp.Id)
}

server

package main

import (
	"context"
	"net"

	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	"google.golang.org/grpc"

	"GolangStudy/Introduction/grpc/validate/proto"
)

type Server struct{}

func (s *Server) SayHello(ctx context.Context, request *proto.Person) (*proto.Person,
	error) {
	return &proto.Person{
		Id: 32,
	}, nil
}

type Validator interface {
	Validate() error
}

func main() {
	var interceptor grpc.UnaryServerInterceptor
	interceptor = func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
		// 继续处理请求
		if r, ok := req.(Validator); ok {
			if err := r.Validate(); err != nil {
				return nil, status.Error(codes.InvalidArgument, err.Error())
			}
		}

		return handler(ctx, req)
	}
	var opts []grpc.ServerOption
	opts = append(opts, grpc.UnaryInterceptor(interceptor))

	g := grpc.NewServer(opts...)
	proto.RegisterGreeterServer(g, &Server{})
	lis, err := net.Listen("tcp", "0.0.0.0:50051")
	if err != nil {
		panic("failed to listen:" + err.Error())
	}
	err = g.Serve(lis)
	if err != nil {
		panic("failed to start grpc:" + err.Error())
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2186293.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大语言模型入门(一)——大语言模型智能助手

一、大语言模型智能助手 2022年末ChatGPT一经推出&#xff0c;一时间不注册个账号用一下都跟不上潮流了。然而&#xff0c;我们要注册OpenAI的账号使用ChatGPT还是一件比较麻烦的事情&#xff08;懂的都懂&#xff09;。好在&#xff0c;国内各大团队非常给力地及时推出了自研的…

野火STM32F103VET6指南者开发板入门笔记:【1】点亮RGB

硬件介绍 提示&#xff1a;本文是基于野火STM32F103指南者开发板所写例程&#xff0c;其他开发板请自行移植到自己的工程项目当中即可。 RGB-LEDPin引脚&#xff1a;低电平-点亮&#xff0c;高电平-熄灭REDPB5GREENPB0BLUEPB1 文章目录 硬件介绍软件介绍&#xff1a;结构体方式…

三、数据链路层(上)

目录 3.1数据链路层概述 3.1.1术语 3.1.2功能 3.2封装成帧和透明传输 3.2.1封装成帧 ①字符计数法 ②字符&#xff08;节&#xff09;填充法 ③零比特填充法 ④违规编码法 3.2.2透明传输 3.2.3差错控制 差错原因 检错编码 奇偶校验 ☆循环冗余码CRC 例题 纠错…

社区医院疫苗接种预约小程序管理系统SpringBoot+vue

目录 一、项目概述 二、系统架构 1. 技术栈 2. 架构图 三、后端设计 1. 数据模型 2. API 设计 四、前端设计 五、功能实现 1. 用户登录注册 2. 接种建档 3. 疫苗展示 六、总结 一、项目概述 本项目旨在为社区医院提供一个高效便捷的疫苗接种预约管理系统。系统主要…

记一次vue路由跳转登陆之前的页面,参数丢失问题

一、背景 vue3.0&#xff0c;项目登陆之前访问某个可访问的页面&#xff0c;当跳转到需要登陆才能访问的页面时&#xff0c;跳转到登陆页面&#xff0c;登陆后再跳转到登陆之前需要登陆才能访问的页面&#xff0c;跳转时发现参数丢失了。 A页面&#xff08;无需登陆&#xff…

【零基础保姆级教程】MMDetection3安装与训练自己的数据集

最近在跑对比试验&#xff0c;由于MMDetection框架的算法较齐全&#xff0c;遂决定写一篇教程留做参考。若你对流程有问题与疑问欢迎评论区指出 本文运行环境如下供参考&#xff1a; python版本3.9MMDetection版本3.3 一、虚拟环境的搭建 参考该博客搭建基本环境&#xff1…

【开源免费】基于SpringBoot+Vue.JS水果购物网站(JAVA毕业设计)

本文项目编号 T 065 &#xff0c;文末自助获取源码 \color{red}{T065&#xff0c;文末自助获取源码} T065&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…

从认识String类,到走进String类的世界

作为一个常用的数据类型&#xff0c;跟随小编一同进入String的学习吧&#xff0c;领略String的一些用法。 1. 认识 String 类 2. 了解 String 类的基本用法 3. 熟练掌握 String 类的常见操作 4. 认识字符串常量池 5. 认识 StringBuffer 和 StringBuilder 一&#xff1a;…

【吊打面试官系列-MySQL面试题】Mysql中的事务回滚机制概述?

大家好&#xff0c;我是锋哥。今天分享关于【Mysql中的事务回滚机制概述&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; Mysql中的事务回滚机制概述&#xff1f; 事务是用户定义的一个数据库操作序列&#xff0c;这些操作要么全做要么全不做&#xff0c;是一个…

职称评审一次通过需要注意什么?

谁能想到 被评委会全票通过的职称材料 居然要注意这么多细节 营业执照需要加盖公章 论文需要拆分上传 业绩需要连续提供近几年的 奖项可以加分 一些表格有模板 所以职称评审做材料还是有很多方面需要好好注意一下的&#xff0c;建议还是找机构帮你代理整理&#xff0c;因…

如何使用ssm实现基于web的网站的设计与实现+vue

TOC ssm756基于web的网站的设计与实现vue 绪论 1.1 研究背景 当前社会各行业领域竞争压力非常大&#xff0c;随着当前时代的信息化&#xff0c;科学化发展&#xff0c;让社会各行业领域都争相使用新的信息技术&#xff0c;对行业内的各种相关数据进行科学化&#xff0c;规范…

10. 模块

理想情况下&#xff0c;程序的结构清晰明了。它的运作方式易于解释&#xff0c;每个部分都发挥着明确的作用。 实际上&#xff0c;程序是有机生长的。当程序员发现新的需求时&#xff0c;就会添加新的功能。要使程序保持良好的结构&#xff0c;需要持续的关注和工作。这些工作只…

Linux ssh 免密登录配置

参考资料 ~/.ssh/configについて~/.ssh/configを使ってSSH接続を楽にする.ssh/configファイルでSSH接続を管理する 目录 一. 密钥生成1.1 生成工具1.1.1 OpenSSH1.1.2 Git 1.2 生成命令1.3 注意事项1.4 解决路径中的用户名乱码 二. 将公钥配置到目标服务&#xff0c;免密登录2…

Pycharm关于Interpreter问题:ModuleNotFoundError: No module named

PS&#xff1a;本来想写一个脚本&#xff0c;也好久没用python了&#xff0c;然后创建项目也不会了。 BG: 一直报错这个 ModuleNotFoundError: No module named 网上教程都试了&#xff0c;都不行&#xff0c;原因是在项目本身创建了一个环境&#xff0c;而不是&#xff0c;…

活动公司都是怎么去寻找客户的

活动公司都是怎么拓业务的&#xff1f;只有我靠缘分吗&#xff1f; 一直觉得这是一个很难的问题&#xff0c;毕竟活动都很低频&#xff0c;是不是都得先去交个朋。下面一些方法&#xff0c;说不定对你有用。 1、小红书推广、B站等自媒体平台; 2、抖音推广、百度推广等推广平台…

招联2025校招内推

【投递方式】 直接扫下方二维码&#xff0c;或点击内推官网https://wecruit.hotjob.cn/SU61025e262f9d247b98e0a2c2/mc/position/campus&#xff0c;使用内推码 igcefb 投递&#xff09; 【招聘岗位】 后台开发 前端开发 数据开发 数据运营 算法开发 技术运维 软件测试 产品策…

68.【C语言】动态内存管理(重点)(上)

本文为数据结构打下基础 备注:数据结构需要掌握指针,结构体和动态内存管理 目录 1.内存开辟的方式 2.malloc函数 cplusplus网翻译 提炼要点 操作内存空间 01.开辟内存空间成功 02.开辟内存空间失败 如果是x64debug环境下,可能会成功 1.内存开辟的方式 01.创建变量 in…

LabVIEW混合控制器质量检测

随着工业自动化水平的提高&#xff0c;对控制器的精度、稳定性、可靠性要求也在不断上升。特别是在工程机械、自动化生产、风力发电等领域&#xff0c;传统的质量检测方法已无法满足现代工业的高要求。因此&#xff0c;开发一套自动化、精确、可扩展的混合控制器质量检测平台成…

Web安全 - 阶段性总结回顾_风险评估

文章目录 OWASP 2023 TOP 10用户数据的威胁评估密码盗窃XSS 漏洞SQL 注入CSRF 漏洞 资产数据的威胁评估SSRF 漏洞反序列化漏洞插件漏洞后门 认证和授权的安全防护检测与过滤加强认证补丁管理 进一步防护手段最小权限原则WAFIDS 小结 OWASP 2023 TOP 10 OWASP Top 10 概述 OWASP…

类似 o1 的推理-Llama3.1-70b 提供支持的 g1 创建推理链

g1简介: g1 是一个利用 Llama 3.1 70b 模型在 Groq 硬件上实现类似 OpenAI o1 推理链能力的开源项目。它通过精心设计的提示策略来引导语言模型进行逐步推理&#xff0c;从而解决了传统语言模型在逻辑推理方面的不足。g1 项目的目标是探索如何利用提示策略来提高语言模型的推理…