2017年7月7日 星期五

MySQL 複製資料表

要複製一個現有的資料表,須先產生結構相同的新資料表,再將資料複製寫入。

複製步驟:
  1. 先產生一個結構相同的新資料表
    CREATE TABLE new_table LIKE old_table;
    
  2. 再將舊資料表資料,寫入新資料表
    INSERT new_table SELECT * FROM old_table;
    


CREATE TABLE ... LIKE 語法,注意事項:
  • 只能用於基本資料表(base table),不能用於 view。
  • 舊資料表 LOCK 時無法使用。(測試 LOCK READ 可以,但 LOCK WRITE 時不行)
  • CREATE TABLE ... LIKE 不是只複製 .frm 檔,而是會做跟 CREATE 一樣的檢查,所以若目前的 SQL mode 跟當初創建舊資料表時不同,若創建語法跟目前 SQL mode 不合時,可能會執行失敗。
  • 無法複製:DATA DIRECTORY 設定、INDEX DIRECTORY 設定、外鍵、trigger。
  • 若是複製的新資料要做成暫存資料表(TEMPORARY),則使用 CREATE TEMPORARY TABLE ... LIKE 語法。


參考:
Duplicating a MySQL table, indexes and data - Stack Overflow
MySQL :: MySQL 5.7 Reference Manual :: 13.1.18.4 CREATE TABLE ... LIKE Syntax

NetBeans 裝 Java plugin 出現 some plugins require JDK

安裝 NetBeans 時系統沒 JDK、或 JDK版本太舊,
則安裝 NetBeans 後,會使用 Java JRE 啟動,而不是 JDK,
之後,若要再加安裝 Java plugin 時,會出現「some plugins require JDK」訊息。


解決方是,先下載 Java SE JDK 安裝:
http://www.oracle.com/technetwork/java/javase/downloads/index.html

安裝完後,修改 NetBeans 設定檔「netbeans.conf」,
設定檔路徑位置如:
C:\Program Files\NetBeans 8.2\etc\netbeans.conf

找到 netbeans_jdkhome 設定的那一行,將路徑改為已安裝的 Java JDK 路徑
#netbeans_jdkhome="C:\Program Files\NetBeans 8.2\bin\jre"
netbeans_jdkhome="C:\Program Files\Java\jdk1.8.0_131"
註:修改後若無法儲存,文字編輯器可能須用系統管理員身分權限開啟


參考:
FaqRunningOnJre - NetBeans Wiki


2017年6月7日 星期三

Nginx 設定 https 連線

假設要自己發憑證給網站。

先建立放SSL憑證的資料夾
$ mkdir /etc/nginx/ssl
產生網站的私鑰、證書。
example.com.key:私鑰(private key)
example.com.crt:證書(certificate)
(其中 -nodes 參數,表示不對 private key 加密,避免每次啟動 nginx 需要輸入密碼。)
$ openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout /etc/nginx/ssl/example.com.key -out /etc/nginx/ssl/example.com.crt
(再來填寫一些基本的資料,即可產生example.com.key、example.com.crt 兩個檔)
Country Name (2 letter code) [XX]:
State or Province Name (full name) []:
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:
Email Address []:


在 nginx 網站設定檔加入監聽 443 SSL 設定、與指定憑證位置(原本 listen 80 可保留共存)
#SSL
listen 443 ssl;
ssl_certificate /etc/nginx/ssl/example.com.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
重新讀取設定
$ systemctl reload nginx
若有設定防火牆,設定防火牆允許 https(443 port) 通行,
$ firewall-cmd --permanent --zone=public --add-service=https
$ firewall-cmd --reload
$ firewall-cmd --list-all --zone=public


其他:
  • 若「listen 443 ssl;」只寫「listen 443;」,缺了「 ssl」
    Chromw 會出現錯誤訊息:「net::ERR_SSL_PROTOCOL_ERROR」
    Firefox 會出現錯誤訊息:「SSL 收到含超出最大允許字串長度的記錄。 錯誤代碼: SSL_ERROR_RX_RECORD_TOO_LONG」
    參考:http://serverfault.com/q/605215
  • 沒加 -nodes 參數,不對 private key 加密,產生的檔案內容格式:
    example.com.key(私鑰)
    -----BEGIN PRIVATE KEY-----
    MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDeicw2jouYIdb3
    +re2QwHGWfrAs7+6gdvPzbsZAX+1MaB5CulMOlqTW5R/xJCTyBRegdpc9Oq8Ufsz
    Nkp5EyABT/1kdACh8HBUd4emaRDdng8nkxi4m9bFuPvDV3eV9b1c44a/PoDrk5Ks
    .....
    GToHKxAElC0nvdYRlTgmm4Gh2AbzaB7uhEkDd8ifuCAt4SssMu0MWvxXgUHNaJKc
    EVg8zxwJUnHotFVsQajaiVYnMDaMYoMe3PeUjIs5EK5ueEJnlB/jBYYlH6haVN2m
    CrOa1VRvAkRmWKUAzMObreEm
    -----END PRIVATE KEY-----
    
    example.com.crt(證書)
    -----BEGIN CERTIFICATE-----
    MIIDkzCCAnugAwIBAgIJAJZQ6uDkx3pPMA0GCSqGSIb3DQEBCwUAMGAxCzAJBgNV
    BAYTAmFhMQswCQYDVQQIDAJhYTELMAkGA1UEBwwCYWExCjAIBgNVBAoMAWExCzAJ
    .....
    pKE6/3wZ4SXio4oLKFGziBGqg+5kxzla2fb1PDUNRbmyQEzB+ZFtFgVHcgXU55ff
    bLprWdbDn4bldhEyl9UHWfwlOs0M6g6yfnc7zmJUxrZ5qmMmMhbkZJ4X30LUYZif
    Vgo4FV3Ujg==
    -----END CERTIFICATE-----
    
  • 有加 -nodes 參數,對 private key 加密,產生的檔案內容格式:
    example.com.key(私鑰)
    -----BEGIN ENCRYPTED PRIVATE KEY-----
    MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIwU2mXoH/UvICAggA
    MBQGCCqGSIb3DQMHBAgnLQEy2LhjSQSCBMiq040M9Ryl5ygXVvNorGkttO3wK0Tl
    uRRRZJplhQVBc09zm0N2HyjO93wZPnVycrI2n6m04w0IMSsc6IpbOaflqwcKN7xG
    .....
    37mVxQx45mN7f8im23uJDNs5n29yexc21YzaEaP5BNwBpJrJtNAVR0p63h+LRhGJ
    ByA24Brmys/RE5xpYkqtp4V47aJcIwYgy4LSyWW6ITGYRMq9FlaziUjyFpEaddIc
    ho8=
    -----END ENCRYPTED PRIVATE KEY-----
    
    example.com.crt(證書)
    -----BEGIN CERTIFICATE-----
    MIIDlTCCAn2gAwIBAgIJAIT9a7cvK/EpMA0GCSqGSIb3DQEBCwUAMGExCzAJBgNV
    BAYTAmFhMQswCQYDVQQIDAJhYTELMAkGA1UEBwwCYWExCzAJBgNVBAoMAmFhMQsw
    .....
    FT9xCMZp+Z6n6LwWdBWkJ1mASwkxgRDKZzSBaiRN35pT/JSbUqwGH8etD8QMXBBq
    CqiTJM/D3X6YMpKInKnFV7Z/qAQqpcfYYPzBLNAosOmUkUBVYxwtKbUxNoPJDMQi
    kEzWv9Oc5VNC
    -----END CERTIFICATE-----
    
  • 查看 example.com.crt 證書內容
    $ openssl x509 -in example.com.crt -text -noout
    
    參考:DER vs. CRT vs. CER vs. PEM Certificates and How To Convert Them
  • A certificate contains a public key
    參考:What is the difference between a certificate and a key with respect to SSL? - Super User
  • TLS:Transport Layer Security
    SSL:Secure Socket Layer
    .key:私鑰。
    .csr:Certificate Signing Request 證書簽名請求,像憑證機構申請憑證時,給憑證機構的檔案。
    .crt:Certificate,證書。
    X.509:一種證書格式。一般 .crt 附檔名。BASE64編碼(apache、linux):.pem。二進位編碼(windows、Java):.der。
    參考:openssl、x509、crt、cer、key、csr、ssl、tls 这些都是什么鬼? - 菩提树下的杨过 - 博客园
  • 一般向憑證機構申請憑證流程:
    「產生 public key(CSR)、private key」-->「public key(CSR)給憑證機構簽署認証」-->「憑證機構回覆簽署後的 Certificate(證書、CRT)」
    參考:SSL憑証(SSL certificate)的原理 - 知識庫 - 無限空間,虛擬主機,網域註冊,網域管理

其他參考:
http://nginx.org/en/docs/http/configuring_https_servers.html
NGINX 設定 HTTPS 網頁加密連線,建立自行簽署的 SSL 憑證 - G. T. Wang
Masterclass: Secure your website with SSL encryption | Linux Voice
openssl入門
寫程式是良心事業: OpenSSL - 金鑰與憑證的管理
OpenSSL 操作筆記 - 檔案格式轉換
不自量力 の Weithenn: SSL Certificate-自行產生 SSL 憑證
7.2. web 伺服器 ssl 證書
Chapter 7. OpenSSL
What is SSL and what are Certificates?


查 openssl 指令:
$ openssl -h (輸入不存在的指令,例如 -h,會列出可用指令)
$ openssl req -h
$ man openssl
$ man req
$ man x509
OpenSSL - OpenFoundry
常用OPENSSL指令介紹 - SSL憑證推薦網 | SSL憑證 | code Sign
https://www.openssl.org/docs/manmaster/
https://www.openssl.org/docs/manmaster/man1/req.html
openssl 证书请求和自签名命令req详解 - Gordon0918 - 博客园
OpenSSL之命令详解 - 让梦冬眠 - 51CTO技术博客


2017年2月28日 星期二

MySQL server Host Cache

MySQL 會將網域IP解析快取。
有時一開始網域解析設定錯了,嘗試連到 MySQL server 才發現這個錯誤。
訂正後,卻還是出現類似這樣的錯誤:
ERROR 1130 (HY000): Host 'new.example.com' is not allowed to connect to this MySQL server


這可能是 MySQL server Host Cache 的影響,更新 Host 快取指令:
使用 mysqladmin
mysqladmin flush-hosts -uroot -p

或登入MySQL後
mysql> flush hosts;


參考:
MySQL :: MySQL 5.7 Reference Manual :: B.5.2.6 Host 'host_name' is blocked
MySQL :: MySQL 5.6 Reference Manual :: 22.10.10.1 The host_cache Table


2017年1月9日 星期一

JavaScript 小數相加

因為浮點數在電腦中不是儲存準確的值,所以會有誤差。
原因參考:
The Floating-Point Guide - Basic Answers
[浮點數] IEEE754 , C/C++ 浮點數誤差 @ Edison.X. Blog :: 痞客邦 PIXNET ::


尤其在經過運算後,可能目視便可看到誤差,也可能多出許多非預期的小數位數。
網路上有幾種處理方式,以下用兩個浮點數相加為例。
測試瀏覽器:Chrome 55.0.2883.87 m

例如:
0.1+0.7 (預計結果為0.8)
=>0.7999999999999999


處理方式 1:
轉成整數運算後,再轉回小數。
(參考:http://www.w3schools.com/js/js_numbers.asphttp://www.cnblogs.com/konooo/archive/2010/01/23/1654617.html)
「先轉成整數運算後」-->「再轉回小數」
(0.1*10+0.7*10)/10
=>0.8

但發現一個特例
155.2+0.67 (預計結果為155.87)
=>155.86999999999998
(155.2*100+0.67*100)/100
=>155.86999999999998
=>「先轉成整數運算後」-->「再轉回小數」,這方法無效


處理方式 2:
轉成整數運算後,緊接著使用 round,再轉回小數。
(參考:http://stackoverflow.com/a/10474055)
「先轉成整數運算後」-->「round處理確保為整數」-->「再轉回小數」
Math.round((155.2*100+0.67*100))/100
=>155.87
參考連結範例,是直接乘上 1e12 倍,看似也正常
Math.round((155.2*1e12+0.67*1e12))/1e12
=>155.87


但 Math.round 直接乘上 1e12 倍再還原,也出現例外
(參考:http://stackoverflow.com/a/13388202)
1234563995.721+12345691212.718+1234568421.5891+12345677093.49284 (預計結果為27160500723.52094)
=>27160500723.520943 (IE11顯示 27160500723.520942)

Math.round(1234563995.721*100000+12345691212.718*100000+1234568421.5891*100000+12345677093.49284*100000)/100000
=>27160500723.52094 (IE11顯示 27160500723.52094)

Math.round(1234563995.721*1000000+12345691212.718*1000000+1234568421.5891*1000000+12345677093.49284*1000000)/1000000
=>27160500723.52094 (IE11顯示 27160500723.52094)

Math.round(1234563995.721*1e12+12345691212.718*1e12+1234568421.5891*1e12+12345677093.49284*1e12)/1e12
=>27160500723.520943  (IE11顯示 27160500723.520942) 
=> 小數原本只有5位,但chrome和IE11都變成6位
=> 直接乘上 1e12 倍再還原,無法完美得出 27160500723.52094


處理方式 3:
前面 http://stackoverflow.com/a/13388202 參考連結,建議用 toFixed
(1234563995.721+12345691212.718+1234568421.5891+12345677093.49284).toFixed(5)
=>"27160500723.52094" (但需注意 toFixed 回傳的結果是字串)

但 toFixed 在某些地方,也會出現不如預期的現象 (參考:http://stackoverflow.com/a/661757)
(1.695).toFixed(2)
=>"1.70"

(0.695).toFixed(2)  (預期結果"0.70")
=>"0.69" (但IE11正常顯示 "0.70")
=> Chrome無法正常四捨五入,但IE11可以正常四捨五入
其他特例
(1.2).toFixed(16)
=>"1.2000000000000000"
(1.2).toFixed(17)
=>"1.19999999999999996"  (但IE11正常顯示 "1.20000000000000000")



結論:如果著重於相加後,小數位數不會變多

解決方式一: 
「先乘上剛剛好能剛好將該小數最大位數變成整數的10倍數」-->「進行相加」-->「round處理確保為整數」-->「再轉回小數」
var floatAdd = function (arg1, arg2) {
    var r1, r2, m;
    try {
        r1 = arg1.toString().split(".")[1].length;
    } catch (e) {
        r1 = 0;
    }
    try {
        r2 = arg2.toString().split(".")[1].length;
    } catch (e) {
        r2 = 0;
    }
    m=Math.pow(10,Math.max(r1,r2))  
    return Math.round((arg1*m+arg2*m))/m;
};


解決方式二: 
「小數直接相加」-->「toFixed小數最大位數」
var floatAdd = function (arg1, arg2) {
    var r1, r2, m;
    try {
        r1 = arg1.toString().split(".")[1].length;
    } catch (e) {
        r1 = 0;
    }
    try {
        r2 = arg2.toString().split(".")[1].length;
    } catch (e) {
        r2 = 0;
    }
    m = Math.max(r1, r2);
    return parseFloat((arg1 + arg2).toFixed(m));
};


解決方式三:
使用The Floating-Point Guide提到的方式 「The Floating-Point Guide - Floating-point cheat sheet for JavaScript