Golang third library 产品： 静态站点：gohugoio/hugo Public 文件同步：syncthing/syncthing Public 反向代理：fatedier/frp 在线终端：yudai/gotty 本地界面：fyne-io/fyne 在线文件：filebrowser/filebrowser 本地代理：v2ray/v2ray-core 发送文件：schollz/croc 坚守进程：ochinchina/supervisord 项目： miekg/dns jeessy2/ddns-go fsnotify/fsnotify drakkan/sftpgo 研发： GoAdminGroup/go-admin go-admin-team/go-admin flipped-aurora/gin-vue-admin qax-os/excelize grpc/grpc-go ethereum/go-ethereum Public go-kit/kit derailed/k9s Golang functions //export GetNetIP func GetNetIP() string { if ifaces, err := net.Interfaces(); err == nil { for _, iface := range ifaces { if iface.Flags&net.FlagUp == 0 || iface.Flags&net.FlagLoopback != 0 { continue // interface down // loopback interface } if addrs, err := iface.Addrs(); err == nil { for _, addr := range addrs { switch v := addr.(type) { case *net.IPAddr: if v.IP.IsGlobalUnicast() && nil != v.IP.To4() { return v.IP.String() // only pick first net card } case *net.IPNet: if v.IP.IsGlobalUnicast() && nil != v.IP.To4() { return v.IP.String() // only pick first net card } } } // end of for addrs } } // end of for iface } // end of net.Interfaces return net.IPv4zero.String() } //export GetMapIP func GetMapIP() map[string]string { m := map[string]string{} if ifaces, err := net.Interfaces(); err == nil { for _, iface := range ifaces { if iface.Flags&net.FlagUp == 0 || iface.Flags&net.FlagLoopback != 0 { continue // interface down // loopback interface } if addrs, err := iface.Addrs(); err == nil { for _, addr := range addrs { switch v := addr.(type) { case *net.IPAddr: if v.IP.IsGlobalUnicast() && nil != v.IP.To4() { m[iface.Name] = v.IP.String() // only pick last net card } case *net.IPNet: if v.IP.IsGlobalUnicast() && nil != v.IP.To4() { m[iface.Name] = v.IP.String() // only pick last net card } } } // end of for addrs } } // end of for iface } // end of net.Interfaces return m }
# MARKDOWN FILE MANAGER Manager all markdown files README.md README.win.md README.osx.md README.termux.md ...
SELECT * FROM SYSTABLECOMMENTS; SELECT COUNT(*) FROM DBA_TABLES; SELECT * FROM USER_TABLES; SELECT * FROM DBA_TABLESPACES; SELECT * FROM USER_TABLESPACES; SELECT * FROM ALL_OBJECTS; SELECT * FROM DBA_OBJECTS; SELECT * FROM USER_OBJECTS; SELECT * FROM DBA_USERS; SELECT * FROM DBA_TABLESPACES; SELECT * FROM DBA_USERS; SELECT * FROM dba_segments; SELECT * FROM V$LICENSE; SELECT * FROM V$DATABASE; SELECT * FROM V$INSTANCE; SELECT * FROM V$TABLESPACE; SELECT * FROM V$VERSION; SELECT SUM(bytes) from dba_data_files; select t.name tablespace_name, d.free_size*SF_GET_PAGE_SIZE()/1024/1024 ||'M' free_space, d.total_size*SF_GET_PAGE_SIZE()/1024/1024 ||'M' total_space, d.free_size*100/d.total_size "% FREE" from v$tablespace t, v$datafile d where t.id=d.group_id; --1）SYSTEM表空间--> 系统表空间有很多的数据字典等 --2）ROLL表空间-->回滚表空间 MVCC（事务多版本机制），消除行锁，回滚段，保 留时长（undo_retention 支持毫秒） --3）TEMP 临时表空间 ，临时段，创建的临时表 --4）MAIN表空间，这是数据库默认的白哦空间，在创建表和数据对象的死后，不指定 存储位置，默认存放在该表空间 --5）HMAIN 存放huge表的表空间 --* SYSTEM-系统表空间，存放数据字典信息 --* ROLL-回滚表空间，存放的回滚数据，MVCC（事务多版本） --* TEMP-临时表空间，存放临时数据 --* MAIN-main表空间，如果用户创建数据对象不指定存储位置，默认存放到main --* HMAIN-hmain表空间，存放huge table信息 --SYS //内置用户，不能登陆 --SYSDBA//管理员 --SYSAUDITOR//审计用户 --SYSSSO //安全用户，安全版 --备注：创建用户时，有些达梦数据库版本 用户跟密码默认都是记录成大写的英文字母，因此登陆时要输入大写才能正常登陆； --DMSQL --SQL分类：（结构话查询语言） --DDL 定义 create drop truncate --DML 管理 select insert update delete --DCL 控制 grant revoke --TCL 事务管理 commit rollback save point select NAME, ID, PID, CRTDATE from SYS.SYSOBJECTS; select file_name,tablespace_name from dba_data_files; Select tablespace_name,status from dba_tablespaces; select path from v$datafile; select * from v$datafile; SELECT SF_GET_CASE_SENSITIVE_FLAG(); CALL sp_close_session(sess_id); CALL SP_SET_PARA_VALUE(1,'PWD_POLICY',0); SELECT SF_GET_PARA_VALUE(1,'PWD_POLICY'); SELECT * FROM V$PARAMETER WHERE NAME='PWD_POLICY'; CREATE USER HWUSER IDENTIFIED BY HWUSER; SP_SET_PARA_VALUE (2,'PARALLEL_THRD_NUM',8); select SF_GET_PARA_VALUE(2,'PARALLEL_THRD_NUM'); select para_name,para_value from v$dm_ini where para_name='PARALLEL_POLICY'; SP_SET_PARA_VALUE (2,'PARALLEL_POLICY',1); select SF_GET_PARA_VALUE(1,'PARALLEL_POLICY'); SP_SET_PARA_VALUE (1,'MAX_PARALLEL_DEGREE',4); select user; CREATE TABLESPACE HWUSER_DAT DATAFILE 'HWUSER_DAT_01.dbf' SIZE 10240; ALTER TABLESPACE HWUSER_DAT ADD DATAFILE 'HWUSER_DAT_02.dbf' SIZE 10240; ALTER TABLESPACE HWUSER_DAT ADD DATAFILE 'HWUSER_DAT_03.dbf' SIZE 10240; ALTER TABLESPACE HWUSER_DAT ADD DATAFILE 'HWUSER_DAT_04.dbf' SIZE 10240; ALTER TABLESPACE HWUSER_DAT ADD DATAFILE 'HWUSER_DAT_05.dbf' SIZE 10240; CREATE TABLESPACE HWUSER_IDX DATAFILE 'HWUSER_IDX_01.dbf' SIZE 2048; ALTER TABLESPACE HWUSER_IDX ADD DATAFILE 'HWUSER_IDX_02.dbf' SIZE 2048; ALTER TABLESPACE HWUSER_IDX ADD DATAFILE 'HWUSER_IDX_03.dbf' SIZE 2048; ALTER TABLESPACE HWUSER_IDX ADD DATAFILE 'HWUSER_IDX_04.dbf' SIZE 2048; ALTER TABLESPACE HWUSER_IDX ADD DATAFILE 'HWUSER_IDX_05.dbf' SIZE 2048; CREATE TABLESPACE HWUSER_DAT DATAFILE 'HWUSER_DAT_01.dbf' SIZE 10240; CREATE TABLESPACE HWUSER_IDX DATAFILE 'HWUSER_IDX_01.dbf' SIZE 2048; CREATE TABLESPACE HWMSAS1000 DATAFILE 'HWMSAS1000_01.dbf' SIZE 10240; ALTER TABLESPACE HWMSAS1000 ADD DATAFILE 'HWMSAS1000_02.dbf' SIZE 10240; ALTER TABLESPACE HWMSAS1000 ADD DATAFILE 'HWMSAS1000_03.dbf' SIZE 10240; ALTER TABLESPACE HWMSAS1000 ADD DATAFILE 'HWMSAS1000_04.dbf' SIZE 10240; ALTER TABLESPACE HWMSAS1000 ADD DATAFILE 'HWMSAS1000_05.dbf' SIZE 10240; CREATE TABLESPACE HWMSAS1000_IDX DATAFILE 'HWMSAS1000_IDX_01.dbf' SIZE 2048; ALTER TABLESPACE HWMSAS1000_IDX ADD DATAFILE 'HWMSAS1000_IDX_02.dbf' SIZE 2048; ALTER TABLESPACE HWMSAS1000_IDX ADD DATAFILE 'HWMSAS1000_IDX_03.dbf' SIZE 2048; ALTER TABLESPACE HWMSAS1000_IDX ADD DATAFILE 'HWMSAS1000_IDX_04.dbf' SIZE 2048; ALTER TABLESPACE HWMSAS1000_IDX ADD DATAFILE 'HWMSAS1000_IDX_05.dbf' SIZE 2048; --ALTER USER HWUSER IDENTIFIED BY HWUSER DEFAULT TABLESPACE HWMSAS1000; CREATE USER "HWUSER" IDENTIFIED BY "HWUSER" DEFAULT TABLESPACE "HWMSAS1000" DEFAULT INDEX TABLESPACE "HWMSAS1000_IDX"; GRANT RESOURCE TO HWUSER; --GRANT CREATE TABLE TO HWUSER; --REVOKE CREATE TABLE FROM HWUSER; --GRANT SELECT ON DMHR.EMPLOYEE TO HWUSER; --GRANT DBA TO HWUSER; GRANT RESOURCE TO HWUSER; GRANT PUBLIC TO HWUSER; REVOKE DBA FROM HWUSER; DROP USER HWUSER; DROP USER HWUSER CASCADE; DROP TABLESPACE HWUSER; DROP TABLESPACE HWUSER_IDX; DROP TABLESPACE HWMSAS1000; DROP TABLESPACE HWMSAS1000_IDX; create tablespace bookshop datafile 'bookshop.dbf' size 1024; create schema persons authorization HWUSER; create table persons.address( addressid int identity(1,1) primary key, address1 varchar(60) not null, address2 varchar(60), city varchar(30) not null, postalcode varchar(15) not null); SELECT * FROM USER_TABLES; SELECT TABLE_NAME FROM USER_TABLES; select SCH_OBJ.NAME , SCH_OBJ.ID , SCH_OBJ.CRTDATE, USER_OBJ.NAME from ( select NAME, ID, PID, CRTDATE from SYS.SYSOBJECTS where TYPE$='SCH' ) SCH_OBJ, ( select NAME, ID from SYS.SYSOBJECTS where TYPE$='UR' and SUBTYPE$='USER' ) USER_OBJ where SCH_OBJ.PID=USER_OBJ.ID ORDER BY SCH_OBJ.NAME DROP TABLE IF EXISTS "BaseDataTab"; CREATE TABLE "BaseDataTab" ( ID BIGINT IDENTITY(1,1) PRIMARY KEY, "IpAddress" CHAR(16) NOT NULL, "Port" INT NOT NULL, "DestinationIpAddress" CHAR(16) DEFAULT NULL, "DestinationPort" INT DEFAULT NULL, "ReportTime" TIMESTAMP(3) NOT NULL, "StorageTime" datetime(3) NOT NULL, "TextType" INT NOT NULL, "DataType" INT NOT NULL, "ShapingValue" INT NOT NULL, "FloatingValue" DOUBLE NOT NULL, "TextValue" TEXT NOT NULL ); CREATE INDEX base_rpttime_idx ON "BaseDataTab" ("ReportTime"); SELECT * FROM "BaseDataTab"; SELECT * FROM "BaseDataTab" LIMIT 10000; SELECT * FROM "BaseDataTab" ORDER BY ReportTime DESC LIMIT 10000; SELECT COUNT(ID) FROM "BaseDataTab"; TRUNCATE TABLE "BaseDataTab"; INSERT INTO "BaseDataTab" VALUES ('10.100.154.197', '0', '', '0', '2020-08-21 09:26:00.290', '2020-07-17 19:32:07', '1000', '3', '0', '0', 'c8 8d 83 6f f7 b5 00 90 0b 20 1a c6 08 00 45 00 00 40 6b f4 40 00 40 06 a2 7d 14 fe 01 0c 14 01 02 3c b1 47 09 64 99 0f f3 53 71 0b fd b2 80 18 00 d1 45 bc 00 00 01 01 08 0a d8 96 45 44 6f d9 e8 a9 68 04 01 00 80 d0 68 04 01 00 84 d0\r\n'); BEGIN FOR v_count IN 1..101 Loop INSERT INTO "BaseDataTab" VALUES ('10.100.154.197', '0', '', '0', CAST(v_count as datetime), CAST(v_count as timestamp), '1000', '3', '0', '0', 'c8 8d 83 6f f7 b5 00 90 0b 20 1a c6 08 00 45 00 00 40 6b f4 40 00 40 06 a2 7d 14 fe 01 0c 14 01 02 3c b1 47 09 64 99 0f f3 53 71 0b fd b2 80 18 00 d1 45 bc 00 00 01 01 08 0a d8 96 45 44 6f d9 e8 a9 68 04 01 00 80 d0 68 04 01 00 84 d0\r\n'); END Loop; COMMIT; END; Select * from v$sessions; call sp_close_session(139789105959456); Select * from v$trxwait; select * from v$sessions where trx_id =1870061; select sess_id,appname,clnt_ip,sql_text,sf_get_session_sql(sess_id) from v$sessions where trx_id =1870061; select sess_id,appname,clnt_ip,sql_text,sf_get_session_sql(sess_id) from v$sessions where trx_id =1870167;
################################################################################### ################################################################################### ################################################################################### ################################################################################### ################################################################################### ################################################################################### TRUNCATE TABLE `PlanTab`; INSERT INTO `PlanTab` VALUES ('1', "call proc_impl_YX_failure_or_success('517&518&520&521^511');", '5', '0', '1'); INSERT INTO `PlanTab` VALUES ('2', 'call procedure_test();', '3', '0', '1'); ################################################################################### DROP PROCEDURE IF EXISTS procedure_plan; delimiter // CREATE PROCEDURE procedure_plan() BEGIN DECLARE v_id INT DEFAULT 1; # ID DECLARE v_cur INT DEFAULT 0; # 默认起始计数0，从表中读取 DECLARE v_step INT DEFAULT 1; # 默认计数每次增加1分钟，过程内置 DECLARE v_preset INT DEFAULT 5; # 默认执行周期每5分钟，从表中读取 DECLARE data_end INT DEFAULT 0; DECLARE data_cur CURSOR FOR SELECT `ID`,PresetCount,CurrentCount FROM PlanTab; DECLARE CONTINUE HANDLER FOR NOT FOUND SET data_end=1; open data_cur; REPEAT FETCH data_cur INTO v_id, v_preset, v_cur; IF data_end <> 1 THEN SET v_cur = v_cur + v_step; IF v_cur > v_preset THEN SET v_cur = FLOOR(MOD(v_cur, v_preset) - 1); END IF; UPDATE PlanTab SET CurrentCount = v_cur WHERE `ID` = v_id; END IF; UNTIL data_end END REPEAT; -- select v_begin, v_end, v_value, v_total; END // delimiter ; call procedure_plan(); ################################################################################### DROP PROCEDURE IF EXISTS procedure_init; delimiter // CREATE PROCEDURE procedure_init() BEGIN DROP TEMPORARY TABLE IF EXISTS temp_message_tab; CREATE TEMPORARY TABLE temp_message_tab ( `id` INTEGER PRIMARY KEY NOT NULL, `totab` VARCHAR(16) NOT NULL, `policy` VARCHAR(64) NOT NULL, `inners` INTEGER DEFAULT NULL, `outers` INTEGER DEFAULT NULL, `vendor` INTEGER DEFAULT NULL, `message` VARCHAR(64) character set utf8 DEFAULT '' ; ) ENGINE=MEMORY ; INSERT INTO temp_message_tab VALUES ('11', 'YXDataTab', '', '511', '11', '3', '遥信变位'); INSERT INTO temp_message_tab VALUES ('12', 'YXDataTab', '', '512', '12', '3', '遥信抖动'); INSERT INTO temp_message_tab VALUES ('13', 'YXDataTab', '', '513', '13', '3', '遥信质量码'); INSERT INTO temp_message_tab VALUES ('14', 'YXDataTab', '', '514', '14', '3', 'SOE发生'); INSERT INTO temp_message_tab VALUES ('15', 'YXDataTab', '', '515', '15', '3', 'SOE抖动'); INSERT INTO temp_message_tab VALUES ('16', 'YXDataTab', '', '516', '16', '3', 'SOE延迟传输'); INSERT INTO temp_message_tab VALUES ('17', 'YKDataTab', '', '517', '17', '3', '遥控选择'); INSERT INTO temp_message_tab VALUES ('18', 'YKDataTab', '', '518', '18', '3', '遥控选择成功'); INSERT INTO temp_message_tab VALUES ('19', 'YKDataTab', '', '519', '19', '3', '遥控选择失败'); INSERT INTO temp_message_tab VALUES ('20', 'YKDataTab', '', '520', '20', '3', '遥控执行'); INSERT INTO temp_message_tab VALUES ('21', 'YKDataTab', '', '521', '21', '3', '遥控执行成功'); INSERT INTO temp_message_tab VALUES ('22', 'YKDataTab', '', '522', '22', '3', '遥控执行失败'); INSERT INTO temp_message_tab VALUES ('23', 'YKDataTab', '', '523', '23', '3', '遥控取消'); INSERT INTO temp_message_tab VALUES ('24', 'YKDataTab', '', '524', '24', '3', '遥控取消成功'); INSERT INTO temp_message_tab VALUES ('25', 'YKDataTab', '', '525', '25', '3', '遥控取消失败'); INSERT INTO temp_message_tab VALUES ('35', 'YCDataTab', '', '535', '35', '3', '遥测变化'); INSERT INTO temp_message_tab VALUES ('36', 'YCDataTab', '', '536', '36', '3', '遥测上送'); INSERT INTO temp_message_tab VALUES ('37', 'YCDataTab', '', '537', '37', '3', '遥测长时间未变化'); INSERT INTO temp_message_tab VALUES ('38', 'YCDataTab', '', '538', '38', '3', '遥测质量码'); INSERT INTO temp_message_tab VALUES ('39', 'YCDataTab', '', '539', '39', '3', '遥测跳变'); -- SELECT * FROM temp_message_tab; DROP TEMPORARY TABLE IF EXISTS temporary_logic; CREATE TEMPORARY TABLE temporary_logic ( `id` INTEGER PRIMARY KEY NOT NULL, `msgtype` INTEGER NOT NULL, `msgname` VARCHAR(64) NOT NULL, `msgidx` INTEGER NOT NULL, `record` INTEGER NOT NULL, `status` INTEGER NOT NULL, `analys` INTEGER NOT NULL ) ENGINE=MEMORY ; END // delimiter ; call procedure_init(); ################################################################################### ################################################################################### ################################################################################### DELIMITER // DROP FUNCTION IF EXISTS setDotRelated; CREATE FUNCTION setDotRelated() RETURNS INT BEGIN DECLARE v_begin INT DEFAULT 0; DECLARE v_end INT DEFAULT 0; DECLARE v_value VARCHAR(32767) DEFAULT ''; DECLARE v_title VARCHAR(32767) DEFAULT ''; DECLARE v_total VARCHAR(32767) DEFAULT ''; DECLARE v_msgidx INT DEFAULT 0; DECLARE v_record INT DEFAULT 0; DECLARE v_status INT DEFAULT 0; DECLARE v_analys INT DEFAULT 0; DECLARE flag_end INT DEFAULT 0; DECLARE data_cur CURSOR FOR SELECT `msgidx`,`record`,`status`,`analys` FROM `temporary_logic` WHERE `msgidx` > 0 AND `id` < 5; DECLARE CONTINUE HANDLER FOR NOT FOUND SET flag_end=1; open data_cur; SET v_begin = 1; REPEAT FETCH data_cur INTO v_msgidx, v_record, v_status, v_analys; IF flag_end <> 1 THEN set v_end = v_end+1; -- PREPARE stmt FROM @proc_call_name; -- EXECUTE stmt; -- DEALLOCATE PREPARE stmt; SELECT `ReportTime`,`TextValue` INTO v_title, v_value FROM `temp_term_tab` WHERE `ID` = v_msgidx; set v_total = TRIM(LEADING '\n' FROM CONCAT_WS('\n',v_total, CONCAT(v_title,' ',v_value))); INSERT INTO `YKDataTab` (SELECT '0' AS `ID`, `IpAddress`,`Port`, `DestinationIpAddress`, `DestinationPort`,`ReportTime`, CURRENT_TIMESTAMP AS `StorageTime`, `Ypoint` AS `YkPointIndex`, `Ydesc` AS `YkPointNumberDescription`, `MessageType`, `Ydot` AS `Dot`, `Yval` AS `DataValue`, v_record AS `YKConclusionRecord`, v_status AS `YKConclusionStatus`, v_analys AS `YKConclusionIndex`, v_total AS `ContentOfProof` FROM `temp_term_tab` WHERE `ID` = v_msgidx); DELETE FROM `BaseDataTab` WHERE `ID` = v_msgidx AND 'HwMsas1000' IN ( SELECT DATABASE() ); END IF; UNTIL flag_end END REPEAT; -- SELECT v_begin, v_end, v_value, v_total; RETURN 4; END // DELIMITER ; SELECT setDotRelated(); ################################################################################### DROP PROCEDURE IF EXISTS procedure_each; DELIMITER // CREATE PROCEDURE procedure_each( IN p_logic TINYTEXT, IN p_table TINYTEXT) BEGIN DECLARE v_begin INT DEFAULT 0; DECLARE v_end INT DEFAULT 0; DECLARE v_value VARCHAR(32767) character set utf8 DEFAULT '' ; DECLARE v_total VARCHAR(32767) character set utf8 DEFAULT '' ; DECLARE v_i int DEFAULT 0; DECLARE v_len int DEFAULT 0; DECLARE v_id int DEFAULT 0; DECLARE v_num int DEFAULT 0; DECLARE v_msgidx int DEFAULT 0; DECLARE v_msgtype int DEFAULT 0; DECLARE v_msgtext VARCHAR(64) character set utf8 DEFAULT '' ; DECLARE flag_end int DEFAULT 0; DECLARE data_cur CURSOR FOR SELECT GROUP_CONCAT(CONCAT_WS(',', `ID`,`MessageType`, SUBSTRING_INDEX(SUBSTRING_INDEX(`TextValue`, '-', -2), '-', 1)) SEPARATOR ';') FROM `temp_term_tab` WHERE `MessageType` IN ('517', '518', '520', '521', '511') GROUP BY `YDot` ORDER BY `ReportTime`; DECLARE CONTINUE HANDLER FOR NOT FOUND SET flag_end=1; -- SELECT * FROM `temp_term_tab` WHERE `MessageType` GROUP BY `YDot` ORDER BY `ReportTime`; -- SELECT `YDot`,`Yindex`,GROUP_CONCAT(CONCAT_WS(',', `ID`,`MessageType`, SUBSTRING_INDEX(SUBSTRING_INDEX(`TextValue`, '-', -2), '-', 1)) SEPARATOR ';') -- FROM `temp_term_tab` WHERE `MessageType` IN ('17', '18', '20', '21', '11') GROUP BY `YDot` ORDER BY `ReportTime`; DROP TEMPORARY TABLE IF EXISTS temporary_logic; CREATE TEMPORARY TABLE temporary_logic ( `id` INTEGER PRIMARY KEY NOT NULL, `msgtype` INTEGER NOT NULL, `msgname` VARCHAR(64) NOT NULL, `msgidx` INTEGER NOT NULL, `record` INTEGER NOT NULL, `status` INTEGER NOT NULL, `analys` INTEGER NOT NULL ) ENGINE=MEMORY ; INSERT INTO `temporary_logic` VALUES ('1', '517', '遥控选择' , 0, 1, 2, 3), ('2', '518', '遥控选择成功' , 0, 1, 2, 3), ('3', '520', '遥控执行' , 0, 1, 2, 3), ('4', '521', '遥控执行成功' , 0, 2, 2, 3), ('5', '511', '遥信变位' , 0, 1, 2, 3); -- SELECT * FROM `temporary_logic`; open data_cur; set v_begin = 1; REPEAT FETCH data_cur INTO v_total; IF flag_end != 1 THEN set v_end = v_end + 1; set v_len = LENGTH(v_total) - LENGTH(REPLACE(v_total,';',''))+1; set v_i = 0; IF v_len >= 4 THEN UPDATE `temporary_logic` SET `msgidx` = 0; END IF; WHILE v_len >= 4 AND v_i < v_len DO set v_i = v_i+1; set v_value = SUBSTRING_INDEX(SUBSTRING_INDEX(v_total, ';', v_i), ';', -1); set v_msgidx = SUBSTRING_INDEX(v_value, ',', 1); set v_msgtype = SUBSTRING_INDEX(SUBSTRING_INDEX(v_value, ',', 2), ',', -1); set v_msgtext = SUBSTRING_INDEX(v_value, ',', -1); SELECT `id` INTO v_id FROM `temporary_logic` WHERE `msgtype` = v_msgtype; -- SET: FIRST MSG OR LAST MSG NOT NULL SHOUL UPDATE CURRENT MSG INDEX IF v_id = 1 THEN UPDATE `temporary_logic` SET `msgidx` = v_msgidx WHERE `msgtype` = v_msgtype; ELSE SELECT `msgidx` INTO v_num FROM `temporary_logic` WHERE `id` IN (SELECT v_id - 1); -- LAST MSG GOT IT OR PREVIEW MSG IS NONE, SHOULD CLENN ALL IF v_id = 5 OR v_num = 0 THEN UPDATE `temporary_logic` SET `msgidx` = 0; ELSE UPDATE `temporary_logic` SET `msgidx` = v_msgidx WHERE `msgtype` = v_msgtype; END IF; -- SOME DATA OR NODATA ---> CLEAN, RECV YK SELECT, OR REACH END END IF; -- CHECK IF RECV FIRST MSG(PROMISE FULL AND WITHOUT YXBW) OR REACH END IF v_id = 1 OR v_i = v_len THEN SELECT COUNT(*) INTO v_num FROM `temporary_logic` WHERE `msgidx` > 0 AND `id` != 5; IF v_num = 4 THEN -- FULL DATA ---> STORE , RECV YK SELECT, OR REACH END UPDATE `temporary_logic` SET `msgname` = 999 WHERE `msgtype` = v_msgtype; -- SELECT v_begin, v_end, v_value, v_total, v_msgidx, v_id, v_msgtype; SELECT * FROM `temporary_logic`; -- SELECT * FROM `temp_term_tab`; SELECT setDotRelated() INTO v_num; -- SELECT v_begin, v_end, v_value, v_total, v_id, v_msgidx, v_msgtype, v_msgtext; END IF; END IF; END WHILE; END IF; UNTIL flag_end END REPEAT; close data_cur; -- SELECT v_begin, v_end, v_value, v_total; END // DELIMITER ; call procedure_each('517&518&520&521^511', 'temp_table_term'); ################################################################################### DROP PROCEDURE IF EXISTS procedure_term; DELIMITER // CREATE PROCEDURE procedure_term( IN p_logic TINYTEXT, IN p_termid INT ) BEGIN DECLARE v_begin INT DEFAULT 0; DECLARE v_end INT DEFAULT 0; DECLARE v_value TINYTEXT DEFAULT ''; DECLARE v_total TINYTEXT DEFAULT ''; DECLARE v_i INT DEFAULT 0; DECLARE v_len INT DEFAULT 0; DECLARE v_delim TINYTEXT DEFAULT '|'; DECLARE v_logic TINYTEXT DEFAULT ''; set v_len = LENGTH(p_logic) - LENGTH(REPLACE(p_logic,v_delim,''))+1; set v_i = 0; WHILE v_i < v_len do set v_i = v_i+1; set v_logic = replace(substring(substring_index(p_logic, v_delim, v_i), length(substring_index(p_logic, v_delim, v_i -1)) + 1), v_delim, ''); set v_total = CONCAT(v_total, ' ', v_logic); call procedure_each(v_logic, 'temp_term_tab'); END WHILE; -- SELECT v_begin, v_end, v_value, v_total; END // DELIMITER ; call procedure_term('517&518&520&521^511', '20511'); ################################################################################### DELIMITER // DROP FUNCTION IF EXISTS genDotRelated; CREATE FUNCTION genDotRelated(msgType INT,dot INT, termid INT, flag VARCHAR(16)) RETURNS VARCHAR(64) BEGIN DECLARE v_result VARCHAR(64) DEFAULT ''; DECLARE v_decideTab VARCHAR(64) DEFAULT ''; DECLARE v_dotAbsAddr INT DEFAULT 0; DECLARE v_pointIdx INT DEFAULT 0; DECLARE v_pointDesc VARCHAR(64) DEFAULT ''; DECLARE has_error int DEFAULT 0; DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET has_error = 1; IF ISNULL(msgType) || LENGTH(trim(msgType))<1 OR ISNULL(dot) || LENGTH(trim(dot))<1 OR ISNULL(termid) || LENGTH(trim(termid))<1 THEN RETURN v_result; END IF; IF 11 <= msgType AND msgType <= 16 THEN set v_decideTab = 'YXDataTab'; set v_dotAbsAddr = 0x1 + dot; -- SELECT IFNULL(`InternalPointIndex`, 0),IFNULL(`DotDescription`, ' ') INTO v_pointIdx,v_pointDesc FROM `YXPointDataTab` -- WHERE `TerminalIndex` = termid AND `DotAbsoluteAddress` = v_dotAbsAddr; ELSEIF 17 <= msgType AND msgType <= 25 THEN set v_decideTab = 'YKDataTab'; set v_dotAbsAddr = 0x4001 + dot; -- SELECT `InternalPointIndex`,`DotDescription` INTO v_pointIdx,v_pointDesc FROM `YKPointDataTab` -- WHERE `TerminalIndex` = termid AND `DotAbsoluteAddress` = v_dotAbsAddr; ELSEIF 35 <= msgType AND msgType <= 39 THEN set v_decideTab = 'YCDataTab'; set v_dotAbsAddr = 0x6001 + dot; -- SELECT `InternalPointIndex`,`DotDescription` INTO v_pointIdx,v_pointDesc FROM `YCPointDataTab` -- WHERE `TerminalIndex` = termid AND `DotAbsoluteAddress` = v_dotAbsAddr; END IF; SELECT CASE WHEN flag = 'TYPE' THEN v_decideTab WHEN flag = 'POINT' THEN v_pointIdx WHEN flag = 'DESC' THEN v_pointDesc ELSE NULL END AS ret INTO v_result; RETURN v_result; END // DELIMITER ; SELECT genDotRelated(17,3,20511, 'TYPE'); ################################################################################### DROP PROCEDURE IF EXISTS procedure_work; delimiter // CREATE PROCEDURE procedure_work(IN p_logic VARCHAR(64) ) BEGIN DECLARE v_begin INT DEFAULT 0; DECLARE v_end INT DEFAULT 0; DECLARE v_value TINYTEXT DEFAULT ''; DECLARE v_total TINYTEXT DEFAULT ''; DECLARE v_num INT DEFAULT 0; DECLARE v_termid INT DEFAULT ''; DECLARE v_ip TINYTEXT DEFAULT ''; DECLARE v_port INT DEFAULT 0; DECLARE flag_end int DEFAULT 0; DECLARE data_cur CURSOR FOR SELECT `TerminalIndex`,`IpAddress`,`Port` FROM TerTab; DECLARE CONTINUE HANDLER FOR NOT FOUND SET flag_end=1; open data_cur; set v_begin = 1; REPEAT FETCH data_cur INTO v_termid, v_ip, v_port; SELECT COUNT(*) INTO v_num FROM `BaseDataTab` WHERE `IpAddress` = v_ip AND `Port` = v_port AND `DataType` = 3; IF flag_end != 1 AND v_num > 0 THEN set v_end = v_end + 1; -- SET @v_termid=20511; -- test v_termid -- SET @p_ip='192.168.10.15'; -- test p_ip -- SET @p_port='2404'; -- test p_port DROP TEMPORARY TABLE IF EXISTS `temp_term_tab`; CREATE TEMPORARY TABLE `temp_term_tab` SELECT `ID`,`IpAddress`,`Port`,`DestinationIpAddress`,`DestinationPort`,`ReportTime`,`MessageType`,`TextValue`, '' AS `Yflag`, -- CASE -- WHEN 11 <= `MessageType` AND `MessageType` <= 16 THEN 'YXDataTab' -- WHEN 17 <= `MessageType` AND `MessageType` <= 25 THEN 'YKDataTab' -- WHEN 35 <= `MessageType` AND `MessageType` <= 39 THEN 'YCDataTab' -- ELSE NULL -- END AS `YType`, '' AS `Ypoint`, '' AS `Ydesc`, genDotRelated(`MessageType`, SUBSTRING_INDEX(SUBSTRING_INDEX(`TextValue`, ']', 1), '[', -1), 20511, 'TYPE') AS `YType`, genDotRelated(`MessageType`, SUBSTRING_INDEX(SUBSTRING_INDEX(`TextValue`, ']', 1), '[', -1), 20511, 'POINT') AS `Ypoint`, genDotRelated(`MessageType`, SUBSTRING_INDEX(SUBSTRING_INDEX(`TextValue`, ']', 1), '[', -1), 20511, 'DESC') AS `Ydesc`, SUBSTRING_INDEX(SUBSTRING_INDEX(`TextValue`, ']', 1), '[', -1) `YDot`, SUBSTRING_INDEX(`TextValue`, '-', -1) AS `Yval`, '' AS `Yrecord`,'' AS `Ystatus`, '3' AS `Yindex`, '' AS `Yproof` -- FROM `BaseDataTab` WHERE `IpAddress` = '192.168.10.15' AND `Port` = '2404' AND `DataType` = 3 FROM `BaseDataTab` WHERE `IpAddress` = v_ip AND `Port` = v_port AND `DataType` = 3 ORDER BY `ReportTime`; SELECT * FROM `temp_term_tab`; -- 开始处理每一个终端，应用所有的逻辑 call procedure_term(p_logic, v_termid); END IF; UNTIL flag_end END REPEAT; close data_cur; -- select v_begin, v_end, v_value, v_total; END // delimiter ; call procedure_work('517&518&520&521^511'); ################################################################################### DROP PROCEDURE IF EXISTS proc_impl_YX_failure_or_success; delimiter // CREATE PROCEDURE proc_impl_YX_failure_or_success(IN p_logic TINYTEXT) BEGIN DECLARE v_begin INT DEFAULT 0; DECLARE v_end INT DEFAULT 0; DECLARE v_value TINYTEXT DEFAULT ''; DECLARE v_total TINYTEXT DEFAULT ''; -- 处理每一个可配置的存储过程 call procedure_work(p_logic); -- SELECT v_begin, v_end, v_title, v_value, v_total; END // delimiter ; call proc_impl_YX_failure_or_success('517&518&520&521^511'); -- -- 8.2 终端异常分析 -- -- 8.2.1 遥控成功但无遥信变位 -- call proc_impl_YK_exec_success_YX_failure('517&518&520&521^511'); -- -- 8.2.2 开关处于分位但仍有电流 -- call proc_impl_YX_switch_off_alternate_on('1&2|3|4'); -- -- 8.2.3 蓄电池活化状态持续为1 -- call proc_impl_YC_bettery_always_one('6|6', ''); -- -- 8.2.4 三相电流不平衡但无零序电流上报 -- call proc_impl_YC_alternate_imbalance_none_zreo( ); -- -- 8.2.5 蓄电池电压突变 -- call proc_impl_YC_bettery_voltage_jump('3&3', '24'); -- -- 8.2.6 某一终端遥测值长时间保持不变 -- call proc_impl_YC_longtime_stable('1&2|1&3&4&5|1&3&4&6&7'); -- -- 8.2.7 终端持续上报“故障总”遥信 -- call proc_impl_YX_continue_report_fault('5&5'); -- -- 8.2.8 终端响应速率慢异常分析 -- call proc_impl_YX_response_slowly( ); ################################################################################### -- 主存储过程调用入口，由事件定时器以最小粒度，比如配置事件每分钟定时调用 DROP PROCEDURE IF EXISTS procedure_main; delimiter // #将语句的结束符号从分号;临时改为两个//(可以是自定义) CREATE PROCEDURE procedure_main() BEGIN DECLARE v_begin INT DEFAULT 0; DECLARE v_end INT DEFAULT 0; DECLARE v_value TINYTEXT DEFAULT ''; DECLARE v_total TINYTEXT DEFAULT ''; DECLARE time_cur INT DEFAULT 0; DECLARE time_per INT DEFAULT 0; DECLARE flag_end INT DEFAULT 0; DECLARE data_cur CURSOR FOR SELECT StoredProcedureName FROM PlanTab WHERE PresetCount = CurrentCount; DECLARE CONTINUE HANDLER FOR NOT FOUND SET flag_end=1; -- 1，初始化逻辑消息配置表，在内存中创建表，每一次调用都执行 call procedure_init(); -- 2，刷新定时器的计数，超出已做翻转重置处理 call procedure_plan(); -- 3，遍历 PlanTab 表，找出到期的任务 open data_cur; SET v_begin = 1; REPEAT FETCH data_cur INTO v_value; IF flag_end <> 1 THEN -- 3，开始调用查询到的存储过程，执行已配置并且到期的存储过程接口 SET @proc_call_name = (SELECT v_value); # call proc_impl_YX_failure_or_success(); PREPARE stmt FROM @proc_call_name; EXECUTE stmt; DEALLOCATE PREPARE stmt; END IF; UNTIL flag_end END REPEAT; SELECT v_begin, v_end, v_value, v_total; END // delimiter ; #将语句的结束符号恢复为分号 call procedure_main(); ################################################################################### DROP PROCEDURE IF EXISTS procedure_test; delimiter // CREATE PROCEDURE procedure_test() BEGIN DECLARE v_begin INT DEFAULT 0; DECLARE v_end INT DEFAULT 0; DECLARE v_value TEXT DEFAULT ''; DECLARE v_total TEXT DEFAULT ''; DECLARE v_title TEXT DEFAULT ''; SELECT v_begin, v_end, v_title, v_value, v_total; -- select v_begin, v_end, v_IpAddress,v_TextValue, v_total, v_title; END // delimiter ; call procedure_test(); ################################################################################### -- 每隔一分钟执行一次，开始执行时间为当前时间的下一分钟 DELIMITER // DROP EVENT IF EXISTS event_minute; CREATE EVENT event_minute ON SCHEDULE EVERY 1 MINUTE STARTS DATE_ADD(now(), INTERVAL 1 MINUTE) ON COMPLETION PRESERVE ENABLE DO BEGIN INSERT INTO `BakDataTab` VALUES ('0', '', '0', '', '0', '', '', CURRENT_TIMESTAMP, '0', '0', '0', '0', ''); call procedure_main(); END // DELIMITER ; ################################################################################### ################################################################################### ################################################################################### ################################################################################### ################################################################################### ################################################################################### -- concat字符串连接函数，只要其中一个是NULL，那么将返回NULL -- concat_ws字符串连接函数，只要有一个字符串不是NULL，就不会返回NULL。需要指定分隔符。 DROP PROCEDURE IF EXISTS test_procedure; delimiter // CREATE PROCEDURE test_procedure() BEGIN DECLARE v_begin INT DEFAULT 0; -- default DECLARE v_end INT DEFAULT 0; -- default DECLARE v_value VARCHAR(64) character set utf8 DEFAULT '' ; -- default DECLARE v_total VARCHAR(64) character set utf8 DEFAULT '' ; -- default DECLARE flag_end int DEFAULT 0; DECLARE data_cur CURSOR FOR SELECT name FROM mysql.event; DECLARE CONTINUE HANDLER FOR NOT FOUND SET flag_end=1; open data_cur; set v_begin = 1; -- default REPEAT FETCH data_cur INTO v_value; IF flag_end <> 1 THEN set v_end = v_end + 1; -- default set v_total = CONCAT_WS(',', v_value, v_value); -- todo. END IF; UNTIL flag_end END REPEAT; close data_cur; -- OPEN data_cur; -- set v_begin = 1; -- default -- FETCH data_cur INTO v_value; -- WHILE flag_end <> 1 DO -- set v_end = v_end + 1; -- default -- set v_total = CONCAT_WS(',', v_value, v_value); -- todo. -- FETCH data_cur INTO v_value; -- END WHILE; -- CLOSE data_cur; select v_begin, v_end, v_value, v_total; END // delimiter ; call test_procedure(); ################################################################################### ################################################################################### ################################################################################### ################################################################################### AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA ################################################################################### ################################################################################### ################################################################################### ################################################################################### ################################################################################### -- 数据表中有自增长主键时，当用SQL插入语句中插入语句带有ID列值记录的时候； -- 如果指定了该列的值，则新插入的值不能和已有的值重复，而且必须大于其中最大的一个值； -- 也可以不指定该列的值，只将其他列的值插入，让ID还是按照MySQL自增自己填； -- 这种情况在进行插入的时候，两种解决方法： -- ①可以把id的值设置为null或者0，这样子mysql都会自己做处理 -- ②手动指定需要插入的列，不插入这一个字段的数据！ ################################################################################### ################################################################################### -- FILE权限与SELECE/DELETE/UPDATE等不同，后者是可以具体指定到某个db的某个表的，而FILE则是全局的， -- 即只能通过grant FILE on *.* to 'abcde'@'%'才能使FILE权限对所有db的所有tables生效。 -- 通过grant all on db.* to 'abcde'@'%'不能使指定的user在指定的db上具有FILE权限。 ################################################################################### ################################################################################### -- MySql的CURRENT_TIMESTAMP在创建时间字段的时候 -- DEFAULT CURRENT_TIMESTAMP 表示当插入数据的时候，该字段默认值为当前时间 -- ON UPDATE CURRENT_TIMESTAMP 表示每次更新这条数据的时候，该字段都会更新成当前时间 -- 这两个操作是mysql数据库本身在维护，生成【创建时间】和【更新时间】两个字段，且不需要代码来维护 -- CREATE TABLE `alls_create_time_update_time` ( -- `index` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT 'INDEX', -- `text` varchar(255) DEFAULT '' COMMENT '内容', -- `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', -- `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间' -- ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- 注意：MySQL 5.6.5 以及之前的版本不支持同时指定两个自动time字段。 ################################################################################### ################################################################################### -- MySQL错误：删除数据库的时候报错ERROR 1010 (HY000) -- 原因是数据/var/lib/mysql/目录下有除了数据库文件以外的文件,可以cd到其目录，清空后。再drop ################################################################################### ################################################################################### -- 问题说明（修改 variables 变量配置，系统重启后将失效，需要修改配置文件，重启数据库）： -- 1，导入文件路径问题，需要修改 secure_file_priv 字段为空，或者指定的某个路径 -- 2，修改创建数据库的默认编码，character_set_server，character_set_database 重启失效。 -- 3， -- 8，忘记密码，修改mysql配置文件 skip-grant-tables 跳过密码检查 -- 9，LOAD DATA 必须针对 用户及访问方式设置 grant file 单独设置，不能针对数据库。 ################################################################################### ################################################################################### ################################################################################### ################################################################################### show variables like 'event%'; show variables like '%char%'; show variables like 'autocommit'; SHOW VARIABLES LIKE 'max_allowed_packet'; SHOW VARIABLES LIKE 'secure_file_priv'; show global variables like "secure_file_priv"; show global variables like 'local_infile'; show variables like 'datadir'; show variables like '%dir%'; show variables like '%log%'; ################################################################################### ################################################################################### ################################################################################### mysql -u root -p mysql -h 127.0.0.1 -P 3306 -uandy -p543604 mysqld_safe --user=mysql --skip-grant-tables --skip-networking ################################################################################### UPDATE mysql.user SET password=PASSWORD('test') WHERE user='test'; UPDATE mysql.user SET password='test' WHERE user='test'; SELECT * FROM mysql.user WHERE user='test'; create user 'hwuser'@'localhost' identified by 'hwuser'; create user 'hwuser'@'%' identified by 'hwuser'; flush privileges; create database HwMsas1000 DEFAULT CHARSET utf8 COLLATE utf8_general_ci; grant all privileges on `HwMsas1000`.* to 'hwuser'@'%' identified by 'hwuser'; grant all privileges on `HwMsas1000`.* to 'hwuser'@'localhost' identified by 'hwuser'; flush privileges; grant file on `TestDev`.* to 'test'@'%' identified by 'test'; grant file on *.* to 'test'@'%' identified BY PASSWORD '*94BDCEBE19083CE2A1F959FD02F964C7AF4CFC29'; grant file on *.* to 'test'@'localhost' identified BY PASSWORD '*94BDCEBE19083CE2A1F959FD02F964C7AF4CFC29'; FLUSH PRIVILEGES; ################################################################################### -- 查询所有事件定时器的特定字段信息 select * from mysql.event; SELECT event_name,event_definition,interval_value,interval_field,status FROM information_schema.EVENTS; ################################################################################### -- 更改单个事件定时器的开启关闭 alter event second_event on completion preserve enable;//开启定时任务 alter event second_event on completion preserve disable;//关闭定时任务 -- 开启事件 定时器执行计划 SET GLOBAL event_scheduler = ON; show variables like 'event%'; ################################################################################### set character_set_server=utf8; set character_set_database=utf8; show variables like '%char%'; alter table `BaseDataTab` convert to character set utf8; ################################################################################### -- DROP DATABASE IF EXISTS dataDictDb; CREATE DATABASE IF NOT EXISTS dataDictDb DEFAULT CHARSET utf8 COLLATE utf8_general_ci; USE dataDictDb; -- TRUNCATE table `TypeTab`; delete from TypeTab; alter table `TypeTab` auto_increment=1; -- DROP TEMPORARY TABLE IF EXISTS `temp_event_term`; CREATE TEMPORARY TABLE `temp_event_term` ENGINE=MEMERY SELECT * mysql.event; CREATE TEMPORARY TABLE temp_a (`inId` int auto_increment, b VARCHAR(20)) ENGINE=MEMORY ; CREATE TABLE `TypeTab` (PRIMARY KEY (`Index`),`Index` int NOT NULL AUTO_INCREMENT,`TerminalName` text NOT NULL DEFAULT '') ENGINE=InnoDB DEFAULT CHARSET=utf8; SELECT * INTO OUTFILE 'TypeTab.csv' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n' FROM TypeTab; load data local infile "TypeTab.csv" INTO table TypeTab FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n'; load data infile '/var/lib/mysql-files/BaseDataTab.csv' into table BaseDataTab fields terminated by ',' optionally enclosed by '"' escaped by '"' lines terminated by '\n'; load data infile '/tmp/t0.txt' into table t0 character set gbk fields terminated by ',' enclosed by '"' lines terminated by '\n' (`name`,`age`,`description`) set update_time=current_timestamp; SELECT LOAD_FILE('/root/TypeTab.csv') AS csvResult; ################################################################################### SELECT * FROM `temp_event_term`; select SUBSTRING("Hello World",1,3) as test; select SUBSTRING("Hello World",2) as test; ################################################################################### SELECT 'YK[-359]-YKSEFA-0.000000' REGEXP '(YKSEFA)'; ################################################################################### SELECT * FROM BaseDataTab WHERE `ID` IN ( SELECT `ID` FROM YKDataTab ); ################################################################################### SELECT * FROM BaseDataTab WHERE `ID` = 17 AND 'HwMsas1000' IN ( SELECT DATABASE() ); ################################################################################### delete from BakDataTab; alter table `BakDataTab` auto_increment=1; ################################################################################### delete from BakDataTab; alter table `BakDataTab` auto_increment=1; SELECT * FROM BakDataTab WHERE date(BackupTime) >= '2020-03-11'; SELECT * FROM BakDataTab WHERE date(BackupTime) between '2013-01-01' and '2013-01-31'; ################################################################################### SELECT "2020-03-10 19:00:04" + INTERVAL 30 SECOND; SELECT DATE_ADD("1997-12-31 23:59:59",INTERVAL 1 SECOND); SELECT DATE_SUB("1998-01-02", INTERVAL 31 DAY); select TO_DAYS(950501); select TO_DAYS('1997-10-07'); select FROM_DAYS(729669); select DATE_FORMAT('1997-10-04 22:23:00', '%W %M %Y'); select DATE_FORMAT('1997-10-04 22:23:00', '%H:%i:%s'); select DATE_FORMAT('1997-10-04 22:23:00', '%H %k %I %r %T %S %w'); ################################################################################### SELECT FIND_IN_SET(',' ,'YK,20;YX,10;YX,5') pos; SELECT POSITION(',' IN 'YK,20;YX,10;YX,5'); ################################################################################### CREATE TABLE `t_test` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(1) NOT NULL DEFAULT '', PRIMARY KEY (`id`), UNIQUE KEY `idx_name` (`name`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 INSERT INTO t_test (`name`)VALUES('a') REPLACE INTO t_test (`name`)VALUES('a')
{ "[c]": { "editor.autoIndent": "brackets", "editor.detectIndentation": true, "editor.emptySelectionClipboard": true, "editor.fontWeight": "normal", "editor.insertSpaces": true, "editor.quickSuggestions": { "comments": true, "other": true, "strings": false }, "editor.quickSuggestionsDelay": 10, "editor.renderWhitespace": "none", "editor.tabSize": 4, "editor.trimAutoWhitespace": true, "editor.useTabStops": true, "editor.wrappingIndent": "indent", "files.insertFinalNewline": true }, "[cpp]": { "editor.autoIndent": "brackets", "editor.detectIndentation": true, "editor.emptySelectionClipboard": true, "editor.fontWeight": "normal", "editor.insertSpaces": true, "editor.quickSuggestions": { "comments": true, "other": true, "strings": false }, "editor.quickSuggestionsDelay": 10, "editor.renderWhitespace": "none", "editor.tabSize": 4, "editor.trimAutoWhitespace": true, "editor.useTabStops": true, "editor.wrappingIndent": "indent", "files.insertFinalNewline": true }, "[css]": { "editor.formatOnSave": true, "editor.tabSize": 2 }, "[html]": { "editor.formatOnSave": true, "editor.tabSize": 2 }, "[javascript]": { "editor.tabSize": 2 }, "[json]": { "editor.formatOnSave": true, "editor.tabSize": 2 }, "[php]": { "editor.formatOnSave": true, "editor.tabSize": 2 }, "breadcrumbs.enabled": true, "code-runner.customCommand": "echo Hello World", "code-runner.executorMap": { "bat": "cmd /c", "c": "cd $dir && gcc -framework OpenGL -framework GLUT -framework Foundation $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt", "cpp": "cd $dir && g++ $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt", "java": "cd $dir && javac $fileName && java $fileNameWithoutExt", "javascript": "node", "python": "python -u", "shellscript": "bash" }, "editor.codeActionsOnSave": { "source.fixAll": true }, "editor.cursorBlinking": "smooth", "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.detectIndentation": true, "editor.fontFamily": "'Courier New', Menlo, Monaco, monospace", "editor.fontLigatures": true, "editor.fontSize": 22, "editor.formatOnPaste": true, "editor.formatOnSave": true, "editor.formatOnType": true, "editor.lineNumbers": "on", "editor.minimap.renderCharacters": false, "editor.multiCursorModifier": "ctrlCmd", "editor.quickSuggestions": { "comments": true, "other": true, "strings": true }, "editor.renderWhitespace": "all", "editor.snippetSuggestions": "top", "editor.suggest.snippetsPreventQuickSuggestions": false, "editor.tabCompletion": "on", "editor.tabSize": 2, "emmet.showSuggestionsAsSnippets": true, "emmet.syntaxProfiles": { "vue": "html", "vue-html": "html" }, "extensions.autoUpdate": true, "extensions.ignoreRecommendations": false, "files.autoSave": "onFocusChange", "files.encoding": "utf8", "files.eol": "auto", "files.exclude": { "**/.DS_Store": true, "**/.git": true, "**/.hg": true, "**/.svn": true }, "files.insertFinalNewline": true, "files.trimFinalNewlines": true, "files.trimTrailingWhitespace": true, "git.ignoreMissingGitWarning": true, "javascript.format.insertSpaceBeforeFunctionParenthesis": true, "markdown.preview.fontSize": 16, "search.followSymlinks": false, "search.smartCase": true, "terminal.integrated.copyOnSelection": true, "terminal.integrated.fontSize": 16, "update.mode": "none", "window.menuBarVisibility": "toggle", "window.openFilesInNewWindow": "off", "window.title": "${dirty}${activeEditorShort}${separator}${folderPath}${separator}${activeEditorLong}${separator}${appName}", "window.titleBarStyle": "custom", "window.zoomLevel": 1, "workbench.colorCustomizations": { "activityBar.background": "#393D49", "editor.background": "#303133", "editor.selectionBackground": "#5FB878", "editorGroup.emptyBackground": "#808695", "sideBar.background": "#2F4056", "tab.activeBackground": "#009688" }, "workbench.colorTheme": "Monokai", "workbench.iconTheme": "vs-seti", "workbench.startupEditor": "none", "explorer.confirmDelete": false }
vim ~/.vimrc syntax enable syntax on filetype on filetype plugin on filetype indent on filetype plugin indent on set number set ignorecase set autoread set showcmd set showmode set incsearch set cursorline "set cursorcolumn set ruler set history=1024 set nobackup set noswapfile set autoindent set cindent set smartindent set tabstop=4 set shiftwidth=4 set guifont=Monaco set background=light "colorscheme evening set t_Co=256 set encoding=utf-8 set fileencodings=ucs-bom,utf-8,cp936,gb18030,big5,euc-jp,euc-kr,latin1 set helplang=cn set termencoding=utf-8 set ffs=unix,dos,mac set statusline=%<%f\ %h%m%r%=%k[%{(&fenc==\"\")?&enc:&fenc}%{(&bomb?\",BOM\":\"\")}]\ %-14.(%l,%c%V%)\ %P set laststatus=2 :set pastetoggle=<F12> if has("autocmd") au BufReadPost * if line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g'\"" | endif endif func! CompileCodeRunResult() exec "w" if &filetype == "c" exec "!gcc -std=c99 -I. -L. -lpthread ./% -o %<" elseif &filetype == "cpp" exec "!g++ -std=c++11 -I. -L. -lpthread ./% -o %<" elseif &filetype == "python" exec "!python ./%" elseif &filetype == "java" exec "!java %<" endif exec "! ./%<" endfunc map <F5> :call CompileCodeRunResult()<CR> map <F9> :call CompileCodeRunResult()<CR> imap <F9> <ESC>:call CompileCodeRunResult()<CR> vmap <F9> <ESC>:call CompileCodeRunResult()<CR>
欢迎使用 Cmd Markdown 编辑阅读器 我们理解您需要更便捷更高效的工具记录思想，整理笔记、知识，并将其中承载的价值传播给他人，Cmd Markdown 是我们给出的答案 —— 我们为记录思想和分享知识提供更专业的工具。 您可以使用 Cmd Markdown： 整理知识，学习笔记 发布日记，杂文，所见所想 撰写发布技术文稿（代码支持） 撰写发布学术论文（LaTeX 公式支持） 除了您现在看到的这个 Cmd Markdown 在线版本，您还可以前往以下网址下载： Windows/Mac/Linux 全平台客户端 请保留此份 Cmd Markdown 的欢迎稿兼使用说明，如需撰写新稿件，点击顶部工具栏右侧的 新文稿 或者使用快捷键 Ctrl+Alt+N。 什么是 Markdown Markdown 是一种方便记忆、书写的纯文本标记语言，用户可以使用这些标记符号以最小的输入代价生成极富表现力的文档：譬如您正在阅读的这份文档。它使用简单的符号标记不同的标题，分割不同的段落，粗体 或者 斜体 某些文字，更棒的是，它还可以 1. 制作一份待办事宜 Todo 列表 [ ] 支持以 PDF 格式导出文稿 [ ] 改进 Cmd 渲染算法，使用局部渲染技术提高渲染效率 [x] 新增 Todo 列表功能 [x] 修复 LaTex 公式渲染问题 [x] 新增 LaTex 公式编号功能 2. 书写一个质能守恒公式1 $$E=mc^2$$ 3. 高亮一段代码2 @requires_authorization class SomeClass: pass if __name__ == '__main__': # A comment print 'hello world' 4. 高效绘制 流程图 st=>start: Start op=>operation: Your Operation cond=>condition: Yes or No? e=>end st->op->cond cond(yes)->e cond(no)->op 5. 高效绘制 序列图 Alice->Bob: Hello Bob, how are you? Note right of Bob: Bob thinks Bob-->Alice: I am good thanks! 6. 高效绘制 甘特图 title 项目开发流程 section 项目确定 需求分析 :a1, 2016-06-22, 3d 可行性报告 :after a1, 5d 概念验证 : 5d section 项目实施 概要设计 :2016-07-05 , 5d 详细设计 :2016-07-08, 10d 编码 :2016-07-15, 10d 测试 :2016-07-22, 5d section 发布验收 发布: 2d 验收: 3d 7. 绘制表格 项目 价格 数量 计算机 \$1600 5 手机 \$12 12 管线 \$1 234 8. 更详细语法说明 想要查看更详细的语法说明，可以参考我们准备的 Cmd Markdown 简明语法手册，进阶用户可以参考 Cmd Markdown 高阶语法手册 了解更多高级功能。 总而言之，不同于其它 所见即所得 的编辑器：你只需使用键盘专注于书写文本内容，就可以生成印刷级的排版格式，省却在键盘和工具栏之间来回切换，调整内容和格式的麻烦。Markdown 在流畅的书写和印刷级的阅读体验之间找到了平衡。 目前它已经成为世界上最大的技术分享网站 GitHub 和 技术问答网站 StackOverFlow 的御用书写格式。 什么是 Cmd Markdown 您可以使用很多工具书写 Markdown，但是 Cmd Markdown 是这个星球上我们已知的、最好的 Markdown 工具——没有之一 ：）因为深信文字的力量，所以我们和你一样，对流畅书写，分享思想和知识，以及阅读体验有极致的追求，我们把对于这些诉求的回应整合在 Cmd Markdown，并且一次，两次，三次，乃至无数次地提升这个工具的体验，最终将它演化成一个 编辑/发布/阅读 Markdown 的在线平台——您可以在任何地方，任何系统/设备上管理这里的文字。 1. 实时同步预览 我们将 Cmd Markdown 的主界面一分为二，左边为编辑区，右边为预览区，在编辑区的操作会实时地渲染到预览区方便查看最终的版面效果，并且如果你在其中一个区拖动滚动条，我们有一个巧妙的算法把另一个区的滚动条同步到等价的位置，超酷！ 2. 编辑工具栏 也许您还是一个 Markdown 语法的新手，在您完全熟悉它之前，我们在 编辑区 的顶部放置了一个如下图所示的工具栏，您可以使用鼠标在工具栏上调整格式，不过我们仍旧鼓励你使用键盘标记格式，提高书写的流畅度。 3. 编辑模式 完全心无旁骛的方式编辑文字：点击 编辑工具栏 最右侧的拉伸按钮或者按下 Ctrl + M，将 Cmd Markdown 切换到独立的编辑模式，这是一个极度简洁的写作环境，所有可能会引起分心的元素都已经被挪除，超清爽！ 4. 实时的云端文稿 为了保障数据安全，Cmd Markdown 会将您每一次击键的内容保存至云端，同时在 编辑工具栏 的最右侧提示 已保存 的字样。无需担心浏览器崩溃，机器掉电或者地震，海啸——在编辑的过程中随时关闭浏览器或者机器，下一次回到 Cmd Markdown 的时候继续写作。 5. 离线模式 在网络环境不稳定的情况下记录文字一样很安全！在您写作的时候，如果电脑突然失去网络连接，Cmd Markdown 会智能切换至离线模式，将您后续键入的文字保存在本地，直到网络恢复再将他们传送至云端，即使在网络恢复前关闭浏览器或者电脑，一样没有问题，等到下次开启 Cmd Markdown 的时候，她会提醒您将离线保存的文字传送至云端。简而言之，我们尽最大的努力保障您文字的安全。 6. 管理工具栏 为了便于管理您的文稿，在 预览区 的顶部放置了如下所示的 管理工具栏： 通过管理工具栏可以： 发布：将当前的文稿生成固定链接，在网络上发布，分享 新建：开始撰写一篇新的文稿 删除：删除当前的文稿 导出：将当前的文稿转化为 Markdown 文本或者 Html 格式，并导出到本地 列表：所有新增和过往的文稿都可以在这里查看、操作 模式：切换 普通/Vim/Emacs 编辑模式 7. 阅读工具栏 通过 预览区 右上角的 阅读工具栏，可以查看当前文稿的目录并增强阅读体验。 工具栏上的五个图标依次为： 目录：快速导航当前文稿的目录结构以跳转到感兴趣的段落 视图：互换左边编辑区和右边预览区的位置 主题：内置了黑白两种模式的主题，试试 黑色主题，超炫！ 阅读：心无旁骛的阅读模式提供超一流的阅读体验 全屏：简洁，简洁，再简洁，一个完全沉浸式的写作和阅读环境 8. 阅读模式 在 阅读工具栏 点击 或者按下 Ctrl+Alt+M 随即进入独立的阅读模式界面，我们在版面渲染上的每一个细节：字体，字号，行间距，前背景色都倾注了大量的时间，努力提升阅读的体验和品质。 9. 标签、分类和搜索 在编辑区任意行首位置输入以下格式的文字可以标签当前文档： 标签： 未分类 标签以后的文稿在【文件列表】（Ctrl+Alt+F）里会按照标签分类，用户可以同时使用键盘或者鼠标浏览查看，或者在【文件列表】的搜索文本框内搜索标题关键字过滤文稿，如下图所示： 10. 文稿发布和分享 在您使用 Cmd Markdown 记录，创作，整理，阅读文稿的同时，我们不仅希望它是一个有力的工具，更希望您的思想和知识通过这个平台，连同优质的阅读体验，将他们分享给有相同志趣的人，进而鼓励更多的人来到这里记录分享他们的思想和知识，尝试点击 (Ctrl+Alt+P) 发布这份文档给好友吧！ 再一次感谢您花费时间阅读这份欢迎稿，点击 (Ctrl+Alt+N) 开始撰写新的文稿吧！祝您在这里记录、阅读、分享愉快！ 作者 @ghosert 2016 年 07月 07日 支持 LaTeX 编辑显示支持，例如：$\sum_{i=1}^n a_i=0$， 访问 MathJax 参考更多使用方法。 ↩ 代码高亮功能支持包括 Java, Python, JavaScript 在内的，四十一种主流编程语言。 ↩
//将下面的文字复制粘贴到你的有道云笔记 Markdown 编辑器/简书 Markdown 编辑器即可在预览中重现上文。 作者：在路上\ 贡献者：诺布 0x00 写在前面 到底什么是个 Markdown? Markdown 是一种文本编辑时候使用的语法，通过在文字中加入助记符，将排版/编号/列表/文字高亮/加粗等问题交给机器处理，对文字进行自动排版，从而大大提高编辑记录效率。 有道云 Markdown 编辑器 or 简书 Markdown 编辑器都是依照这种 Markdown语法的实现，所以难免上渲染出来的效果有些小偏差，但是排版方式是通用的。 为什么要用 Markdown? 文章的排版很麻烦，如果有一种对于文章排版的解决方案就好了。 学习实践 Markdown 语法后你可以自定义你的文章排版。 这是一套定义文章排版格式的语法。 这是一个边际成本递减的升维实践过程。 Markdown 的应用场景? 可以说，所有的文本场景下都可以使用 Markdown 语法，只要你有一个支持 Markdown 语法的编辑器就可以，笔者使用的是有道云笔记的 Markdown 编辑器，因为其支持语法全面(包括文本高亮标记)。当前探索出的支持 Markdown 的环境有:有道云笔记、简书、微信公众号推送(粘贴渲染排版后的文本即可)。 本文逻辑安排目录： Markdown 可以实现的排版效果 Markdown 文章示例 本文的 Markdown 语法的原文 0x01 标题相关示例 主标题 副标题 一级标题 二级标题 三级标题 六级小标题 标题网址 引用文字块 0x02 无序列表相关示例 # 一级列表 ## 二级列表 ### 三级列表 #### 四级列表 ##### 五级列表 ###### 六级列表 0x03 有序列表相关示例 加粗标题 1 自编号标题 1.1 ++下划线自编号标题 1.1.1++ 斜体自编号标题 1.1.1.1 0x04 综合使用示例 使用 MD 时候的要点，合理使用无序列表语法与自定义序号，尽量少使用有序列表语法，因为存在兼容性问题(有道云笔记兼容性比简书好很多)会导致标题无层次分类，示例开始。 一、如何更好地理解第四章？ (一) 前置两个问题：升维与复杂系统 1. 升维 (1) 维度是什么？ 时空坐标体系下的坐标轴数量，可以理解为增加的视野角度。 (2) 高维和低维的关系 信息密度高，信息量大 低维是高维的切片 高维的低维展开会导致低维量级的无限扩张 推演：高维比低维的视角更多 2. 复杂系统 (1) 定义 什么叫系统？一组组内相互作用、相互依赖的复杂整体 (2) 要素 (3) 系统的三要素 系统关系 元素间关系 系统功能 (4) 两大类系统 ① 他组织系统 系统元素 系统结构关系 系统功能 特点：功能稳定，输入一定，输出一定。 ② 自组织系统 0x05 Markdown 原文 Markdown 与 Markdown 编辑器与排版文字的关系梳理与实践： Markdown 格式原文->有道云 Markdown 编辑器 or 简书 Markdown 编辑器->预览效果就是发布后的效果 简书中 Markdown 编辑器开启方式 个人设置-基础设置-常用编辑器-Markdown 有道云笔记 Markdown 编辑器开启方式 新文档-新建Markdown 六、Markdown 代码框 如果是段落上的一个函数或片段的代码可以用两个'把它包起来。
Sqlite3并发读写注意事项 sqlite3的锁及事务类型 sqlite3总共有三种事务类型：BEGIN [DEFERRED /IMMEDIATE / EXCLUSIVE] TRANSCATION， 五种锁，按锁的级别依次是：UNLOCKED /SHARED /RESERVERD /PENDING /EXCLUSIVE。 当执行select即读操作时，需要获取到SHARED锁（共享锁）， 当执行insert/update/delete操作(即内存写操作时)， 需要进一步获取到RESERVERD锁（保留锁）， 当进行commit操作(即磁盘写操作时)，需要进一步获取到EXCLUSIVE锁（排它锁）。 对于RESERVERD锁，sqlite3保证同一时间只有一个连接可以获取到保留锁，也就是同一时间只有一个连接可以写数据库(内存)，但是其它连接仍然可以获取SHARED锁，也就是其它连接仍然可以进行读操作（这里可以认为写操作只是对磁盘数据的一份内存拷贝进行修改，并不影响读操作）。 对于EXCLUSIVE锁，是比保留锁更为严格的一种锁，在需要把修改写入磁盘即commit时需要在保留锁/未决锁的基础上进一步获取到排他锁，顾名思义，排他锁排斥任何其它类型的锁，即使是SHARED锁也不行，所以，在一个连接进行commit时，其它连接是不能做任何操作的（包括读）。 PENDING锁（即未决锁），则是比较特殊的一种锁，它可以允许已获取到SHARED锁的事务继续进行，但不允许其它连接再获取SHARED锁，当已存在的SHARED锁都被释放后（事务执行完成），持有未决锁的事务就可以获得commit的机会了。sqlite3使用这种锁来防止writer starvation（写饿死）。 这里写图片描述 死锁的情况 死锁的情况：当两个连接使用begin transaction开始事务时， 第一个连接执行了一次select操作（已经获取到SHARED锁）， 第二个连接执行了一次insert操作（已经获取到了RESERVERD锁）， 此时第一个连接需要进行一次insert/update/delete（需要获取到RESERVERD锁）， 第二个连接则希望执行commit（需要获取到EXCLUSIVE锁），由于第二个连接已经获取到了RESERVERD锁，根据RESERVERD锁同一时间只有一个连接可以获取的特性，第一个连接获取RESERVERD锁的操作必定失败， 而由于第一个连接已经获取到SHARED锁，第二个连接希望进一步获取到EXCLUSIVE锁的操作也必定失败。就导致了事务死锁。 事务类型的使用原则 在用”begin transaction”显式开启一个事务时，默认的事务类型为DEFERRED，锁的状态为UNLOCKED，即不获取任何锁，如果在使用的数据库没有其它的连接，用begin就可以了。如果有多个连接都需要对数据库进行写操作，那就得使用BEGIN IMMEDIATE/EXCLUSIVE开始事务了。 使用事务的好处是： 1.一个事务的所有操作相当于一次原子操作，如果其中某一步失败，可以通过回滚来撤销之前所有的操作，只有当所有操作都成功时，才进行commit，保证了操作的原子特性； 2.对于多次的数据库操作，如果我们希望提高数据查询或更新的速度，可以在开始操作前显式开启一个事务，在执行完所有操作后，再通过一次commit来提交所有的修改或结束事务。 对SQLITE_BUSY的处理 当有多个连接同时对数据库进行写操作时，根据事务类型的使用原则，我们在每个连接中用BEGIN IMMEDIATE开始事务，即多个连接都尝试取得保留锁的情况，根据保留锁同一时间只有一个连接可以获取到的特性，其它连接都将获取失败，即事务开始失败，这种情况下，sqlite3将返回一个SQLITE_BUSY的错误，如果我们不希望操作就此失败而返回，就必须处理SQLITE_BUSY的情况， sqlite3提供了sqlite3_busy_handler或sqlite3_busy_timeout来处理SQLITE_BUSY， 对于sqlite3_busy_handler，我们可以指定一个busy_handler来处理，并可以指定失败重试的次数。 而sqlite3_busy_timeout则是由sqlite3自动进行sleep并重试，当sleep的累积时间超过指定的超时时间时，最终返回SQLITE_BUSY。 需要注意的是，这两个函数同时只能使用一个，后面的调用会覆盖掉前次调用。从使用上来说，sqlite3_busy_timeout更易用一些，只需要指定一个总的超时时间，然后sqlite自己会决定多久进行重试以及重试的次数，直到达到总的超时时间最终返回SQLITE_BUSY。并且，这两个函数一经调用，对其后的所有数据库操作都有效，非常方便。 sqlite3 多线程和锁 ，优化插入速度及性能优化 一、 是否支持多线程？ SQLite官网上的“Is SQLite threadsafe?”这个问答。 简单来说，从3.3.1版本开始，它就是线程安全的了。而iOS的SQLite版本没有低于这个版本的，当然，你也可以自己编译最新版本。 不过这个线程安全仍然是有限制的，在这篇《Is SQLite thread-safe?》里有详细的解释。 另一篇重要的文档就是《SQLite And Multiple Threads》。它指出SQLite支持3种线程模式： 单线程：禁用所有的mutex锁，并发使用时会出错。当SQLite编译时加了SQLITE_THREADSAFE=0参数，或者在初始化SQLite前调用sqlite3_config(SQLITE_CONFIG_SINGLETHREAD)时启用。 多线程：只要一个数据库连接不被多个线程同时使用就是安全的。源码中是启用bCoreMutex，禁用bFullMutex。实际上就是禁用数据库连接和prepared statement（准备好的语句）上的锁，因此不能在多个线程中并发使用同一个数据库连接或prepared statement。当SQLite编译时加了SQLITE_THREADSAFE=2参数时默认启用。若SQLITE_THREADSAFE不为0，可以在初始化SQLite前，调用sqlite3_config(SQLITE_CONFIG_MULTITHREAD)启用；或者在创建数据库连接时，设置SQLITE_OPEN_NOMUTEX flag。 串行：启用所有的锁，包括bCoreMutex和bFullMutex。因为数据库连接和prepared statement都已加锁，所以多线程使用这些对象时没法并发，也就变成串行了。当SQLite编译时加了SQLITE_THREADSAFE=1参数时默认启用。若SQLITE_THREADSAFE不为0，可以在初始化SQLite前，调用sqlite3_config(SQLITE_CONFIG_SERIALIZED)启用；或者在创建数据库连接时，设置SQLITE_OPEN_FULLMUTEX flag。 而这里所说的初始化是指调用sqlite3_initialize()函数，这个函数在调用sqlite3_open()时会自动调用，且只有第一次调用是有效的。 调用sqlite3_threadsafe()可以获得编译期的SQLITE_THREADSAFE参数。标准发行版是1，也就是串行模式；而iOS上是2，也就是多线程模式；Python的sqlite3模块也默认使用串行模式，可以用sqlite3.threadsafety来配置。 另一个要说明的是prepared statement，它是由数据库连接（的pager）来管理的，使用它也可看成使用这个数据库连接。因此在多线程模式下，并发对同一个数据库连接调用sqlite3_prepare_v2()来创建prepared statement，或者对同一个数据库连接的任何prepared statement并发调用sqlite3_bind_*()和sqlite3_step()等函数都会出错（在iOS上，该线程会出现EXC_BAD_ACCESS而中止）。这种错误无关读写，就是只读也会出错。文档中给出的安全使用规则是：没有事务正在等待执行，所有prepared statement都被finalized。 但是默认情况下，一个线程只能使用当前线程打开的数据库连接，除非在连接时设置了check_same_thread=False参数。如果是用不同的数据库连接，每个连接都不能读取其他连接中未提交的数据，除非使用read-uncommitted模式。 现在3种模式都有所了解了，清楚SQLite并不是对多线程无能为力后，接下来就了解下事务吧。 二、事务 数据库只有在事务中才能被更改。所有更改数据库的命令（除SELECT以外的所有SQL命令）都会自动开启一个新事务，并且当最后一个查询完成时自动提交。 而BEGIN命令可以手动开始事务，并关闭自动提交。当下一条COMMIT命令执行时，自动提交再次打开，事务中所做的更改也被写入数据库。当COMMIT失败时，自动提交仍然关闭，以便让用户尝试再次提交。若执行的是ROLLBACK命令，则也打开自动提交，但不保存事务中的更改。关闭数据库或遇到错误时，也会自动回滚事务。 经常有人抱怨SQLite的插入太慢，实际上它可以做到每秒插入几万次，但是每秒只能提交几十次事务。因此在插入大批数据时，可以通过禁用自动提交来提速。 还有一个很重要的知识点需要强调：事务是和数据库连接相关的，每个数据库连接（使用pager来）维护自己的事务，且同时只能有一个事务（但是可以用SAVEPOINT来实现内嵌事务）。也就是说，事务与线程无关，一个线程里可以同时用多个数据库连接来完成多个事务，而多个线程也可以同时（非并发）使用一个数据库连接来共同完成一个事务。 而要实现事务，就不得不用到锁。 一个SQLite数据库文件有5种锁的状态： UNLOCKED：表示数据库此时并未被读写。 SHARED：表示数据库可以被读取。SHARED锁可以同时被多个线程拥有。一旦某个线程持有SHARED锁，就没有任何线程可以进行写操作。 RESERVED：表示准备写入数据库。RESERVED锁最多只能被一个线程拥有，此后它可以进入PENDING状态。 PENDING：表示即将写入数据库，正在等待其他读线程释放SHARED锁。一旦某个线程持有PENDING锁，其他线程就不能获取SHARED锁。这样一来，只要等所有读线程完成，释放SHARED锁后，它就可以进入EXCLUSIVE状态了。 EXCLUSIVE：表示它可以写入数据库了。进入这个状态后，其他任何线程都不能访问数据库文件。因此为了并发性，它的持有时间越短越好。 一个线程只有在拥有低级别的锁的时候，才能获取更高一级的锁。SQLite就是靠这5种类型的锁，巧妙地实现了读写线程的互斥。同时也可看出，写操作必须进入EXCLUSIVE状态，此时并发数被降到1，这也是SQLite被认为并发插入性能不好的原因。 另外，read-uncommitted和WAL模式会影响这个锁的机制。在这2种模式下，读线程不会被写线程阻塞，即使写线程持有PENDING或EXCLUSIVE锁。 提到锁就不得不说到死锁的问题，而SQLite也可能出现死锁。 下面举个例子： 连接1：BEGIN （UNLOCKED） 连接1：SELECT ... （SHARED） 连接1：INSERT ... （RESERVED） 连接2：BEGIN （UNLOCKED） 连接2：SELECT ... （SHARED） 连接1：COMMIT （PENDING，尝试获取EXCLUSIVE锁，但还有SHARED锁未释放，返回SQLITE_BUSY） 连接2：INSERT ... （尝试获取RESERVED锁，但已有PENDING锁未释放，返回SQLITE_BUSY） 现在2个连接都在等待对方释放锁，于是就死锁了。当然，实际情况并没那么糟糕，任何一方选择不继续等待，回滚事务就行了。 不过要更好地解决这个问题，就必须更深入地了解事务了。 实际上BEGIN语句可以有3种起始状态： DEFERRED：默认值，开始事务时不获取任何锁。进行第一次读操作时获取SHARED锁，进行第一次写操作时获取RESERVED锁。 IMMEDIATE：开始事务时获取RESERVED锁。 EXCLUSIVE：开始事务时获取EXCLUSIVE锁。 现在考虑2个事务在开始时都使用IMMEDIATE方式： 连接1：BEGIN IMMEDIATE （RESERVED） 连接1：SELECT ... （RESERVED） 连接1：INSERT ... （RESERVED） 连接2：BEGIN IMMEDIATE （尝试获取RESERVED锁，但已有RESERVED锁未释放，因此事务开始失败，返回SQLITE_BUSY，等待用户重试） 连接1：COMMIT （EXCLUSIVE，写入完成后释放） 连接2：BEGIN IMMEDIATE （RESERVED） 连接2：SELECT ... （RESERVED） 连接2：INSERT ... （RESERVED） 连接2：COMMIT （EXCLUSIVE，写入完成后释放） 这样死锁就被避免了。 而EXCLUSIVE方式则更为严苛，即使其他连接以DEFERRED方式开启事务也不会死锁： 连接1：BEGIN EXCLUSIVE （EXCLUSIVE） 连接1：SELECT ... （EXCLUSIVE） 连接1：INSERT ... （EXCLUSIVE） 连接2：BEGIN （UNLOCKED） 连接2：SELECT ... （尝试获取SHARED锁，但已有EXCLUSIVE锁未释放，返回SQLITE_BUSY，等待用户重试） 连接1：COMMIT （EXCLUSIVE，写入完成后释放） 连接2：SELECT ... （SHARED） 连接2：INSERT ... （RESERVED） 连接2：COMMIT （EXCLUSIVE，写入完成后释放） 不过在并发很高的情况下，直接获取EXCLUSIVE锁的难度比较大；而且为了避免EXCLUSIVE状态长期阻塞其他请求，最好的方式还是让所有写事务都以IMMEDIATE方式开始。 顺带一提，要实现重试的话，可以使用sqlite3_busy_timeout()或sqlite3_busy_handler()函数。 由此可见，要想保证线程安全的话，可以有这4种方式： SQLite使用单线程模式，用一个专门的线程访问数据库。 SQLite使用单线程模式，用一个线程队列来访问数据库，队列一次只允许一个线程执行，队列里的线程共用一个数据库连接。 SQLite使用多线程模式，每个线程创建自己的数据库连接。 SQLite使用串行模式，所有线程共用全局的数据库连接。 三、sqlite3插入速度慢 1.像上述一样显示的给多个insert加上事务 sqlite在没有显式使用事务的时候会为每条insert都使用事务操作，而sqlite数据库是以文件的形式存在磁盘中，就相当于每次访问时都要打开一次文件，如果对数据进行大量的操作，时间都耗费在I/O操作上，所以很慢。 解决方法是显式使用事务的形式提交：因为我们开始事务后，进行的大量操作的语句都保存在内存中，当提交时才全部写入数据库，此时，数据库文件也就只用打开一次。 2.如果加上事务还是不行，可以尝试修改同步模式 初用sqlite3插入数据时，插入每条数据大概需要100ms左右。如果是批量导入，可以引进事务提高速度。但是假设你的业务是每间隔几秒插入几条数据，显然100ms是不能容许的。 解决办法是，在调用sqlite3_open函数后添加下面一行代码： sqlite3_exec(db, "PRAGMA synchronous = OFF; ", 0,0,0); 上面的解决办法貌似治标不治本，为什么加上上面的代码行，速度会提高那么多？ 磁盘同步 1.如何设置： PRAGMA synchronous = FULL; (2) PRAGMA synchronous = NORMAL; (1) PRAGMA synchronous = OFF; (0) 2.参数含义： 当synchronous设置为FULL (2), SQLite数据库引擎在紧急时刻会暂停以确定数据已经写入磁盘。这使系统崩溃或电源出问题时能确保数据库在重起后不会损坏。FULL synchronous很安全但很慢。 当synchronous设置为NORMAL(1), SQLite数据库引擎在大部分紧急时刻会暂停，但不像FULL模式下那么频繁。 NORMAL模式下有很小的几率(但不是不存在)发生电源故障导致数据库损坏的情况。但实际上，在这种情况 下很可能你的硬盘已经不能使用，或者发生了其他的不可恢复的硬件错误。 设置为synchronous OFF (0)时，SQLite在传递数据给系统以后直接继续而不暂停。若运行SQLite的应用程序崩溃， 数据不会损伤，但在系统崩溃或写入数据时意外断电的情况下数据库可能会损坏。另一方面，在synchronous OFF时 一些操作可能会快50倍甚至更多。在SQLite 2中，缺省值为NORMAL.而在3中修改为FULL。 www.2cto.com 3.建议： 如果有定期备份的机制，而且少量数据丢失可接受，用OFF。 注意上面红色加粗的字样。总结：如果你的数据对安全性完整性等要求不是太高，可以采用设置为0的方法，毕竟只是“数据库可能会损坏”，至于损坏几率为多大，笔者也暂不知晓。。。。。。还没遇到过损坏，不知什么时候才会发生。 四、性能优化（可参考http://blog.csdn.net/tietao/article/details/6890350） 很多人直接就使用了，并未注意到SQLite也有配置参数，可以对性能进行调整。有时候，产生的结果会有很大影响。 主要通过pragma指令来实现。 比如： 空间释放、磁盘同步、Cache大小等。 1 auto_vacuum 最好不要打开auto_vacuum, Vacuum的效率非常低！ PRAGMA auto_vacuum; PRAGMA auto_vacuum = 0 | 1; 查询或设置数据库的auto-vacuum标记。 正常情况下，当提交一个从数据库中删除数据的事务时，数据库文件不改变大小。未使用的文件页被标记并在以后的添加操作中再次使用。这种情况下使用VACUUM命令释放删除得到的空间。 当开启auto-vacuum，当提交一个从数据库中删除数据的事务时，数据库文件自动收缩， (VACUUM命令在auto-vacuum开启的数据库中不起作用)。数据库会在内部存储一些信息以便支持这一功能，这使得数据库文件比不开启该选项时稍微大一些。 只有在数据库中未建任何表时才能改变auto-vacuum标记。试图在已有表的情况下修改不会导致报错。 2 cache_size 建议改为8000 PRAGMA cache_size; PRAGMA cache_size = Number-of-pages; 查询或修改SQLite一次存储在内存中的数据库文件页数。每页使用约1.5K内存，缺省的缓存大小是2000. 若需要使用改变大量多行的UPDATE或DELETE命令，并且不介意SQLite使用更多的内存的话，可以增大缓存以提高性能。 当使用cache_size pragma改变缓存大小时，改变仅对当前对话有效，当数据库关闭重新打开时缓存大小恢复到缺省大小。 要想永久改变缓存大小，使用default_cache_size pragma. 3 case_sensitive_like 打开。不然搜索中文字串会出错。 PRAGMA case_sensitive_like; PRAGMA case_sensitive_like = 0 | 1; LIKE运算符的缺省行为是忽略latin1字符的大小写。因此在缺省情况下'a' LIKE 'A'的值为真。可以通过打开case_sensitive_like pragma来改变这一缺省行为。当启用case_sensitive_like，'a' LIKE 'A'为假而 'a' LIKE 'a'依然为真。 4 count_changes 打开。便于调试 PRAGMA count_changes; PRAGMA count_changes = 0 | 1; 查询或更改count-changes标记。正常情况下INSERT, UPDATE和DELETE语句不返回数据。 当开启count-changes，以上语句返回一行含一个整数值的数据——该语句插入，修改或删除的行数。 注意：返回的行数不包括由（触发器产生的插入，修改或删除等改变的行数）。 5 page_size PRAGMA page_size; PRAGMA page_size = bytes; 查询或设置page-size值。只有在未创建数据库时才能设置page-size。页面大小必须是2的整数倍且大于等于512小于等于8192。 上限可以通过在编译时修改宏定义SQLITE_MAX_PAGE_SIZE的值来改变。上限的上限是32768. 6 synchronous 如果有定期备份的机制，而且少量数据丢失可接受，用OFF PRAGMA synchronous; PRAGMA synchronous = FULL; (2) PRAGMA synchronous = NORMAL; (1) PRAGMA synchronous = OFF; (0) 查询或更改"synchronous"标记的设定。第一种形式(查询)返回整数值。 当synchronous设置为FULL (2), SQLite数据库引擎在紧急时刻会暂停以确定数据已经写入磁盘。 这使系统崩溃或电源出问题时能确保数据库在重起后不会损坏。FULL synchronous很安全但很慢。 当synchronous设置为NORMAL, SQLite数据库引擎在大部分紧急时刻会暂停，但不像FULL模式下那么频繁。 NORMAL模式下有很小的几率(但不是不存在)发生电源故障导致数据库损坏的情况。但实际上，在这种情况下很可能你的硬盘已经不能使用，或者发生了其他的不可恢复的硬件错误。 设置为synchronous OFF (0)时，SQLite在传递数据给系统以后直接继续而不暂停。若运行SQLite的应用程序崩溃， 数据不会损伤，但在系统崩溃或写入数据时意外断电的情况下数据库可能会损坏。另一方面，在synchronous OFF时 一些操作可能会快50倍甚至更多。 在SQLite 2中，缺省值为NORMAL.而在3中修改为FULL. 7 temp_store 使用2，内存模式。 PRAGMA temp_store; PRAGMA temp_store = DEFAULT; (0) PRAGMA temp_store = FILE; (1) PRAGMA temp_store = MEMORY; (2) 查询或更改"temp_store"参数的设置。当temp_store设置为DEFAULT (0),使用编译时的C预处理宏 TEMP_STORE来定义储存临时表和临时索引的位置。当设置为MEMORY (2)临时表和索引存放于内存中。 当设置为FILE (1)则存放于文件中。temp_store_directorypragma 可用于指定存放该文件的目录。当改变temp_store设置，所有已存在的临时表，索引，触发器及视图将被立即删除。 经测试，在类BBS应用上，通过以上调整，效率可以提高2倍以上。 附指令表集： 序号 指令 含义 缺省值 1 auto_vacuum 空间释放 0 2 cache_size 缓存大小 2000 3 case_sensitive_like LIKE大小写敏感 （注意：SQLite3.6.22不支持） 4 count_changes 变更行数 0 5 page_size 页面大小 1024 6 synchronous 硬盘大小 2 7 temp_store; 内存模式 0 sqlite3之SQLITE_OPEN_NOMUTEX与WAL模式（多线程与并发读写） 一 . Sqlite多线程概述 SQLite 支持三种线程模式： 1. 单线程模式 这种模式下，没有进行互斥，多线程使用不安全 2. 多线程模式 这种模式下，在多线程中使用单个数据库连接是不安全的，否则就是安全的。（译注：即不能在多个线程中共享数据库连接） 3. 串行模式 这种模式下，sqlite是线程安全的。（译注：即使在多个线程中不加互斥的使用同一个数据库连接） 线程模式可以在编译时（通过源码编译sqlite库时）、启动时（使用sqlite的应用程序初始化时）或者运行时（创建数据库连接时）来指定。一般而言，运行时指定的模式将覆盖启动时的指定模式，启动时指定的模式将覆盖编译时指定的模式。但是，单线程模式一旦被指定，将无法被覆盖。 默认的线程模式是串行模式。 编译时选择线程模式 可以通过定义SQLITE_THREADSAFE宏来指定线程模式。如果没有指定，默认为串行模式。定义宏SQLITE_THREADSAFE=1指定使用串行模式;=0使用单线程模式；＝2使用多线程模式。 创建多线程数据库 sqlite3_threadsafe()函数的返回值可以确定编译时指定的线程模式。如果指定了单线程模式，函数返回false。如果指定了串行或者多线程模式，函数返回true。由于sqlite3_threadsafe()函数要早于多线程模式以及启动时和运行时的模式选择，所以它既不能区别多线程模式和串行模式也不能区别启动时和运行时的模式。 译注：最后一句可通过sqlite3_threadsafe函数的实现来理解 SQLITE_API int sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; } 如果编译时指定了单线程模式，那么临界互斥逻辑在构造时就被省略，因此也就无法在启动时或运行时指定串行模式或多线程模式。 启动时选择线程模式 假如在编译时没有指定单线程模式，就可以在应用程序初始化时使用sqlite3_config()函数修改线程模式。参数SQLITE_CONFIG_SINGLETHREAD可指定为单线程模式，SQLITE_CONFIG_MULTITHREAD指定为多线程模式，SQLITE_CONFIG_SERIALIZED指定为串行模式。 运行时选择线程模式 如果没有在编译时和启动时指定为单线程模式，那么每个数据库连接在创建时可单独的被指定为多线程模式或者串行模式，但是不能指定为单线程模式。如果在编译时或启动时指定为单线程模式，就无法在创建连接时指定多线程或者串行模式。 创建连接时用sqlite3_open_v2()函数的第三个参数来指定线程模式。SQLITE_OPEN_NOMUTEX标识创建多线程模式的连接；SQLITE_OPEN_FULLMUTEX标识创建串行模式的连接。如果没有指定标识，或者使用sqlite3_open()或sqlite3_open16()函数来创建数据库连接，那么在编译时或启动时指定的线程模式将作为默认的线程模式使用。 二. WAL并发读写 在3.7.0以后，WAL(Write-Ahead Log)模式可以使用，是另一种实现事务原子性的方法。 1. WAL的优点 在大多数情况下更快 并行性更高。因为读操作和写操作可以并行。 文件IO更加有序化，串行化（more sequential） 使用fsync()的次数更少，在fsync()调用时好时坏的机器上较为未定。 缺点 一般情况下需要VFS支持共享内存模式。(shared-memory primitives) 操作数据库文件的进程必须在同一台主机上，不能用在网络操作系统。 持有多个数据库文件的数据库连接对于单个数据库时原子的，对于全部数据库是不原子的。 进入WAL模式以后不能修改page的size。 不能打开只读的WAL数据库(Read-Only Databases)，这进程必须有"-shm"文件的写权限。 对于只进行读操作，很少进行写操作的数据库，要慢那么1到2个百分点。 会有多余的"-wal"和"-shm"文件 需要开发者注意checkpointing 2. 原理 回滚日志的方法是把为改变的数据库文件内容写入日志里，然后把改变后的内容直接写到数据库文件中去。在系统crash或掉电的情况下，日志里的内容被重新写入数据库文件中。日志文件被删除，标志commit着一次commit的结束。 WAL模式于此此相反。原始为改变的数据库内容在数据库文件中，对数据库文件的修改被追加到单独的WAL文件中。当一条记录被追加到WAL文件后，标志着一次commit的结束。因此一次commit不必对数据库文件进行操作，当正在进行写操作时，可以同时进行读操作。多个事务的内容可以追加到一个WAL文件的末尾。 checkpoint 最后WAL文件的内容必须更新到数据库文件中。把WAL文件的内容更新到数据库文件的过程叫做一次checkpoint。 回滚日志的方法有两种操作：读和写。WAL有三种操作，读、写和checkpoint。 默认的，SQL会在WAL文件达到1000page时进行一次checkpoint。进行WAL的时机也可以由应用程序自己决定。 并发性 当一个读操作发生在WAL模式的数据库上时，会首先找到WAL文件中最后一次提交，叫做"end mark"。每一个事务可以有自己的"end point"，但对于一个给定额事务来说，end mark是固定的。 当读取数据库中的page时，SQLite会先从WAL文件中寻找有没有对应的page，从找出离end mark最近的那一条记录；如果找不到，那么就从数据库文件中寻找对一个的page。为了避免每次事务都要扫描一遍WAL文件，SQLite在共享内存中维护了一个"wal-index"的数据结构，帮助快速定位page。 写数据库只是把新内容加到WAL文件的末尾，和读操作没有关系。由于只有一个WAL文件，因此同时只能有一个写操作。 checkpoint操作可以和读操作并行。但是如果checkpoint把一个page写入数据库文件，而且这个page超过了当前读操作的end mark时，checkpoint必须停止。否则会把当前正在读的部分覆盖掉。下次checkpoint时，会从这个page开始往数据库中拷贝数据。 当写操作时，会检查WAL文件被拷贝到数据库的进度。如果已经完全被拷贝到数据库文件中，已经同步，并且没有读操作在使用WAL文件，那么会把WAL文件清空，从其实开始追加数据。保证WAL文件不会无限制增长。 性能 写操作是很快的，因为只需要进行一次写操作，并且是顺序的（不是随机的，每次都写到末尾）。而且，把数据刷到磁盘上是不必须的。（如果PRAGMA synchronous是FULL，每次commit要刷一次，否则不刷。） 读操作的性能有所下降，因为需要从WAL文件中查找内容，花费的时间和WAL文件的大小有 关。wal-index可以缩短这个时间，但是也不能完全避免。因此需要保证WAL文件的不会太大。 为了保护数据库不被损坏，需要在把WAL文件写入数据库之前把WAL文件刷入磁盘；在重置WAL文件之前要把数据库内容刷入数据库文件。此外checkpoint需要查找操作。这些因素使得checkpoint比写操作慢一些。 默认策略是很多线程可以增长WAL文件。把WAL文件大小变得比1000page大的那个线程要负责进行checkpoint。会导致绝大部分读写操作都是很快的，随机有一个写操作非常慢。也可以禁用自动checkpoint的策略，定期在一个线程或进程中进行checkpoint操作。 高效的写操作希望WAL文件越大越好；高效的读操作希望WAL文件越小越好。两者存在一个tradeoff。 3. 激活和配置WAL模式 执行命令：PRAGMA journal_mode=WAL;，如果成功，会返回"wal"。 配置数据库为WAL并发模式 自动checkpoint 可以手动checkpoint同步wal文件数据到数据库中 同步wal数据到数据库中，清空wal文件 sqlite3_wal_checkpoint(sqlite3*db, const char *zDb) 配置checkpoint sqlite3_wal_autocheckpoint(sqlite3 *db,intN); Application-Initiated Checkpoints 可以在任意一个可以进行写操作的数据库连接中调用sqlite3_wal_checkpoint_v2()或sqlite3_wal_checkpoint()。 WAL模式的持久性 当一个进程设置了WAL模式，关闭这个进程，重新打开这个数据库，仍然是WAL模式。 如果在一个数据库连接中设置了WAL模式，那么这个数据库的所有连接都将被设为WAL模式。 4. 只读数据库 如果数据库需要恢复，而你只有读权限，没有写权限，那么你不能读取这个数据库，因为进行读操作的第一步就是恢复数据库。 类似的，因为WAL模式下的数据库进行读操作时，需要类似数据库恢复的操作，因此如果只有读权限，也不能对打开数据库。 WAL的实现需要有一个基于WAL文件的哈希表在共享内存中。在Unix和Windows的VFS实现中，是基于MMap的。将共享内存映射到同目录下的"-shm"文件中。因此即使是对WAL模式下的数据库文件进行读操作，也需要写权限。 为了把数据库文件转化为只读的文件，需要先把这个数据库的日志模式改为"delete". 5. 避免过大的WAL文件 6. WAL-index的共享内存实现 在WAL发布之前，曾经尝试过将wal-index映射到临时目录，如/dev/shm或/tmp。但是不同的用户看到的目录是不同的，所以此路不通。 后来尝试将wal-index映射到匿名的虚拟内存块中，但是无法在不用的Unix版本中保持一致。 最终决定采用将wal-index映射到同目录下。这样子会导致不必要的磁盘IO。但是问题不大，是因为wal-index很少超过32k，而且从不会调用sync操作。此外，最后一个数据库连接关闭以后，这个文件会被删除。 如果这个数据库只会被一个进程使用，那么可以使用heap memory而不是共享内存。 7. 不用共享内存实现WAL 在3.7.4版本以后，只要SQLite的lock mode被设为EXCLUSIVE，那么即使共享内存不支持，也可以使用WAL模式。 换句话说，如果只有一个进程使用SQLite，那么不用共享内存也可以使用WAL。 此时，将lock mode改为normal是无效的，需要实现取消WAL模式。 总结：总过最近对sqlite3的学习，移动端的数据库最然不如后台数据库那么复杂，但也存在着很多可以发掘和优化的技术点。这次尝试了对sqlite3多线程操作和并发读写的优化，希望后续还可以学习到更好的优化方案。
内存分配，堆栈 class 的成员变量的存储在堆上还是栈上，取决于class的对象创建在堆上还是栈上 string 对象内部约定字符串字面量小于上表的阀值（15BYTE），分配在栈上，否在在堆上创建 vector 这个对象存在栈中,肯定是堆，只有堆能动态分配内存 函数模板 typename 参数自动分展开，析出 std::forword 参数转发 OTHER 为什么在处理“Hello,Word!!”只在栈中进行内存分配？ 为什么在处理“Hello,My name is peter!!”这样的字符串,就会在堆中进行内存分配？ string对象内部约定: 只要传入的字符串字面量小于上表的阀值,string内部实现在栈中分配内存,有个很骚的名字小型字符串优化(Small String Optimisation)。 只要大于上述C++编译器指定阀值,string对象内部会隐式执行new操作在堆中根据指定的字符串尺寸分配初次内存。 如果后续任何字符串的push_back操作,string会根据“double方案”的内存分配方式对堆内存执行扩容操作,见前文《对[C/C++]指针与字符串的总结》。 还有根据RAII的约定,C++编译器会对string对象在其调用函数的生命周期结束之时自动执行垃圾回收。(见上图的输出)。
【Golang】基础语法总结 一，关键字 （关键字25个） break default func interface select case defer go map struct chan else goto package switch const fallthrough if range type continue for import return var 二，数据类型 NUMBER，STRING， BOOLEAN ARRAYS，SLICES，MAPS 三，内置常量 true false iota nil 三，内建类型 int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 uintptr float32 float64 complex128 complex64 bool byte rune string error 三，内建函数 make len cap new append copy close delete complex real imag panic recover close 用于channel 通讯。使用它来关闭channel delete 用于在map 中删除实例。 len 和cap 可用于不同的类型， len 用于返回字符串、slice 和数组的长度. new 用于各种类型的内存分配。 make 用于内建类型（map、slice 和channel）的内存分配。 copy 用于复制slice append 用于追加slice。 panic 和recover 用于异常处理机制 print 和println 是底层打印函数，可以在不引入fmt 包的情况下使用。 complex、real 和imag 全部用于处理复数 四，变量声明 使用const关键字：const 常量名 常量类型 = 常量值 数组 声明格式：var 数组名 [元素个数]元素类型 var arr1 [5]int //具有5个int元素的数组，未进行初始化，元素默认为零值 var arr2 [5]int{1, 2, 3, 4, 5} //定义并直接初始化 切片 声明格式：var 切片名 []切片类型 var sic1 []int //声明含有多个未知元素的切片 var sic2 []int{} //声明空切片 结构体声明 type 结构体名 struct {}：右括号必须和type在同一行 枚举声明 使用iota+const关键字 const ( r = iota //0 s = iota //1 t = iota //2 ) const ( u = iota //0 v //1 w //2 ) const ( u1 = iota //0 v1, w1, x1 = iota, iota, iota //1, 1, 1 ) 类型别名 type 类型别名 类型原名 for 初始条件; 判断条件; 条件变换 { //TODO } range关键字的使用 作用：迭代遍历切片/数组中的每一个元素，默认有两个返回值，第一个为元素下标，第二个为元素数据 switch语句 golang保留break关键字，在switch语句中如果不写则默认添加 break可用于for/switch/select continue只可以用于for case后面可以跟多个条件 Go语言改进了 switch 的语法设计，case 与 case 之间是独立的代码块，不需要通过 break 语句跳出当前 case 代码块以避免执行到下一行 switch 中的表达式是可选的，可以省略。如果省略表达式，则相当于 switch true，这种情况下会将每一个 case 的表达式的求值结果与 true 做比较，如果相等，则执行相应的代码 //首先声明变量 var num1 int = 1 switch num1 { case 1: //... case 2: //... case 3, 4, 5: //... ... default: //... } //直接使用初始化语句 switch num2 := 1; num1 { case 1: //... case 2: //... ... default: //... } //switch后面可以不添加参数 var num int = 0 switch { case num > 90: //... case num < 90: //... default: //... } var name, sex, addr string = "andy", "man", "xian" name := "string" （自动推导类型不可以写到函数外，作为全局变量） numbers := make([]int, 5, 10) var m map[string]int m := make(map[string]int) for key := range m { delete(m, key) } data := map[string]string{"1": "A", "2": "B", "3": "C"} for k, v := range data { data[v] = k fmt.Printf("res %v\n", data) } type Person struct { Name string Age int } func add(a int, b int) (c int) { c = a + b return } 内置函数 Go 语言拥有一些不需要进行导入操作就可以使用的内置函数。它们有时可以针对不同的类型进行操作，例如：len、cap 和 append，或必须用于系统级的操作，例如：panic。因此，它们需要直接获得编译器的支持。 append -- 用来追加元素到数组、slice中,返回修改后的数组、slice close -- 主要用来关闭channel delete -- 从map中删除key对应的value panic -- 停止常规的goroutine （panic和recover：用来做错误处理） recover -- 允许程序定义goroutine的panic动作 real -- 返回complex的实部 （complex、real imag：用于创建和操作复数） imag -- 返回complex的虚部 make -- 用来分配内存，返回Type本身(只能应用于slice, map, channel) new -- 用来分配内存，主要用来分配值类型，比如int、struct。返回指向Type的指针 cap -- capacity是容量的意思，用于返回某个类型的最大容量（只能用于切片和 map） copy -- 用于复制和连接slice，返回复制的数目 len -- 来求长度，比如string、array、slice、map、channel ，返回长度 print、println -- 底层打印函数，在部署环境中建议使用 fmt 包 数组和切片 Array 是同类型元素的数组。Array在声明的时候会指定长度且不能改变。定义一个固定长度为3的数组： Slices 是能随时扩容的同类型元素的序列 。Slice的声明方式如下定义一个长度为0 的slices： Slice 是数组的封装，其内部实现是数组，slice有三个元素，容量，长度和指向内部数组的指针。 Slice 的容量可以通过append 或者 copy函数增加。Append函数也能在数组的末尾添加元素，在容量不足的情况下会对slice扩容。 make和new Go有两个数据结构创建函数：new和make。 new返回一个指向已清零内存的指针，而make返回一个复杂的结构。 基本的区别是 new(T) 返回一个 *T ，返回的这个指针可以被隐式地消除引用（图中的黑色箭头） 。而 make(T, args) 返回一个普通的T. 注意：空切片和 nil 切片是不同的，空切片指向的地址不是nil，指向的是一个内存地址，但是它没有分配任何内存空间，即底层元素包含0个元素。 不管是使用 nil 切片还是空切片，对其调用内置函数 append，len 和 cap 的效果都是一样的。 只有make能做的操作： a.创建一个chan b.创建一个内存预分配的map c.创建一个内存预分配的slice，并且slice的len可以不等于cap make用于内建类型（map、slice 和channel）的内存分配。new用于各种类型的内存分配。 内建函数new本质上说跟其它语言中的同名函数功能一样：new(T)分配了零值填充的T类型的内存空间，并且返回其地址，即一个T类型的值。用Go的术语说，它返回了一个指针，指向新分配的类型T的零值。有一点非常重要：new返回指针。 内建函数make(T, args)与new(T)有着不同的功能，make只能创建slice、map和channel，并且返回一个有初始值(非零)的T类型，而不是T。 本质来讲，导致这三个类型有所不同的原因是指向数据结构的引用在使用前必须被初始化。例如，一个slice，是一个包含指向数据（内部array）的指针、长度和容量的三项描述符；在这些项目被初始化之前，slice为nil。对于slice、map和channel来说，make初始化了内部的数据结构，填充适当的值。make返回初始化后的（非零）值。 make 是 引用类型 初始化的方法。 零值和特性 Go任何类型在未初始化时都对应一个零值：布尔类型是false，整型是0，字符串是""，而指针，函数，interface，slice，channel和map的零值都是nil。 golang 不是完全的面向对象语言，但是支持很多面向对象的特性，例如有结构体，接口，方法等。 bool类型不能转换为整型，整型也不能转换为bool类型，这种不能转换的类型叫做不兼容类型。 官方的go编译器限制channel最多能容纳到65535个元素 列表列表与切片和 map 不同的是，列表并没有具体元素类型的限制，因此，列表的元素可以是任意类型，这既带来了便利，也引来一些问题， 例如给列表中放入了一个 interface{} 类型的值，取出值后，如果要将 interface{} 转换为其他类型将会发生宕机。 container/list nameList := list.New() var nameList list.List l.PushBack("fist") l.PushFront(67) go只提供了一种循环方式，即for循环，在使用时可以像c那样使用，也可以通过for range方式遍历容器类型如数组、切片和映射 c++ ： 编译时生成每种类型的方法，缺点编译慢，需要后端消除无用代码 java： 类型擦除，所有类型都转换成Object，取值再做一次拆箱，缺点运行慢 移除原因 支持泛型的Go 1.18 Beta 1版本发布以来，围绕着constraints包的争议很多。 主要是以下因素，导致Russ Cox决定从Go标准库中移除constraints包。 constraints名字太长，代码写起来比较繁琐。大多数泛型的代码只用到了any和comparable这2个类型约束。 constaints包里只有constraints.Ordered使用比较广泛，其它很少用。所以完全可以把Ordered设计成和any以及comparable一样， 都作为Go的预声明标识符，不用单独弄一个constraints包。 在官方的最新proposal里有提到，在Golang中，并不是所有的类型都满足+号运算。 在go 泛型的版本中，泛型函数只能使用类型参数所能实例化出的任意类型都能支持的操作。 函数可以通过type关键字引入额外的类型参数(type parameters)列表：func F(type T)(p T) { ... } 。 这些类型参数可以像一般的参数一样在函数体中使用。 类型也可以拥有类型参数列表：type M(type T) []T。 每个类型参数可以拥有一个约束：func F(type T Constraint)(p T) { ... }。 使用interface来描述类型的约束。 被用作类型约束的interface可以拥有一个预声明类型列表，限制了实现此接口的类型的基础类型。 使用泛型函数或类型时需要传入类型实参。 一般情况下，类型推断允许用户在调用泛型函数时省略类型实参。 如果类型参数具有类型约束，则类型实参必须实现接口。 泛型函数只允许进行类型约束所规定的操作。 尽管最新的proposal冗长而详尽，但总结起来如下： 函数和类型可以具有类型参数，该类型参数使用可选约束（接口类型）定义，约束描述了这些参数所需的方法和允许的类型。 当使用类型参数调用函数时，类型推断通常会允许用户省略类型参数。 泛型函数只能使用约束允许的所有类型支持的操作 此设计完全向后兼容，但建议对func F(x(T))的含义进行更改。 func printSlice[T any](s []T) { for _, v := range s { fmt.Printf("%v ", v) } fmt.Print("\n") } func main() { printSlice[int]([]int{1, 2, 3, 4, 5}) printSlice[float64]([]float64{1.01, 2.02, 3.03, 4.04, 5.05}) printSlice([]string{"Hello", "World"}) printSlice[int64]([]int64{5, 4, 3, 2, 1}) } type Addable interface { type int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr, float32, float64, complex64, complex128, string } func add[T Addable] (a, b T) T { return a + b } func main() { fmt.Println(add(1,2)) fmt.Println(add("hello","world")) } func mapFunc[T any, M any](a []T, f func(T) M) []M { n := make([]M, len(a), cap(a)) for i, e := range a { n[i] = f(e) } return n } func main() { vi := []int{1, 2, 3, 4, 5, 6} vs := mapFunc(vi, func(v int) string { return "<" + fmt.Sprint(v*v) + ">" }) fmt.Println(vs) } func findFunc[T comparable](a []T, v T) int { for i, e := range a { if e == v { return i } } return -1 } func main() { fmt.Println(findFunc([]int{1, 2, 3, 4, 5, 6}, 5)) }
【python】基础语法总结 1 代码作用域 代码作用域 1，块级作用域：python没有，比如if for里面定义的变量外层可用 2，局部作用域：python有，函数里面定义的变量外部不可用 3，作用域链：Python中有，变量会由函数内到外找，作用域执行前已定 4，函数在没有执行前，内部代码不执行，这点Python和javascript有共性 li = [lambda :x for x in range(10)] print(li0) # ：9 5，函数内部的变量，无global声明直接使用，会去查找外层当做全局变量使用，不可赋值 6，函数内部的变量，如果不加global声明直接赋值定义，会被当做局部变量，跟全局无关 函数定义了本地作用域，而模块定义的是全局作用域。 如果想要在函数内定义全局作用域，需要加上global修饰符。
docker 命令操作笔记 docker在线安装： apt install docker.io docker离线安装： tar -zxvf docker-18.06.3-ce.tgz cp docker/* /usr/bin/ dockerd & docker info docker run hello-world # Hello from Docker! docker search ubuntu docker pull --help docker images --help docker update --help docker run --help docker rm --help docker rmi --help docker attach --help docker exec --help docker inspect --help -- 说明操作容器ID和操作容器name效果一样 帮助命令:docker version 帮助命令:docker info 帮助命令:docker --help 停止容器: docker stop 095815a83b5a 启动容器: docker start 095815a83b5a 重启容器: docker restart ubuntuexe 进入容器: docker exec -it 095815a83b5a /bin/bash 删除容器: docker rm -f 095815a83b5a 删除镜像: docker rmi -f imageID 删除多个镜像：docker rmi $(docker images -q ubuntu) 删除多个容器：docker rm -f $(docker ps -a -q) 拉取镜像：docker pull debian 拉取镜像：docker pull ubuntu:18.04 # xxx[:TAG] ubuntu:18.04 ubuntu:latest 搜索镜像：docker search --limit 5 redis 导出镜像：docker save -o ubuntu.tar ubuntu:18.04 导入镜像：docker load < ubuntu.tar 镜像打标签：docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG] 容器详情: docker inspect ubuntuexe 容器进程: docker top ubuntuexe 容器日志: docker logs ubuntuexe 运行容器：docker exec -it ubuntuexe/bin/bash # 新开bash，exit退出原容器不会结束 附上容器：docker attach ubuntuexe # 登入原有bash，exit退出会退出停止原有容器 提交容器：docker commit ubuntuexe/ubuntu 保存镜像：docker save imageid > /tmp/ubuntu.tar 加载镜像：docker load < /tmp/ubuntu.tar 导出容器：docker export containerid > /tmp/ubuntu.tar 导入容器：docker import - exe/ubuntu:latest < < /tmp/ubuntu.tar 容器传输：docker cp .vimrc ubuntuexe:/root/.vimrc 容器传输：docker cp ubuntuexe:/root/READEME.md READEME.md 运行容器：docker run --privileged=true -it ubuntu:18.04 /bin/bash 运行容器：docker run --privileged=true --restart=always -v /opt:/opt -v -p 8022:22 -itd ubuntu:18.04 /bin/bash 已经过运行的容器设置自启动： docker update --restart=always ubuntuname 自动启动 ： docker update --restart=always d5c440e6d44f 更新 CPU 共享数量： docker update --cpu-shares 512 f361b7d8465 更新容器的重启策略： docker update --restart=always f361b7d8465 更新容器内存： docker update -m 500M f361b7d8465 -- docker run -d启动的容器和--restart=always每次进入退出直接 docker attach <container ID> 即可。 -- # ps -ef | grep exe_ | grep -v grep | awk '{print $2}' | xargs kill -9 -- # (./bin/exe_analyse &) && (./bin/exe_inotify &) && (./bin/exe_insert &) && (./bin/exe_python &) 1.在/usr/lib/systemd/system/目录下创建docker.service文件 sudo systemctl enable docker #设置docker开机自启动 sudo systemctl start docker #启动docker.service服务 systemctl daemon-reload ## 2.重新加载unit配置文件 systemctl start/stop docker ## 3.启动/停止docker服务 systemctl enable/disable docker ## 4.开机自启/取消开机自启 docker 服务 systemctl list-units --type=service # 查看已启动的服务 systemctl list-unit-files | grep enable # 查看是否设置开机启动 用户和属组可以不用设置 服务管理：sudo systemctl enable docker #设置docker开机自启动 服务管理：sudo systemctl start docker #启动docker.service服务 服务管理：sudo groupadd docker 服务管理：sudo usermod -aG docker $USER vim /usr/lib/systemd/system/docker.service vim /etc/systemd/system/docker.service [Unit] Description=Docker Application Container Engine Documentation=https://docs.docker.com After=network-online.target firewalld.service Wants=network-online.target [Service] Type=notify ExecStart=/usr/bin/dockerd ExecReload=/bin/kill -s HUP $MAINPID LimitNOFILE=infinity LimitNPROC=infinity TimeoutStartSec=0 Delegate=yes KillMode=process Restart=on-failure StartLimitBurst=3 StartLimitInterval=60s [Install] WantedBy=multi-user.target vim /etc/systemd/system/docker.service [Unit] Description=Docker Application Container Engine Documentation=https://docs.docker.com After=network-online.target firewalld.service Wants=network-online.target [Service] Type=notify # the default is not to use systemd for cgroups because the delegate issues still # exists and systemd currently does not support the cgroup feature set required # for containers run by docker ExecStart=/usr/bin/dockerd ExecReload=/bin/kill -s HUP $MAINPID # Having non-zero Limit*s causes performance problems due to accounting overhead # in the kernel. We recommend using cgroups to do container-local accounting. LimitNOFILE=infinity LimitNPROC=infinity LimitCORE=infinity # Uncomment TasksMax if your systemd version supports it. # Only systemd 226 and above support this version. #TasksMax=infinity TimeoutStartSec=0 # set delegate yes so that systemd does not reset the cgroups of docker containers Delegate=yes # kill only the docker process, not all processes in the cgroup KillMode=process # restart the docker process if it exits prematurely Restart=on-failure StartLimitBurst=3 StartLimitInterval=60s [Install] WantedBy=multi-user.target Docker 命令大全 --容器生命周期管理 docker docker run docker start/stop/restart docker kill docker rm docker pause/unpause docker create docker exec --docker 容器操作 docker ps docker inspect docker top docker attach docker events docker logs docker wait docker export docker port docker stats --docker 容器rootfs命令 docker commit docker cp docker diff --docker 镜像仓库 docker login docker pull docker push docker search --docker 本地镜像管理 docker images docker rmi docker tag docker build docker history docker save docker load docker import --docker 详情版本info|version docker info docker version Docker常用命令大全（万字详解） 启动docker： systemctl start docker 启动docker： systemctl start docker 停止docker： systemctl stop docker 停止docker： systemctl stop docker 重启docker： systemctl restart docker 重启docker： systemctl restart docker 查看docker状态： systemctl status docker 查看docker状态： systemctl status docker 开机启动： systemctl enable docker 查看docker概要信息： docker info 查看docker概要信息： docker info 查看docker总体帮助文档： docker --help 查看docker总体帮助文档： docker --help 查看docker命令帮助文档： docker 具体命令 --help 查看docker命令帮助文档： docker 具体命令 --help 如果你不指定一个镜像的版本标签，docker 将默认使用 xxx:latest 镜像 官方搜索网址：https://hub.docker.com/ docker images docker images -a docker images -q docker search [OPTIONS] 镜像名字 [root@docker ~]# docker search mysql [root@docker ~]# docker search mysql mysql/mysql-server Optimized MySQL Server Docker images. Create… 917 [OK] 12345 docker pull 某个XXX镜像名字[:TAG] 等价于：docker pull 镜像名字:latest docker search --limit 5 redis docker pull 某个XXX镜像名字 docker system df 查看镜像/容器/数据卷所占的空间 docker rmi -f 镜像ID docker rmi -f 镜像名1:TAG 镜像名2:TAG docker rmi -f $(docker images -qa) docker run [OPTIONS] IMAGE [COMMAND] [ARG...] docker run -it centos /bin/bash docker ps [OPTIONS] docker start 容器ID或者容器名 docker ps [OPTIONS] docker start 容器ID或者容器名 docker ps -a -q ：查询进行的容器ID docker stop 容器ID或者容器名 docker kill 容器ID或容器名 docker rm 容器ID [root@docker ~]# docker rm -f $(docker ps -a -q) [root@docker ~]# docker rm -f $(docker ps -a -q) [root@docker ~]# docker ps -a -q | xargs docker rm [root@docker ~]# docker ps -a -q | xargs docker rm docker run -d 容器名 [root@docker ~]# docker run -d centos [root@docker ~]# docker run -it redis [root@docker ~]# docker run -d redis docker logs 容器ID [root@docker ~]# docker ps [root@docker ~]# docker logs 94b docker top 容器ID [root@docker ~]# docker top 94b [root@docker ~]# docker top 94b docker inspect 容器ID docker exec -it 容器ID bashShell [root@docker ~]# docker exec -it 94b /bin/bash [root@docker ~]# docker exec -it 94b /bin/bash [root@docker ~]# docker exec --help docker exec [OPTIONS] CONTAINER COMMAND [ARG...] docker start 容器ID docker attach 容器ID <退出之后自动stop容器> docker cp 容器ID:容器内路径 目的主机路径 [root@docker /]# docker cp 3065f084c80d:a.txt a.txt docker export 容器ID > 文件名.tar docker import - 镜像用户/镜像名:镜像版本号 < 文件名.tar [root@docker /]# docker export 3065f084c80d > centos.tar.gz [root@docker /]# cat centos.tar.gz | docker import - xiaobear/centos:8.8 [root@docker /]# docker import - xiaobear/centos:8.8 < centos.tar.gz [root@docker /]# docker images