MyCat


  

1 MyCat背景

  Mycat的前身是阿里巴巴大名鼎鼎的Cobar,Cobar在開源了一段時間後,就沒有再維護了,阿里巴巴放棄了該項目,再加上Cobar在使用過程中也發現存在一些問題;2013年國內一批開源軟件愛好者對Cobar這個項目進行了改進,並命名爲Mycat,這就是MyCat的誕生。
  MyCat是完全免費開源的,不屬於任何商業公司。Mycat於2014年首次在上海的《中華架構師》大會上對外宣講,隨後越來越多的項目採用了Mycat;截至2015年11月,超過300個項目採用Mycat,涵蓋銀行、電信、電子商務、物流、移動應用、O2O的衆多領域和公司;
  Mycat官網:http://www.mycat.io/

2 MyCat是什麼

Mycat是一個開源數據庫中間件;

什麼是中間件?
比如你帶了一些家鄉的特產打算送給一個朋友,那麼怎麼送給你的朋友?

第一方式不用中間件:
你親自坐車到你朋友家,把特產送給你的朋友,或者是你朋友來你家取這些特產;

第二種方式使用中間件:
你叫一個快遞,把這些特產同城郵寄給你的朋友,那麼這個快遞員就充當中間件的角色。

  Mycat是一個實現了MySQL協議的的數據庫中間件服務器,我們可以把它看作是一個數據庫代理,用MySQL客戶端工具和命令行訪問Mycat,而Mycat再使用MySQL原生(Native)協議與多個MySQL服務器通信;
  Mycat也可以使用JDBC協議與大多數主流數據庫服務器通信,包括SQL Server、Oracle、DB2、PostgreSQL 等主流數據庫,也支持MongoDB這種新型NoSQL方式的存儲,未來還會支持更多類型的存儲;
  一般地,Mycat主要用於代理MySQL數據庫,雖然它也支持去訪問其他類型的數據庫;Mycat的默認端口是8066,可以使用常見的對象映射框架比如MyBatis操作Mycat;

3 Mycat主要能做什麼

1、數據庫的讀寫分離
  通過Mycat可以自動實現讀寫分離,寫數據時操作主數據庫,讀數據時操作從數據庫,這樣能有效地分攤數據庫壓力;當主數據庫出現故障後,Mycat能自動切換到另一個主數據庫上,進而提供高可用的數據庫服務,當然這需要部署多主多從的模式;

2、數據庫分庫分表
  分庫分表指的是對數據庫數據的拆分;
  分庫分表分爲兩種:水平拆分和垂直拆分;
  一種是根據表中數據的邏輯關係,將同一個表中的數據按照某種條件拆分到多臺數據庫服務器上面,這種切分稱之爲數據的水平切分,也可以稱爲橫向切分;
  一種是按照不同的表來切分到不同的數據庫服務器之上,這種切可以稱之爲數據的垂直切分,也可以稱爲縱向切分;
  性能有瓶頸了,可以讀寫分離;
  數據庫容量有瓶頸了,可以分庫分表

3 Mycat環境搭建

1、下載:

http://dl.mycat.io/1.6-RELEASE/
wget http://dl.mycat.io/1.6-RELEASE/Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz

2、下載後解壓即可:

tar  –zxvf  Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz  –C  /usr/local

3、解壓後即安裝完成;

Java語言開發的,直接解壓即可使用:
tomcat
maven
zookeeper
activemq
mycat

4 Mycat日常管理

4.1 Mycat啓動和關閉

Mycat啓動

切換到mycat的bin路徑下
./mycat start
mycat安裝後需要配置,然後才能啓動

Mycat關閉

切換到mycat的bin路徑下
./mycat stop

4.2 Mycat命令行

登錄mycat,可以使用mysql的命令行工具來操作:
./mysql -umycat -p -P8066 -h127.0.0.1
mycat默認數據訪問端口是8066

4.3 MyCat配置文件

1、server.xml

主要用於配置mycat的服務器信息
常用配置:
1、配置序列生成方式(數據庫表的主鍵生成方式)
2、配置mycat邏輯數據庫
3、配置mycat的訪問賬戶和密碼

2、schema.xml

用於配置邏輯數據庫的映射、表、分片規則、數據結點及真實的數據庫信息;
常用配置:
1、配置邏輯庫映射
2、配置水平切分的表
3、配置垂直切分的表
4、配置真實的數據庫
5、配置讀寫結點

5 Mycat讀寫分離

1、配置server.xml文件

設置連接mycat時的用戶名和密碼, 邏輯庫:
<user name="mycat">
     <property name="password">123456</property>
     <property name="schemas">mycatdb</property>
</user>

參考配置

<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">

	<system>
		<property name="useSqlStat">0</property>  <!-- 1爲開啓實時統計、0爲關閉 -->
		<property name="useGlobleTableCheck">0</property>  <!-- 1爲開啓全加班一致性檢測、0爲關閉 -->
		<property name="sequnceHandlerType">2</property>
		<!--  <property name="useCompression">1</property>--> <!--1爲開啓mysql壓縮協議-->
        <!--  <property name="fakeMySQLVersion">5.6.20</property>--> <!--設置模擬的MySQL版本號-->
		<!-- <property name="processorBufferChunk">40960</property> -->
		<!-- 
		<property name="processors">1</property> 
		<property name="processorExecutor">32</property> 
		 -->
		<!--默認爲type 0: DirectByteBufferPool | type 1 ByteBufferArena-->
		<property name="processorBufferPoolType">0</property>
		<!--默認是65535 64K 用於sql解析時最大文本長度 -->
		<!--<property name="maxStringLiteralLength">65535</property>-->
		<!--<property name="sequnceHandlerType">0</property>-->
		<!--<property name="backSocketNoDelay">1</property>-->
		<!--<property name="frontSocketNoDelay">1</property>-->
		<!--<property name="processorExecutor">16</property>-->
		<!--
			<property name="serverPort">8066</property> <property name="managerPort">9066</property> 
			<property name="idleTimeout">300000</property> <property name="bindIp">0.0.0.0</property> 
			<property name="frontWriteQueueSize">4096</property> <property name="processors">32</property> -->
		<!--分佈式事務開關,0爲不過濾分佈式事務,1爲過濾分佈式事務(如果分佈式事務內只涉及全局表,則不過濾),2爲不過濾分佈式事務,但是記錄分佈式事務日誌-->
		<property name="handleDistributedTransactions">0</property>
		<!--
			off heap for merge/order/group/limit      1開啓   0關閉
		-->
		<property name="useOffHeapForMerge">1</property>
		<!--
			單位爲m
		-->
		<property name="memoryPageSize">1m</property>
		<!--
			單位爲k
		-->
		<property name="spillsFileBufferSize">1k</property>
		<property name="useStreamOutput">0</property>
		<!--
			單位爲m
		-->
		<property name="systemReserveMemorySize">384m</property>
		<!--是否採用zookeeper協調切換  -->
		<property name="useZKSwitch">true</property>
	</system>
	
	<!-- 全局SQL防火牆設置 -->
	<!-- 
	<firewall> 
	   <whitehost>
	      <host host="127.0.0.1" user="mycat"/>
	      <host host="127.0.0.2" user="mycat"/>
	   </whitehost>
       <blacklist check="false">
       </blacklist>
	</firewall>
	-->
	
	<!-- 配置mycat的訪問賬號 -->
	<user name="mycat">
		<property name="password">123456</property>
		<!-- mycat的邏輯數據庫 -->
		<property name="schemas">mycatdb</property>
		
		<!-- 表級 DML 權限設置 -->
		<!-- 		
		<privileges check="false">
			<schema name="mycatdb" dml="0110" >
				<table name="tb01" dml="0000"></table>
				<table name="tb02" dml="1111"></table>
			</schema>
		</privileges>		
		-->
	</user>

	<!-- 配置mycat的訪問賬號 -->
	<user name="user">
		<property name="password">123456</property>
		<property name="schemas">mycatdb</property>
		<property name="readOnly">true</property>
	</user>

</mycat:server>

2、配置schema.xml文件
2.1、配置schema

作用:schema用於配置邏輯庫
只做讀寫分離,不做分庫分表,則schema標籤裏面不用配置table;
給schema標籤加上屬性dataNode,配置dataNode的名字(name);
最終配置如下:
<!--schema配置邏輯數據庫與真實數據庫的映射-->
<schema name="mycatdb" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"/>

2.2、配置dataNode

作用:dataNode定義了MyCat中的數據節點,也就是我們通常說所的數據分片,
一個dataNode標籤就是一個獨立的數據分片,通俗理解,一個分片就是一個物理數據庫;
配置說明:
name 定義數據節點的名字,這個名字需要是唯一的,這個名字在schema裏面會使用到;
dataHost用於定義該分片屬於哪個數據庫實例的,屬性值是引用dataHost標籤上定義的name屬性;
database用於對應真實的數據庫名,必須是真實存在的;
最終配置如下:
<dataNode name="dn1" dataHost="localhost1" database="workdb" />

2.3、配置dataHost

作用:定義具體的數據庫實例、讀寫分離配置和心跳語句;
balance屬性:
負載均衡類型,目前的取值有4種:
1. balance="0", 不開啓讀寫分離機制,所有讀操作都發送到當前可用的writeHost上;
2. balance="1",全部的readHost與stand by writeHost參與select語句的負載均衡,
	簡單的說,當雙主雙從模式(M1->S1,M2->S2,並且M1與 M2互爲主備),正常情況下,
	M2,S1,S2都參與select語句的負載均衡。
3.balance="2",所有讀操作都隨機的在writeHost、readhost上分發;
4.balance="3",所有讀請求隨機的分發到wiriterHost對應的readhost執行,writerHost
  不負擔讀壓力;
推薦balance設置爲1;
switchType屬性:
1.用於指定主服務器發生故障後的切換類型:
2.-1 表示不自動切換 1 默認值,自動切換 2 基於MySQL主從同步的狀態決定是否切換
	3 基於MySQL galary cluster的切換機制(適合集羣)(1.4.1)
通常情況下,我們MySQL採用雙主雙從的模式下,switchType爲1即可。
因爲雙主從模式下,主從同步關係很複雜,不能根據MySQL的狀態來切換。
只需要在一個主出問題後,切換到另外的主。
heartbeat標籤
1.用於和後端數據庫進行心跳檢查的語句
2.當switchType爲1時,mysql心跳檢查語句是select user()
3.switchType爲2時,心跳檢查語句是show slave status
writeHost與readHost標籤:
1. 這兩個標籤都指定後端數據庫的相關配置給mycat,用於實例化後端連接池。唯一不同的是,
	writeHost指定寫實例、readHost指定讀實例,組合這些讀寫實例來滿足系統的要求。
2.在一個dataHost內可以定義多個writeHost和readHost。但是,如果writeHost指定的後端
	數據庫宕機,那麼這個writeHost綁定的所有readHost都將不可用。另一方面,由於這個
	writeHost宕機系統會自動的檢測到,並切換到備用的writeHost上去。

一主三從配置參考:

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

	<schema name="mycatdb" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
		<!-- 只實現讀寫分離,沒有涉及到分庫分表,那麼<schema>標籤下不需要配置任何表 -->
	</schema>

	<!--配置真實的數據庫名稱 test01 -->
	<dataNode name="dn1" dataHost="localhost1" database="test01" />

	<!--配置具體的數據庫連接信息、讀寫分離、心跳語句 -->
	<dataHost name="localhost1" 
	          maxCon="1000" 
			  minCon="10" 
			  balance="1"
			  writeType="0" 
			  dbType="mysql" 
			  dbDriver="native" 
			  switchType="1"  
			  slaveThreshold="100">
		<heartbeat>select user()</heartbeat>
		
		<!--配置寫數據庫(主庫) 一主三從的讀寫分離配置 -->
		<writeHost host="hostM3307" url="localhost:3307" user="root" password="123456">
			<!--配置寫數據庫下的讀數據庫(從庫)-->
			<readHost host="hostS3308" url="localhost:3308" user="root" password="123456" />
			<readHost host="hostS3309" url="localhost:3309" user="root" password="123456" />
			<readHost host="hostS3310" url="localhost:3310" user="root" password="123456" />
		</writeHost>
		
	</dataHost>
</mycat:schema>

雙主雙從配置參考

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

	<!--schema配置邏輯數據庫與真實數據庫的映射-->
	<schema name="mycatdb" checkSQLschema="false" sqlMaxLimit="1000" dataNode="dn1">
		
		<!---3307主、3308主、3309從、3310從-->
		
		<!---讀寫分離,在schema標籤下不需要配置table,當分庫分表的時候才需要配置table-->
	</schema>

	<!---3307主、3308主、3309從、3310從-->
	<dataNode name="dn1" dataHost="localhost1" database="test01" />

	<!--
		1、balance="1" 開啓讀寫分離,如果是0表示沒有開啓讀寫分離
		2、switchType="1" 故障切換類型,1代表自動切換
	-->
	<dataHost name="localhost1" 
			  maxCon="1000" 
			  minCon="10" 
			  balance="1"
			  writeType="0" 
			  dbType="mysql" 
			  dbDriver="native" 
			  switchType="1"  
			  slaveThreshold="100">
		
		<!--心跳語句 檢查服務器有沒有故障-->
		<heartbeat>select user()</heartbeat>
		
		<!---主庫3307-->
		<writeHost host="hostM3307" url="localhost:3307" user="root" password="123456">
			<!---從庫3309-->
			<readHost host="hostS3309" url="localhost:3309" user="root" password="123456" />
			<!---從庫3308-->
			<readHost host="hostS3308" url="localhost:3308" user="root" password="123456" />
		</writeHost>
		
		<!---主庫3308-->
		<writeHost host="hostM3308" url="localhost:3308" user="root" password="123456">
			<!---從庫3310-->
			<readHost host="hostS3310" url="localhost:3310" user="root" password="123456" />
			<!---從庫3307-->
			<readHost host="hostS3307" url="localhost:3307" user="root" password="123456" />
		</writeHost>
		
	</dataHost>
	
</mycat:schema>

3 測試讀寫分離
1、配置好MySQL主從複製並啓動主從MySQL;
2、啓動Mycat:/usr/local/mycat/bin/mycat start
3、登錄Mycat:mysql -uroot -p -P8066 -h 192.168.230.129
4、mycat默認數據訪問端口是8066
5、use mycatdb;
6、創建表,插入數據,觀察MySQL數據的情況;

 insert into orders (id, money) values (next value for MYCATSEQ_GLOBAL, 105);

7、在從庫中創建一個表tables,從庫數據不會同步到主庫;
8、然後通過mycat往tables中插入數據,觀察是否能插入成功,若不能成功,表示已經實現了讀寫分離;
9、然後,關閉主MySQL3308的服務;
10、在這裏再進行數據插入,觀察其它MySQL實例數據同步情況。
11、最後,把3308啓動,再觀察數據能不能同步到3308和它的從節點;
12、主節點的自動切換,會記錄在文件dnindex.properties在停掉3306主之前,cat一下該文件的內容;停掉之後,再cat一下;

6 MyCat分庫分表(水平)

1、配置server.xml

指定主鍵生成策略
<property name="sequnceHandlerType">1</property>

指定使用Mycat全局序列的類型:
0爲本地文件方式,1爲數據庫方式,2爲時間戳序列方式

2、配置schema.xml
指定邏輯庫,分片結點,結點主機等

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

	<!--schema配置邏輯數據庫與真實數據庫的映射-->
	<schema name="mycatdb" checkSQLschema="false" sqlMaxLimit="1000">
		
		<!---3307主、3308主、3309從、3310從-->
		
		<!---水平切分,需要在schema標籤下需要配置需要對哪個table進行水平切分, orders表有1000萬數據需要水平切分-->
		
		<!--rule="mod-long"指定切分的規則,取模的規則 表的id % 4 = 餘數-->
		<table name="orders" primaryKey="id" dataNode="dn1,dn2,dn3,dn4" rule="mod-long" />
		
	</schema>

	<!---3307主、3308主、3309從、3310從-->
	<dataNode name="dn1" dataHost="localhost1" database="test01" />
	<dataNode name="dn2" dataHost="localhost1" database="test02" />
	<dataNode name="dn3" dataHost="localhost1" database="test03" />
	<dataNode name="dn4" dataHost="localhost1" database="test04" />

	<!--
		1、balance="1" 開啓讀寫分離,如果是0表示沒有開啓讀寫分離
		2、switchType="1" 故障切換類型,1代表自動切換
	-->
	<dataHost name="localhost1" 
			  maxCon="1000" 
			  minCon="10" 
			  balance="1"
			  writeType="0" 
			  dbType="mysql" 
			  dbDriver="native" 
			  switchType="1"  
			  slaveThreshold="100">
		
		<!--心跳語句 檢查服務器有沒有故障-->
		<heartbeat>select user()</heartbeat>
		
		<!---主庫3307-->
		<writeHost host="hostM3307" url="localhost:3307" user="root" password="123456">
			<!---從庫3309-->
			<readHost host="hostS3309" url="localhost:3309" user="root" password="123456" />
			<!---從庫3308-->
			<readHost host="hostS3308" url="localhost:3308" user="root" password="123456" />
		</writeHost>
		
		<!---主庫3308-->
		<writeHost host="hostM3308" url="localhost:3308" user="root" password="123456">
			<!---從庫3310-->
			<readHost host="hostS3310" url="localhost:3310" user="root" password="123456" />
			<!---從庫3307-->
			<readHost host="hostS3307" url="localhost:3307" user="root" password="123456" />
		</writeHost>
		
	</dataHost>
	
</mycat:schema>

3、配置rule.xml

指定分片結點數
改爲4

4、插入數據驗證

insert into tb11 (id, name) values (next value for MYCATSEQ_GLOBAL,'zhangsan');

不管是何種方式的切分,主鍵生成必須交給MyCat實現;

7 Mycat分庫分表(垂直)

1、修改server.xml

<property name="sequnceHandlerType">0</property>

2、修改schema.xml

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

	<!--schema配置邏輯數據庫與真實數據庫的映射-->
	<schema name="mycatdb" checkSQLschema="false" sqlMaxLimit="1000">
		<!---3307主、3308主、3309從、3310從-->
		
		<!---垂直切分,需要在schema標籤下需要配置需要對哪個table進行垂直切分-->
		
		<!--需求:原來是一個數據庫共120張表,現在進行垂直切分,切分成3個數據庫,分別是:
			web(前臺數據庫30張表)、admin(後臺數據庫45張表)、red(紅包數據庫45張表)
		-->
		
		<!--web(前臺數據庫30張表)-->
		<table name="users" primaryKey="id" dataNode="dn1" />
		<table name="auth" primaryKey="id" dataNode="dn1" />
		<!--...省略了下面的28張表...-->
		
		
		<!--admin(後臺數據庫45張表)-->
		<table name="products" primaryKey="id" dataNode="dn2" />
		<table name="creditors" primaryKey="id" dataNode="dn2" />
		<!--...省略了下面的43張表...-->
		
		
		<!--red(紅包數據庫45張表)-->
		<table name="redpackage" primaryKey="id" dataNode="dn3" />
		<table name="redpackageType" primaryKey="id" dataNode="dn3" />
		<!--...省略了下面的43張表...-->
		
	</schema>

	<!---3307主、3308主、3309從、3310從-->
	<dataNode name="dn1" dataHost="localhost1" database="web" />
	<dataNode name="dn2" dataHost="localhost1" database="admin" />
	<dataNode name="dn3" dataHost="localhost1" database="red" />

	<!--
		1、balance="1" 開啓讀寫分離,如果是0表示沒有開啓讀寫分離
		2、switchType="1" 故障切換類型,1代表自動切換
	-->
	<dataHost name="localhost1" 
			  maxCon="1000" 
			  minCon="10" 
			  balance="1"
			  writeType="0" 
			  dbType="mysql" 
			  dbDriver="native" 
			  switchType="1"  
			  slaveThreshold="100">
		
		<!--心跳語句 檢查服務器有沒有故障-->
		<heartbeat>select user()</heartbeat>
		
		<!---主庫3307-->
		<writeHost host="hostM3307" url="localhost:3307" user="root" password="123456">
			<!---從庫3309-->
			<readHost host="hostS3309" url="localhost:3309" user="root" password="123456" />
			<!---從庫3308-->
			<readHost host="hostS3308" url="localhost:3308" user="root" password="123456" />
		</writeHost>
		
		<!---主庫3308-->
		<writeHost host="hostM3308" url="localhost:3308" user="root" password="123456">
			<!---從庫3310-->
			<readHost host="hostS3310" url="localhost:3310" user="root" password="123456" />
			<!---從庫3307-->
			<readHost host="hostS3307" url="localhost:3307" user="root" password="123456" />
		</writeHost>
		
	</dataHost>
	
</mycat:schema>

3、插入數據驗證

插入數據驗證
insert into tb11 (id, name) values (next value for MYCATSEQ_GLOBAL,'zhangsan');

4、垂直切分價值:
垂直切分帶來的價值:可以屏蔽掉多數據源的問題,只需要一個統一入口mycat就可以操作下面的多個數據庫;不管是何種方式的切分,主鍵生成必須交給MyCat實現;

8 Mycat全局序列號

8.1 本地文件方式

server.xml配置文件:sequnceHandlerType=0
conf/sequence_conf.properties 

8.2 時間戳方式

server.xml配置文件:sequnceHandlerType=2
使用一個時間戳作爲主鍵

8.3 數據庫方式

1、在數據庫中執行腳本

DROP TABLE IF EXISTS MYCAT_SEQUENCE;

CREATE TABLE MYCAT_SEQUENCE (name VARCHAR(50) NOT NULL,current_value INT NOT NULL,increment INT NOT NULL DEFAULT 1,
PRIMARY KEY(name)) ENGINE=InnoDB default charset=utf8;

INSERT INTO MYCAT_SEQUENCE(name,current_value,increment) VALUES ("GLOBAL", 0, 100);

DROP FUNCTION IF EXISTS mycat_seq_currval;
DELIMITER //
CREATE FUNCTION mycat_seq_currval(seq_name VARCHAR(50)) RETURNS varchar(64) CHARSET utf8
DETERMINISTIC
BEGIN
DECLARE retval VARCHAR(64);
SET retval="-999999999,null";
SELECT concat(CAST(current_value AS CHAR),",",CAST(increment AS CHAR)) INTO retval FROM MYCAT_SEQUENCE WHERE name = seq_name;
RETURN retval;
END //
DELIMITER  ;


DROP FUNCTION IF EXISTS mycat_seq_setval;
DELIMITER //
CREATE FUNCTION mycat_seq_setval(seq_name VARCHAR(50),value INTEGER) RETURNS varchar(64) CHARSET utf8
DETERMINISTIC
BEGIN
UPDATE MYCAT_SEQUENCE
SET current_value = value
WHERE name = seq_name;
RETURN mycat_seq_currval(seq_name);
END //
DELIMITER ;

DROP FUNCTION IF EXISTS mycat_seq_nextval;
DELIMITER //
CREATE FUNCTION mycat_seq_nextval(seq_name VARCHAR(50)) RETURNS varchar(64) CHARSET utf8
DETERMINISTIC
BEGIN
UPDATE MYCAT_SEQUENCE
SET current_value = current_value + increment WHERE name = seq_name;
RETURN mycat_seq_currval(seq_name);
END //
DELIMITER ;

2、server.xml配置:

<property name="sequnceHandlerType">1</property>

注:sequnceHandlerType 需要配置爲1,表示使用數據庫方式生成sequence.
3、指定sequence在哪個結點

sequence_db_conf.properties相關配置,指定sequence相關配置在哪個節點上
GLOBAL=dn1,dn2,dn3,dn4

4、插入數據

插入時怎麼用
insert into tb1(id,name) values(next value for MYCATSEQ_GLOBAL,"test");
發佈了123 篇原創文章 · 獲贊 5 · 訪問量 8027
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章