系统开发中时常会需要缓存来提升并发读的能力,这时可以通过mysql的UDF和hiredis来进行同步

原理:

通过mysql自动同步redis

在服务端开发过程中,一般会使用MySQL等关系型数据库作为最终的存储引擎,Redis其实也可以作为一种键值对型的数据库,但在一些实际场景中,特别是关系型结构并不适合使用Redis直接作为数据库。这俩家伙简直可以用“男女搭配,干活不累”来形容,搭配起来使用才能事半功倍。本篇我们就这两者如何合理搭配以及他们之间数据如何进行同步展开。

一般地,Redis可以用来作为MySQL的缓存层。为什么MySQL最好有缓存层呢?想象一下这样的场景:在一个多人在线的游戏里,排行榜、好友关系、队列等直接关系数据的情景下,如果直接和MySQL正面交手,大量的数据请求可能会让MySQL疲惫不堪,甚至过量的请求将会击穿数据库,导致整个数据服务中断,数据库性能的瓶颈将掣肘业务的开发;那么如果通过Redis来做数据缓存,将大大减小查询数据的压力。在这种架子里,当我们在业务层有数据查询需求时,先到Redis缓存中查询,如果查不到,再到MySQL数据库中查询,同时将查到的数据更新到Redis里;当我们在业务层有修改插入数据需求时,直接向MySQL发起请求,同时更新Redis缓存。

在上面这种架子中,有一个关键点,就是MySQL的CRUD发生后自动地更新到Redis里,这需要通过MySQL UDF来实现。具体来说,我们把更新Redis的逻辑放到MySQL中去做,即定义一个触发器Trigger,监听CRUD这些操作,当操作发生后,调用对应的UDF函数,远程写回Redis,所以业务逻辑只需要负责更新MySQL就行了,剩下的交给MySQL UDF去完成。

那 什么是UDF呢?

UDF,是User Defined Function的缩写,用户定义函数。MySQL支持函数,也支持自定义的函数。UDF比存储方法有更高的执行效率,并且支持聚集函数。

UDF定义了5个API:xxx_init()、xxx_deinit()、xxx()、xxx_add()、xxx_clear()。官方文档(http://dev.mysql.com/doc/refman/5.7/en/adding-udf.html)给出了这些API的说明。相关的结构体定义在mysql_com.h里,它又被mysql.h包含,使用时只需#include<mysql.h>即可。他们之间的关系和执行顺序可以以下图来表示:

1. xxx()

这是主函数,5个函数至少需要xxx(),对MySQL操作的结果在此返回。函数的声明如下:

char *xxx(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error);

long long xxx(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error);

double xxx(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error);

SQL的类型和C/C++类型的映射:

SQL Type C/C++ Type
STRING char *
INTEGER long long
REAL double

2. xxx_init()

xxx()主函数的初始化,如果定义了,则用来检查传入xxx()的参数数量、类型、分配内存空间等初始化操作。函数的声明如下:

my_bool xxx_init(UDF_INIT *initid, UDF_ARGS *args, char *message);

3. xxx_deinit()

xxx()主函数的反初始化,如果定义了,则用来释放初始化时分配的内存空间。函数的声明如下:

void xxx_deinit(UDF_INIT *initid);

4. xxx_add()

在聚合UDF中反复调用,将参数加入聚合参数中。函数的声明如下:

void xxx_add(UDF_INIT *initid, UDF_ARGS *args, char *is_null,char *error);

5. xxx_clear()

在聚合UDF中反复调用,重置聚合参数,为下一行数据的操作做准备。函数的声明如下:

void xxx_clear(UDF_INIT *initid, char *is_null, char *error);

(二.) UDF函数的基本使用

在此之前,需要先安装mysql的开发包:

[root@localhost zhxilin]# yum install mysql-devel -y

我们定义一个最简单的UDF主函数:

 1 /*simple.cpp*/2 #include <mysql.h>3 4 extern "C" long long simple_add(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)5 {6     int a = *((long long *)args->args[0]);7     int b = *((long long *)args->args[1]);8     return a + b;9 }
10
11 extern "C" my_bool simple_add_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
12 {
13     return 0;
14 }

由于mysql提供的接口是C实现的,我们在C++中使用时需要添加:

extern "C" { ... }

接下来编译成动态库.so:

[zhxilin@localhost mysql-redis-test]$ g++ -shared -fPIC -I /usr/include/mysql -o simple_add.so simple.cpp

-shared 表示编译和链接时使用的是全局共享的类库;

-fPIC编译器输出位置无关的目标代码,适用于动态库;

-I /usr/include/mysql 指明包含的头文件mysql.h所在的位置。

编译出simple_add.so后用root拷贝到/usr/lib64/mysql/plugin下:

[root@localhost mysql-redis-test]# cp simple_add.so /usr/lib64/mysql/plugin/

紧接着可以在MySQL中创建函数执行了。登录MySQL,创建关联函数:

mysql> CREATE FUNCTION simple_add RETURNS INTEGER SONAME 'simple_add.so';
Query OK, 0 rows affected (0.04 sec)

测试UDF函数:

mysql> select simple_add(10, 5);
+-------------------+
| simple_add(10, 5) |
+-------------------+
|                15 |
+-------------------+
1 row in set (0.00 sec)

可以看到,UDF正确执行了加法。

创建UDF函数的语法是 CREATE FUNCTION xxx RETURNS [INTEGER/STRING/REAL] SONAME '[so name]';

删除UDF函数的语法是 DROP FUNCTION simple_add;

mysql> DROP FUNCTION simple_add;
Query OK, 0 rows affected (0.03 sec)

(三). 在UDF中访问Redis

跟上述做法一样,只需在UDF里调用Redis提供的接口函数。Redis官方给出了Redis C++ Client (https://github.com/mrpi/redis-cplusplus-client),封装了Redis的基本操作。

源码是依赖boost,需要先安装boost:

[root@localhost dev]# yum install boost boost-devel

然后下载redis cpp client源码:

[root@localhost dev]# git clone https://github.com/mrpi/redis-cplusplus-client

使用时需要把redisclient.h、anet.h、fmacros.h、anet.c 这4个文件考到目录下,开始编写关于Redis的UDF。我们定义了redis_hset作为主函数,连接Redis并调用hset插入哈希表,redis_hset_init作为初始化,检查参数个数和类型。

 1 /* test.cpp */2 #include <stdio.h>3 #include <mysql.h>4 #include "redisclient.h"5 using namespace boost;6 using namespace std;7 8 static redis::client *m_client = NULL;9
10 extern "C" char *redis_hset(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error) {
11     try {
12         // 连接Redis
13         if(NULL == m_client) {
14             const char* c_host = getenv("REDIS_HOST");
15             string host = "127.0.0.1";
16             if(c_host) {
17                 host = c_host;
18             }
19             m_client = new redis::client(host);
20         }
21
22         if(!(args->args && args->args[0] && args->args[1] && args->args[2])) {
23             *is_null = 1;
24             return result;
25         }
26
27         // 调用hset插入一个哈希表
28         if(m_client->hset(args->args[0], args->args[1], args->args[2])) {
29             return result;
30         } else {
31             *error = 1;
32             return result;
33         }
34     } catch (const redis::redis_error& e) {
35         return result;
36     }
37 }
38
39 extern "C" my_bool redis_hset_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
40     if (3 != args->arg_count) {
41         // hset(key, field, value) 需要三个参数
42         strncpy(message, "Please input 3 args for: hset('key', 'field', 'value');", MYSQL_ERRMSG_SIZE);
43         return -1;
44     }
45     if (args->arg_type[0] != STRING_RESULT  ||
46         args->arg_type[1] != STRING_RESULT  ||
47         args->arg_type[2] != STRING_RESULT) {
48         // 检查参数类型
49         strncpy(message, "Args type error: hset('key', 'field', 'value');", MYSQL_ERRMSG_SIZE);
50         return -1;
51     }
52
53     args->arg_type[0] = STRING_RESULT;
54     args->arg_type[1] = STRING_RESULT;
55     args->arg_type[2] = STRING_RESULT;
56
57     initid->ptr = NULL;
58     return 0;
59 }

编译链接:

[zhxilin@localhost mysql-redis-test]$ g++ -shared -fPIC -I /usr/include/mysql -lboost_serialization -lboost_system -lboost_thread -o libmyredis.so anet.c test.cpp

编译时需要加上-lboost_serialization -lboost_system -lboost_thread, 表示需要链接三个动态库:libboost_serialization.so、libboost_system.so、libboost_thread.so,否则在运行时会报缺少函数定义的错误。

编译出libmyredis.so之后,将其拷贝到mysql的插件目录下并提权:

[root@localhost mysql-redis-test]# cp libmyredis.so /usr/lib64/mysql/plugin/ & chmod 777 /usr/lib64/mysql/plugin/libmyredis.so 

完成之后登录MySQL,创建关联函数测试一下:

mysql> DROP FUNCTION IF EXISTS `redis_hset`;
Query OK, 0 rows affected (0.16 sec)mysql> CREATE FUNCTION redis_hset RETURNS STRING SONAME 'libmyredis.so';
Query OK, 0 rows affected (0.02 sec)

先删除老的UDF,注意函数名加反引号(``)。调用UDF测试,返回0,执行成功:

mysql> SELECT redis_hset('zhxilin', 'id', '09388334');
+-----------------------------------------+
| redis_hset('zhxilin', 'id', '09388334') |
+-----------------------------------------+
| 0                                                     |
+-----------------------------------------+
1 row in set (0.00 sec)

打开redis-cli,查看结果:

127.0.0.1:6379> HGETALL zhxilin
1) "id"
2) "09388334"

四. 通过MySQL触发器刷新Redis

在上一节的基础上,我们想让MySQL在增删改查的时候自动调用UDF,还需要借助MySQL触发器。触发器可以监听INSERT、UPDATE、DELETE等基本操作。在MySQL中,创建触发器的基本语法如下:

CREATE TRIGGER trigger_name
trigger_time
trigger_event ON table_name
FOR EACH ROW
trigger_statement

trigger_time表示触发时机,值为AFTERBEFORE

trigger_event表示触发的事件,值为INSERTUPDATEDELETE等;

trigger_statement表示触发器的程序体,可以是一句SQL语句或者调用UDF。

在trigger_statement中,如果有多条SQL语句,需要用BEGIN...END包含起来:

BEGIN
[statement_list]
END

由于MySQL默认的结束分隔符是分号(;),如果我们在BEGIN...END中出现了分号,将被标记成结束,此时没法完成触发器的定义。有一个办法,可以调用DELIMITER命令来暂时修改结束分隔符,用完再改会分号即可。比如改成$:

mysql> DELIMITER $

我们开始定义一个触发器,监听对Student表的插入操作,Student表在上一篇文章中创建的,可以查看上一篇文章。

mysql > DELIMITER $> CREATE TRIGGER tg_student > AFTER INSERT on Student > FOR EACH ROW > BEGIN> SET @id = (SELECT redis_hset(CONCAT('stu_', new.Sid), 'id', CAST(new.Sid AS CHAR(8))));> SET @name = (SELECT redis_hset(CONCAT('stu_', new.Sid), 'name', CAST(new.Sname AS CHAR(20))));> Set @age = (SELECT redis_hset(CONCAT('stu_', new.Sid), 'age', CAST(new.Sage AS CHAR))); > Set @gender = (SELECT redis_hset(CONCAT('stu_', new.Sid), 'gender', CAST(new.Sgen AS CHAR))); > Set @dept = (SELECT redis_hset(CONCAT('stu_', new.Sid), 'department', CAST(new.Sdept AS CHAR(10))));    > END $

创建完触发器可以通过show查看,或者drop删除:

mysql> SHOW TRIGGERS;

mysql> DROP TRIGGER tg_student;

接下来我们调用一句插入语句,然后观察Redis和MySQL数据的变化:

mysql> INSERT INTO Student VALUES('09388165', 'Rose', 19, 'F', 'SS3-205');
Query OK, 1 row affected (0.27 sec)

MySQL的结果:

mysql> SELECT * FROM Student;
+----------+---------+------+------+---------+
| Sid      | Sname   | Sage | Sgen | Sdept   |
+----------+---------+------+------+---------+
| 09388123 | Lucy    |   18 | F    | AS2-123 |
| 09388165 | Rose    |   19 | F    | SS3-205 |
| 09388308 | zhsuiy  |   19 | F    | MD8-208 |
| 09388318 | daemon  |   18 | M    | ZS4-630 |
| 09388321 | David   |   20 | M    | ZS4-731 |
| 09388334 | zhxilin |   20 | M    | ZS4-722 |
+----------+---------+------+------+---------+
6 rows in set (0.00 sec)

Redis的结果:

127.0.0.1:6379> HGETALL stu_093881651) "id"2) "09388165"3) "name"4) "Rose"5) "age"6) "19"7) "gender"8) "F"9) "department"
10) "SS3-205"

以上结果表明,当MySQL插入数据时,通过触发器调用UDF,实现了自动刷新Redis的数据。另外,调用MySQL插入的命令,可以通过C++实现,进而就实现了在C++的业务逻辑里,只需调用MySQL++的接口就能实现MySQL数据库和Redis缓存的更新,这部分内容在上一篇文章已经介绍过了。

总结

通过实践,能体会到MySQL和Redis是多么相亲相爱吧!^_^

本篇文章讲了从最基础的UDF开始,再到通过UDF连接Redis插入数据,再进一步介绍通过MySQL Trigger自动更新Redis数据的整个思路,实现了一个目标,即只在业务代码中更新MySQL数据库,进而Redis能够自动同步刷新。

MySQL对UDF函数和触发器的支持,使得实现Redis数据和MySQL自动同步成了可能。当然UDF毕竟是通过插件的形式运行在MySQL中的,并没有过多的安全干预,一旦插件发生致命性崩溃,有可能MySQL也会挂,所以在编写UDF的时候需要非常谨慎!

说了原理,接下来看如何使用,其实有很多已经实现的比较好的,我们可以直接使用

A high performance mysql udf to sync the newly modified/inserted data from mysql to redis cache.

https://github.com/dawnbreaks/mysql2redis(推荐使用这个,下面的例子以这个为主,具体原理请看上面)

A UDF(user defined functions) plugin for MySQL, which can be used for pushing data to Redis

https://github.com/jackeylu/mysql2redis

This is used to move the mysql data to redis or from redis to mysql.

https://github.com/zhangjg/mysql2redis

MySQL Syncer is a project which parse mysql binlog and sync to other datases, such as redis, mongodb and any other databases..

https://github.com/Terry-Mao/MySQL-Syncer

前题:安装了mysql5.5(以上)和client

  • apr-1.4.6(http://apr.apache.org/download.cgi)
  • apr-util-1.5.2(http://apr.apache.org/download.cgi)
  • hiredis(https://github.com/redis/hiredis)
  • lib_mysqludf_json(https://github.com/mysqludf/lib_mysqludf_json)

下面依次安装
1 安装apr-1.4.6

   1. wget   https://www-us.apache.org/dist//apr/apr-1.7.0.tar.gz

   2.     tar -xvf   apr-1.7.0.tar.gz

   3   ./configure --prefix=/usr/local/apr //配置到指定目录,如果此时报错是关于aprd ,则需要安装gcc,只需sudo apt-get install gcc即可,然后再次执行上一步
      mak&&make install //需要再root模式下运行?前面加sudo

1.2.安装apr-util

  wget https://www-us.apache.org/dist//apr/apr-util-1.6.1.tar.gz
  cd ../apr-util/
  ./configure   --with-apr=/usr/local/apr
  make
  make install //需要root权限 前面加sudo

安装后请检验生成库是否的路径可以访问:(usr/local/apr/lib/)

  不能的话拷贝库到/lib或者/usr/lib

或者配置

  export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/apr/lib/

2、安装mysql2redis

Shell代码    
  1. git clone https://github.com/dawnbreaks/mysql2redis
  2. cd mysql2redis
  3. make

如果出现关于off64_t错误(在Makefile中加入 -Doff64_t=__off64_t)

避免把警告当成错误,可以去掉-Werr
3、安装hiredis

Shell代码    
  1. git clone http://github.com/redis/hiredis
  2. cd hiredis
  3. make && make install

3、安装mysql json udf

Shell代码    
  1. git clone https://github.com/mysqludf/lib_mysqludf_json.git
  2. cd lib_mysqludf_json
  3. gcc $(/usr/local/mariamysql/bin/mysql_config --cflags) -shared -fPIC -o lib_mysqludf_json.so lib_mysqludf_json.c(如果已经存在则可以直接使用)

然后将lib_mysqludf_json.so拷贝到mysql的plugin (查看插件目录:mysql_config --plugindir)
在mysql里执行lib_mysqludf_json.sql

执行mysql2redis目录下的:两个install*.sql文件

测试使用test*.sql;

其中install_redis_udf.sql

DROP FUNCTION IF EXISTS redis_servers_set_v2;
DROP FUNCTION IF EXISTS redis_command_v2;
DROP FUNCTION IF EXISTS free_resources;CREATE FUNCTION redis_servers_set_v2 RETURNS int SONAME "lib_mysqludf_redis_v2.so";
CREATE FUNCTION redis_command_v2 RETURNS int SONAME "lib_mysqludf_redis_v2.so";
CREATE FUNCTION free_resources RETURNS int SONAME "lib_mysqludf_redis_v2.so";

  其实就是把函数生成库到mysql,使用mysql的udf进行调用redis接口访问redis

lib_mysqludf_json(https://github.com/mysqludf/lib_mysqludf_json)

A UDF library of functions to map relational data to the JSON format

就是把mysql的数据转换成json格式存储在redis中

select
redis_command_v2("lpush","crmInboxEvents11",json_object(json_members("op","insert","value","valuettt")));select redis_servers_set_v2("192.168.0.118",6379);
select redis_command_v2("lpush","crmInboxEvents11",json_object(json_members("op","insert","value","valuettt")));select redis_command_v2("hset","hkey","hfield",json_object(json_members("op","insert","value","valuettt")));select free_resources();
select redis_servers_set_v2("192.168.0.118",6379);

  

  • json_members - maps a variable number of name-value pairs to a list of JSON object members.
  • json_object - maps a variable number of arguments to a JSON object

例子如下:

表结构

创建mysql触发器,每插入一条数据,更新redis,以json风格,程序可以直接读取redis下的存储的json

DELIMITER $$
CREATE TRIGGER xb_ai AFTER INSERT ON xb
FOR EACH ROW
BEGIN
DECLARE ret INT DEFAULT 999;  SET ret=redis_command_v2("set",concat("user:","id:",cast(NEW.id as CHAR)),json_object(NEW.id as "id",NEW.name as "name"));
if ret>0 then  SIGNAL sqlstate '45001' set message_text = "Redis error! ";
end if ;  END$$
DELIMITER ;

  

就是json_object(NEW.Idas"id",NEW.name as"type")//新增加的行id,name各种生成key-value json对

新增一条数据:

进入redis-cli可以看到

json如何使用请看下面(

参考:、

lib_mysqludf_json(https://github.com/mysqludf/lib_mysqludf_json)

A UDF library of functions to map relational data to the JSON format

To obtain nested objects, use this function as an argument for json_object

select      json_object(f.last_update,   json_members('film',   json_object(f.film_id,   f.title,   f.last_update),   'category',   json_object(c.category_id,   c.name,   c.last_update))) as film_category
from        film_category fc
inner join  film f
on          fc.film_id = f.film_id
inner join  category c
on          fc.category_id = c.category_id
where       f.film_id =1;

yields a string representing the following JSON object (indentation added for readability):

{last_update:"2006-02-15 05:03:42"
,   film:{"film_id":1,   "title":"ACADEMY DINOSAUR",   "last_update":"2006-02-15 05:03:42"}
,   category:{"category_id":6,   "name":"Documentary",   "last_update":"2006-02-15 04:46:27"}
}

例子2:

在mysql里创建table,trigger

Sql代码    
CREATE  TABLE IF NOT EXISTS `test`.`t_users` (  `user_name` VARCHAR(50) NOT NULL ,  `nick_name` VARCHAR(100) NOT NULL ,  `password` VARCHAR(32) NOT NULL ,  `age` INT NULL ,  `create_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ,  PRIMARY KEY (`user_name`) ,  UNIQUE INDEX `un_t_users_nick_name` (`nick_name` ASC) )
ENGINE = InnoDB;

  

Sql代码    
DELIMITER |
create trigger tri_users_redis_json BEFORE INSERT on t_users  For EACH ROW
BEGIN
DECLARE done INT DEFAULT 999;  set done = redis_command_v2("set",concat("user::",cast(NEW.user_name as CHAR),,json_object(NEW.user_name as userName,NEW.nick_name as nickName,NEW.age as age))); if done>0 then   SIGNAL sqlstate '45001' set message_text = "Redis error! "; end if ; END; | DELIMITER ;

  

Sql代码    
  1. insert into t_users(user_name,nick_name,password,age,create_time) values('Sally','雪莉','123456',25,CURRENT_TIMESTAMP)

mysql的

redis的

使用mysql的udf和trigger可以保证mysql和redis的数据一致性,SIGNAL sqlstate '45001'会在redis失败时回滚事物。

问题:hiredis里递交带空格数据需要这样使用

C代码    
  1. reply = redisCommand(context, "SET key:%s %s", myid, value);

那么对于mysql2redis的redis_command是无法工作的,这部分可以为不同命令单写函数。如redis_command_set。

转载于:https://www.cnblogs.com/bwbfight/p/11099482.html

mysql与redis数据同步(c/c++)(写mysql同步到redis,并且以json格式保存)相关推荐

  1. MySQL基础day03_数据的导入、导出-MySQL 5.6

    MySQL基础day03_数据的导入.导出-MySQL 5.6 注:把数据按照一定格式存放到文件里才能进行数据的导入. 1,数据导入的条件 把文件里的内容保存到数据的表里: 把数据按照一定格式存放文件 ...

  2. php mysql 读取中文数据的函数_php读取mysql中文数据出现乱码的解决方法

    以下是对php读取mysql中文数据出现乱码问题的解决方法进行了介绍,需要的朋友可以过来参考下 1.PHP页面语言本身的编码类型不合适,这时候,你直接在脚本中写的中文肯定是乱码,不用说数据库了 解决方 ...

  3. mysql 清洗字段数据,根据字段条件清理MySQL数据库数据

    背景 线上某个数据库有1000个分库的DB,磁盘告警,每个库的大小都不是很大但是加起来就非常大了.手动根据时间字段来清理数据不太现实,于是决定写脚本来删除指定时间以前的数据. 脚本: #/bin/ba ...

  4. Redis的读更新和写更新-如何保证Redis与数据库的数据一致性

    背景 日前面试的时候被问到我们项目里面使用Redis的时候是如何更新缓存的,我的回答是写操作的时候的时候把缓存删了,然后读操作的时候就会读取出来最新的值.面试管继续问:Redis的写时更新和读时更新有 ...

  5. mysql命令导出数据不完整_使用MySQL MySqldump命令导出数据时的注意事项

    今天使用mysqldump命令备份数据的时候出现了一个问题. 一开始迁移 Discuz 7 论坛的 mysql 数据库时,采用 mysqldump 命令的时候一切顺利,但导入的时候却遇到了 ERROR ...

  6. python mysql批量insert数据_使用python往mysql批量插入数据时,报错not all arguments converted...

    我用这段命令可以往mysql数据库插入数据 insert into moderation_task(id, media_id, user_id, media_url_or_path, media_ti ...

  7. mysql数据库读取数据,教你如何从 MySQL 数据库读取数据

    从 MySQL 数据库读取数据 SELECT 语句用于从数据表中读取数据: SELECT column_name(s) FROM table_name 我们可以使用 * 号来读取所有数据表中的字段: ...

  8. ajax返回数据输出成表,javascript代码实例教程-ajax请求返回Json格式数据如何循环输出成table形式...

    小宝典致力于为广大程序猿(媛)提供高品质的代码服务,请大家多多光顾小站,小宝典在此谢过. 首先,Ajax请求数据,(用的是Jquery的Ajax) [javascript] $(function(){ ...

  9. 在mysql中更新数据sql语句怎么写_在MySQL中,更新数据库表记录的SQL语句,包括______语句...

    在MySQL中,更新数据库表记录的SQL语句,包括______语句 答:insert replace update delete 在域F中,设其特征为2,对于任意a,b∈F,则(a+b)2 等于多少 ...

最新文章

  1. 在ATS 5.3.0上开启stats_over_http插件
  2. FFmpeg 5.0 正式发布
  3. libvirtError: 无效参数:could not find capabilities for domaintype=kvm
  4. You must define a PAYPAL_PAYFLOW_VENDOR_ID setting
  5. C# 之 Math取整
  6. Javascript实现信息滚动效果的方法
  7. 服务化改造实践(二)| Dubbo + Kubernetes
  8. 别惹老黄!英伟达遭网络攻击后,反手就把黑客黑了
  9. 在教学中利用计算机软件,计算机软件在数学教学中的应用
  10. 只使用Feign不引入Eureka
  11. count(*) 的实现方式
  12. 排序算法基础+冒泡排序+冒泡排序的小优化
  13. 交通分配四阶段法(一)
  14. 车牌识别-基于模板匹配
  15. mybatis-plus环境搭建
  16. group by 与 order by的用法
  17. Office Word中由于自定义了新的样式名称,而导致题注显示:错误!文档中没有指定的样式文字
  18. idea 启动参数设置
  19. 算法中的大O是什么意思
  20. 华为勇敢星实习生招聘面试经历和华为优招面试经历

热门文章

  1. 冰蝎shell_冰蝎动态二进制加密WebShell特征分析
  2. python统计英文文章中单词的个数无文件_求Python统计英文文件内单词个数的思路...
  3. 三国大时代java_横跨,塞班、安卓、pc的国产良心作《三国大时代》系列
  4. synchronized.1
  5. Html HBuilder封装APP
  6. Android手工打造脑图控件
  7. 基于RTL—SDR及Simulink的FM收音机仿真
  8. 人到五十岁以后做什么生意最好?
  9. 基于CNN卷积神经网络的商品识别(毕设)
  10. 面试官问上一家公司离职原因怎么办?