Phoenix入門(下)

本文作者:林偉兵丹允,叩丁狼高級(jí)講師郭厌。原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明出處雕蔽。

3.5.使用DBeaver客戶端

Phoenix常見的客戶端連接工具有SQuirrel和DBeaver,這里主要介紹DBeaver客戶端的使用方式折柠。
安裝DBeaver,啟動(dòng)DBeaver批狐,將 phoenix-[version]-client.jar 拷貝到客戶端扇售。

01.png

02.png

03.png

04.png

注意:客戶端如何缺失某些參數(shù)配置,可以上面第4步的驅(qū)動(dòng)屬性添加再測(cè)試連接,這是因?yàn)镈Beaver不支持hbase-site.xml配置文件的使用.

3.6.Phoenix二級(jí)索引

前一章介紹了Phoenix簡(jiǎn)單的DDL和CURD操作承冰,接下來(lái)這一節(jié)主要介紹Phoenix獨(dú)有的特性[二級(jí)索引](http://phoenix.apache.org/secondary_indexing.html),并在DBeaver中實(shí)踐华弓。

? 對(duì)HBase來(lái)說(shuō),我們通常使用字典序的RowKey來(lái)快速訪問數(shù)據(jù)巷懈,除此之外也可使用自定義的Filter來(lái)搜索數(shù)據(jù)该抒,但是它是基于全表掃描的。而Phoenix提供的二級(jí)索引是避開了全表掃描顶燕,其利用空間換時(shí)間的來(lái)解決查詢過(guò)程中的緩慢問題;默認(rèn)情況下客戶端不支持二級(jí)索引凑保,需要將以下配置添加到HBase的各個(gè)RegionServer節(jié)點(diǎn)的hbase-site.xml文件中:

<property>
  <name>hbase.regionserver.wal.codec</name>
  <value>org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec</value>
</property>

覆蓋索引 Covered Indexes

? Phoenix提供了一種叫Covered Index的二級(jí)索引。這種索引在獲取數(shù)據(jù)的過(guò)程中涌攻,內(nèi)部不需再去HBase原表中獲取任何數(shù)據(jù)欧引,轉(zhuǎn)而在索引表查詢結(jié)果即可。

? 要想達(dá)到這種效果恳谎,你的select 的列芝此,where 的列都需要在索引表中出現(xiàn)。舉個(gè)例子因痛,如果你的SQL語(yǔ)句是SELECT name FROM WOLFCODE_MDB.t_employee ORDER BY SALARY DESC;婚苹,要達(dá)到最大化查詢效率和速度最快,你就需要建立覆蓋索引:

CREATE INDEX salary_idx ON wolfcode_mdb.t_employee(salary DESC) INCLUDE (name);
## 原表的內(nèi)容是:
+-----+-----------+----------+---------+
| ID  |   NAME    |  SALARY  | GENDER  |
+-----+-----------+----------+---------+
| 1   | zhangsan  | 10800.0  | M       |
| 2   | lisi      | 9900.0   | M       |
| 3   | wangwu    | 7500.0   | F       |
| 4   | zhaoliu   | 10000.0  | M       |
+-----+-----------+----------+---------+
## 索引表建立后內(nèi)容是:
+-----------+------+-----------+
| 0:SALARY  | :ID  |  0:NAME   |
+-----------+------+-----------+
| 1.08E+4   | 1    | zhangsan  |
| 1E+4      | 4    | zhaoliu   |
| 9.9E+3    | 2    | lisi      |
| 7.5E+3    | 3    | wangwu    |
+-----------+------+-----------+

## 當(dāng)執(zhí)行如下SQL時(shí)鸵膏,系統(tǒng)會(huì)找到對(duì)應(yīng)的二級(jí)索引表進(jìn)行查詢膊升,二級(jí)索引表的表內(nèi)容明顯比原表的內(nèi)容少,并且在查詢的過(guò)程無(wú)需再次排序谭企,這也大大減少了查詢的時(shí)間廓译。
## 但是索引表的建立無(wú)疑也降低了集群的存儲(chǔ)能力。
SELECT name FROM WOLFCODE_MDB.t_employee ORDER BY SALARY DESC;

? 覆蓋索引就是一種典型的全局索引债查,全局索引適合那些讀多寫少的場(chǎng)景非区。使用全局索引,讀數(shù)據(jù)基本不損耗性能盹廷,所有的性能損耗都來(lái)源于寫數(shù)據(jù)征绸。數(shù)據(jù)表的添加、刪除和修改都會(huì)更新相關(guān)的索引表速和。而查詢數(shù)據(jù)的時(shí)候歹垫,Phoenix會(huì)通過(guò)索引表來(lái)快速低損耗的獲取數(shù)據(jù)。

如下當(dāng)在原表插入數(shù)據(jù)后颠放,索引表也會(huì)插入對(duì)應(yīng)的數(shù)據(jù):

UPSERT INTO t_employee VALUES(5,'亦舒',8800,'F');
+-----------+------+-----------+
| 0:SALARY  | :ID  |  0:NAME   |
+-----------+------+-----------+
| 1.08E+4   | 1    | zhangsan  |
| 1E+4      | 4    | zhaoliu   |
| 9.9E+3    | 2    | lisi      |
| 8.8E+3    | 5    | 亦舒       |
| 7.5E+3    | 3    | wangwu    |
+-----------+------+-----------+

如果某個(gè)查詢已不在頻繁排惨,建議刪除索引表以換取更多的空間,代碼如下:

use wolfcode_mdb;
DROP INDEX SALARY_IDX ON wolfcode_mdb.t_employee;

函數(shù)索引 Functional Indexes

? 函數(shù)索引從4.3版本就有碰凶,這種索引的內(nèi)容不局限于列暮芭,還能在表達(dá)式上建立索引鹿驼。如果你使用的表達(dá)式正好就是索引的話,數(shù)據(jù)也可以直接從這個(gè)索引獲取辕宏,而不需要從數(shù)據(jù)庫(kù)獲取畜晰。比如說(shuō),在一個(gè)表達(dá)式上建立索引瑞筐,這個(gè)表達(dá)式是salary * 12,值得注意的是凄鼻,函數(shù)索引不支持排序:

CREATE INDEX SALARY_PER_YEAR_IDEX2 ON t_employee(salary * 12);
SELECT * FROM wolfcode_mdb.SALARY_PER_YEAR_IDEX2;
## 查詢結(jié)果如下
+-----------------+------+
| :(SALARY * 12)  | :ID  |
+-----------------+------+
| 9E+4            | 3    |
| 1.056E+5        | 5    |
| 1.188E+5        | 2    |
| 1.2E+5          | 4    |
| 1.296E+5        | 1    |
+-----------------+------+

本地索引 Local Indexes

? 本地索引適合那些寫多讀少或存儲(chǔ)空間有限的場(chǎng)景。和全局索引一樣聚假,Phoenix也會(huì)在查詢的時(shí)候自動(dòng)選擇是否使用本地索引块蚌。本地索引之所以是本地,主要是因?yàn)樗饕龜?shù)據(jù)和真實(shí)數(shù)據(jù)存儲(chǔ)在同一臺(tái)機(jī)器上膘格,這樣做主要是為了避免網(wǎng)絡(luò)數(shù)據(jù)傳輸?shù)拈_銷峭范。

異步創(chuàng)建索引

注意:https://yq.aliyun.com/ask/438584/

注意:http://hbase.group/question/27

? 一般我們可以使用CREATE INDEX來(lái)創(chuàng)建一個(gè)索引,這是一種同步的方法瘪贱。但是有時(shí)候我們創(chuàng)建索引的表非常大纱控,我們需要等很長(zhǎng)時(shí)間。Phoenix 4.5以后有一個(gè)異步創(chuàng)建索引的方式菜秦,使用關(guān)鍵字ASYNC來(lái)創(chuàng)建索引:

CREATE INDEX my_index ON t_employee(salary desc) async;
SELECT * FROM my_index;

? 這時(shí)候創(chuàng)建的索引表中不會(huì)有數(shù)據(jù)甜害。你還必須要單獨(dú)的使用命令行工具來(lái)執(zhí)行數(shù)據(jù)的創(chuàng)建。當(dāng)語(yǔ)句給執(zhí)行的時(shí)候球昨,后端會(huì)啟動(dòng)一個(gè)map reduce任務(wù)唾那,只有等到這個(gè)任務(wù)結(jié)束,數(shù)據(jù)都被生成在索引表中后褪尝,這個(gè)索引才能被使用。啟動(dòng)工具的方法:

${HBASE_HOME}/bin/hbase org.apache.phoenix.mapreduce.index.IndexTool \
  --schema wolfcode_mdb --data-table t_employee --index-table my_index \
  --output-path /async_idx_hfiles

這個(gè)任務(wù)不會(huì)因?yàn)榭蛻舳私o關(guān)閉而結(jié)束期犬,是在后臺(tái)運(yùn)行河哑。你可以在指定的文件ASYNC_IDX_HFILES中找到最終實(shí)行的結(jié)果。

3.7.JDBC API的實(shí)現(xiàn)

  1. 添加依賴龟虎。

    <dependency>
        <groupId>org.apache.phoenix</groupId>
        <artifactId>phoenix-core</artifactId>
        <version>4.14.1-HBase-1.2</version>
    </dependency>
    
  2. 添加日志璃谨。

    ### set log levels ###
    log4j.rootLogger = debug ,  stdout ,  D ,  E
    
    ### 輸出到控制臺(tái) ###
    log4j.appender.stdout = org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.Target = System.out
    log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern =  %d{ABSOLUTE} %5p %c 1 :%L - %m%n
    
  3. 因?yàn)橹胺?wù)端已經(jīng)添加了支持分組的功能,所以還要添加hbase-site.xml文件鲤妥。

    <configuration>
        <property>
            <name>hbase.regionserver.wal.codec</name>
            <value>org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec</value>
        </property>
        <!-- 指定啟動(dòng)分組功能 -->
        <property>
            <name>phoenix.schema.isNamespaceMappingEnabled</name>
            <value>true</value>
        </property>
    </configuration>
    
  4. 測(cè)試JDBC客戶端連接狀況:

    public class ConnectionTest {
    
        public static void main(String[] args) {
            Connection conn=null;
            Statement stmt = null;
            try {
                Class.forName("org.apache.phoenix.jdbc.PhoenixDriver");
                conn = DriverManager
                        .getConnection("jdbc:phoenix:hdp01,hdp02,hdp03:2181");
                stmt = conn.createStatement();
                ResultSet rs = stmt.executeQuery("select * from wolfcode_mdb.t_employee");
                while (rs.next()) {
                    String name = rs.getString("name");
                    double salary = rs.getDouble("salary");
                    String gender = rs.getString("gender");
                    System.out.println("name:" + name + ",salary:" + salary + ",gender:" + gender);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                try {
                    stmt.close();
                    conn.close();
                }catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    
    }
    
  5. 測(cè)試CURD:

    public class CURDTest {
    
        private Connection _conn = null;
        private PreparedStatement _stmt = null;
    
        @Before
        public void init() {
            try {
                Class.forName("org.apache.phoenix.jdbc.PhoenixDriver");
                _conn = DriverManager
                            .getConnection("jdbc:phoenix:hdp01,hdp02,hdp03:2181");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        @Test
        public void testQuery() throws SQLException {
            String sql = "select * from wolfcode_mdb.t_employee";
            _stmt = _conn.prepareStatement(sql);
            ResultSet rs = _stmt.executeQuery();
            while (rs.next()) {
                String name = rs.getString("name");
                double salary = rs.getDouble("salary");
                String gender = rs.getString("gender");
                System.out.println("name:" + name + ",salary:" + salary + ",gender:" + gender);
            }
        }
    
        @Test
        public void testInsert() {
            try {
                String sql = "upsert into wolfcode_mdb.t_employee values (?,?,?,?)";
                _stmt = _conn.prepareStatement(sql);
                _stmt.setLong(1, 6);
                _stmt.setString(2, "趙無(wú)眠");
                _stmt.setDouble(3, 9700.00d);
                _stmt.setString(4, "F");
                _stmt.execute();
                // 如無(wú)自動(dòng)提交任務(wù)佳吞,是不會(huì)生效的。
                _conn.commit();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    
        @Test
        public void testDelete() {
            try {
                String sql = "delete from wolfcode_mdb.t_employee where name=?";
                _stmt = _conn.prepareStatement(sql);
                _stmt.setString(1, "趙無(wú)眠");
                _stmt.execute();
                // 如無(wú)自動(dòng)提交任務(wù)棉安,是不會(huì)生效的底扳。
                _conn.commit();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    
        @Test
        public void testUpdate() {
            try {
                //更新數(shù)據(jù)必須攜帶主鍵,否則更新失敗
                String sql = "upsert into wolfcode_mdb.t_employee(id,name) values(?,?)";
                _stmt = _conn.prepareStatement(sql);
                _stmt.setLong(1, 1);
                _stmt.setString(2, "張三");
                _stmt.execute();
                // 如無(wú)自動(dòng)提交任務(wù)贡耽,是不會(huì)生效的衷模。
                _conn.commit();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    
    
        @After
        public void destory() {
            try {
                if (null != _stmt && !_stmt.isClosed()) {
                    _stmt.close();
                }
                if (null != _conn && !_conn.isClosed()) {
                    _conn.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    
    }
    

4. 加鹽表

什么是加鹽鹊汛?

加鹽可以簡(jiǎn)單的理解為加密。

舉個(gè)例子阱冶,假設(shè)我們要做一個(gè)人員管理系統(tǒng)刁憋,將用戶登陸的賬號(hào)密碼直接保存到數(shù)據(jù)庫(kù)上,用戶登陸時(shí)先去數(shù)據(jù)庫(kù)匹配木蹬,成功則登陸至耻。但是實(shí)際的應(yīng)用系統(tǒng)中這是非常不安全的,賬戶密碼不論是在數(shù)據(jù)庫(kù)中存儲(chǔ)還是在網(wǎng)上傳輸過(guò)程中都應(yīng)該是密文而不能是明文镊叁。

一般都是采用MD5或者SHA加密算法把密碼加密尘颓,我們把這種方式稱之為加鹽,這個(gè)鹽一般是一個(gè)字符串意系,在本案例中泥耀,該字符串是固定的,我們稱之為固定鹽蛔添。

固定鹽也是不安全的痰催,因?yàn)榫W(wǎng)上也有各種在線MD5解密的網(wǎng)站,黑客可以通過(guò)這些解密網(wǎng)站對(duì)密碼進(jìn)行破解測(cè)試迎瞧。這時(shí)就可以采用動(dòng)態(tài)加鹽的方式來(lái)增加密碼的安全性夸溶,比如,我們可以將需要這個(gè)固定的字符串改為每個(gè)用戶的賬號(hào)凶硅。每個(gè)用戶都需要用一個(gè)庫(kù)去比較缝裁,大大增加了破解所有賬戶的難度。

Phoenix的加鹽有什么好處足绅?

傳統(tǒng)的加鹽主要是用來(lái)增加數(shù)據(jù)的安全性捷绑,而Phoenix中加鹽是指對(duì)primary key對(duì)應(yīng)的字節(jié)數(shù)組插入特定的byte數(shù)據(jù)。因?yàn)閜rimary key底層對(duì)應(yīng)的是HBase的row key氢妈。在插入數(shù)據(jù)的時(shí)候粹污,單調(diào)遞增rowkey會(huì)存儲(chǔ)在某一個(gè)RS上,使得負(fù)載集中在某一個(gè)RegionServer上引起的熱點(diǎn)問題首量。加鹽可以解決這一問題壮吩。

怎么對(duì)表加鹽?

在創(chuàng)建表的時(shí)候指定屬性值:SALT_BUCKETS加缘,其值表示所分buckets(region)數(shù)量鸭叙, 范圍是1~256。
use wolfcode_mdb;
CREATE TABLE t_scores(id varchar primary key,student varchar,scores varchar array[3]) salt_buckets = 4;

加鹽的過(guò)程就是在原來(lái)key的基礎(chǔ)上增加一個(gè)byte作為前綴,計(jì)算公式如下:

new_row_key = (++index % BUCKETS_NUMBER) + original_key

原理:

05.png

測(cè)試:

upsert into t_scores values('100','aaa',ARRAY['75','75','75']);
upsert into t_scores values('200','bbb',ARRAY['75','75','75']);
upsert into t_scores values('300','ccc',ARRAY['75','75','75']);
upsert into t_scores values('400','ddd',ARRAY['75','75','75']);
upsert into t_scores values('500','eee',ARRAY['75','75','75']);
upsert into t_scores values('600','fff',ARRAY['75','75','75']);
upsert into t_scores values('700','ggg',ARRAY['75','75','75']);
upsert into t_scores values('800','hhh',ARRAY['75','75','75']);
upsert into t_scores values('900','iii',ARRAY['75','75','75']);

驗(yàn)證Region的個(gè)數(shù):

06.png

想獲取更多技術(shù)干貨拣宏,請(qǐng)前往叩丁狼官網(wǎng):http://www.wolfcode.cn/all_article.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末沈贝,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子勋乾,更是在濱河造成了極大的恐慌缀程,老刑警劉巖搜吧,帶你破解...
    沈念sama閱讀 216,997評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異杨凑,居然都是意外死亡滤奈,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門撩满,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蜒程,“玉大人,你說(shuō)我怎么就攤上這事伺帘≌烟桑” “怎么了?”我有些...
    開封第一講書人閱讀 163,359評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵伪嫁,是天一觀的道長(zhǎng)领炫。 經(jīng)常有香客問我,道長(zhǎng)张咳,這世上最難降的妖魔是什么帝洪? 我笑而不...
    開封第一講書人閱讀 58,309評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮脚猾,結(jié)果婚禮上葱峡,老公的妹妹穿的比我還像新娘。我一直安慰自己龙助,他們只是感情好砰奕,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評(píng)論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著提鸟,像睡著了一般军援。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上称勋,一...
    開封第一講書人閱讀 51,258評(píng)論 1 300
  • 那天盖溺,我揣著相機(jī)與錄音,去河邊找鬼铣缠。 笑死,一個(gè)胖子當(dāng)著我的面吹牛昆禽,可吹牛的內(nèi)容都是我干的蝗蛙。 我是一名探鬼主播,決...
    沈念sama閱讀 40,122評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼醉鳖,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼捡硅!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起盗棵,我...
    開封第一講書人閱讀 38,970評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤壮韭,失蹤者是張志新(化名)和其女友劉穎北发,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體喷屋,經(jīng)...
    沈念sama閱讀 45,403評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡琳拨,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了屯曹。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片狱庇。...
    茶點(diǎn)故事閱讀 39,769評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖恶耽,靈堂內(nèi)的尸體忽然破棺而出密任,到底是詐尸還是另有隱情,我是刑警寧澤偷俭,帶...
    沈念sama閱讀 35,464評(píng)論 5 344
  • 正文 年R本政府宣布浪讳,位于F島的核電站,受9級(jí)特大地震影響涌萤,放射性物質(zhì)發(fā)生泄漏淹遵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評(píng)論 3 327
  • 文/蒙蒙 一形葬、第九天 我趴在偏房一處隱蔽的房頂上張望合呐。 院中可真熱鬧,春花似錦笙以、人聲如沸淌实。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)拆祈。三九已至,卻和暖如春倘感,著一層夾襖步出監(jiān)牢的瞬間放坏,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工老玛, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留淤年,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,831評(píng)論 2 370
  • 正文 我出身青樓蜡豹,卻偏偏與公主長(zhǎng)得像麸粮,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子镜廉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • JDBC簡(jiǎn)介 SUN公司為了簡(jiǎn)化弄诲、統(tǒng)一對(duì)數(shù)據(jù)庫(kù)的操作,定義了一套Java操作數(shù)據(jù)庫(kù)的規(guī)范娇唯,稱之為JDBC齐遵。JDBC...
    奮斗的老王閱讀 1,518評(píng)論 0 51
  • 內(nèi)存泄漏 為什么會(huì)產(chǎn)生內(nèi)存泄漏寂玲? 當(dāng)一個(gè)對(duì)象已經(jīng)不需要再使用了,本該被回收時(shí)梗摇,而有另外一個(gè)正在使用的對(duì)象持有它的引...
    桑享閱讀 213評(píng)論 0 0
  • 當(dāng)蜘蛛網(wǎng)無(wú)情地爬封了我的爐臺(tái)拓哟,當(dāng)黑暗的余煙嘆息著生命的悲哀,我堅(jiān)信你依舊能夠用凝霜的枯藤留美,在凄涼的大地上寫下:我絕...
    Amber520閱讀 329評(píng)論 0 1
  • 論武俠我最愛古龍的武俠谎砾,但他的小說(shuō)我也只看過(guò)那幾部逢倍。《三少爺?shù)膭Α凡皇俏业淖類劬巴迹踔潦俏易顭o(wú)感和莫名其妙的一部较雕。當(dāng)...
    涼州喵閱讀 393評(píng)論 0 0
  • 前言 時(shí)隔一年多,第一篇評(píng)測(cè)就拿著名的桌游《三國(guó)殺》IP衍生而來(lái)的《三國(guó)殺傳奇》開刀吧挚币。周所周知亮蒋,移動(dòng)平臺(tái)上的《...
    onlinew閱讀 729評(píng)論 1 5