文档章节

利用系统缓存提高PostgreSQL操作效率

PGSmith
 PGSmith
发布于 2015/12/17 00:38
字数 2460
阅读 4601
收藏 71
点赞 7
评论 0

环境介绍:

                OS:Centos 6.4 64bit
                Database:PostgreSQL9.4
                Memory:2G
                CPU:1核

下载安装:

    在pgfoundry下载pgfincore-v1.1.1.tar.gz,,将源码解压到数据库源码下的contrib下。不要在其github上下载,目前应该有一些bug,最新版本为1.1.1,1.1.2在我试用的时候发现大部分函数无法使用。

    其次在我编译时一直出现如下错误:

[postgres@localhost pgfincore-1.1.1]$ make
/bin/sh: pg_config: command not found
make: pg_config: Command not found
cp pgfincore.sql pgfincore--1.1.1.sql
cp: cannot create regular file `pgfincore--1.1.1.sql': Permission denied
make: *** [pgfincore--1.1.1.sql] Error 1
    所以在此我修改了一下Makefile文件,内容如下:
# contrib/pgfincore/Makefile

MODULE_big = pgfincore
OBJS = pgfincore.o

EXTENSION = pgfincore
DATA = pgfincore--1.1.1.sql pgfincore--unpackaged--1.1.1.sql

ifdef USE_PGXS
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
else
subdir = contrib/pgfincore
top_builddir = ../..
include $(top_builddir)/src/Makefile.global
include $(top_srcdir)/contrib/contrib-global.mk
    现在进行make,即可:
[postgres@localhost pgfincore-1.1.1]$ make
gcc -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -g -O2 -fpic -I. -I. -I../../src/include -D_GNU_SOURCE   -c -o pgfincore.o pgfincore.c
pgfincore.c: In function ‘pgsysconf’:
pgfincore.c:227: warning: implicit declaration of function ‘heap_form_tuple’
pgfincore.c:227: warning: assignment makes pointer from integer without a cast
pgfincore.c: In function ‘pgfadvise’:
pgfincore.c:477: warning: assignment makes pointer from integer without a cast
pgfincore.c: In function ‘pgfadvise_loader’:
pgfincore.c:710: warning: assignment makes pointer from integer without a cast
pgfincore.c: In function ‘pgfincore’:
pgfincore.c:1016: warning: assignment makes pointer from integer without a cast
gcc -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -g -O2 -fpic -shared -o pgfincore.so pgfincore.o -L../../src/port -L../../src/common -Wl,--as-needed -Wl,-rpath,'/opt/hg3.0/lib',--enable-new-dtags  
[postgres@localhost pgfincore-1.1.1]$ make install
/bin/mkdir -p '/opt/hg3.0/lib/postgresql'
/bin/mkdir -p '/opt/hg3.0/share/postgresql/extension'
/bin/mkdir -p '/opt/hg3.0/share/postgresql/extension'
/usr/bin/install -c -m 755  pgfincore.so '/opt/hg3.0/lib/postgresql/pgfincore.so'
/usr/bin/install -c -m 644 pgfincore.control '/opt/hg3.0/share/postgresql/extension/'
/usr/bin/install -c -m 644 pgfincore--1.1.1.sql pgfincore--unpackaged--1.1.1.sql '/opt/hg3.0/share/postgresql/extension/'
[postgres@localhost pgfincore-1.1.1]$
实验记录:

    1、安装:

[postgres@localhost bin]$ ./psql 
psql (9.4.5)
Type "help" for help.

postgres=# create extension pgfincore ;
CREATE EXTENSION
postgres=# select * from pg_extension ;
  extname  | extowner | extnamespace | extrelocatable | extversion | extconfig |
 extcondition 
-----------+----------+--------------+----------------+------------+-----------+
--------------
 plpgsql   |       10 |           11 | f              | 1.0        |           |
 
 pgfincore |       10 |         2200 | t              | 1.1.1      |           |
 
(2 rows)

postgres=#

    2、准备工作:记录比较使用pgfincore前后的性能差,使用插件pg_stat_statments记录每条sql的使用时间。
其次将shared_buffer改为16mb,减少其对pgfincore的影响。

postgres=# create extension pg_stat_statements ;
CREATE EXTENSION
postgres=# select * from pg_extension ;
      extname       | extowner | extnamespace | extrelocatable | extversion | ex
tconfig | extcondition 
--------------------+----------+--------------+----------------+------------+---
--------+--------------
 plpgsql            |       10 |           11 | f              | 1.0        |   
        | 
 pgfincore          |       10 |         2200 | t              | 1.1.1      |   
        | 
 pg_stat_statements |       10 |         2200 | t              | 1.2        |   
        | 
(3 rows)

    3、建立表testmem,分别在使用和不适用pgfincore情况下进行select, update, delete的操作,并对比执行时间,在这里为了更好的去作比较,建立三张表testmem1,testmem2,testmem3,分别进行三种操作进行对比。并插入相同的数据。

[postgres@localhost bin]$ ./psql 
psql (9.4.5)
Type "help" for help.

postgres=# \d
No relations found.
postgres=# create table testmem1(t1 int, t2 text, t3 text, t4 bigint, t5 text, t6 text, t7 varchar, t8 char(22), t9 numeric);CREATE TABLE
postgres=# create table testmem2(t1 int, t2 text, t3 text, t4 bigint, t5 text, t6 text, t7 varchar, t8 char(22), t9 numeric);
CREATE TABLE
postgres=# create table testmem3(t1 int, t2 text, t3 text, t4 bigint, t5 text, t6 text, t7 varchar, t8 char(22), t9 numeric);
CREATE TABLE
postgres=# insert into testmem1 select generate_series(1,999999), 'wangshuo'||generate_series(1,999999)::text||random()::text, generate_series(1,999999)::text||'sure',generate_series(1,999999), random()::text,random()::text,random()::text,'liuyuanyuan', generate_series(1,999999);
INSERT 0 999999
postgres=# select pg_relation_size('testmem1')/1024/1024||'MB';
 ?column? 
----------
 166MB
(1 row)

postgres=# insert into testmem2 select generate_series(1,999999), 'wangshuo'||generate_series(1,999999)::text||random()::text, generate_series(1,999999)::text||'sure',generate_series(1,999999), random()::text,random()::text,random()::text,'liuyuanyuan', generate_series(1,999999);
INSERT 0 999999
postgres=# insert into testmem3 select generate_series(1,999999), 'wangshuo'||generate_series(1,999999)::text||random()::text, generate_series(1,999999)::text||'sure',generate_series(1,999999), random()::text,random()::text,random()::text,'liuyuanyuan', generate_series(1,999999);
INSERT 0 999999
postgres=# select pg_relation_size('testmem2')/1024/1024||'MB'; ?column? 
----------
 166MB
(1 row)

postgres=# select pg_relation_size('testmem3')/1024/1024||'MB';
 ?column? 
----------
 166MB
(1 row)

postgres=#

    三种操作性能对比:

postgres=# select * from testmem1 where t1 < 789432 and t1 > 1208;
   t1   |                 t2                 |     t3     |   t4   |          t5
          |          t6          |          t7          |           t8          
 |   t9   
--------+------------------------------------+------------+--------+------------
----------+----------------------+----------------------+-----------------------
-+--------
   1209 | wangshuo12090.964191045146435      | 1209sure   |   1209 | 0.075409890
152514    | 0.468206159770489    | 0.692714618053287    | liuyuanyuan           
 |   1209
   1210 | wangshuo12100.652063825167716      | 1210sure   |   1210 | 0.026932121
720165    | 0.802233531605452    | 0.706556385848671    | liuyuanyuan           
 |   1210
   1211 | wangshuo12110.724962076637894      | 1211sure   |   1211 | 0.732285636
477172    | 0.816857317462564    | 0.868489125277847    | liuyuanyuan           
 |   1211
   1212 | wangshuo12120.0478062951005995     | 1212sure   |   1212 | 0.190716865
006834    | 0.898683389648795    | 0.537546805106103    | liuyuanyuan           
 |   1212
   1213 | wangshuo12130.582098880317062      | 1213sure   |   1213 | 0.161297460
086644    | 0.395338968373835    | 0.684920639265329    | liuyuanyuan           
 |   1213
   1214 | wangshuo12140.53120110463351       | 1214sure   |   1214 | 0.253457680
810243    | 0.428548218682408    | 0.671272001229227    | liuyuanyuan           

postgres=# update testmem2 set t7 = random()::text where t1 < 789432 and t1 > 1208;
UPDATE 788223
postgres=# delete from testmem3 where t1 < 789432 and t1 > 1208;
DELETE 788223

    使用pgfincore前:通过查询表pg_stat_statments查看三种操作时间:

postgres=# SELECT query, calls, total_time, rows, 100.0 * shared_blks_hit /                
               nullif(shared_blks_hit + shared_blks_read, 0) AS hit_percent
          FROM pg_stat_statements ORDER BY total_time DESC;
-[ RECORD 1 ]------------------------------------------------------
query       | update testmem2 set t7 = random()::text where t1 < ? and t1 > ?;
calls       | 1
total_time  | 14303.53
rows        | 788223
hit_percent | 97.7162513440240383
-[ RECORD 2 ]------------------------------------------------------
query       | delete from testmem3 where t1 < ? and t1 > ?;
calls       | 1
total_time  | 5256.305
rows        | 788223
hit_percent | 97.4004941321803582
-[ RECORD 6 ]------------------------------------------------------
query       | select * from testmem1 where t1 < ? and t1 > ?;
calls       | 1
total_time  | 2397.866
rows        | 788223
hit_percent | 0.15039714245429336843

    使用pgfincore后:通过查询表pg_stat_statments查看三种操作时间(重启机器后,重新建库,重新建表、插数据):

SELECT query, calls, total_time, rows, 100.0 * shared_blks_hit /
               nullif(shared_blks_hit + shared_blks_read, 0) AS hit_percent
          FROM pg_stat_statements ORDER BY total_time DESC;
-[ RECORD 1 ]------------------------------------------------------
query       | update testmem2 set t7 = random()::text where t1 < ? and t1 > ?;
calls       | 1
total_time  | 6800.237
rows        | 788223
hit_percent | 97.6908892215405358
-[ RECORD 2 ]------------------------------------------------------
query       | delete from testmem3 where t1 < ? and t1 > ?;
calls       | 1
total_time  | 3295.312
rows        | 788223
hit_percent | 97.3715873996294009
-[ RECORD 3 ]------------------------------------------------------
query       | select * from testmem1 where t1 < ? and t1 > ?;
calls       | 1
total_time  | 891.002
rows        | 788223
hit_percent | 0.000000000000000000000000

    明显看出当执行select时速度提升明显,其他的时间提升并不明显,这是因为数据还需要进行IO操作,所以在这里速度提升应该仅仅是读入的时间节省掉了。

postgres=# select pgfadvise_willneed('testmem1');
-[ RECORD 1 ]------+-------------------------------------
pgfadvise_willneed | (base/13003/16384,4096,42554,279311)

postgres=# select * from pgfincore('testmem1');
-[ RECORD 1 ]-+-----------------
relpath       | base/13003/16384
segment       | 0
os_page_size  | 4096
rel_os_pages  | 42554
pages_mem     | 42554
group_mem     | 1
os_pages_free | 279317
databit       | 

postgres=# select count(*) from testmem1 where t1 < 99999 and t1 > 12;
-[ RECORD 1 ]
count | 99986

postgres=# insert into testmem1 select generate_series(1,9999), 'wangshuo'||generate_series(1,9999)::text||random()::text, generate_series(1,9999)::text||'sure',generate_series(1,9999), random()::text,random()::text,random()::text,'liuyuanyuan', generate_series(1,9999);
INSERT 0 9999
postgres=# select * from pgfincore('testmem1');-[ RECORD 1 ]-+-----------------
relpath       | base/13003/16384
segment       | 0
os_page_size  | 4096
rel_os_pages  | 42980
pages_mem     | 42980
group_mem     | 1
os_pages_free | 277433
databit       | 

postgres=# select pg_relation_size('testmem1');
-[ RECORD 1 ]----+----------
pg_relation_size | 176046080

postgres=# select 42980*4096;
-[ RECORD 1 ]-------
?column? | 176046080

postgres=# insert into testmem1 select generate_series(1,999999), 'wangshuo'||generate_series(1,999999)::text||random()::text, generate_series(1,999999)::text||'sure',generate_series(1,999999), random()::text,random()::text,random()::text,'liuyuanyuan', generate_series(1,999999);
INSERT 0 999999
postgres=# select * from pgfincore('testmem1');
-[ RECORD 1 ]-+-----------------
relpath       | base/13003/16384
segment       | 0
os_page_size  | 4096
rel_os_pages  | 85532
pages_mem     | 6188
group_mem     | 22
os_pages_free | 403050
databit       | 

postgres=#
    上面这个实验验证了willneed会将小部分新加入的数据加载到cache中,能够快速的定位查找,但是当插入数据量较大时,就不会及时的写入到cache中了。

总结:pgfincore目前适用于数据量非常大、更新不频繁、更新量较小的表去加载到缓存中,有助于提高应用效率。

    插件函数介绍:

    这里会对函数进行介绍,并对所有函数进行操作实验。

    1、pgsysconf:
         这个函数输出OS block的大小(os_page_size),OS中剩余的page数(os_pages_free)和OS拥有的page总数(os_total_pages)。

postgres=# select * from pgsysconf();
 os_page_size | os_pages_free | os_total_pages 
--------------+---------------+----------------
         4096 |        167445 |         476688
(1 row)
    2、pgsysconf_pretty:
        这个函数和上面的一样,仅仅是输出更易懂些。

postgres=# select * from pgsysconf_pretty();
 os_page_size | os_pages_free | os_total_pages 
--------------+---------------+----------------
 4096 bytes   | 654 MB        | 1862 MB
(1 row)

    3、pgfadvise_willneed:

    这个函数是
    输出文件名(relpath),OS block大小(os_page_size),对象占用系统page数(rel_os_pages),OS剩余的page数(os_pages_free)。

postgres=# select * from pgfadvise_willneed('testmem1');
     relpath      | os_page_size | rel_os_pages | os_pages_free 
------------------+--------------+--------------+---------------
 base/13003/16384 |         4096 |        42554 |        167294
(1 row)
    4、pgfadvise_dontneed:

    这个函数对当前对象设置dontneed标记。dontneed标记的意思就是当操作系统需要释放内存时优先释放标记为dontneed的pages。输出的意义和上面一致,就不多做介绍了。

postgres=# select * from pgfadvise_dontneed('testmem1');
     relpath      | os_page_size | rel_os_pages | os_pages_free 
------------------+--------------+--------------+---------------
 base/13003/16384 |         4096 |        42554 |        332798
(1 row)
    5、pgfadvise_NORMAL、pgfadvise_SEQUENTIAL、pgfadvise_RANDOM:

    和pgfadvise_dontneed大同小异,分别将对象标记为normal、sequential、random,意思按照字面意思理解就可以了。
    其实pgfadvise是一个单独的函数,参数是relname,fork,action,含义分别为对象名、文件分支名以及行为id,上面的3、4、5函数都是输入不同参数而设置的函数,其中willneed、dontneed、normal、sequential、random的值分别是10、20、30、40、50,且默认fork为main,即表文件。
    这里的pgfadvise主要调用了Linux下的函数posix_fadvise,标记值也是posix_fadvise所需要的。

    6、pgfincore:

    这个函数是是提供对象在操作系统缓存中的信息的。
    它分为三个函数,参数分别为(relname, fork, getdatabit),relname, getdatabitrelname),三个参数意思为对象名,进程名(这个地方默认是main),是否要显示databit(很长,注意显示)
,第一个函数需要全部输入,第二个函数默认fork为main,第三个函数默认fork为main,getdatabit为false。
    它输出的是文件位置及名称(relpath),文件顺序(segment),OS page或block大小(os_page_size),对象占用系统缓存需要的页面个数(rel_os_pages),对象已经占用缓存页面个数(pages_mem),在缓存中连续的页面组的个数(group_mem),OS剩余的page数(os_pages_free),加载信息的位图(databit)。

postgres=# select * from pgfincore('testmem1', 'main', false);
-[ RECORD 1 ]-+-----------------
relpath       | base/13003/16384
segment       | 0
os_page_size  | 4096
rel_os_pages  | 42554
pages_mem     | 2
group_mem     | 1
os_pages_free | 325475
databit       | 

postgres=# select * from pgfincore('testmem1', false);
-[ RECORD 1 ]-+-----------------
relpath       | base/13003/16384
segment       | 0
os_page_size  | 4096
rel_os_pages  | 42554
pages_mem     | 2
group_mem     | 1
os_pages_free | 325475
databit       | 

postgres=# select * from pgfincore('testmem1');
-[ RECORD 1 ]-+-----------------
relpath       | base/13003/16384
segment       | 0
os_page_size  | 4096
rel_os_pages  | 42554
pages_mem     | 2
group_mem     | 1
os_pages_free | 325475
databit       |

    7、pgfadvise_loader:

    这个函数可以对页面缓存直接进行两方面的作用。因此,它能通过页面的位图在缓存中来对页面进行加载或卸载。
    它分为两个函数和上边的类似,就是设置缺省值,的输入参数是(relname, fork, segment, load, unload, databit)和(relname, segment, load, unload, databit),分别是对象名,文件分支名,文件序号,是否加载,是否卸载,位图信息。第二个函数默认fork为main。
它输出的是物理文件名及path(relpath),OS page或block大小(os_page_size), OS中剩余的page数(os_pages_free),加载的page数(pages_load),卸载的page数(pages_unload)。

postgres=# select * from pgfincore('testmem1');
-[ RECORD 1 ]-+-----------------
relpath       | base/13003/16384
segment       | 0
os_page_size  | 4096
rel_os_pages  | 42554
pages_mem     | 0
group_mem     | 0
os_pages_free | 331290
databit       | 

postgres=# select * from pgfadvise_loader('testmem1', 0, true, true, B'1100');
-[ RECORD 1 ]--+-----------------
relpath        | base/13003/16384
os_page_size   | 4096
os_pages_free  | 331294
pages_loaded   | 2
pages_unloaded | 2

postgres=# select * from pgfincore('testmem1');
-[ RECORD 1 ]-+-----------------
relpath       | base/13003/16384
segment       | 0
os_page_size  | 4096
rel_os_pages  | 42554
pages_mem     | 2
group_mem     | 1
os_pages_free | 331290
databit       |

© 著作权归作者所有

共有 人打赏支持
PGSmith

PGSmith

粉丝 91
博文 53
码字总数 59331
作品 0
济南
后端工程师
PostgreSQL 数据库初体验

高强,“DBA+济南群”联合发起人。现就职于山东华鲁科技发展股份有限公司。擅长Oracle、AIX、Linux、PostgreSQL和DB2等产品的实施、运维和故障处理。曾是一名存储工程师,负责实施存储、双机...

高强 ⋅ 2015/10/15 ⋅ 0

科普一种可以将PG变成通用SQL引擎的技术

作者介绍 伊翼,网名“小wing”,野生PG爱好者,从事数据库相关工作已近十年,目前供职于全球最大的通讯设备供应商。 原标题:《当FDW遇上GO》 FDW(Foreign Data Wrapper)是PostgreSQL(下...

伊翼 ⋅ 06/14 ⋅ 0

PostgreSQL CVE-2018-1058(search_path) - 暨数据库的那些陷阱与攻防指南

标签 PostgreSQL , search_path , 陷阱 , overload function 背景 PostgreSQL 元宵节对各个版本发布了小版本补丁,主要是解决一个search_path的功能,被攻击者利用来设置陷阱的问题。 https:...

德哥 ⋅ 04/18 ⋅ 0

PostgreSQL 类微博FEED系统 - 设计与性能指标

标签 PostgreSQL , feed , 微博 , 推送 , 分区 , 分片 , UDF , 挖掘 , 文本挖掘 背景 类微博系统,最频繁用到的功能: 之前写过一篇《三体高可用PCC大赛 - facebook微博 like场景 - 数据库设...

德哥 ⋅ 04/18 ⋅ 0

AntDB中tableoid等特殊字段使用注意事项

AntDB是一款分布式数据库产品,其分布式的特性决定了当我们使用某些字段,例如tableoid和xcnodeid系统字段,及enum类型字段,xcnodeid,xcnodestr(), adbnodeoid() GUC变量可能出现以下问题...

珊珊AntDB ⋅ 06/13 ⋅ 0

PostgreSQL和MySQL

翻译来源:https://www.2ndquadrant.com/en/postgresql/postgresql-vs-mysql/ PostgreSQL和MySQL 之间有着根本的区别。在评估两个系统之间的差异和折衷之后,必须做出明智的决定。 我们已经提...

悟道之客 ⋅ 05/04 ⋅ 0

数据库案例集锦 - 开发者的《如来神掌》

标签 PostgreSQL , PG DBA cookbook , PG Oracle兼容性 , PG 架构师 cookbook , PG 开发者 cookbook , PG 应用案例 背景 「剑魔独孤求败,纵横江湖三十馀载,杀尽仇寇,败尽英雄,天下更无抗...

德哥 ⋅ 2017/06/09 ⋅ 0

EDB PPAS(Oracle 兼容版) Oracle与PostgreSQL 兼容模式的参数配置切换

标签 PostgreSQL , EDB , PPAS , 参数 , Oracle模式 , PostgreSQL模式 背景 EDB PPAS是EDB推出的一款同时兼容Oracle和PostgreSQL协议的数据库,在去O的场景中,使用非常广泛,价格便宜,同时...

德哥 ⋅ 05/06 ⋅ 0

PostgreSQL 生成任意基数数独 - 3

标签 PostgreSQL , 数独 背景 使用随机填充的方法,很难生成一个有解的数独。 《PostgreSQL 生成任意基数数独 - 2》 本文使用了《编程之美》中提到的另一种生成随机数独的方法,模板+映射法。...

德哥 ⋅ 04/18 ⋅ 0

PostgreSQL 数据离散性 与 索引扫描性能(btree and bitmap index scan)

标签 PostgreSQL , 数据离散性 , 扫描性能 , 重复扫 , bitmap index scan , 排序扫描 背景 PostgreSQL中数据的扫描方法很多,常见的有: 1、全表顺序扫描(seqscan) 2、索引+回表扫描(index ...

德哥 ⋅ 04/18 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

HiSDP —— 高效的C++软件开发平台

目前阿里集团每天有近1000PB的数据是通过LogAgent采集的,为了让LogAgent做到资源占用节省和高效采集,背后是基于HiSDP去构建的。 缘由 当决定采用C++编程语言去开发一个软件时,紧接着所面临...

阿里云云栖社区 ⋅ 27分钟前 ⋅ 0

zookeeper-3.4.12 下载与安装教程

一、zookeeper下载地址 http://mirrors.hust.edu.cn/apache/zookeeper/ 二、启动教程 把压缩包放在指定目录下 第三: 进入 conf文件夹底下 zoo_sample.cfg 文件名改成 zoo.cfg 第四步: 进入b...

泉天下 ⋅ 28分钟前 ⋅ 0

Oracle 中文日期转换

SELECT TO_date('2011年11月11日', 'yy"年"mm"月"dd"日"') FROM DUAL; 1. Oracle无法识别中文格式,所以添加双引号。 2. 后面的格式是指字符串在转换前的格式,而不是指转换后的格式。...

江戸川 ⋅ 30分钟前 ⋅ 0

MySell:API Spring Boot

起步 类目 商品 订单

BeanHo ⋅ 32分钟前 ⋅ 0

Spring方法拦截器MethodInterceptor

参考资料 1、Spring方法拦截器MethodInterceptor 2、Sharding JDBC源码分析-JdbcMethodInvocation类的作用

哎小艾 ⋅ 35分钟前 ⋅ 0

正则表达式

元字符 元字符,又叫字符集,就是用一些特殊符号表示特定种类的字符或位置。 匹配字符 . 匹配除换行符以外的任意字符 \w 匹配字母或数字或下划线或汉字 \s 匹配任意的空白符 \d 匹配数字 匹配...

wangchen1999 ⋅ 35分钟前 ⋅ 0

数据库数据导入Elasticsearch案例分享

基于bboss持久层和bboss elasticsearch客户端实现数据库数据导入es案例分享(支持各种数据库和各种es版本) 1.案例对应的源码 https://gitee.com/bboss/bboss-elastic/blob/master/bboss-el...

bboss ⋅ 36分钟前 ⋅ 0

动手---sbt(2)

参考 https://blog.csdn.net/leishangwen/article/details/46225587 建立一个chisel_max目录,文件内容如后面所述,现在开始执行命令: joe@joe-Aspire-Z3730:/media/sdb4/download/scala$ c......

whoisliang ⋅ 43分钟前 ⋅ 0

纯js实现最简单的文件上传(后台使用MultipartFile)

<!DOCTYPE html><html><head> <meta charset="UTF-8"> <title>XMLHttpRequest上传文件</title> <script type="text/javascript"> //图片上传 var xhr......

孟飞阳 ⋅ 48分钟前 ⋅ 0

iOS宇宙大战游戏、调试工具、各种动画、AR相册、相机图片编辑等源码

iOS精选源码 日期时间选择器,swift Space Battle 宇宙大战 SpriteKit游戏源码 LLDebugTool - 便捷的IOS调试工具(新增截屏功能) 相机扫描or长按识别二维码、FMDB、键盘动态高度、定位等 动画...

sunnyaigd ⋅ 49分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部