Netty

Netty - это java библиотека и АPI для  написание concurrent сетевых приложений.
Netty:
Асинхронный ввод/вывод (неблокирующий) - основной поток не блокируется при вводе или выводе, а продолжает работать не ожидая результата (синхронизации с клиентом).
Event-driven - (событийно-ориентированный) - выполнения программы определяется событиями (сообщениями других приложений, потоков). Два основных действия прослеживается: выборка события и его обработка.

Основным и самым низким объектом в Netty является ChannelBuffer ( по которому передаются массив байтов).  Более абстрактным понятием есть Сhannel.
Все методы в Сhannel делятся на две категории:
- простые атрибутные методы (синхронные), которые предоставляют информацию о текущем канале
- асинхронные методы, типа I/O операции: bind, write, disconnect. Эти методы возврщают ChannelFuture (отложенный результат)

Создание каналов соединений:
Каналы не создаются не на прямую, а через фабрики.

Фабрика каналов (TCP) требует в конструкторе два вида Thread пулов или Executors (аналог thread):
1. Boss потоки: создает, прослушивает соединения (bind/connect). Дальше передает управление рабочим потокам. Со стороны сервера может быть только один босс поток на один прослушиваемый сокет.
2. Worker потоки: выполняют асинхронный іnput/output.

Чистый Channel может работать только с СhannelBuffer. Для обработки других сложных объектов  в Channel есть ChannelPipeLine (трубопровод), который состоит из специальных обработчиков (СhannelHandler). PipeLine имеет строгий порядок и вначале он к первому обработчику всегда приходит СhannelBuffer (байты почти в чистом виде).

В большинстве случаев Handlers используются как кодеры и декодеры:
Encoder (кодер) - конвертирует объект в СhannelBuffer или в другой тип понятный для следущего обработчика. (например ObjectEncoder  конвертирует java объект в СhannelBuffer).
Decoder (декодер) - конвертирует СhannelBuffer в другой более полезный объект.



Все хендлеры деляется на две большие группы :
ChannelDownstreamHandler (outBound) - вызываются, когда сообщение идет от сервера.
ChannelUpstreamHandler (inBound) - вызываются, когда сообщение идет к серверу.

HttpServerCoder - пример duplex хендлера, который при Upstream работает как HttpRequstDecoder (преобразует ByteBuff в HttpRequest), downstream - HttpResponseEncoder (преобразует HttpResponse в ByteBuf).

Как добавлять обработчики. Имя (name) можно не указывать (имя произвольное).

ChannelPipeline p = ch.pipeline();
p.addLast(new HttpServerCodec());
p.addLast(new HttpServerHandler());


Design pattern (Mеmento)

Хранитель (англ. Memento) — поведенческий шаблон проектирования, позволяющий, не нарушая инкапсуляцию, зафиксировать и сохранить внутреннее состояние объекта так, чтобы позднее восстановить его в это состояние.
Существует два возможных варианта реализации данного шаблона: классический, описанный в книге Design Patterns, и реже встречающийся нестандартный вариант.

Применение

Шаблон Хранитель используется, когда:
  • необходимо сохранить снимок состояния объекта (или его части) для последующего восстановления
  • прямой интерфейс получения состояния объекта раскрывает детали реализации и нарушает инкапсуляцию объекта

Структурa

Классический вариант:

  • Originator - "Создатель"
  • Caretaker - "Опекун"
  • Memento - "Хранитель"

Описание

Классический вариант: Шаблон Хранитель используется двумя объектами: "Создателем" (originator) и "Опекуном" (caretaker). "Создатель" - это объект, у которого есть внутреннее состояние. Объект "Опекун" может производить некоторые действия с "Создателем", но при этом необходимо иметь возможность откатить изменения. Для этого "Опекун" запрашивает у "Создателя" объект "Хранителя". Затем выполняет запланированное действие (или последовательность действий). Для выполнения отката "Создателя" к состоянию, которое предшествовало изменениям, "Опекун" возвращает объект "Хранителя" его "Создателю". "Хранитель" является непрозрачным (т.е. таким, который не может или не должен изменяться "Опекуном").
Нестандартный вариант: Отличие данного варианта от классического заключено в более жёстком ограничении на доступ "Опекуна" к внутреннему состоянию "Создателя". В классическом варианте у "Опекуна" есть потенциальная возможность получить доступ к внутренним данным "Создателя" через "Хранителя", изменить состояние и установить его обратно "Создателю". В данном варианте "Опекун" обладает возможностью лишь восстановить состояние "Хранителя", вызвав Restore. Кроме всего прочего, "Опекуну" не требуется владеть связью на "Хранителя", чтобы восстановить его состояние. Это позволяет сохранять и восстанавливать состояние сложных иерархических или сетевых структур (состояния объектов и всех связей между ними) путём сбора снимков всех зарегистрированных объектов системы.

Примеры реализации

Стандартный вариант шаблона на Java

Design pattern(iterator)

Iterator — поведенческий шаблон проектирования. Представляет собой объект, позволяющий получить последовательный доступ к элементам объекта-агрегата без использования описаний каждого из агрегированных объектов.
Create interfaces.
Iterator.java
public interface Iterator {
   public boolean hasNext();
   public Object next();
}
Container.java
public interface Container {
   public Iterator getIterator();
}

Step 2

Create concrete class implementing the Container interface. This class has inner class NameIterator implementing the Iterator interface.
NameRepository.java
public class NameRepository implements Container {
   public String names[] = {"Robert" , "John" ,"Julie" , "Lora"};

   @Override
   public Iterator getIterator() {
      return new NameIterator();
   }

   private class NameIterator implements Iterator {

      int index;

      @Override
      public boolean hasNext() {
      
         if(index < names.length){
            return true;
         }
         return false;
      }

      @Override
      public Object next() {
      
         if(this.hasNext()){
            return names[index++];
         }
         return null;
      }  
   }
}

Step 3

Use the NameRepository to get iterator and print names.
IteratorPatternDemo.java
public class IteratorPatternDemo {
 
   public static void main(String[] args) {
      NameRepository namesRepository = new NameRepository();

      for(Iterator iter = namesRepository.getIterator(); iter.hasNext();){
         String name = (String)iter.next();
         System.out.println("Name : " + name);
      }  
   }
}

Step 4

Verify the output.
Name : Robert
Name : John
Name : Julie
Name : Lora

Design pattern (Singleton)

Singleton
 Порождающий шаблон проектирования, гарантирующий, что в однопоточном приложении будет единственный экземпляр класса с глобальной точкой доступа.


Без внутренних классов (ленивая синхронизированная реализация).


public class Singleton {
        private static volatile Singleton instance;
    
        public static Singleton getInstance() {
        Singleton localInstance = instance;
        if (localInstance == null) {
            synchronized (Singleton.class) {
                localInstance = instance;
                if (localInstance == null) {
                    instance = localInstance = new Singleton();
                }
            }
        }
        return localInstance;
    }
}

Без внутренних классов (ленивая несинхронизированная реализация).


public class Singleton {
  private static Singleton instance;
  private Singleton () {}

  public static Singleton getInstance() {
    if (instance == null) {
      instance = new Singleton();
    }
    return instance;
  }
}
public class Singleton {  
   private Singleton() {}

   private static class SingletonHolder {  
      public static final Singleton instance = new Singleton();  
   }  
   
   public static Singleton getInstance()  {  
      return SingletonHolder.instance;  
   }  
}

Design patterns (Stragedy)

Stragedy - поведенческий
Определяет семейство алгоритмов, инкапсулирует каждый из них и обеспечивает их взаимозаменяемость. Он позволяет модифицировать алгоритмы независимо от их использования на стороне клиента.

Мотивы

  • Программа должна обеспечивать различные варианты алгоритма или поведения
  • Нужно изменять поведение каждого экземпляра класса
  • Необходимо изменять поведение объектов на стадии выполнения
  • Введение интерфейса позволяет классам-клиентам ничего не знать о классах, реализующих этот интерфейс и инкапсулирующих в себе конкретные алгоритмы
// Класс реализующий конкретную стратегию, должен наследовать этот интерфейс
// Класс контекста использует этот интерфейс для вызова конкретной стратегии
interface Strategy {
    int execute(int a, int b); 
}

// Реализуем алгоритм с использованием интерфейса стратегии
class ConcreteStrategyAdd implements Strategy {
 
    public int execute(int a, int b) {
        System.out.println("Called ConcreteStrategyAdd's execute()");
        return a + b;  // Do an addition with a and b
    }
}
 
class ConcreteStrategySubtract implements Strategy {
 
    public int execute(int a, int b) {
        System.out.println("Called ConcreteStrategySubtract's execute()");
        return a - b;  // Do a subtraction with a and b
    }
}
 
class ConcreteStrategyMultiply implements Strategy {
 
    public int execute(int a, int b) {
        System.out.println("Called ConcreteStrategyMultiply's execute()");
        return a * b;   // Do a multiplication with a and b
    }    
}

// Класс контекста использующий интерфейс стратегии
class Context {
 
    private Strategy strategy;
 
    // Constructor
    public Context() {
    }

    // Set new strategy
    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }

    public int executeStrategy(int a, int b) {
        return strategy.execute(a, b);
    }
}
 
// Тестовое приложение
class StrategyExample {
 
    public static void main(String[] args) {
 
        Context context = new Context();
 
        context.setStrategy(new ConcreteStrategyAdd());
        int resultA = context.executeStrategy(3,4);
 
        context.setStrategy(new ConcreteStrategySubtract());
        int resultB = context.executeStrategy(3,4);
 
        context.setStrategy(new ConcreteStrategyMultiply());
        int resultC = context.executeStrategy(3,4);

        System.out.println("Result A : " + resultA );
        System.out.println("Result B : " + resultB );
        System.out.println("Result C : " + resultC );
    }
}

SQL


  1. SELECT * FROM Customers;
  2. SELECT * FROM Customers WHERE city LIKE='K%'; ( _ - один символ; [!a-c] - не начинается с "а b c";)
  3. SELECT * FROM Customers WHERE city IN ('Kovel', 'London');
  4. SELECT * FROM Customers WHERE price BETWEEN 10 AND 20; (включительно)
  5. SELECT DISTINCT country FROM Customers;
  6. SELECT * FROM Customers WHERE country IS NOT NULL;
  7. SELECT * FROM Customers WHERE country='Germany' AND NOT city='Berlin';
  8. SELECT * FROM Customers WHERE country='Ukraine' OR country='Italy';
  9. SELECT * FROM Customers ORDER BY country DESC, customerName ASC; //default ASC
  10. INSERT INTO Customers (customerName, country) VALUES ('Max', 'Ukraine');
  11. UPDATE SET Customers customerName='Max', country='Ukraine' WHERE city='Kovel'; (если не будет WHERE, то обновит тупо все записи)
  12. DELETE FROM Customers WHERE customerName='Max';
  13. SELECT CustomerName, Address+', '+City+', '+PostalCode+', '+Country AS Address FROM Customers AS MyTable;
  • INNER JOIN: Returns all rows when there is at least one match in BOTH tables
  • LEFT JOIN: Return all rows from the left table, and the matched rows from the right table
  • RIGHT JOIN: Return all rows from the right table, and the matched rows from the left table
  • FULL JOIN: Return all rows when there is a match in ONE of the tables (даже если не будет совпадений, выведет все)
  • CROSS JOIN
  • SELECT * 
    FROM table1 
    CROSS JOIN table2;
  • или
  • SELECT *
    FROM
      Person,
      City
Если добавить условие, то будет работать как обычный JOIN (INNER JOIN) 
SELECT * FROM Customers INNER JOIN Orders ON Customers.city=Orders.city;
SELECT * FROM Customers LEFT JOIN Orders ON Customers.CustomerID=Orders.CustomerID;

SELECT City, Country FROM Customers
WHERE Country='Germany'
UNION ALL
SELECT City, Country FROM Suppliers
WHERE Country='Germany'
ORDER BY City;
Если без ALL, то не будут выводиться города дубликаты. Запросы должны иметь равное количество столбцов.

SELECT * INTO CustomersBackup2013 IN 'Backup.mdb' FROM Customers; - внешнюю базу можно не указывать. Копирует данные из одной таблицы в другую НОВУЮ.

Аналог SELECT INTO, только данные копирует в уже существующую таблицу.
INSERT INTO Customers (CustomerName, Country) SELECT SupplierName, Country FROM Suppliers WHERE Country='Germany';

CREATE DATABASE my_db;

CREATE TABLE Persons
(
P_Id int NOT NULL CHECK (P_Id>0),
LastName varchar(255) NOT NULL,
FirstName varchar(255),
Address varchar(255),
City varchar(255),
PRIMARY KEY (P_Id)
FOREIGN KEY (P_Id) REFERENCES Persons(P_Id)
);

ALTER TABLE Persons DROP PRIMARY KEY;

CREATE INDEX PIndex ON Persons (LastName); - создает индекс. Ускоряет работу поисковых запросов, но замедляет работу вставки и обновления. Indexes allow the database application to find data fast; without reading the whole table.

TRUNCATE TABLE table_name; - удаляет данные внутри таблицы.
DROP TABLE table_name; - удаляет таблицу.

ALTER TABLE Persons DROP COLUMN DateOfBirth;
ALTER TABLE Persons ALTER COLUMN DateOfBirth year;
ALTER TABLE Persons ADD COLUMN DateOfBirth date;

CREATE VIEW view_name AS SELECT column_name(s) FROM table_name
WHERE condition

SELECT * FROM [Current Product List]

Преимущества использования представлений:


  1. Дает возможность гибкой настройки прав доступа к данным за счет того, что права даются не на таблицу, а на представление. Это очень удобно в случае если пользователю нужно дать права на отдельные строки таблицы или возможность получения не самих данных, а результата каких-то действий над ними.
  2. Позволяет разделить логику хранения данных и программного обеспечения. Можно менять структуру данных, не затрагивая программный код, нужно лишь создать представления, аналогичные таблицам, к которым раньше обращались приложения. Это очень удобно когда нет возможности изменить программный код или к одной базе данных обращаются несколько приложений с различными требованиями к структуре данных.
  3. Удобство в использовании за счет автоматического выполнения таких действий как доступ к определенной части строк и/или столбцов, получение данных из нескольких таблиц и их преобразование с помощью различных функций.

Useful aggregate functions:
  • AVG() - Returns the average value
  • COUNT() - Returns the number of rows
  • FIRST() - Returns the first value
  • LAST() - Returns the last value
  • MAX() - Returns the largest value
  • MIN() - Returns the smallest value
  • SUM() - Returns the sum
Useful scalar functions:
  • UCASE() - Converts a field to upper case
  • LCASE() - Converts a field to lower case
  • MID() - Extract characters from a text field
  • LEN() - Returns the length of a text field
  • ROUND() - Rounds a numeric field to the number of decimals specified
  • NOW() - Returns the current system date and time
  • FORMAT() - Formats how a field is to be displayed
SELECT ProductName, Price FROM Products WHERE Price>(SELECT AVG(Price) FROM Products);

SELECT COUNT(DISTINCT column_name) FROM table_name;

SELECT column_name FROM table_name ORDER BY column_name DESC|ASC 
LIMIT 1; - Аналог FIRST() LAST()

SELECT column_name, aggregate_function(column_name)
FROM table_name
WHERE column_name operator value
GROUP BY column_name;

SELECT Employees.LastName, COUNT(Orders.OrderID) AS NumberOfOrders FROM (Orders
INNER JOIN Employees
ON Orders.EmployeeID=Employees.EmployeeID)
GROUP BY LastName
HAVING COUNT(Orders.OrderID) > 10;

SELECT ProductName, ROUND(Price,1) AS RoundedPrice
FROM Products; - округляет и оставляет одну цифру после комы.