[Linux] 解決 mysql 無法寫出檔案問題

在red hat系列的linux中selinux對哪些daemon可以進行怎麼樣的操作是有限制的,mysql的select into outfile的命令是mysql的daemon來負責寫文件操作的。寫檔之前當然要具有寫檔的許可權。而selinux對這個許可權做了限制。如果selinux是關閉的吧,這個命令執行是沒有問題的
mysql> select user from user into outfile ‘/home/test.txt’;
Query OK, 2 rows affected (0.02 sec)
當時selinux開啟時
selinux對mysql的守護進程mysqld進行了限制。
mysql> select user from user into outfile ‘/home/test.txt’;
ERROR 1 (HY000): Can’t create/write to file ‘/home/test.txt’ (Errcode: 13)
出現了沒有許可權寫的error。
解決方法,可以關閉selinux。
可以在/etc/selinux中找到config
root用戶,
shell>vi /etc/selinux/config

# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing – SELinux security policy is enforced.
# permissive – SELinux prints warnings instead of enforcing.
# disabled – SELinux is fully disabled.
SELINUX=enforcing

修改SELINUX=disabled關閉selinux就可以了,這個問題就可以解決了。
不過全部關閉SELINUX有帶來一些安全問題。
當然也可以,單獨給mysql的守護進程許可權,
shell>getsebool -a可以查看當前的對系統一系列守護進程的許可權情況。

lpd_disable_trans –> off
mail_read_content –> off
mailman_mail_disable_trans –> off
mdadm_disable_trans –> off
mozilla_read_content –> off
mysqld_disable_trans –> off
nagios_disable_trans –> off
named_disable_trans –> off
named_write_master_zones –> off
nfs_export_all_ro –> on
nfs_export_all_rw –> on
nfsd_disable_trans –> off
nmbd_disable_trans –> off
nrpe_disable_trans –> off

shell>setsebool -P mysqld_disable_trans=1
開啟對mysql守護進程的許可權,這樣
mysql> select user from user into outfile ‘/home/test.txt’;
寫入到自訂的目錄就沒有問題了。
-P表示 是永久性設置,否則重啟之後又恢復預設值。
getsebool setsebool命令在root用戶下有許可權。

除了對selinux的許可權,當然首先要保證該目錄擁有讀寫許可權。
在ubuntu下 ,可以對AppArmor(/etc/apparmor.d/usr.sbin.mysqld) 修改,類似selinux。
添加/etc/squid/lists/eighties.txt w,類似。

延伸閱讀:http://www.fromdual.com/mysql-and-secure-linux-selinux

MySQL 預設行為

MySQL 預設行為: completion_type=0 (or NO_CHAIN) & Row Exclusive (X) Lock
1. COMMIT 和 ROLLBACK 不被附加在原本 SQL 頭尾
2. BEGIN (or START TRANSACTION): 若沒 COMMIT 又再下一次 BEGIN,則前一次 TRX 會被 AUTOCOMMIT
3. BEGIN 後下 UPDATE 的時候,此時若別人 SELECT,別人不會被 LOCK,會顯示舊的值;若別人是下 UPDATE 影響到該 row,別人會被 LOCK

— 檢查哪個 TRX 正在執行或被 Block
SET @threshold = 0;

SELECT p.user,
LEFT(p.HOST, LOCATE(‘:’, p.HOST) – 1) host, p.id,
TIMESTAMPDIFF(SECOND, t.TRX_STARTED, NOW()) duration,
COUNT(DISTINCT ot.REQUESTING_TRX_ID) waiting
FROM INFORMATION_SCHEMA.INNODB_TRX t
JOIN INFORMATION_SCHEMA.PROCESSLIST p
ON ( p.ID = t.TRX_MYSQL_THREAD_ID )
LEFT JOIN INFORMATION_SCHEMA.INNODB_LOCK_WAITS ot
ON ( ot.BLOCKING_TRX_ID = t.TRX_id )
WHERE t.TRX_STARTED + INTERVAL @threshold SECOND <= NOW()
GROUP BY LEFT(p.HOST, LOCATE(‘:’, p.HOST) – 1), p.id, duration
HAVING duration >= @threshold OR waiting > 0;

資料來源:http://mysqlblog.fivefarmers.com/2012/08/28/identifying-and-killing-blocking-transactions-in-innodb/