標籤: 網頁設計

  • 阻塞隊列一——java中的阻塞隊列

    阻塞隊列一——java中的阻塞隊列

    目錄

    • 阻塞隊列簡介:介紹阻塞隊列的特性與應用場景
    • java中的阻塞隊列:介紹java中實現的供開發者使用的阻塞隊列
    • BlockQueue中方法:介紹阻塞隊列的API接口
    • 阻塞隊列的實現原理:具體的例子說明阻塞隊列的實現原理
    • 總結

    阻塞隊列簡介

    阻塞隊列(BlockingQueue)首先是一個支持先進先出的隊列,與普通的隊列完全相同;
    其次是一個支持阻塞操作的隊列,即:

    • 當隊列滿時,會阻塞執行插入操作的線程,直到隊列不滿。
    • 當隊列為空時,會阻塞執行獲取操作的線程,直到隊列不為空。

    阻塞隊列用在多線程的場景下,因此阻塞隊列使用了鎖機制來保證同步,這裏使用的可重入鎖;
    而對於阻塞與喚醒機制則有與鎖綁定的Condition實現

    應用場景:生產者消費者模式

    java中的阻塞隊列

    java中的阻塞隊列根據容量可以分為有界隊列和無界隊列:

    • 有界隊列:隊列中只能存儲有限個元素,超出后存放元素線程會被阻塞或者失敗。
    • 無界隊列:隊列中可以存儲無限個元素。

    java8中提供了7種阻塞隊列阻塞隊列供開發者使用,如下錶:

    類名 描述
    ArrayBlockingQueue 一個由數組結構組成的有界阻塞隊列
    LinkedBlockingQueue 由鏈表結構組成的有界阻塞隊列(默認大小Integer.MAX_VALUE)
    PriorityBlockingQueue 支持優先級排序的無界阻塞隊列
    DelayQueue 使用優先級隊列實現的延遲無界阻塞隊列
    SynchronousQueue 不存儲元素的阻塞隊列,即單個元素的隊列
    LinkedTransferQueue 由鏈表結構組成的無界阻塞隊列
    LinkedBlockingDeque 由鏈表結構組成的雙向阻塞隊列

    另外還有一個在ScheduledThreadPoolExecutor中實現的DelayedWorkQueue阻塞隊列,
    但這個阻塞隊列開發者不能使用。它們之間的UML類圖如下圖:

    BlockingQueue接口是阻塞隊列對外的訪問接口,所有的阻塞隊列都實現了BlockQueue中的方法

    BlockQueue中方法

    作為一個隊列的核心方法就是入隊和出隊。由於存在阻塞策略,BlockQueue將出隊入隊的情況分為了四組,每組提供不同的方法:

    • 拋出異常:當隊列滿時,如果再往隊列中插入元素,則拋出IllegalStateException異常;
      當隊列為空時,從隊列中獲取元素則拋出NoSuchElementException異常。

    • 返回特定值(布爾值):當隊列滿時,如果再往隊列中插入元素,則返回false;當隊列為空時,從隊列中獲取元素則返回null。

    • 一直阻塞:當隊列滿時,如果再往隊列中插入元素,阻塞當前線程直到隊列中至少一個被移除或者響應中斷退出;
      當隊列為空時,則阻塞當前線程直到至少一個元素元素入隊或者響應中斷退出。

    • 超時退出:當隊列滿時,如果再往隊列中插入元素,阻塞當前線程直到隊列中至少一個被移除或者達到指定的等待時間退出或者響應中斷退出;
      當隊列為空時,則阻塞當前線程直到至少一個元素元素入隊或者達到指定的等待時間退出或者響應中斷退出。

    對於每種情況BlockingQueue提供的方法如下錶:

    方法\處理方式 拋出異常 返回特定值(布爾值) 一直阻塞 超時退出
    插入 add(e) offer(e) put(e) offer(e,time,unit)
    移除 remove() poll() take() poll(time.unit)
    檢查 element() peek() 不可用 不可用

    上述方法一般用於生產者-消費者模型中,是其中的生產和消費操作隊列的核心方法。
    除了這些方法,BlockingQueue還提供了一些其他的方法如下錶:

    方法名稱 描述
    remove(Object o) 從隊列中移除一個指定值
    size() 獲取隊列中元素的個數
    contains(Object o) 判斷隊列是否包含指定的元素,但是這個元素在這次判斷完可能就會被消費
    drainTo(Collection<? super E> c) 將隊列中元素放在給定的集合中,並返回添加的元素個數
    drainTo(Collection<? super E> c, int maxElements) 將隊列中元素取maxElements(不超過隊列中元素個數)個放在給定的集合中,並返回添加的元素個數
    remainingCapacity() 計算隊列中還可以存放的元素個數
    toArray() 以objetc數組的形式獲取隊列中所有的元素
    toArray(T[] a) 以給定類型數組的方式獲取隊列中所有的元素
    clear() 清空隊列,危險的操作

    阻塞隊列的實現原理

    阻塞隊列的實現依靠通知模式實現:當生產者向滿了的隊列中添加元素時,會阻塞住生產者,
    直到消費者消費了一個隊列中的元素後會通知消費者隊列可用,此時再由生產者向隊列中添加元素。反之亦然。

    阻塞隊列的阻塞喚醒依靠Condition——條件隊列來實現。

    ArrayBlockingQueue為例說明:

    ArrayBlockingQueue的定義:

    public class ArrayBlockingQueue<E> extends AbstractQueue<E>
            implements BlockingQueue<E>, java.io.Serializable {
       
        /** The queued items */
        //以數組的結構存儲隊列的元素,採用的是循環數組
        final Object[] items;
    
        /** items index for next take, poll, peek or remove */
        //隊列的隊頭索引
        int takeIndex;
    
        /** items index for next put, offer, or add */
        //隊列的隊尾索引
        int putIndex;
    
        /** Number of elements in the queue */
        //隊列中元素的個數
        int count;
    
        /** Main lock guarding all access */
        //對於ArrayBlockingQueue所有的操作都需要加鎖,
        final ReentrantLock lock;
    
        /** Condition for waiting takes */
        //條件隊列,當隊列為空時阻塞消費者並在生產者生產後喚醒消費者
        private final Condition notEmpty;
    
        /** Condition for waiting puts */
        //條件隊列,當隊列滿時阻塞生產者,並在消費者消費隊列后喚醒生產者
        private final Condition notFull;
    }
    

    根據類的定義字段可以看到,有兩個Condition條件隊列,猜測以下過程

    • 當隊列為空,消費者試圖消費時應該調用notEmpty.await()方法阻塞,並在生產者生產後調用notEmpty.single()方法
    • 當隊列已滿,生產者試圖放入元素應調用notFull.await()方法阻塞,並在消費者消費隊列后調用notFull.single()方法

    向隊列中添加元素put()方法的添加過程。

        /**
        * 向隊列中添加元素
        * 當隊列已滿時需要阻塞當前線程
        * 放入元素后喚醒因隊列為空阻塞的消費者
        */
        public void put(E e) throws InterruptedException {
            checkNotNull(e);
            final ReentrantLock lock = this.lock;
            lock.lockInterruptibly();
            try {
                //當隊列已滿時需要notFull.await()阻塞當前線程
                //offer(e,time,unit)方法就是阻塞的時候加了超時設定
                while (count == items.length)
                    notFull.await();
                //放入元素的過程
                enqueue(e);
            } finally {
                lock.unlock();
            }
        }
        
        /**enqueue實際添加元素的方法*/
        private void enqueue(E x) {
            // assert lock.getHoldCount() == 1;
            // assert items[putIndex] == null;
            final Object[] items = this.items;
            items[putIndex] = x;
            if (++putIndex == items.length)
                putIndex = 0;
            count++;
            //如果條件隊列中存在等待的線程
            //喚醒
            notEmpty.signal();
        }
    

    從隊列中獲取元素take()方法的獲取過程。

        /**
        * 從隊列中獲取元素
        * 當隊列已空時阻塞當前線程
        * 從隊列中消費元素后喚醒等待的生產線程
        */
        public E take() throws InterruptedException {
            final ReentrantLock lock = this.lock;
            lock.lockInterruptibly();
            try {
                //隊列為空需要阻塞當前線程
                while (count == 0)
                    notEmpty.await();
                //獲取元素的過程
                return dequeue();
            } finally {
                lock.unlock();
            }
        }
        
        /**dequeue實際消費元素的方法*/
        private E dequeue() {
           // assert lock.getHoldCount() == 1;
           // assert items[takeIndex] != null;
           final Object[] items = this.items;
           @SuppressWarnings("unchecked")
           E x = (E) items[takeIndex];
           items[takeIndex] = null;
           if (++takeIndex == items.length)
               takeIndex = 0;
           count--;
           if (itrs != null)
               itrs.elementDequeued();
           //消費元素后從喚醒阻塞的生產者線程
           notFull.signal();
           return x;
        }
    

    總結

    阻塞隊列提供了不同於普通隊列的增加、刪除元素的方法,核心在與隊列滿時阻塞生產者和隊列空時阻塞消費者。
    這一阻塞過程依靠與鎖綁定的Condition對象實現。Condition接口的實現在AQS中實現,具體的實現類是
    ConditionObject

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※別再煩惱如何寫文案,掌握八大原則!

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※超省錢租車方案

    ※教你寫出一流的銷售文案?

    網頁設計最專業,超強功能平台可客製化

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • 程序員過關斬將–作為一個架構師,我是不是應該有很多職責?

    每一個程序員都有一個架構夢。

    上面其實本質上是一句富有事實哲理的廢話,要不然也不會有這麼多人關注你的公眾號。這些年隨着“企業数字化”轉型的口號,一大批企業奔跑在轉型的路上,希望領先一步對手將企業IT部門從單純的成本中心轉變為業務驅動者,而這個過程中,企業的架構師起着舉足輕重的作用。架構師的工作在很多擼碼的開發者眼中是很一項很神聖的工作,而且富有挑戰性。

    但是事物都有兩面性,很多管理者和技術人員都認為架構師的薪酬不符合實際,有很多架構師確實只會用PPT和大幅海報來應付了事,而且會依仗着在公司地位把自己的一些想法強加給公司其他同事,有的架構師甚至會追求一些無關緊要的概念,在高層和底層灌輸一些錯誤的思想,從而導致做出一些不可逆轉的糟糕決策,使公司陷入危險逆境。

    很多時候,公司給予架構師這個角色太多的責任,管理者希望他們能在突發性能問題時能快速解決問題,還能推動企業快速轉型,甚至能幫助企業文化的快速建立,作為一個架構師是不是要抗下這些職責呢?

    我不是項目經理

    架構師的日常工作經常會面臨并行處理多個不同維度的問題,這些問題可能是不同的主題,甚至在做決策的時候也需要考慮人員的分配,項目時間表的排期,需要用的核心技術以及組件等。有很多高層領導喜歡直接在架構師這裏獲取項目的詳細信息以及技術方案,雖然架構師角色涉及這些信息並且很了解這些信息,但是這並不是架構師的職責所在,甚至很多情況下令架構師處於項目經理的尷尬角色。

    我不是開發人員

    我想很多人看過那篇文章:作為架構師該不該寫代碼?很多架構師是出身於開發人員,這也難怪會出現這樣的疑問。但是,架構師其實和資深開發是兩條不同的職業路線,我認為兩者沒有高低之分。出色的開發人員需要很深的開發功力,需要最終交付出可運行的軟件。而架構師則需要更廣闊的知識面,更好的組織戰略思想,更好的溝通能力。在一個產品的開發流水線上,架構師可能會負責一部分核心代碼的編寫,但是最主要的工作還是保證這條流水線的正常運轉。

    我不是救火員

    由於架構師這個角色在公司的地位,很多管理者認為架構師要隨時隨地的能分析並解決任何突發的問題,不瞞各位,這種現象在很多大廠依然存在,包括我司(雖然只是一個四線小廠)。如果一個架構師每天都忙着“救火”這種工作,根本沒有時間去做真正的架構工作,真正的架構設計需要思考,是不可能在短短時間內完成的。但是架構師必須接受出現的產品問題,因為這些問題的產生有可能和架構有着直接關係,在很大程度上能反應架構的缺陷或者問題。

    寫在最後

    架構師作為企業中很重要的一環,在很多重大技術問題中都作為決策者而存在。很難用代碼的多少或者質量來衡量一個架構師的好壞,如果一個系統在正常運行5年後依然能良好運行並且可以承受一定的變更能力,說明這個系統的架構師的工作是很出色的。如果非要給架構師定義一個KPI標準的話,以下這些工作也許能成為一個參考

    1. 定義IT戰略。小到一個系統的組件列表可行性的確定,大到公司技術的發展方向,乃至未來10年公司技術的預測與大膽嘗試。這些技術戰略都需要架構師根據自身經驗來制定。

    2. 落實對IT藍圖的管控,以實現協調一致,降低複雜度,保證公司所有系統有條不紊的正常工作,架構師的工作之一就是要把複雜度降低,化繁為簡,這需要架構師很強的抽象能力。

    3. 關注項目的實際落地情況,並根據項目實施中反饋的問題進行戰略的適當調整。一個合格的架構師從來不會忽略來自實際項目中的問題反饋。

    架構師一定要避免和消除那些系統設計中不可逆轉的錯誤決策

    來源參考:架構師應該知道的37件事

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

    南投搬家公司費用需注意的眉眉角角,別等搬了再說!

    ※教你寫出一流的銷售文案?

  • Autoware 標定工具 Calibration Tool Kit 聯合標定 Robosense-16 和 ZED 相機!

    Autoware 標定工具 Calibration Tool Kit 聯合標定 Robosense-16 和 ZED 相機!

    一、安裝 Autoware & ZED 內參標定 & 外參標定準備

    之前的這篇文章:Autoware 進行 Robosense-16 線雷達與 ZED 雙目相機聯合標定! 記錄了我用 Autoware 標定相機和雷達的過程,雖然用的不是 Calibration Tool Kit 工具,但是博客裏面的以下章節也適用本次的 Calibration Tool Kit :

    • 一、編譯安裝 Autoware-1.10.0
    • 二、標定 ZED 相機內參
    • 3.1 聯合標定準備

    如果你是第一次看這篇 Calibration Tool Kit 聯合標定的博客,建議先按照之前的博客安裝 Autoware、標定 ZED 內參和做好外參標定的準備(標定板,錄製標定包等),最好用上篇博客的方法標定一次。

    這篇博客我就直接開始介紹使用 Calibration Tool Kit 標定雷達和相機外參的過程!

    二、Calibration Tool Kit 聯合標定雷達和 ZED 相機

    2.1 啟動 Autoware

    先啟動 Autoware-1.10.0,啟動過程中可能需要輸入 root 密碼:

    # 1. 進入 autoware 的 ros 目錄下
    cd autoware-1.10.0/ros
    
    # 2. source 環境,zsh 或 bash
    source devel/setup.zsh[.bash]
    
    # 3. 啟動主界面
    ./run
    

    切換到 Sensing 選項卡:

    2.2 回放雷達相機 Bag

    這裏回放時需要更改雷達的話題為 /points_raw,因為這個工具訂閱的雷達主題是固定的:

    rosbag play --pause xxx.bag /rslidar_points:=/points_raw
    

    我用的 Robosense 雷達,發布的話題是 rslidar_points,這個回放默認暫停,防止跑掉數據,按空格繼續或暫停。

    2.3 啟動 Calibration Tool Kit

    點擊 Calibration Tool Kit 啟動標定工具:

    選擇圖像輸入話題,我只用的 ZED 的左圖像話題,如果沒有相機話題,確保前面你已經回放了 bag,選擇好了點擊 OK 確定:

    選擇標定類型為相機到 velodyne 雷達的標定(對 Robosense 雷達也適用,只不過需要更改點雲的發布話題),點擊 OK 確定:

    進入標定主界面 MainWindow:

    配置標定板棋盤格參數:

    • Pattern Size(m):標定板中每個格子的邊長,單位 m,我的標定板每個格子長 0.025 m
    • Pattern Number:標定板長X寬的單元格數量 – 1,我的標定板是長有 12 個格子,寬有 9 個,所以填 11×8,減一是因為標定檢測的是內部角點

    設置好了后,重啟 Calibration Tool Kit,點擊左上角 Load 導入第一步標定的相機內參 YAML 文件,但是這個工具只能導入 YML 格式的文件:

    因此需要把前面的內參標定文件拷貝一份,修改格式為 yml 即可,YAML 和 YML 其實是一樣的:

    修改好了之後,再點擊 Load 加載 yml 格式的內參文件即可:

    選擇不加載相機和雷達的標定數據,因為我是直接回放 Bag 標定:

    到這裏都設置好了,下面開始外參標定過程!

    2.4 標定過程

    打開回放 bag 終端,按空格繼續回放數據,主界面會显示相機圖像:

    但是右邊的點雲窗口沒有显示數據,需要我們調整視角才可以,視角的調整方法如下(文末有個 pdf 專門介紹):

    簡單解釋下,建議直接操作,很容易:

    • 移動點雲:上下左右方向鍵、PgUp、PgDn
    • 旋轉點雲:a、d、w、s、q、e
    • 切換模式:数字 1 和数字 2
    • 視角縮放:減號縮小、加號放大
    • 點雲大小:o 鍵使用小點雲、p 使用大點雲
    • 改變點雲窗口背景顏色:b

    我使用的使用直接按数字 2 切換模式就能看到點雲了,其實這些模式我也不是很懂。。。:

    如果需要更換背景,按 b 鍵改變為大致灰色即可:

    我這裏就不改背景了,黑色也挺好看出點雲的,然後使用上面的視角操作方法,把點雲中的標定板放大到中心位置:

    之後點擊右上角的 Grab 捕獲當前幀的圖像和點雲,使用 -+ 縮放視角:

    如果你點擊 grab 沒反應很正常,可能是棋盤格離得太遠或者模糊了,你多試幾個位置應該就能捕獲到,我回放一個 Bag 也就捕獲了 9 張左右。

    然後把鼠標放到右下角捕獲的點雲窗口,選擇一個棋盤格的中心位置區域,關於這個區域的選擇,我是參考這個標定工具的文檔例子(文末有鏈接)選擇的,大概就是標定板的中心位置選擇一個圓形的區域,盡量保證向外側的平面法向量垂直於標定板平面:

    鼠標左鍵點擊選擇,右鍵點擊取消,我的選擇如下,可以參考:

    然後重複以上步驟,不斷回放暫停,Grab 捕獲單幀圖像和點雲(多選一些),選擇點雲區域,直到回放結束,接着就可以點擊右上角的「Calibrate」按鈕計算外參矩陣(左上角显示),然後再點擊「Project」查看標定效果:

    切換左下方的單幀圖片和點雲窗口,捕獲的每一幀圖像和點雲都可以看到對齊效果,另外左邊也能看到標定的誤差,當然是越小越好,我目前的標定效果一般般,後續打算再標幾次。

    標定好之後,點擊左上角「save」保存外參矩陣即可,文件名建議帶上時間戳方便識別:

    最後的外參數文件如下,這個文件包含了相機內參和相機到雷達的外參:

    以上就是我的雷達相機聯合標定過程!希望能幫助正在標定雷達和相機的同學 ^_^!

    三、標定結果測試

    可以直接用之前博客 Autoware 進行 Robosense-16 線雷達與 ZED 雙目相機聯合標定! 中的「四、標定結果測試」一節介紹的步驟來測試融合效果:

    前幾天我把 ROS 的點雲和圖像的融合節點也調試好了,所以直接在程序裏面加載了外參矩陣,然後做了個初步的融合,效果如下:

    我也錄了個融合視頻,可以看看:B 站:Robosense-16 雷達與 ZED 相機數據融合。

    五、標定資源

    以下是我標定過程中收集的一些好的資料,這裏也分享給大家:

    • 標定工具的使用文檔在這裏:CalibrationToolkit_Manual.pdf
    • 這裏還有個視頻,有條件的同學可以看看:Yutobe:Autoware 標定相機和雷達

    另外 ROS 融合節點的程序我還在完善中,建議關注我的 Github 項目,後續會上傳節點代碼:AI-Notes: lidar_camera_fusion,如果標定遇到問題,可以公眾號後台給我發消息,或者直接在博客平台留言,我看到會儘快回復的,不過公眾號應該回復的快些,哈哈 :)

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※想知道最厲害的網頁設計公司"嚨底家"!

    ※別再煩惱如何寫文案,掌握八大原則!

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • SpringBoot 2.3 整合最新版 ShardingJdbc + Druid + MyBatis 實現分庫分表

    SpringBoot 2.3 整合最新版 ShardingJdbc + Druid + MyBatis 實現分庫分表

      今天項目不忙,想搞一下shardingJDBC分庫分表看看,主要想實現以下幾點:

    1. 捨棄xml配置,使用.yml或者.properties文件+java的方式配置spring。
    2. 使用 Druid 作為數據庫連接池,同時開啟監控界面,並支持監控多數據源。
    3. 不依賴 com.dangdangsharding-jdbc-core 包。此包過於古老,最後一次更新在2016年。目測只是封裝了一層,意義不大。感覺如果不是dangdang公司內部開發,沒必要用這個包。(且本人實測不能和最新的Druid包一起用,insert語句報錯)

      折騰了半天,網上找的例子大部分跑不通。直接自己從零開搞,全部組件直接上當前最新版本。

      SpringBoot: 2.3.0

      mybatis: 2.1.3

      druid: 1.1.22

      sharding-jdbc: 4.1.1

      注意:這裏因為是自己邊看源碼邊配置,(sharding官網的例子可能是版本問題基本沒法用,GitHub 我這裏網絡基本打不開),所以數據源和sharding大部分用java代碼配置。了解配置原理后,也可以簡化到 .yml / .properties 文件中。

    Sharding-JDBC簡介

      Apache ShardingSphere 是一套開源的分佈式數據庫中間件解決方案組成的生態圈,它由 JDBC、Proxy 和 Sidecar(規劃中)這 3 款相互獨立,卻又能夠混合部署配合使用的產品組成。

      Sharding-JDBC定位為輕量級 Java 框架,在 Java 的 JDBC 層提供的額外服務。 它使用客戶端直連數據庫,以 jar 包形式提供服務,無需額外部署和依賴,可理解為增強版的 JDBC 驅動,完全兼容 JDBC 和各種 ORM 框架。

    • 適用於任何基於 JDBC 的 ORM 框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template 或直接使用 JDBC。
    • 支持任何第三方的數據庫連接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP 等。
    • 支持任意實現JDBC規範的數據庫。目前支持 MySQL,Oracle,SQLServer,PostgreSQL 以及任何遵循 SQL92 標準的數據庫。

    Sharding配置示意圖

      簡單的理解如下圖,對sharding-jdbc進行配置,其實就是對所有需要進行分片的表進行配置。對錶的配置,則主要是對分庫的配置和分表的配置。這裏可以只分庫不分表,或者只分表不分庫,或者同時包含分庫和分表邏輯。

     

      先看一下我的項目目錄結構整體如下:

      

    一、POM依賴配置

      完整的pom表如下,其中主要是對 mysql-connector-java、mybatis-spring-boot-starter、druid-spring-boot-starter、sharding-jdbc-core 的依賴。

      注意:sharding-jdbc-core 我用的4.0+的版本,因為已經晉陞為 apache 基金會的頂級項目,其 groupId 變為了 org.apache.shardingsphere,之前是io.shardingsphere。

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.3.0.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.example</groupId>
        <artifactId>shardingjdbc</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>shardingjdbc</name>
        <description>Demo project for Spring Boot</description>
    
        <properties>
            <!--<sharding.jdbc.version>3.0.0</sharding.jdbc.version>-->
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-tx</artifactId>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>2.1.3</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>1.1.22</version>
            </dependency>
            <dependency>
                <groupId>org.apache.shardingsphere</groupId>
                <artifactId>sharding-jdbc-core</artifactId>
                <version>4.1.1</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
                <exclusions>
                    <exclusion>
                        <groupId>org.junit.vintage</groupId>
                        <artifactId>junit-vintage-engine</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.16</version>
            </dependency>
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-log4j12</artifactId>
                <version>1.7.5</version>
            </dependency>
        </dependencies>
    
        <build>
            <resources>
                <resource>
                    <directory>src/main/java</directory>
                    <includes>
                        <include>**/*.xml</include>
                    </includes>
                </resource>
            </resources>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>

    pom.xml

    二、application.properties

      這裏配置了兩個數據源,為避免和自動裝配產生衝突,屬性前綴要和自動裝配掃描的前綴區分開,這裏我用 datasource0datasource1

      下面 spring.datasource.druid 開頭的配置,會被 druid 的代碼自動掃描裝配。

    #################################### common config : ####################################
    spring.application.name=shardingjdbc
    # 應用服務web訪問端口
    server.port=8080
    
    # mybatis配置
    mybatis.mapper-locations=classpath:com/example/shardingjdbc/mapper/*.xml
    mybatis.type-aliases-package=com.example.shardingjdbc.**.entity
    
    datasource0.url=jdbc:mysql://localhost:3306/test0?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
    datasource0.driver-class-name=com.mysql.cj.jdbc.Driver
    datasource0.type=com.alibaba.druid.pool.DruidDataSource
    datasource0.username=root
    datasource0.password=852278
    
    datasource1.url=jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
    datasource1.driver-class-name=com.mysql.cj.jdbc.Driver
    datasource1.type=com.alibaba.druid.pool.DruidDataSource
    datasource1.username=root
    datasource1.password=852278
    
    #
    ##### 連接池配置 #######
    # 過濾器設置(第一個stat很重要,沒有的話會監控不到SQL)
    spring.datasource.druid.filters=stat,wall,log4j2
    
    ##### WebStatFilter配置 #######
    #啟用StatFilter
    spring.datasource.druid.web-stat-filter.enabled=true
    #添加過濾規則
    spring.datasource.druid.web-stat-filter.url-pattern=/*
    #排除一些不必要的url
    spring.datasource.druid.web-stat-filter.exclusions=*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*
    #開啟session統計功能
    spring.datasource.druid.web-stat-filter.session-stat-enable=true
    #缺省sessionStatMaxCount是1000個
    spring.datasource.druid.web-stat-filter.session-stat-max-count=1000
    #spring.datasource.druid.web-stat-filter.principal-session-name=
    #spring.datasource.druid.web-stat-filter.principal-cookie-name=
    #spring.datasource.druid.web-stat-filter.profile-enable=
    
    ##### StatViewServlet配置 #######
    #啟用內置的監控頁面
    spring.datasource.druid.stat-view-servlet.enabled=true
    #內置監控頁面的地址
    spring.datasource.druid.stat-view-servlet.url-pattern=/druid/*
    #關閉 Reset All 功能
    spring.datasource.druid.stat-view-servlet.reset-enable=false
    #設置登錄用戶名
    spring.datasource.druid.stat-view-servlet.login-username=admin
    #設置登錄密碼
    spring.datasource.druid.stat-view-servlet.login-password=123
    #白名單(如果allow沒有配置或者為空,則允許所有訪問)
    spring.datasource.druid.stat-view-servlet.allow=127.0.0.1
    #黑名單(deny優先於allow,如果在deny列表中,就算在allow列表中,也會被拒絕)
    spring.datasource.druid.stat-view-servlet.deny=

    三、數據源和分片配置

      如下代碼,先從配置文件讀取數據源的所需要的屬性,然後生成 Druid 數據源。注意這裏配置語句中的 setFilters,如果不添加 filters,則 Duird 監控界面無法監控到sql。另外,其他諸如最大連接數之類的屬性這裏沒有配,按需配置即可。數據源創建好后,添加到 dataSourceMap 集合中。

      再往下註釋比較清楚,構造 t_user 表的分片規則(包括分庫規則 + 分表規則),然後將所有表的分片規則組裝成 ShardingRuleConfiguration

      最後,將前兩步配好的 dataSourceMapshardingRuleConfiguration 交給 ShardingDataSourceFactory,用來構造數據源。

      到這裏,sharding 、druid 的配置代碼就都寫好了。剩下基本都是業務代碼了。

    package com.example.shardingjdbc.config;
    
    import com.alibaba.druid.pool.DruidDataSource;
    import com.example.shardingjdbc.sharding.UserShardingAlgorithm;
    import org.apache.shardingsphere.api.config.sharding.ShardingRuleConfiguration;
    import org.apache.shardingsphere.api.config.sharding.TableRuleConfiguration;
    import org.apache.shardingsphere.api.config.sharding.strategy.StandardShardingStrategyConfiguration;
    import org.apache.shardingsphere.shardingjdbc.api.ShardingDataSourceFactory;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import javax.sql.DataSource;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Properties;
    
    @Configuration
    public class DataSourceConfig {
        @Value("${datasource0.url}")
        private String url0;
        @Value("${datasource0.username}")
        private String username0;
        @Value("${datasource0.password}")
        private String password0;
        @Value("${datasource0.driver-class-name}")
        private String driverClassName0;
    
        @Value("${datasource1.url}")
        private String url1;
        @Value("${datasource1.username}")
        private String username1;
        @Value("${datasource1.password}")
        private String password1;
        @Value("${datasource1.driver-class-name}")
        private String driverClassName1;
    
        @Value(("${spring.datasource.druid.filters}"))
        private String filters;
    
        @Bean("dataSource")
        public DataSource dataSource() {
            try {
                DruidDataSource dataSource0 = new DruidDataSource();
                dataSource0.setDriverClassName(this.driverClassName0);
                dataSource0.setUrl(this.url0);
                dataSource0.setUsername(this.username0);
                dataSource0.setPassword(this.password0);
                dataSource0.setFilters(this.filters);
    
                DruidDataSource dataSource1 = new DruidDataSource();
                dataSource1.setDriverClassName(this.driverClassName1);
                dataSource1.setUrl(this.url1);
                dataSource1.setUsername(this.username1);
                dataSource1.setPassword(this.password1);
                dataSource1.setFilters(this.filters);
    
                //分庫設置
                Map<String, DataSource> dataSourceMap = new HashMap<>(2);
                //添加兩個數據庫database0和database1
                dataSourceMap.put("ds0", dataSource0);
                dataSourceMap.put("ds1", dataSource1);
    
                // 配置 t_user 表規則
                TableRuleConfiguration userRuleConfiguration = new TableRuleConfiguration("t_user", "ds${0..1}.t_user${0..1}");
                // 配置分表規則
                userRuleConfiguration.setTableShardingStrategyConfig(new StandardShardingStrategyConfiguration("id", UserShardingAlgorithm.tableShardingAlgorithm));
                // 配置分庫規則
                userRuleConfiguration.setDatabaseShardingStrategyConfig(new StandardShardingStrategyConfiguration("id", UserShardingAlgorithm.databaseShardingAlgorithm));
                // Sharding全局配置
                ShardingRuleConfiguration shardingRuleConfiguration = new ShardingRuleConfiguration();
                shardingRuleConfiguration.getTableRuleConfigs().add(userRuleConfiguration);
                // 創建數據源
                DataSource dataSource = ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfiguration, new Properties());
                return dataSource;
            } catch (Exception ex) {
                ex.printStackTrace();
                return null;
            }
        }
    }

    DataSourceConfig.java

      上面構造分片規則的時候,我定義了User表的分片算法類 UserShardingAlgorithm,並定義了兩個內部類分別實現了數據庫分片和表分片的邏輯。代碼如下:

    package com.example.shardingjdbc.sharding;
    
    import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
    import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
    
    import java.util.Collection;
    
    public class UserShardingAlgorithm {
        public static final DatabaseShardingAlgorithm databaseShardingAlgorithm = new DatabaseShardingAlgorithm();
        public static final TableShardingAlgorithm tableShardingAlgorithm = new TableShardingAlgorithm();
    
        static class DatabaseShardingAlgorithm implements PreciseShardingAlgorithm<Long> {
            @Override
            public String doSharding(Collection<String> databaseNames, PreciseShardingValue<Long> shardingValue) {
                for (String database : databaseNames) {
                    if (database.endsWith(String.valueOf(shardingValue.getValue() % 2))) {
                        return database;
                    }
                }
    
                return "";
            }
        }
    
        static class TableShardingAlgorithm implements PreciseShardingAlgorithm<Long> {
            @Override
            public String doSharding(Collection<String> tableNames, PreciseShardingValue<Long> shardingValue) {
                for (String table : tableNames) {
                    if (table.endsWith(String.valueOf(shardingValue.getValue() % 2))) {
                        return table;
                    }
                }
    
                return "";
            }
        }
    }

    UserShardingAlgorithm.java

      這裏實現分片規則時,實現的接口是 PreciseShardingAlgorithm,即精確分片,將指定的鍵值記錄映射到指定的1張表中(最多1張表)。這個接口基本上能滿足80%的需求了。

      其他的還有 Range、ComplexKey、Hint分片規則,這3種都可以將符合條件的鍵值記錄映射到多張表,即可以將記錄 a 同時插入A、B 或 B、C多張表中。

      其中,

        Range 是範圍篩選分片。我個人理解,比如id尾數1-5插入A表,6-0插入B表,這種情況,使用Range作為篩選條件更方便。也可以根據時間範圍分片。(如有誤請指正)。

        ComplexKey 看名字就是組合鍵分片,可以同時根據多個鍵,制定映射規則。

        Hint 看名字沒看懂,但看源碼其實也是組合鍵分片,但僅支持對組合鍵進行精確篩選。

        而 ComplexKey 支持對組合鍵進行範圍篩選。所以可以理解為 ComplexKey 是 Hint 的高級版本。  

      不管實現哪種分片算法,都要確保算法覆蓋所有可能的鍵值。

    四、使用行表達式配置分片策略(對第三步優化,可略過)

        上面第三步,我們通過實現 PreciseShardingValue 接口,來定義分片算法。這樣每有一張表需要分片,都要重新定義一個類,太麻煩。

      Sharding 提供了行表達式配置的方式,對簡單的分片邏輯,直接定義一個行表達式即可。(這種方式其實就是直接在 .yml 文件中配置分片策略的解析方式)

      和上面的代碼類似,這裏之改動了6、8行,直接 new 一個 InlineShardingStrategyConfiguration,省去了定義分片算法類的繁瑣步驟。

     

     1              // .....省略其他代碼
     2  
     3             // 配置 t_user 表規則
     4             TableRuleConfiguration userRuleConfiguration = new TableRuleConfiguration("t_user", "ds${0..1}.t_user${0..1}");
     5             // 行表達式分表規則
     6             userRuleConfiguration.setTableShardingStrategyConfig(new InlineShardingStrategyConfiguration("id", "t_user${id % 2}"));
     7             // 行表達式分庫規則
     8             userRuleConfiguration.setDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration("id", "ds${id % 2}"));
     9 
    10             // Sharding全局配置
    11             ShardingRuleConfiguration shardingRuleConfiguration = new ShardingRuleConfiguration();
    12             shardingRuleConfiguration.getTableRuleConfigs().add(userRuleConfiguration);
    13             // 創建數據源
    14             DataSource dataSource = ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfiguration, new Properties());
    15             return dataSource;

    五、分佈式主鍵(雪花算法)

      分庫后,不能再使用 mysql 的自增主鍵,否則會產生重複主鍵。自定義主鍵,主要需要解決兩個問題:

    1. 主鍵唯一(必須)
    2. 主鍵單調遞增(可選)(提升索引效率,減少索引重排產生的空間碎片)

      Sharding 內部提供了2個主鍵生成器,一個使用雪花算法 SnowflakeShardingKeyGenerator,一個使用 UUID(考慮上面第2條,因此不使用 UUID)。

      雪花算法的主要原理:用一個 64 bit 的 long 型数字做主鍵。其中,

        第 1 位,1 bit 作為符號位永遠為 0,表示是正數。

        第 2 – 42 位, 41 個 bit 填充時間戳。

        第 43 – 52 位,10 個 bit 填充機器唯一id。舉個例子,可以用前4位標識機房號,后6位標識機器號。

        第 53 – 64 位,12 個 bit 填充id序號。範圍 0 – 4095,即每台機器每 1 毫秒最多生成 4096 個不同的主鍵id。

      雪花算法的主要實現代碼如下

    1. 先判斷時鐘是否回調。這裏默認容忍回調時間為0,如有回調則會產生異常。可以通過配置 max.tolerate.time.difference.milliseconds 屬性,讓其自旋等待時鐘回到上一次執行時間。
    2. 按當前毫秒數,遞增生成id序號。如果時鐘進入了下一毫秒,則從0開始重新生成id序號,範圍 0 – 4095。
    3. 將 時間戳 + 機器序號 + id序號 拼裝成 主鍵id。這裏機器序號默認為0,可以通過 worker.id 屬性進行配置。不同的服務器需要配置成不同的数字,範圍 0 – 1023。

      其中 EPOCH 是時鐘起點,sharding中設置的是2016年11月1日,那麼41位的時間戳差不多可以用70年,一直到2086年。

        public synchronized Comparable<?> generateKey() {
            long currentMilliseconds = timeService.getCurrentMillis();
            if (this.waitTolerateTimeDifferenceIfNeed(currentMilliseconds)) {
                currentMilliseconds = timeService.getCurrentMillis();
            }
    
            if (this.lastMilliseconds == currentMilliseconds) {
                if (0L == (this.sequence = this.sequence + 1L & 4095L)) {
                    currentMilliseconds = this.waitUntilNextTime(currentMilliseconds);
                }
            } else {
                this.vibrateSequenceOffset();
                this.sequence = (long)this.sequenceOffset;
            }
    
            this.lastMilliseconds = currentMilliseconds;
            return currentMilliseconds - EPOCH << 22 | this.getWorkerId() << 12 | this.sequence;
        }

    六、業務代碼

      使用分佈式的主鍵ID生成器,需要給不同的表注入不同的ID生成器,在config包下加一個KeyIdConfig類,如下:

      (為了保持時鐘的統一,可以專門找一台機器作為時鐘服務,然後給所有主鍵生成器配置統一的時鐘服務。下圖中未配置,如需配置,直接調用setTimeService方法即可)

    @Configuration
    public class KeyIdConfig {
        @Bean("userKeyGenerator")
        public SnowflakeShardingKeyGenerator userKeyGenerator() {
            return new SnowflakeShardingKeyGenerator();
        }
    
        @Bean("orderKeyGenerator")
        public SnowflakeShardingKeyGenerator orderKeyGenerator() {
            return new SnowflakeShardingKeyGenerator();
        }
    }

      其他業務代碼,整體如下:

    package com.example.shardingjdbc.entity;
    
    import lombok.Data;
    
    import java.io.Serializable;
    import java.util.Date;
    
    @Data
    public class User implements Serializable {
        private Long id;
        private String name;
        private String phone;
        private String email;
        private String password;
        private Integer cityId;
        private Date createTime;
        private Integer sex;
    }

    User.java

    package com.example.shardingjdbc.mapper;
    
    import com.example.shardingjdbc.entity.User;
    import org.apache.ibatis.annotations.Mapper;
    
    import java.util.List;
    
    public interface UserMapper {
        /**
         * 保存
         */
        void save(User user);
    
        /**
         * 查詢
         * @param id
         * @return
         */
        User get(Long id);
    }

    UserMapper.java

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.example.shardingjdbc.mapper.UserMapper">
        <resultMap id="resultMap" type="com.example.shardingjdbc.entity.User">
            <id column="id" property="id" />
            <result column="name" property="name" />
            <result column="phone" property="phone"  />
            <result column="email" property="email"  />
            <result column="password" property="password"  />
            <result column="city_id" property="cityId"  />
            <result column="create_time" property="createTime"  />
            <result column="sex" property="sex"  />
        </resultMap>
    
        <insert id="save">
            insert into t_user (id, name, phone, email, password, city_id, create_time, sex)
            values (#{id}, #{name}, #{phone}, #{email}, #{password}, #{cityId}, #{createTime}, #{sex})
        </insert>
    
        <select id="get" resultMap="resultMap">
            select *
            from t_user
            where id = #{id}
        </select>
    </mapper>

    UserMapper.xml

     1 package com.example.shardingjdbc.controller;
     2 
     3 import com.example.shardingjdbc.entity.User;
     4 import com.example.shardingjdbc.mapper.UserMapper;
     5 import org.apache.shardingsphere.core.strategy.keygen.SnowflakeShardingKeyGenerator;
     6 import org.springframework.beans.factory.annotation.Autowired;
     7 import org.springframework.stereotype.Controller;
     8 import org.springframework.web.bind.annotation.PathVariable;
     9 import org.springframework.web.bind.annotation.RequestMapping;
    10 import org.springframework.web.bind.annotation.ResponseBody;
    11 
    12 import javax.annotation.Resource;
    13 import java.util.Date;
    14 
    15 @Controller
    16 public class UserController {
    17     @Autowired
    18     private UserMapper userMapper;
    19 
    20     @Resource
    21     SnowflakeShardingKeyGenerator userKeyGenerator;
    22 
    23     @RequestMapping("/user/save")
    24     @ResponseBody
    25     public String save() {
    26         for (int i = 0; i < 50; i++) {
    27             Long id = (Long)userKeyGenerator.generateKey();
    28             User user = new User();
    29             user.setId(id);
    30             user.setName("test" + i);
    31             user.setCityId(i);
    32             user.setCreateTime(new Date());
    33             user.setSex(i % 2 == 0 ? 1 : 2);
    34             user.setPhone("11111111" + i);
    35             user.setEmail("xxxxx");
    36             user.setCreateTime(new Date());
    37             user.setPassword("eeeeeeeeeeee");
    38             userMapper.save(user);
    39         }
    40 
    41         return "success";
    42     }
    43 
    44     @RequestMapping("/user/get/{id}")
    45     @ResponseBody
    46     public User get(@PathVariable Long id) {
    47         User user = userMapper.get(id);
    48         return user;
    49     }
    50 }

    UserController.java

     1 CREATE TABLE `t_user` (
     2   `id` bigint(20) NOT NULL,
     3   `name` varchar(64) DEFAULT NULL COMMENT '名稱',
     4   `city_id` int(12) DEFAULT NULL COMMENT '城市',
     5   `sex` tinyint(1) DEFAULT NULL COMMENT '性別',
     6   `phone` varchar(32) DEFAULT NULL COMMENT '電話',
     7   `email` varchar(32) DEFAULT NULL COMMENT '郵箱',
     8   `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '創建時間',
     9   `password` varchar(32) DEFAULT NULL COMMENT '密碼',
    10   PRIMARY KEY (`id`)
    11 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    t_user.sql

      啟動類如下:

     1 package com.example.shardingjdbc;
     2 
     3 import org.mybatis.spring.annotation.MapperScan;
     4 import org.springframework.boot.SpringApplication;
     5 import org.springframework.boot.autoconfigure.SpringBootApplication;
     6 
     7 @MapperScan("com.example.shardingjdbc.mapper")
     8 @SpringBootApplication
     9 public class ShardingjdbcApplication {
    10     public static void main(String[] args) {
    11         SpringApplication.run(ShardingjdbcApplication.class, args);
    12     }
    13 }

    ShardingjdbcApplication .java

      注意,這裏我在啟動類上加了 @MapperScan 註解。可能是因為引用依賴的問題,.properties 配置的 mybatis 包掃描目錄不管用了,後面有時間再研究。

    七、其他

      除了基本的分庫分表規則以外,還有一些其他的配置,比如綁定表。這裏先不詳細解釋了,舉個簡單的例子:

      現在有 order, order_detail兩張表,1 : 1的關係。

      在配置的時候,應該將相同 order_id 的 order 記錄 和 order_detail 記錄 映射到相同尾號的表中,方便連接查詢。

      比如 id % 2 = 1的,都插入到  order0, order_detail0 中。

      如果配置了綁定關係,那麼查找 id = 1 的記錄,只會產生一次查詢 select * from order0 as o join order_detail0 as d  on o.order_id = d.order_id where o.oder_id = 1。

      否則會產生笛卡兒積查詢, 

        select * from order0 as o join order_detail0 as d  on o.order_id = d.order_id where o.order_id = 1

        select * from order0 as o join order_detail1 as d  on o.order_id = d.order_id where o.order_id = 1

        select * from order1 as o join order_detail0 as d  on o.order_id = d.order_id where o.order_id = 1

        select * from order1 as o join order_detail1 as d  on o.order_id = d.order_id where o.order_id = 1

    八、總結

      項目啟動前,先創建數據庫 test0, test1, 然後分別建表 t_user0, t_user1。 可以全部在同一台機器。

      項目啟動后,訪問 http://localhost:8080/user/save, id 是 偶數的都插入到了 test0 庫的 t_user0 表中, 奇數的都插入到了 test1 庫中的 t_user1 表中。

      druid 的後台監控頁面地址: http://localhost:8080/druid/。

      項目啟動后,sharding日誌會將配置已 yml 格式的形式打印出來,也可以省去 java 配置,將其優化到 .yml 配置文件中去,如下圖:

      

      本文原文地址:https://www.cnblogs.com/lyosaki88/p/springboot_shardingjdbc_druid_mybatis.html

      源碼下載地址:https://474b.com/file/14960372-448059323

      作者QQ: 116269651

     

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※別再煩惱如何寫文案,掌握八大原則!

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※超省錢租車方案

    ※教你寫出一流的銷售文案?

    網頁設計最專業,超強功能平台可客製化

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • 7.98萬起產品力不輸哈弗H6,這款SUV車主是怎樣評價的?

    7.98萬起產品力不輸哈弗H6,這款SUV車主是怎樣評價的?

    最不滿意的地方:起步有點肉,而且這個時候發動機聲音是比較大的。所以感覺上這個發動機實際動力還是比較一般的,而且發動機倉隔音也是比較一般。車主:老兵哥購買車型:北汽幻速S6 2017款 1。5T CVT樂享型裸車購買價:10。

    前言

    作為國內的造車大戶,北汽奉行着“多生孩兒多掙錢”的政策,有注重一般家用市場的北汽紳寶、有注重硬派SUV市場的北京汽車、還有着北汽幻速以及北汽比速這兩個入門品牌。那麼作為一個比較年輕的品牌,北汽幻速的口碑究竟怎樣呢?今天筆者就搜集了幾位北汽幻速S6車主的意見,這款7.98萬起售的緊湊型SUV有着該價位中不俗的競爭力。全系標配的是1.5T發動機,而且有着CVT變速箱作為自動擋的選擇。

    那麼多孩子,打起群架肯定贏

    北汽銀翔幻速S6

    官方指導價:7.98-11.68萬

    編者意見:

    性價比較高,動力表現在同價位中表現比較優秀。不過全系沒能標配ESp車身穩定系統以及电子助力轉向比較可惜。

    車主:BY2000

    購買車型:北汽幻速S6 2017款 1.5T CVT尊享型

    裸車購買價11.68 萬元

    最滿意的地方:整體都比較滿意,但是最滿意的的是價格,性價比很高。能在這個價格買到這樣配置的緊湊型SUV還是不錯的,而且是渦輪增壓發動機。

    最不滿意的地方:起步有點肉,而且這個時候發動機聲音是比較大的。所以感覺上這個發動機實際動力還是比較一般的,而且發動機倉隔音也是比較一般。

    車主:老兵哥

    購買車型:北汽幻速S6 2017款 1.5T CVT樂享型

    裸車購買價:10.68 萬元

    最滿意的地方:乘坐空間,沒有想到這個價格的車還能有着那麼大的空間,滿載的情況下也不是很擁擠。而且後備箱容積也是相當可觀,大天窗還有那麼多的配置,買這款車真的是比較值。

    最不滿意的地方:裝配工藝有待加強,有些部分的縫隙是比較大的,就如尾門的縫隙,看着很掉價,而且方向盤塑料感太強了。

    車主:smg20900

    購買車型:北汽幻速S6 2017款 1.5T CVT尊享型

    裸車購買價:10.68 萬元

    最滿意的地方:外觀,看着更像是二十多萬的SUV。能給人更多的面子,而且在動力方面感覺還是不錯的,一直都可以維持在較低轉速,120km/h時速下轉速也只是2200rpm左右,這個是最為滿意的,所以綜合油耗上也是9L左右,對於一款SUV來說是滿意了。

    最不滿意的地方:儲物空間實在是少得可憐,中間只有一個杯架,不夠用。其次是噪音的問題,不過對於如此便宜的車來說,還是可以接受的。

    編者總結:

    北汽雖然是個歷史悠長的品牌,但事實基本是為別人“代工”,自身在工藝方面以及控製成本方面還是需要向合資學習,所以在做工以及隔音用料上表現一般。不過在主要的發動機上表現卻是相當不錯,雖然渦輪遲滯現象還是有的,但是油耗表現卻是令人信服的。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※為什麼 USB CONNECTOR 是電子產業重要的元件?

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※台北網頁設計公司全省服務真心推薦

    ※想知道最厲害的網頁設計公司"嚨底家"!

    ※推薦評價好的iphone維修中心

  • 我敢說這幾款是2016年最成功的自主車型!你同不同意?

    我敢說這幾款是2016年最成功的自主車型!你同不同意?

    如果要盤點2016年自主品牌中最有設計感的車型,寶駿510必定首當其沖。這款定位僅在6萬左右的SUV,居然擁有如此前衛和新潮的設計,不得不佩服上汽高層的決策。叫獸在後台大家對510的評論中可以預料到,這必將又是一款未上市已成爆款的車型。

    又到了辭舊迎新的日子,我們即將迎來嶄新的2017年。回望2016,汽車圈內發生了不少大事,也湧現出了非常多的好車。其中不少中國品牌的表現尤其搶眼,叫獸似乎從它們身上看到了正在崛起的“Made in China”,讓我對2017充滿期待。

    如今GS4甚至成了傳祺的代名詞,目前傳祺絕大部分的銷量和產能均來自GS4。廣汽同樣也審時度勢,在“SUV熱”持續不降的情形下推出了GS8。這款以中大型7座SUV身份登場的GS8,憑藉非常符合國人審美的大氣造型迅速俘獲了眾多青睞。

    據說現在GS8也是一車難求的狀態,訂單量已經排到了明年開年以後。傳祺現在的當務之急是儘快擴大產量,以保證GS4和GS8的銷量需求。對了,傳祺全新的MpV – GM8也將在明年初上市,2017將是廣汽傳祺非常有挑戰和希望的一年。

    SUV市場已經成為兵家必爭之地,幾乎所有中國品牌都在這看到了“彎道超車”的希望。最典型的如哈弗H6成了月銷超7萬的“無敵神車”(叫獸的印象中只有五菱達到過這樣的成績)。

    在殺得“頭破血流”的SUV爭奪中,想成為爆款可沒那麼簡單。榮威旗下的最新SUV – RX5,通過全新的面貌以及有馬雲“加持”的首款量產互聯網SUV身份登場,從北京車展亮相便收穫了極大關注。上市兩個月後,成為月銷破2萬的“黑馬”,風頭甚至蓋過了博越。

    廣州車展亮相的首款量產互聯網轎車 – 榮威i6和MG 推出的最新互聯網SUV – ZS再次成為焦點。以上3款車型雖然都打着互聯網的旗號,但叫獸相信互聯網只是錦上添花,真正讓它們成為“網紅”的是上汽旗下產品設計以及品質的全面提升。要知道,這些才是一款車成功的根本。

    寶駿是諸多中國品牌中比較特殊的存在,它身上流淌着上汽、通用以及五菱三家的血液。自730熱銷以及SUV 560成為“黑馬”后,寶駿也頻頻進入大眾的視線。

    這都不算啥,真正讓寶駿走向公眾焦點的是310。這款擁有超高顏值的入門小車,以3.68萬的起售價贏得了無數年輕消費者的關注和喜愛。要知道如今入門級轎車市場已經沒有幾款拿得出手的車型了。而310的推出將成為不少第一次買車的消費者的最新選擇,叫獸甚至認為它還影響到部分二手車的銷量。事實上,310已經連續兩個月月銷破萬,這樣的成績對早已被“邊緣化”的A0級市場無疑是一劑強心針。

    如果要盤點2016年自主品牌中最有設計感的車型,寶駿510必定首當其沖。這款定位僅在6萬左右的SUV,居然擁有如此前衛和新潮的設計,不得不佩服上汽高層的決策。叫獸在後台大家對510的評論中可以預料到,這必將又是一款未上市已成爆款的車型。

    2016是吉利最“吉利”的一年,去年上市的首款“3.0精品”車型 – 博瑞成了吉利集團成立近20年最重要的分水嶺之一。收購沃爾沃之後,吉利“蟄伏”5年終於放出了“大招”,以一款中高級轎車博瑞拉開了“3.0精品”的序幕。

    吉利的選擇很大膽,以高開高走的策略打造全新的精品之路。幸運的是博瑞成功了,甚至成為中國品牌汽車發展多年來首款真正成功的進軍高端的轎車。家族旗艦的成功,也將吉利帶入了一個新的高度,隨後以“3.0精品”身份誕生的博越、帝豪GS、帝豪GL以及僅僅只能算是改款的遠景SUV無一不成為月銷過萬的爆款車型。

    銷量說明一切。11月,吉利月銷量首次突破10萬大關,不僅老李笑得合不攏嘴,對整个中國品牌來說都是一件值得驕傲的事情。

    10月20號,吉利正“春風得意”的時候,總裁安聰慧在德國召開了一場“舉世奪目”的發布會,推出了全新高端品牌- LYNK & CO並亮相兩款概念車。LYNK & CO的目標對手為大眾、豐田等,從此吉利集團旗下品牌將覆蓋到各個檔次。

    我想說老李的野心可真不小。無論如何,吉利為中國品牌起了個好頭,值得我們肯定,加油吧。

    以上是2016年裡關注度最高的幾个中國品牌。誠然從銷量上它們已經達到和超越與外國品牌競爭的水平,甚至不少車型在價格上比大眾等一線合資品牌還要“堅挺”。這是好事,一來反映出中國品牌已經逐漸被廣大消費者認可,再也不用靠低價吸引顧客;二來說明中國品牌車型的造車水準和品牌影響有了質的提升,這才是最根本也是最重要的。

    誇了這麼多,叫獸也不得不提醒一句,雖然中國品牌看似在這兩年集體爆發,但細心的你一定會發現成功的品牌和車型大部分都靠的是SUV。迎合市場潮流成功固然可取,但全面均衡的發展更重要。偏科可不是優秀生,只有SUV、轎車、MpV多領域的成功才是真正的“三好學生”。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

    南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

    ※教你寫出一流的銷售文案?

    ※超省錢租車方案

  • 這輛售價不到10萬的SUV能帶你勇闖雪地

    這輛售價不到10萬的SUV能帶你勇闖雪地

    針對行駛方面,外后視鏡電加熱、360°全景影像、9寸大屏、車內氛圍燈、無鑰匙進入+一鍵啟動、天窗、定速巡航、發動機怠速啟停等配置都一應俱全,真正的讓駕駛人員也感受得到森雅R7帶來的那份舒適。穩定可靠的動力系統森雅R7搭載代號為CA4GB16的直列4缸1。

    俗話說真金不怕火煉,就是說真正好的東西,是經得起考驗的。那對於汽車來說,“火煉”明顯不是現實的考驗方案,真正想檢驗一輛車的極限性能,-20攝氏度下的冰雪試駕就是最好的方法。

    在嚴寒環境中,鋼鐵、橡膠、塑料都會變脆,一些平時看上去不起眼的顛簸、磕碰都可能會造成斷開、破裂。可以說,嚴寒用車環境是對整車品質的全面考驗,直接體現廠家的專業化造車水準。就在12月17日,森雅R7“柒待•玩美之行”冰雪試駕活動就在平均積雪厚度達2米,雪量堪稱中國之最的雪鄉舉行。

    這輛售價不到十萬的SUV,憑什麼有信心能在冰天雪地下讓我們檢驗它的實力?

    7位一體的智能主動安全系統

    大家都知道冰雪路面極其濕滑,即使車子換上了雪地胎,車輛依然很容易發生側滑或者甩尾等現象,如果沒有及時的控制好車輛,事故的發生就在頃刻之間。那麼在這個時候,主動安全配置就發揮了重要的作用,這一次在雪鄉試駕的森雅R7就搭載了比較全面的主動安全系統。其中就包括了ABS防抱死、EBD制動力分配、ESp車身穩定系統、牽引力控制、剎車輔助、上坡輔助、胎壓監測等。

    在雪鄉試駕的時候就體現了森雅R7這些主動安全配置的作用,整個車身給的感覺都是穩定可控的,即使在濕滑的路面車子也能按照駕駛者的意願來行駛。而縱觀國內的各大汽車品牌,能夠在售價十萬不到的車型齊全配備這七大主動安全配置的品牌並不多,所以森雅R7在這方面的表現可謂相當厚道。

    人性化的設計,讓駕乘人員更加舒適

    在寒冷的冰天雪地里行駛的話,溫暖和舒適往往是最能夠打動人心的,而在舒適性的配置方面,森雅R7絲毫沒有吝嗇。森雅R7自動擋車型配有6向調節駕駛座椅並搭配了腰部支撐和座椅加熱功能,即使在冰天雪地也能提供溫暖、舒適的乘坐感受,另外,自動空調、後排足部的採暖出風口等配置都體現了森雅R7的人性化設計思想。

    針對行駛方面,外后視鏡電加熱、360°全景影像、9寸大屏、車內氛圍燈、無鑰匙進入+一鍵啟動、天窗、定速巡航、發動機怠速啟停等配置都一應俱全,真正的讓駕駛人員也感受得到森雅R7帶來的那份舒適。

    穩定可靠的動力系統

    森雅R7搭載代號為CA4GB16的直列4缸1.6L自然吸氣發動機,最大馬力為116ps,最大扭矩為155N•m,由一汽自主研發的這台發動機勝在輸出線性,質量可靠,搭配技術同樣成熟的愛信第三代6AT手自一體變速器,換擋邏輯聰明,動力傳輸平順。這讓駕駛員在駕駛的過程中沒有後顧之憂,能夠盡情的征戰冰雪。

    實際駕駛過程中,由於該車的油門調教比較靈敏,所以整車的動力響應不會給人慵懶、遲滯的感覺,而是偏向於輕快的調性。第三代的愛信6AT手自一體變速箱是最新一代產品,動力輸出平順,沒有頓挫,該變速箱的升擋時機比較遲,偏向高轉速的輸出會讓車輛有更加积極的動力響應。

    回歸到靜態:高原創度的設計

    自主品牌被詬病山寨抄襲已是家常便飯,森雅R7卻沒有同流合污,在外觀的自主設計方面下了不少功夫。外觀由大眾控股的IDG公司設計,在森雅R7身上找不到一絲山寨的痕迹。

    前臉的整體感很強,大燈-中網一體式的設計,而且採用了微微上揚的線條,頗像一張笑臉。車頭大燈為鹵素光源,但帶有日間行車燈,配合上流線形的造型,科技感十足。

    側面的造型則能看出車身的比例十分協調,通過硬朗的線條和突出的輪拱展現了森雅R7的力量美。

    車尾的造型圓潤飽滿,尾燈採用LED光源,點亮效果很好,而且尾燈的造型也是和頭燈前後呼應的,頗有心思。

    總結

    試駕過森雅R7之後,最大的感觸是這輛車的配置實在豐富,特別是在寒冷的冬天,當你坐進一輛車子之後發現它是有座椅加熱功能的,那種感覺是既驚喜又感動的。而森雅R7就是這麼一輛車,以不到十萬的價格,不僅有全面的主動安全配置,在動力系統方面還搭載了最新一代的愛信6AT手自一體變速箱,可以說森雅R7是一汽給我們帶來的又一款誠意之作。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※Google地圖已可更新顯示潭子電動車充電站設置地點!!

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※別再煩惱如何寫文案,掌握八大原則!

    網頁設計最專業,超強功能平台可客製化

  • 為什麼我心目中的年度車型一定會有他?

    為什麼我心目中的年度車型一定會有他?

    在材料與結構上的極致輕量化,不僅帶來更低的能耗,關鍵在於輕量化與高剛性的車身是整車高性能的基礎。與車身科技一樣, ESS II智能安全、安吉星4G LTE移動互聯等產品優勢都是CT6家族全系共享的。此外,三款車在技術與調教上有相同的底蘊,也造就了共通的調性,豪華舒適但不失操控的樂趣。

    轉眼又到車市年終盤點的時候了,循例會收到很多平台年度車型的評選邀請,凱迪拉克CT6在我的榜單中從來不會缺席。之所以會選CT6,不是因為其中一款車型,而是在這個級別中, CT6家族中每一款車的產品力在其所在細分市場都處於領先地位。今日,CT6插電式混合動力(plug-in)正式上市,售價55.88-65.88萬元。隨着這款pHEV的加入,凱迪拉克CT6家族變得更加完善,我也覺得是時候與大家聊一下這款我心目中的年度車型。

    凱迪拉克CT6 plug-in雖然是CT6家族中的首個新能源車型,但這個級別中本身也有不少插電式混動的車型,為何偏偏要選TA? 其實仔細分析一下豪華插電混動細分市場的車型就很容易明白了,特別是德系选手,這裏就不點名批評了,在汽油車型的基礎上加個電機和電池就叫pHEV了,電機夾在變速箱和發動機之間的串聯式結構,整套傳動系統都是來自供應商,簡單粗暴完全沒有技術含量,無論是發動機還是電機驅動的效率都很低,對能源的利用效率甚至不如普通汽油車型,充其量只能說是大環境下逼出來的產物。

    舉例說明,同樣是pHEV的車型,CT6 plug-in與寶馬的iperformance的理念則完全不一樣,凱迪拉克的performance Hybrid對新能源的理解屬於性能趨向,直接打造出一款技術含量最高,專為插電式混動打造的解決方案,其power Split動力分流技術可以說是目前最先進的電驅動科技,CT6 plug-in也是細分市場內的最強單品。而反觀寶馬iperformance,自成都車展大規模發布新車后,收效甚微,因為其多款產品都是由燃油車加一個電機,技術含量相對較低。我們可以理解iperformance更多是為了迎合排放政策,博眼球的戰術,而非精心打造的產品,其戰略意義更明顯。但CT6 plug-in對細分市場向高性能發展的長期引領作用,未來將會越來越明顯。很顯然,新能源行業是得技術者得天下。

    相比之下,CT6 plug-in這套系統在結構上具有絕對的領先優勢,其搭載的DHT變速箱其實與本家的HEV有異曲同工之妙,兩種動力耦合的關鍵在於行星齒輪組,從而實現power Split動力分流技術,3排行星齒輪與5組離合器不只是簡單的耦合動力,配合智能電控系統更可以實現四種智能能量輸出狀態(純電力驅動、發動機驅動、混合動力驅動以及智能能量回收),在各種複雜的工況下都有最合適的動力組合去適應,通用是混動領域內首次將這個概念進行量產的廠商。

    此外,CT6 plug-in的整套動力系統是圍繞performance Hybrid(性能駕享)豪華新能源研發策略開發的,得益於三組行星齒輪組的動力耦合結構,兩台電機與2.0T SIDI 渦輪增壓直噴發動機可以共同發力驅動車輛,最大扭矩達586Nm,靠着電機瞬間爆發的扭矩,百公里加速只需5.4s,在同級中性能無出其右。對於追求駕控樂趣的人而言,例如我,對如此高性能自然是無抗拒之力的。

    除了DHT變速箱先進的結構,還需要強大的控制系統,CT6 plug-in的智能電控系統通過TpIM驅動能量轉換模塊協同電驅單元與發動機的高效工作,帶來更加智能的動力組合路徑,也能實現比傳統燃油車更平順的駕駛體驗。此外,CT6 plug-in還擁有巡航、運動、電量保持三種駕駛模式,讓駕駛者在任何工況下都能享受更多駕駛樂趣。

    同樣是源自performance Hybrid這個理念, 強於一般混動車型的還有電池,CT6 plug-in搭載18.4kWh大容量鋰離子電池,能量密度遠超其他混動車型搭載的鎳氫電池,可以提供80Km的純電里程,綜合續航里程能夠達到935km。雖與特斯拉一樣是鋰離子電池,但其BMS電池熱管理及液冷技術,可通過3組冷液循環系統進行散熱,這在全球都是處於領先地位的。其實電池技術和汽油機也有共通之處,越高的性能相對就需要越強的冷卻效果,要知道布加迪的W12發動機可是配了11個散熱器,這套熱管理系統能更好的配合高密度的鋰離子電池,適應高性能的輸出。

    誠然,憑藉著這套業界領先的高性能混動系統,CT6 plug-in就足以讓我對其傾心,但CT6的能力卻不止於此。輕量化一直是近幾年汽車工業的一大主題,車身技術一直是我非常看重的技術點,在其他條件相仿的情況下,輕量化做的越好,車子的動態響應自然就會更好。

    因此CT6全系都擁有宇航級輕量化車身,這在我的選車之道中無疑是關鍵的加分點。鋁材用量超過57%,11種混合材質輕量化車身,通過獨特的專利技術,首次實現了鋼、鋁兩種不同材質的焊接。在材料與結構上的極致輕量化,不僅帶來更低的能耗,關鍵在於輕量化與高剛性的車身是整車高性能的基礎。

    與車身科技一樣, ESS II智能安全、安吉星4G LTE移動互聯等產品優勢都是CT6家族全系共享的。此外,三款車在技術與調教上有相同的底蘊,也造就了共通的調性,豪華舒適但不失操控的樂趣。而我之所以視CT6為年度車型,是因在此基礎上,家族各成員又都有不同的亮點。

    其中凱迪拉克CT6 40T作為凱迪拉克的,乃至整個通用車系的旗艦車型,集成了通用的所有科技技術,在同級中無出其右,追求的是技術的巔峰。搭載3.0T雙渦輪增壓發動機不僅擁有405ps和543N·m的傲人數據,配合閉缸技術與自動啟停,兼顧性能與油耗。除了車身材質與結構的高度輕量化, ARS主動式後輪轉向系統和AWD全時四驅系統的搭載,讓身長5米多的大車開起來依然保持靈巧,彎道表現穩健,車身響應积極,讓“大車也能玩操控”變成了現實。360°全方位降噪,MRC主動電磁感應懸挂等技術的搭載則保證了其安靜舒適的豪華本色。

    不難發現在CT6 40T上所體驗到的一切都來自於科技,其實每個車型都有自己的側重點,特別是豪華車型都有其獨有的底蘊與內涵。你們知道日本的匠心,德國的精工,但這個世界上最好的手機,最好的電腦,最先進的產品都來自美國。CT6作為新美式豪華的代表,帶給消費者科技與豪華結合的完美體驗。

    作為CT6家族中最走量的一款車型,想必關注CT6 28T的人應該是最多的。確實如此,三款車各自扮演的角色不同,28T的品質很大程度上能決定整個家族能走多遠。因此,我們可以看見28T傳承了40T上的諸多產品優勢,標配20多項同級獨有的配置,你完全不用懷疑其豪華程度。另一方面,受到大環境的改變影響,2.0T的大型豪華車正在逐步為大家所接受,特別是生活在擁堵的城市環境中, 想兼顧節能與樂趣卻着實不易。CT6 28T搭載的是為數不多,在大型車上動力表現還能讓我滿意的2.0T發動機。沃德十佳的2.0T SIDI 渦輪增壓直噴發動機可以輸出276ps與400N·m的動力,其表現已經完全超越了3.0L排量的車型。加之與40T共享的輕量化車身與底盤技術,輕快的動力響應,精準的轉向手感,紮實的底盤質感加上更經濟的油耗,配合上終端合理的優惠,CT6 28T更像是一輛能取悅你的車。

    現如今路上豪車觸目皆是,汽車對於國人而言早已不只是代步工具,無論是對面子還是品質都有更高的追求。寶馬5系月銷輕鬆過萬,奔馳新E級一上來也是呼風喚雨,其中大家對BBA豪華老字號的追捧起了關鍵性的作用。在我看來,凱迪拉克CT6家族產品力完全不輸5系E級等對手,甚至直逼7系與A8L等車型,這樣的錯位競爭無疑讓CT6更具入手的價值。而就我個人而言,CT6最打動我的是在其豪華配置之下還為駕駛者提供了這個級別罕有的駕駛樂趣,這是非常難能可貴的。同時你不難發現,plug-in創新高的性能駕趣,40T造就的技術巔峰,28T迎合了城市通勤,不同的需求不同的價位你都能找到合適的CT6,這就是為何我的年度車型榜單中必備凱迪拉克CT6的原因。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

    南投搬家公司費用需注意的眉眉角角,別等搬了再說!

    ※教你寫出一流的銷售文案?

  • 不要小看這款常見的家用車!懂得買這款車的人都不簡單…

    不要小看這款常見的家用車!懂得買這款車的人都不簡單…

    為什麼日產要推出這樣的一輛車,並且把重點放在舒適性上,其實和它的“大哥”有一定的聯繫。我們都十分熟悉的風神藍鳥,就是由第九代藍鳥U13衍生而來,為了迎合國內市場做了大量的修改,更加顯得豪華,雖然市場表現很好,但隨着時間的推移,時代的變遷,無論是技術層面還是還是設計層面,都已經被市場淘汰。

    2006年,日產推出了一款介於天籟與藍鳥之間的全新中高級轎車,英文名為BLUEBIRD SYLpHY,當時的新車指導價為:14.38萬-21.48,主打2.0L車型,其實日產推出這款車型的目的明確,就是為了替代BLUEBIRD藍鳥。

    外觀造型飽滿圓潤,鍍鉻裝飾的中網突顯檔次,前大燈的設計與風雅有相似之處,整車設計給人感覺大方得體,非常流暢,這也是軒逸經典款至今仍在出售的原因之一。

    堪稱沙發級別的座椅是軒逸的殺手鐧,座椅寬大、厚實、飽滿,一坐進去軒逸的後排,就像是坐在家裡的沙發一樣,整個人陷入其中,坐墊非常軟,同時還有着非常寬裕的腿部空間,大家要知道,那時候可是2006年,能夠有這麼優秀的舒適性,是非常難得的。

    為什麼日產要推出這樣的一輛車,並且把重點放在舒適性上,其實和它的“大哥”有一定的聯繫。我們都十分熟悉的風神藍鳥,就是由第九代藍鳥U13衍生而來,為了迎合國內市場做了大量的修改,更加顯得豪華,雖然市場表現很好,但隨着時間的推移,時代的變遷,無論是技術層面還是還是設計層面,都已經被市場淘汰。

    日產需要一輛能夠霸佔家用轎車市場的車型,就這樣,軒逸應運而生,外觀大氣、乘坐舒適、空間寬裕,動力方面使用了MR20DE的2.0L發動機和第三代XTRONIC CVT無極變速箱,側重於追求低油耗和低噪音,這些所有的一切,都是為了舒適性,做出高級感。

    最終日產的確憑藉著它在市場中站穩腳跟,聽到日產軒逸就會想起那舒適居家的溫馨感,其實我們可以看得出來,當初軒逸的成功是必然的,因為市場就是需要這樣的產品,同時我們也看到日產似乎對於“藍鳥”這個名字念念不忘。

    日產通過LANNIA 藍鳥很全面的詮釋了V-motion家族式設計風格,告訴我們什麼才叫“驚艷”,由一開始的BLUEBIRD,到後來的BLUEBIRD SYLpHY,然後BLUEBIRD消失,剩下SYLpHY,最後LANNIA 藍鳥出現。

    第一代藍鳥

    “藍鳥”這兩個字包含着很多歷史,很多情懷,還有我們小時候的生活場景,它註定不會消失,這些歷史的沉澱,我們都應該好好記住。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※想知道最厲害的網頁設計公司"嚨底家"!

    ※別再煩惱如何寫文案,掌握八大原則!

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • 從7萬到25萬,這些車為了衝量竟然最高降3.7萬!

    從7萬到25萬,這些車為了衝量竟然最高降3.7萬!

    6L自動擋版本綜合油耗在5毛錢以內。別克君威指導價:17。89-27。99萬降價幅度:3。7萬推薦車型:2015款1。6T領先技術型君威作為別克的一款中高檔轎車,定位介於英朗和君越之間,屬於一款20萬級別的中型車,在乘坐空間,配置,做工用料上,都比代步車上了一個層次,而這款車的優惠幅度也是同級別車型中最大的,最高達到了3。

    許多經銷商們為了年底衝量,在7萬-25萬這個區間的車型,許多都放出了最大降價的優惠,從小型車,緊湊型車再到中級車,SUV,羅列了幾款降價幅度很大的好品質車型,供大家參考參考。

    雪鐵龍愛麗舍

    指導價:8.38-12.08萬元

    降價幅度:1.5萬元

    車型:2016款1.6L自動豪華型

    愛麗舍是法國雪鐵龍推出的一款家用轎車,自2002年誕生以來,用戶好口碑一直不斷積累着,為了針對中國人的審美觀,新款愛麗舍擁有更加動感的車身線條和造型設計,廠家似乎正通過這款車和消費者說:其實我們要造好造型還是不差於別人的。

    愛麗舍內飾的整體風格簡潔,清新,高雅,且空調出風口設計得很大,製造出風最好的效率,每個區域分隔清晰,操作非常方便,車型上推薦買自動豪華版,因為配置豐富帶ESp,真皮座椅,倒車影像,安全側氣囊等,優惠完車身價大概在10萬元左右。動力則全系搭載1.6L自然吸氣發動機,匹配5擋手動和6擋手自一體變速器。

    車主評價:動力充足,配置夠用,外形沉穩時尚,底盤舒服有韌性,剎車感覺非常線性。

    大眾高爾夫

    指導價:12.19-23.99萬

    降價幅度:2.8萬

    推薦車型:2016款 1.6L自動時尚型

    從1974年開始,大眾高爾夫就誕生了,直至今年,已經在全球市場推出七代車型,也是大眾最暢銷的車型之一,在中國,兩廂的高爾夫非常受人們歡迎,比起六代,七代高爾夫在外觀造型上更加犀利運動。

    內飾風格同樣也是大眾風格,簡約實用,對於家用代步來說,車型版本選擇1.6L自然吸氣排量就夠了,如果不需要天窗的可以選自動時尚型,匹配6擋手自一體,配置安全側氣囊,ESp車身穩定控制,上坡輔助,自動駐車等等,而如果是喜歡追尋動力的年輕人,可以考慮1.4T渦輪增壓發動機版本,匹配7擋雙離合變速器,更有操控和駕駛的樂趣。

    車主評價:外觀好看,舒適度滿意,轉向精準,隔音做得蠻好,油耗低,1.6L自動擋版本綜合油耗在5毛錢以內。

    別克君威

    指導價:17.89-27.99萬

    降價幅度:3.7萬

    推薦車型:2015款1.6T領先技術型

    君威作為別克的一款中高檔轎車,定位介於英朗和君越之間,屬於一款20萬級別的中型車,在乘坐空間,配置,做工用料上,都比代步車上了一個層次,而這款車的優惠幅度也是同級別車型中最大的,最高達到了3.7萬元。

    推薦的這款1.6T領先技術型,匹配6速手自一體變速箱,算是各方面相對均衡的一個版本,動力夠用,配置齊全,帶有胎壓監測,ESp,上坡輔助,電動天窗,自動空調等等,再加上美系車蠻好的隔音效果,優質的底盤響應,用料十分厚道,總有一種讓人們覺得這個價格買得值的感覺。

    車主口碑:隔音好,外觀公認好看,車身穩重,安全感強烈。

    現代ix35

    指導價:14.98-22.28萬

    降價幅度:2.8萬元

    推薦車型:2015款 2.0L自動兩驅智能型國IV

    現代ix35的外形設計由德國法蘭克福研發中心完成,帶有明顯歐式風格,時尚前衛,動感強韌,韓系車都喜歡將錢花在大家都看得到的地方,同樣的價格,假如這台車外形更好看的話,中國老百姓就喜歡,就覺得值,同樣車內空間的拓展上做得非常好,後備箱也一樣寬大。

    內飾方面,營造了一種溫馨家用的風格,做工細膩手感順滑,並採用大面積的銀色裝飾,方向盤採用真皮縫製,配置非常貼心,配備有安全側氣囊,無鑰匙進入與啟動,ESp,上坡輔助,電動天窗等等,同等價位里這個配置挺高分的了,搭載有2.0L和2.4L自然吸氣發動機,匹配6速手動和6速手自一體變速器。

    車主評價:同等級對比后,內部空間大,配置高,性價比強。

    本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※別再煩惱如何寫文案,掌握八大原則!

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※超省錢租車方案

    ※教你寫出一流的銷售文案?

    網頁設計最專業,超強功能平台可客製化

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!