Thứ Hai, 1 tháng 4, 2019

Kafka là gì? Tại sao lại cần Kafka.

 Rất khó để hiểu được hoàn toàn Kafka. Mặc dù  cốt lõi của Kafka vẫn ổn định qua các giai đoạn phát triển. Tuy nhiên những framework xoay qunah Kafka lại phát triển với một tốc độ chóng mặt.
 Một vài năm trước, Kafka rất đơn giản và dễ hiểu: Chỉ gồm Producer và Consumer. Hiện tại chúng ta có thêm: Kafka Connect, Kafka Streams và KSQL vào hệ sinh thái Kafka. Những thành phần mới này thay thế cho Producer & Consumer hay hoàn thiện Kafka.
 Hãy cùng làm rõ những vấn đề này:
 Ý tưởng của từng API Kafka:
  Có 5 loại công việc trong Apache Kafka, và nó tương ứng với 5 API của Kafka.
 - Kafka Producer API:  Ứng dụng trực tiếp xuất bản data (VD: Clickstream, logs,IoT)
 - Kafka Connect Source API: Bridging giữa Kafka và một datasource mà chúng ta không nắm quyền kiểm soát (CDC, Postgres, MongoDB, Twitter, REST API)
 - Kafka Streams API/ KSQL: Ứng dụng muốn tổng hợp từ Kafka và đẩy ngược lại chính Kafka, còn được gọi là stream processing.
   + Sử dụng KSQL khi muốn xử lý công việc 1 cách real-time như SQL hoặc tính toán đơn giản. Sử dụng Kafka Stream API nếu bạn sử dụng logic phức tạp trong xử lý dữ liệu của bạn.
  - Kafka Consumer API: Đọc 1 stream và ngay lập tức xử lý một hành động  với nó (Ví dụ : Gửi Email,...)
  - Kafka Connect Sink API: Đọc 1 stream và lưu trữ nó vào một target store (Kafka to S3, Kafka to HDFS, Kafka to PostgreSQL,  Kafka to MongoDB, etc.)
  Về cơ bản, Kafka Consumer và Kafka Sink API có thể dễ dàng thay  thế cho nhau, nếu bạn sẵn sàng tự viết code cho những gì bạn cần.
  => Tổng hợp lại, những gạch đầu dòng kể trên sẽ giúp bạn thực hiện được những luồng một cách hiệu quả với ít lượng code nhất và giảm thiểu rủi ro thất bại nhất.

1.  Kafka Producer API
  •  Lợi thế: 
    • Dễ sử dụng: Gửi data, là bất đồng bộ và sẽ nhận được 1 callback khi gửi xong. Vô cùng phù hợp với những ứng dụng mà trực tiếp điều hướng message như logs, clickstreams, IoT.
    • Rất thường xuyên được sử dụng khi kết hợp với Proxy.
  • Hạn chế:
    •  Kafka Producer API có thể mở rộng và xây dựng lên để làm rất nhiều thứ, tuy nhiên nó yêu cầu người phát triển phả viết thêm rất nhiều code. Vấn đề lớn nhất là khi mọi ngừoi cố gắng thực thi ETL giữa các databasse và Kafka khi sử dụng Producer API. Dứoi đấy là một số thứ mà không dễ để thực hiện:
    • Làm sao để có thể theo dõi source Offset (i.e Làm sao để tiếp tục Producer xử lý tiếp luồng khi nó bị stop.)
    • Làm thế nào để chia tải giữa các Producer?
 => Để làm những việc này, tốt nhất chúng ta nên sử dụng Kafka Connect Source API.

2. Kafka Connect Source API:
  •  Lợi thế:
    • Kafka Connect Source API là 1 framework xây dựng trên nền của  Producer API. Nó được xây dựng để :
      • Phân tán task cho các Producer xử lý song song
      • Cơ chế dễ dàng để các Producer xử lý tiếp tại nơi mình đang bỏ dở.
      • Cuối cùng là một loạt các trình kết nối có sẵn mà có thể tạn dụng ngay từ hôm nay để lấy dữ liệu từ hầu hết các nguồn dữ liệu mà k cần tốn dòng code nào.
  •  Hạn chế: 
    • Lợi thế cũng chính là nhược điểm, việc có các trình kết nối có sẵn có nghĩa là chúng ta phải tự viết các trình kết nối đến nguồn dữ liệu của chúng ta. 
3. Kafka Consumer API:
  • Lợi thế: 
    •  Kafka Consumer API thậm chí còn đơn giản hơn nữa, sử dụng Consumer Group từ đó Topic của bạn có thể được consumed song song. Tuy nhiên bạn cần cẩn thận với một số thứ, như là offset management và commits. Cũng như là sự cân bằng tải và hạn chế tạm thời. Rất dễ để viết. Nó phù hợp cho bất cứ loại nào công việc nào statelesss. Như là notification!
  • Nhược điểm:
    • Khi bạn thực hiện một số thao tác như ETL, Kafka Connect Sinks sẽ phù hợp hơn vì chúng sẽ giúp bạn tránh đc một số luồng logic phức tạp cũng như kết nối đến external data source.
4. Kafka Connect Sink API
  • Lợi thế:
    • Tương tự như Kafka Connect Source API, Kafka Connect Sink API cho phép bạn nâng tầm hệ sinh thái có sẵn của Kafka. Sử dụng Kafka Connector để thực  hiện thao tác stream ETL mà k phải viết một dòng code nào. Kafka Connect cũng là API bậc cao của Consumer API nhưng nó dùng giống với Consumer.
  •  Nhược điểm:
    • Giống Kafka Connect Source.
5. Kafka Streams API: 
  • Lợi thế: 
    • Nếu bạn muốn truy cập vào trong luồng xử lý, như là đọc dữ liệu từ Kafka 1 cách real-time và sau khi xử lý nó, viết lại vào Kafka. Bạn gần như không thể làm được với Kafka  Consumer API và Kafka Producer API. (Vì 1 thằng chỉ chuyên đọc và 1 thằng chỉ chuyên viết). May mắn thay, Kafka Project giờ có Kafka Streams API, cho phép bạn viết với High Level DSL (resembling to a functional programming / Apache Spark type of program), hoặc Low Level API (resembling more to Apache Storm). Kafka Streams API yêu cầu bạn cần phải viết code, nhưng che giấu và bạn không phải quan tâm tới độ phức tạp của bảo trì producers và consumers. Để bạn có thể tập trung vào logic của luồng xử lý. Nó cũng đi kèm với join, aggregations và khả năng chính xác 1 lần.
  • Nhược điểm:  
    • Bạn có thể viết thêm code vào làm rối rắm và phức tạp. Do việc debug và test là khá khó. Mặc dù hiện tại đã có test-utils library. 
    • Cuối cùng, mặc dù Kafka Streams nhìn đơn giản, nhưng nó thực ra rất khó để học và sẽ tạo thành 1 ra 1 chuỗi state, mà thường đc backup ở Kafka Topics. Điều này có nghĩa là tuỳ thuộc vào độ phức tạp của cấu trúc, Kafka Streams sẽ phải xử lý rất nhiều message, mặc dù đi vs nó bạn sẽ có stateless và chịu lỗi cao.





























  • Add to Phrasebook
    • No word lists for English -> Vietnamese...
    • Create a new word list...
  • Copy

Thứ Bảy, 10 tháng 12, 2016

25 típ để tăng hiệu suất cho câu lệnh sql

Mỗi khách hàng hay người dùng đều muốn được trả về dữ liệu nhanh nhất do đó chúng ta cần thiết kế một cơ sở dữ liệu tốt mà tăng hiệu suất cho mỗi lẫn thao tao với dữ liệu. Không có con đường thẳng để định nghĩa hiệu suất tốt nhất nhưng có nhiều cách để cải thiện câu lệnh sql ví dụ như tạo index , sử dụng join , viết lại subquery để chỉ dùng join v.v.
Là Dev, chúng ta biết sql có thể viết bằngrất nhiều cách nhưng chúng ta nên follow theo cách tốt nhất để đạt được hiệu suất tốt nhất. Dưới đây là các típ cho chúng ta:
  1. Hãy dùng EXISTS thay vì IN để kiểm tra sự tồn tại của dữ liệu.
  2. Tránh * trong câu lệnh SELECT. Hãy dùng tên cột thích hợp.
  3. Chọn loại dữ liệu thích hợp . Ví dụ lưu chuỗi sử dụng loại varchar thay vì sử dụng loại Text. Khi muốn sử dụng loại Text, là khi bạn cần lưu dữ liệu lơn (nhiều hơn 8000 ký tự).
  4. Tránh dùng nchar và nvarchar vì cả hai đều tăng bộ nhớ lên gấp đôi so với char và varchar.
  5. Tránh NULL đối với những trường mà đã cố định độ dài. Trong trường hợp yêu cầu là NULL hãy sử dụng một trường loại varchar với độ dài tùy biến thì vẫn lấy space ít hơn là NULL.
  6. Tránh dùng mệnh đề Having. Chỉ dùng khi muốn lọc kết quả trả về.
  7. Hãy tạo ra indexs là cách tốt nhất tăng tốc . Indexs bao gồm Clustered và Non-Clustered.
  8. Hãy giữ index của clustered nhỏ thôi vì trường mà dùng trong cluster index đó thì cũng được dùng trong non-clustered index.
  9. Đa số cột được chọn nên đặt trong non-clustered index.
  10. Những index nào không được dùng thì nên xóa đi.
  11. Tốt hơn là tạo ra index trên những cột có giả trị là số thay vì là ký tự. Giá trị số sử dụng ít bộ nhớ hơn ký tự.
  12. Dùng câu lệnh join thay vì dùng select trong select
  13. Hãy sử dụng mệnh đề WHERE để giới hạn cỡ của bảng kết quả trả về mà được tạo ra với câu lệnh join.
  14. Hãy dùng TABLOCKX trong khi chèn dữ liệu vào bảng và TABLOCK trong khi merging dữ liệu
  15. Sử dụng WITH (NOLOCK) trong khi truy xuất dữ liệu từ bất kỳ một bảng nào.
  16. Dùng SET NOCOUNT ON và sử dụng TRY – CATCH để tránh điều kiện deadlock.
  17. Tránh dùng cursor vì nó ảnh hưởng đến hiệu suất của chương trình rất chậm.
  18. Sử dụng biến TABLE thay vì dùng bảng TEMP. Dùng bảng TEMP đòi hỏi tương tác với cơ sở dữ liệu TEMPDB mà mất thời gian để thực hiện một tác vụ.
  19. Sử dụng UNION ALL thay vì UNION nếu có thể.
  20. Sử dụng tên Schema trước tên đối tượng SQL.
  21. Sử dụng Stored Procedure cho những dữ liệu thường xuyên được sử dụng và những query hỗn hợp , hoặc những câu lệnh chứa nhiều logic phức tạp.
  22. Giữ transaction nhỏ nhất có thể vì transaction khóa việc xử lý dữ liệu bảng và có thể dẫn đến kết quả bị deadlocks.
  23. Tránh tiền tố “sp_” với tên store procedure người dùng tự định nghĩa bởi vì SQL server đầu tiên tìm kiếm những thủ tục người dùng định nghĩa trong cơ sở dử liệu master và sau đó mới sử dụng phiên làm việc của cơ sở dữ liệu hiện hành.
  24. Tránh dùng câu query Non-correlated . Sử dụng câu query này như một câu query riêng instead thay vì là query chính và lưu output trong một biến, mà có thể tham chiếu đến câu query chính hoặc là một phần sau của batch.
  25. Tránh Table Valued Functions (TVFs) với nhiều câu lệnh. Vì nó giảm hiệu suất
Xem thêm : https://www.codeproject.com/articles/34372/top-steps-to-optimize-data-access-in-sql-server

Thứ Sáu, 14 tháng 10, 2016

[Android] Navigation Drawer

   Navigation Drawer là một bảng điều khiển nằm ở cạnh bên trái màn hình,nó hiển thị sự tùy chọn điều hướng của main app.
   Nó được ẩn đi trong gần như hầu hết thời gian,và được gọi khi người dùng lướt ngón tay từ bên cạnh trái màn hình vào hoặc khi người dùng ấn vào biểu tượng ứng dụng trên thanh action bar.

   Bài viết sẽ mô tả làm như thế nào để triển khai một navigation drawer sử dụng 'DrawerLayout APIs' có trong thư viện hỗ trợ 'Support Library'

   Một số lưu ý về nguyên tắc thiết kế,khuôn mẫu của Navigation Drawer:
 https://material.google.com/patterns/navigation-drawer.html#navigation-drawer-specs


  1. Tạo một Drawer Layout
    • Để thêm một navigation drawer,khai báo tại giao diện người dùng một đối tượng DrawerLayout như một root view trong file layout .xml . 
    • Ở trong DrawerLayout,thêm một view mà chứa cái nội dung chính cho màn hình (Màn hình để hiển thị khi mà Navigation Drawer ẩn đi) và một view khác chứa nội dung của chính cái navigation drawer đấy.
    • Thường sử dụng FrameLayout cho màn hình chính với vai trò là một Fragment trong khi app chạy để có thể dễ dàng thay đổi,di chuyển giữa các màn hình. Và một ListView để hiển thị nội dung cho Navigation Drawer.
    • <android.support.v4.widget.DrawerLayout
          xmlns:android="http://schemas.android.com/apk/res/android"
          android:id="@+id/drawer_layout"
          android:layout_width="match_parent"
          android:layout_height="match_parent">
          <!-- The main content view -->
          <FrameLayout
              android:id="@+id/content_frame"
              android:layout_width="match_parent"
              android:layout_height="match_parent" />
          <!-- The navigation drawer -->
          <ListView android:id="@+id/left_drawer"
              android:layout_width="240dp"
              android:layout_height="match_parent"
              android:layout_gravity="start"
              android:choiceMode="singleChoice"
              android:divider="@android:color/transparent"
              android:dividerHeight="0dp"
              android:background="#111"/>
      </android.support.v4.widget.DrawerLayout>
    • Dựa vào code ở trên chúng ta có thể rút ra được một số điều quan trọng như:
    1. Main content view phải được khai báo như là phần tử đầu tiên của root view vì XML order được triển khai theo z-ordering,nghĩa là phần tử khai báo trước sẽ nằm ở phía sau.
    2. Main content view được đặt giá trị là match_parent vì nó đại diện cho toàn bộ UI khi drawer ẩn đi
    3. Drawer view (List view) phải được xác định trọng lực ngang của nó với thuộc tính : android:layout_gravity. Để hỗ trợ ngôn ngữ đọc từ trái sang phải,giá trị của thuộc tính này phải được đặt là 'start' thay vì 'left' cho bố cục hỗ trợ đọc từ phải sang trái.
    4. Drawer view được xác định chiều rộng với giá trị dp. Giá trị này không nên vượt quá 320 dp để người dùng có thể nhìn thấy một phần của main content phía sau. Thường được đặt là 240dp
  2. Khởi tạo Drawer List
    • Trong activity,một trong những điều đầu tiên cần phải khởi tạo là list item của navigation drawer. List item này phụ thuộc vào nội dung app bạn là gì. Và nó được khởi tạo cũng như đổ dữ liệu y hệt như list view bình thường. Sử dụng Adapter (Như là ArrayAdapter hoặc là SimpleCursorAdapter)
    • Dưới đây là một ví dụ khởi tạo list navigation với String Array:
      public class MainActivity extends Activity {
          private String[] mPlanetTitles;
          private DrawerLayout mDrawerLayout;
          private ListView mDrawerList;
          ...
      
          @Override
          public void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
      
              mPlanetTitles = getResources().getStringArray(R.array.planets_array);
              mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
              mDrawerList = (ListView) findViewById(R.id.left_drawer);
      
              // Set the adapter for the list view
              mDrawerList.setAdapter(new ArrayAdapter<String>(this,
                      R.layout.drawer_list_item, mPlanetTitles));
              // Set the list's click listener
              mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
      
              ...
          }
      }
    •  Đoạn code có phương thức setOnItemClickListener() để nhận được sự kiện click vào drawer list. Phần tiếp theo sẽ cho bạn thấy làm thế nào để triển khai giao diện và thay đổi content view khi người dùng chọn một item.
  3. Xử lý sự kiện click điều hướng
    • Khi người dùng chọn một item trong drawer list,hệ thống gọi phương thức onItemClick() trong lớp OnItemClickListener được gán trong phương thức setOnItemClickListener(OnItemClickListener listener).
    • Trong ví dụ dưới đây,mỗi khi người dùng lựa chọn một item trong list,main content view sẽ hiển thị những fragment khác nhau:
      private class DrawerItemClickListener implements ListView.OnItemClickListener {
          @Override
          public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
              selectItem(position);
          }
      }
      /** Swaps fragments in the main content view */
      private void selectItem(int position) {
          // Create a new fragment and specify the planet to show based on position
          Fragment fragment = new PlanetFragment();
          Bundle args = new Bundle();
          args.putInt(PlanetFragment.ARG_PLANET_NUMBER, position);
          fragment.setArguments(args);
      
          // Insert the fragment by replacing any existing fragment
          FragmentManager fragmentManager = getFragmentManager();
          fragmentManager.beginTransaction()
                         .replace(R.id.content_frame, fragment)
                         .commit();
      
          // Highlight the selected item, update the title, and close the drawer
          mDrawerList.setItemChecked(position, true);
          setTitle(mPlanetTitles[position]);
          mDrawerLayout.closeDrawer(mDrawerList);
      }
      @Override
      public void setTitle(CharSequence title) {
          mTitle = title;
          getActionBar().setTitle(mTitle);
      }
  4. Lắng nghe sự kiện đóng hoặc mở
    • Để lắng nghe sự kiện đóng hoặc mở navigation drawer,gọi phương thức setDrawerListener() của đối tượng DrawerLayout và gán cho nó một thực thi của lớp DrawerLayout.DrawerListener. Giao diện này sẽ cung cấp một hàm callbacks cho 2 sự kiện của drawer là 2 phương thức onDrawerOpened() và onDrawerClosed(). 
    • Tuy nhiên,xa hơn việc thực thi lớp DrawerListener,nếu app của bạn có actionbar,bạn có thể thay thế bằng cách kế thừa lớp ActionBarDrawerToggle. Lớp này là là lớp phụ thuộc của DrawerListener nên bạn vẫn có thể override lại những callback trên,và còn có thể thực thi những hành vi tương tác giữa biểu tượng trên thanh actionbar và navigation drawer (Sẽ được trình bày sâu hơn vào phần tiếp theo)
    • Như những gì đã trình bày ở bài hướng dẫn thiết kế Navigation Drawer,bạn nên tùy chỉnh nội dung của action bar khi drawer hiển thị. Vì vậy chúng ta sẽ thay đổi tên title action bar và xóa action items mà liên kết với main content đang hiển thi. Phần code dưới đây sẽ hướng dẫn bạn làm việc đó như thế nào với việc override lại các phương thức của lớp DrawerListener với một instance (thực thể) của lớp ActionbarDrawerToggle:
      public class MainActivity extends Activity {
          private DrawerLayout mDrawerLayout;
          private ActionBarDrawerToggle mDrawerToggle;
          private CharSequence mDrawerTitle;
          private CharSequence mTitle;
          ...
      
          @Override
          public void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
              ...
      
              mTitle = mDrawerTitle = getTitle();
              mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
              mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
                      R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close) {
      
                  /** Called when a drawer has settled in a completely closed state. */
                  public void onDrawerClosed(View view) {
                      super.onDrawerClosed(view);
                      getActionBar().setTitle(mTitle);
                      invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
                  }
      
                  /** Called when a drawer has settled in a completely open state. */
                  public void onDrawerOpened(View drawerView) {
                      super.onDrawerOpened(drawerView);
                      getActionBar().setTitle(mDrawerTitle);
                      invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
                  }
              };
      
              // Set the drawer toggle as the DrawerListener
              mDrawerLayout.setDrawerListener(mDrawerToggle);
          }
      
          /* Called whenever we call invalidateOptionsMenu() */
          @Override
          public boolean onPrepareOptionsMenu(Menu menu) {
              // If the nav drawer is open, hide action items related to the content view
              boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
              menu.findItem(R.id.action_websearch).setVisible(!drawerOpen);
              return super.onPrepareOptionsMenu(menu);
          }
      }
  5. Đóng hoặc mở với app icon
    • Phần này sẽ mô tả tham số khởi tạo của lớp ActionBarDrawerToggle và những bước cần thiết để cài đặt nhằm xử lý những tương tác giữa icon của action bar và Navigation Drawer
    • Người dùng có thể mở và đóng navigation drawer với thao tác lướt nhưng nếu app của bạn sử dụng action bar,bạn nên cho phép người dùng mở và đóng navigation bar bằng cách chạm vào biểu tượng trên thanh action bar. Và biểu tượng app này cũng nên biểu thị sự hiện diện của navigation drawer với biểu tượng đặc biệt (3 dấu * dọc nhau). Bạn có thể thực hiện tất cả các hành vi này bằng việc sử dụng ActionBarDrawerToggle mà đã được giới thiệu ở phần trước.
    • Để có thể sử dụng được ActionBarDrawerToggle,bạn cần tạo một instance của nó với hàm khởi tạo cùng với những tham số cần thiết sau
      • Activity chủ của drawer
      • DrawerLayout (tất nhiên)
      • Drawable resource để sử dụng làm icon đại diện cho drawer
      • 1 chuỗi String để mô tả cho hành động 'open drawer'
      • 1 chuỗi String để mô tả cho hành động 'close drawer'
    • Bây giờ thì có hoặc không bạn tạo một subclass của ACtionBarDrawerToggle như một listener cho drawer của bạn,bạn cần gọi ActionBarDrawerToggle trong một vài chỗ xuyên suốt vòng đời activity của bạn
      public class MainActivity extends Activity {
          private DrawerLayout mDrawerLayout;
          private ActionBarDrawerToggle mDrawerToggle;
          ...
      
          public void onCreate(Bundle savedInstanceState) {
              ...
      
              mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
              mDrawerToggle = new ActionBarDrawerToggle(
                      this,                  /* host Activity */
                      mDrawerLayout,         /* DrawerLayout object */
                      R.drawable.ic_drawer,  /* nav drawer icon to replace 'Up' caret */
                      R.string.drawer_open,  /* "open drawer" description */
                      R.string.drawer_close  /* "close drawer" description */
                      ) {
      
                  /** Called when a drawer has settled in a completely closed state. */
                  public void onDrawerClosed(View view) {
                      super.onDrawerClosed(view);
                      getActionBar().setTitle(mTitle);
                  }
      
                  /** Called when a drawer has settled in a completely open state. */
                  public void onDrawerOpened(View drawerView) {
                      super.onDrawerOpened(drawerView);
                      getActionBar().setTitle(mDrawerTitle);
                  }
              };
      
              // Set the drawer toggle as the DrawerListener
              mDrawerLayout.setDrawerListener(mDrawerToggle);
      
              getActionBar().setDisplayHomeAsUpEnabled(true);
              getActionBar().setHomeButtonEnabled(true);
          }
      
          @Override
          protected void onPostCreate(Bundle savedInstanceState) {
              super.onPostCreate(savedInstanceState);
              // Sync the toggle state after onRestoreInstanceState has occurred.
              mDrawerToggle.syncState();
          }
      
          @Override
          public void onConfigurationChanged(Configuration newConfig) {
              super.onConfigurationChanged(newConfig);
              mDrawerToggle.onConfigurationChanged(newConfig);
          }
      
          @Override
          public boolean onOptionsItemSelected(MenuItem item) {
              // Pass the event to ActionBarDrawerToggle, if it returns
              // true, then it has handled the app icon touch event
              if (mDrawerToggle.onOptionsItemSelected(item)) {
                return true;
              }
              // Handle your other action bar items...
      
              return super.onOptionsItemSelected(item);
          }
      
          ...
      }

Thứ Tư, 27 tháng 1, 2016

Lưu ý khi học Java

Con người là 1 lớp: chân, tay, tuổi, học vấn,... là thuộc tính, đi chạy, nhảy là phương thức.
Di chuyển là một interface: chỉ bao gồm phương thức..

Đến đây chắc bạn hiểu rồi.
Một lớp có thể thừa kế (extends) một lớp khác: con người extends động_vật
một interface có thể extends từ một interface: di_chuyển extends cử_động.
một lớp có thể implement (triển khai) một interface: con_người implements di_chuyển

Thứ Tư, 6 tháng 1, 2016

Kinh nghiệm xương máu của anh chị đi trước

[01/06/2015]
Appending model là một mô hình thiết kế CSDL tối ưu cho việc ghi, khi chỉ insert mà không có update, delete. Đây là một mô hình rất tốt cho các CSDL đòi hỏi hiệu năng rất cao việc ghi. 

Nó có thể mở rộng ra không chỉ cho các table trong database, mà còn với các cấu trúc file. Đây cũng là mô hình được các hệ thống như viễn thông, hệ thống quảng cáo sử dụng để xây dựng các cấu trúc lưu trữ đòi hỏi hiệu năng rất cao.

Thứ Hai, 15 tháng 6, 2015

Lời mở đầu

Chào các bạn,mình là Nguyễn Gia Tú,mình đang là sinh viên đã học hết năm thứ 3 của ĐHBK HN .
Mình yêu thích Công nghệ thông tin,cũng có cảm xúc vui vẻ tột cùng khi solve được 1 bài toán,1 chương trình,thỏa mãn khi nhìn thành quả của mình.
Nhưng có một vấn đề ...
Lòng quyết tâm của mình quá thấp,mình dễ dàng bị lôi cuốn vào những trò chơi điện tử,những bộ phim hay,những cuộc rủ rê của bạn bè,hay thậm chí là một cuốn manga hay...
Và mình muốn thay đôi nó...
Vì vậy,mình sẽ bắt đầu viết blog,cho dù bây giờ sẽ chẳng ai đọc nó đâu,nhưng nó sẽ như 1 người bạn thúc giục mình để mình có thể không xao lãng vấn đề học tập.
Mình sẽ tự học về chủ đề,hiện tại là JAVA,mình sẽ học xong trong 1 tháng hè,mỗi tuần mình sẽ cố gắng viết 1 đến 2 bài về những kiến thức cũng như những chú ý của mình trong quãng thời gian học JAVA.
Tiếp đến,mục tiêu của mình trong tương lai là ngôn ngữ Ruby,PHP,Java Script . . .
Nếu có ai đó đọc được blog này,mình xin cảm ơn vì đã quan tâm và đọc đến đây .
Hôm nay,16/6/2015, Tôi sẽ bắt đầu thay đổi . . .