Начало работы с Acapella DB
Введение
Что такое Acapella DB?
Это NewSQL база данных. От новых NoSQL баз данных она взяла масштабируемость и отказоустойчивость, а от классических – мощный язык запросов и ACID транзакции.
Acapella DB поддерживает распределённые транзакции, непривязанные к соединению: можно запустить транзакцию в одном месте, а продолжить из другого, указав её идентификатор. Уровень изоляции транзакций всегда SERIALIZABLE.
В этой статье описано начало работы с базой: подключение через SqlLine и JDBC, создание схемы и заполнение данных.
Когда нужна Acapella DB?
При работе с большими объёмами реляционных данных. Для реляционных данных небольшого объёма (до 1 ТБ) существуют классические SQL базы. Для плохо структурированных или слабо связанных данных используются NoSQL базы.
NewSQL – единственный способ работы с большим количеством сложно взаимосвязанных консистентных данных.
При необходимости распределённых транзакций. У вас есть веб-сервис, который должен поддерживать расширения через web-hooks, но при этом нужно запускать их в одной транзакции с изначальным запросом. Распределённые транзакции Acapella DB позволяют это сделать.
Acapella DB уже можно пользоваться?
Да, на февраль 2019 года Acapella DB на раннем этапе развития: поддерживается не весь SQL, не полностью реализовано распределение данных по узлам, возможны баги. Но мы уже реализовали распределённые транзакции и реплицирование. Доступ к текущей версии можно получить по адресу db.acapella.ru:4567.
Начало работы
У Acapella DB ещё нет своего консольного клиента, но можно воспользоваться утилитой sqlline, которая позволяет подключиться к любой SQL базе через JDBC драйвер. SqlLine написан на Java, поэтому поддерживаются Windows, Linux и MacOS. Здесь приведены команды для Linux.
Скачаем sqlline, специально собранный для работы с Acapella DB: со всеми зависимостями и JDBC драйвером:
1 | wget https://github.com/AcapellaSoft/adb-tools/releases/download/0.2.0/sqlline-0.2.0.jar -O sqlline.jar |
Для запуска требуется Java Runtime Environment (JRE) версии 1.8 или выше.
Создадим пользователя. Его имя должно быть уникальным:
1 2 | $ java -jar sqlline.jar -u jdbc:acapelladb://db.acapella.ru:4567 > CREATE USER <username> WITH PASSWORD '<password>'; |
Сейчас имя базы данных привязано к имени пользователя. Для входа в свою базу, её имя должно совпадать с именем пользователя.
Подключимся к базе данных и создадим простую таблицу:
1 2 3 | $ java -jar sqlline.jar -u jdbc:acapelladb://db.acapella.ru:4567/<username> -n <username> -p <password> > CREATE TABLE test("key" VARCHAR, "value" VARCHAR, PRIMARY KEY("key")); No rows affected (2.337 seconds) |
Первые запросы после изменения схемы могут быть долгими, не пугайтесь :). Созданная таблица с именем test содержит две колонки: key и value, обе строкового типа. Колонка key является основным ключом, по нему данные таблицы будут распределяться по узлам базы. Создать таблицу без основного ключа пока нельзя.
Создадим первую запись в таблице:
1 2 | > INSERT INTO test VALUES ('hello', 'world'); 1 ROW affected (0.045 seconds) |
и получим её обратно:
1 2 3 4 5 6 7 | > SELECT * FROM test; +--------+--------+ | KEY | VALUE | +--------+--------+ | hello | world | +--------+--------+ 1 ROW selected (0.343 seconds) |
Работа с базой через sqlline подходит для проведения экспериментов, создания и изменения схемы данных, но не для полноценной работы. Дальше рассмотрим другие варианты использования базы.
JDBC-клиент
Чтобы начать работу с JDBC, подключим adb-jdbc-driver к приложению:
Maven:
1 2 3 4 5 6 7 8 9 10 11 12 13 | <repositories> <repository> <id>jcenter</id> <url>https://jcenter.bintray.com/</url> </repository> </repositories> ... <dependency> <groupId>ru.acapella.db</groupId> <artifactId>adb-jdbc-driver</artifactId> <version>0.2.0</version> <type>pom</type> </dependency> |
Gradle:
1 2 3 4 5 6 7 | repositories { jcenter() } ... dependencies { compile 'ru.acapella.db:adb-jdbc-driver:0.2.0' } |
Создадим соединение:
1 2 3 4 5 6 7 8 | // Kotlin Class.forName("ru.acapella.db.jdbc.Driver") val connection = DriverManager.getConnection( "jdbc:acapelladb://db.acapella.ru:4567/<username>", "<username>", "<password>" ) connection.autoCommit = true |
1 2 3 4 5 6 7 | Class.forName("ru.acapella.db.jdbc.Driver"); Connection connection = DriverManager.getConnection( "jdbc:acapelladb://db.acapella.ru:4567/<username>", "<username>", "<password>" ); connection.setAutoCommit(true); |
Создадим и заполним таблицу:
1 2 3 4 | // Kotlin val statement = connection.createStatement() statement.execute("""CREATE OR REPLACE TABLE test("key" VARCHAR, "value" VARCHAR, PRIMARY KEY("key"))""") statement.execute("""INSERT INTO test VALUES ('hello', 'world')""") |
1 2 3 4 | // Java Statement statement = connection.createStatement(); statement.execute("CREATE OR REPLACE TABLE test("key" VARCHAR, "value" VARCHAR, PRIMARY KEY("key"))"); statement.execute("INSERT INTO test VALUES ('hello', 'world')"); |
Выполним простую выборку:
1 2 3 4 5 6 7 | // Kotlin val resultSet = statement.executeQuery("""SELECT * FROM test""") while (resultSet.next()) { val key = resultSet.getString(1) val value = resultSet.getString(2) println("$key, $value") } |
1 2 3 4 5 6 7 |
JDBC клиент позволяет менять схему, обновлять и выбирать данные. Поддерживаются prepared statements, получение мета-информации о БД и основные типы данных. Уже сейчас можно запустить Hibernate поверх драйвера, чтобы работать с базой было удобнее.
«Real-world example»
Чтобы показать больше возможностей Acapella DB, создадим БД для работы с отелями, которую часто используют как пример работы с SQL:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | CREATE TABLE city ( zip VARCHAR, name VARCHAR, state VARCHAR, PRIMARY KEY(zip) ); CREATE TABLE customer ( id INTEGER, title VARCHAR, first_name VARCHAR, name VARCHAR, zip VARCHAR, address VARCHAR, PRIMARY KEY(id) ); CREATE TABLE hotel ( id INTEGER, name VARCHAR, zip VARCHAR, address VARCHAR, PRIMARY KEY(id) ); CREATE INDEX hotel_by_name ON hotel (name); CREATE TABLE room ( hotel_id INTEGER, TYPE VARCHAR, "free" DECIMAL, price DECIMAL, PRIMARY KEY (hotel_id, TYPE) ); CREATE TABLE reservation ( id INTEGER, customer_id INTEGER, hotel_id INTEGER, TYPE VARCHAR, arrival DATE, departure DATE, PRIMARY KEY(id) ); |
Acapella DB поддерживает основные типы данных: INTEGER, VARCHAR, DATE и др. Сейчас на создание таблиц действует ограничение: они должны иметь основной ключ. Поддерживаются PRIIMARY KEY с одной колонкой или с несколькими. Уже поддерживаются индексы, но пока нельзя создать уникальный индекс. Нет ограничений на вставку значения с уже существующим PRIMARY KEY, при этом произойдёт обновление записи.
Заполним таблицы данными:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | INSERT INTO city VALUES ('60615','Chicago','IL'); INSERT INTO city VALUES ('45211','Cincinnati','OH'); INSERT INTO city VALUES ('33575','Clearwater','FL'); INSERT INTO city VALUES ('75243','Dallas','TX'); INSERT INTO city VALUES ('32018','Daytona Beach','FL'); INSERT INTO city VALUES ('33441','Deerfield Beach','FL'); INSERT INTO city VALUES ('48226','Detroit','MI'); INSERT INTO city VALUES ('90029','Hollywood','CA'); INSERT INTO city VALUES ('92714','Irvine','CA'); INSERT INTO city VALUES ('90804','Long Beach','CA'); INSERT INTO city VALUES ('11788','Long Island','NY'); INSERT INTO city VALUES ('90018','Los Angeles','CA'); INSERT INTO city VALUES ('70112','New Orleans','LA'); INSERT INTO city VALUES ('10580','New York','NY'); INSERT INTO city VALUES ('10019','New York','NY'); INSERT INTO city VALUES ('92262','Palm Springs','CA'); INSERT INTO city VALUES ('97213','Portland','OR'); INSERT INTO city VALUES ('60018','Rosemont','IL'); INSERT INTO city VALUES ('95054','Santa Clara','CA'); INSERT INTO city VALUES ('20903','Silver Spring','MD'); INSERT INTO city VALUES ('20037','Seattle','WA'); INSERT INTO city VALUES ('20005','Seattle','WA'); INSERT INTO city VALUES ('20019','Seattle','WA'); INSERT INTO customer VALUES (3000,'Mrs','Jenny','Porter','10580','1340 N. Ash Street, #3'); INSERT INTO customer VALUES (3100,'Mr','Peter','Brown','48226','1001 34th St., APT.3'); INSERT INTO customer VALUES (3200,'Company',NULL,'Datasoft','90018','486 Maple St.'); INSERT INTO customer VALUES (3300,'Mrs','Rose','Brian','75243','500 Yellowstone Drive, #2'); INSERT INTO customer VALUES (3400,'Mrs','Mary','Griffith','20005','3401 Elder Lane'); INSERT INTO customer VALUES (3500,'Mr','Martin','Randolph','60615','340 MAIN STREET, #7'); INSERT INTO customer VALUES (3600,'Mrs','Sally','Smith','75243','250 Curtis Street'); INSERT INTO customer VALUES (3700,'Mr','Mike','Jackson','45211','133 BROADWAY APT. 1'); INSERT INTO customer VALUES (3800,'Mrs','Rita','Doe','97213','2000 Humboldt St., #6'); INSERT INTO customer VALUES (3900,'Mr','George','Howe','75243','111 B Parkway, #23'); INSERT INTO customer VALUES (4000,'Mr','Frank','Miller','95054','27 5th St., 76'); INSERT INTO customer VALUES (4100,'Mrs','Susan','Baker','90018','200 MAIN STREET, #94'); INSERT INTO customer VALUES (4200,'Mr','Joseph','Peters','92714','700 S. Ash St., APT.12'); INSERT INTO customer VALUES (4300,'Company',NULL,'TOOLware','20019','410 Mariposa St., #10'); INSERT INTO customer VALUES (4400,'Mr','Antony','Jenkins','20903','55 A Parkway, #15'); INSERT INTO hotel VALUES (10,'Congress','20005','155 Beechwood St.'); INSERT INTO hotel VALUES (30,'Regency','20037','477 17th Avenue'); INSERT INTO hotel VALUES (20,'Long Island','11788','1499 Grove Street'); INSERT INTO hotel VALUES (70,'Empire State','12203','65 Yellowstone Dr.'); INSERT INTO hotel VALUES (80,'Midtown','10019','12 Barnard St.'); INSERT INTO hotel VALUES (40,'Eighth Avenue','10019','112 8th Avenue'); INSERT INTO hotel VALUES (50,'Lake Michigan','60601','354 OAK Terrace'); INSERT INTO hotel VALUES (60,'Airport','60018','650 C Parkway'); INSERT INTO hotel VALUES (90,'Sunshine','33575','200 Yellowstone Dr.'); INSERT INTO hotel VALUES (100,'Beach','32018','1980 34th St.'); INSERT INTO hotel VALUES (110,'Atlantic','33441','111 78th St.'); INSERT INTO hotel VALUES (120,'Long Beach','90804','35 Broadway'); INSERT INTO hotel VALUES (150,'Indian Horse','92262','16 MAIN STREET'); INSERT INTO hotel VALUES (130,'Star','90029','13 Beechwood Place'); INSERT INTO hotel VALUES (140,'River Boat','70112','788 MAIN STREET'); INSERT INTO room VALUES (10,'single',20,135.00); INSERT INTO room VALUES (10,'double',45,200.00); INSERT INTO room VALUES (30,'single',12,45.00); INSERT INTO room VALUES (30,'double',15,80.00); INSERT INTO room VALUES (20,'single',10,70.00); INSERT INTO room VALUES (20,'double',13,100.00); INSERT INTO room VALUES (70,'single',4,115.00); INSERT INTO room VALUES (70,'double',11,180.00); INSERT INTO room VALUES (80,'single',15,90.00); INSERT INTO room VALUES (80,'double',19,150.00); INSERT INTO room VALUES (80,'suite',5,400.00); INSERT INTO room VALUES (40,'single',20,85.00); INSERT INTO room VALUES (40,'double',35,140.00); INSERT INTO room VALUES (50,'single',50,105.00); INSERT INTO room VALUES (50,'double',230,180.00); INSERT INTO room VALUES (50,'suite',12,500.00); INSERT INTO room VALUES (60,'single',10,120.00); INSERT INTO room VALUES (60,'double',39,200.00); INSERT INTO room VALUES (60,'suite',20,500.00); INSERT INTO room VALUES (90,'single',45,90.00); INSERT INTO room VALUES (90,'double',145,150.00); INSERT INTO room VALUES (90,'suite',60,300.00); INSERT INTO room VALUES (100,'single',11,60.00); INSERT INTO room VALUES (100,'double',24,100.00); INSERT INTO room VALUES (110,'single',2,70.00); INSERT INTO room VALUES (110,'double',10,130.00); INSERT INTO room VALUES (120,'single',34,80.00); INSERT INTO room VALUES (120,'double',78,140.00); INSERT INTO room VALUES (120,'suite',55,350.00); INSERT INTO room VALUES (150,'single',44,100.00); INSERT INTO room VALUES (150,'double',115,190.00); INSERT INTO room VALUES (150,'suite',6,450.00); INSERT INTO room VALUES (130,'single',89,160.00); INSERT INTO room VALUES (130,'double',300,270.00); INSERT INTO room VALUES (130,'suite',100,700.00); INSERT INTO room VALUES (140,'single',10,125.00); INSERT INTO room VALUES (140,'double',9,200.00); INSERT INTO room VALUES (140,'suite',78,600.00); INSERT INTO reservation VALUES (100,3000,80,'single',DATE'2004-11-13',DATE'2004-11-15'); INSERT INTO reservation VALUES (110,3000,100,'double',DATE'2004-12-24',DATE'2005-01-06'); INSERT INTO reservation VALUES (120,3200,50,'suite',DATE'2004-11-14',DATE'2004-11-18'); INSERT INTO reservation VALUES (130,3900,110,'single',DATE'2005-02-01',DATE'2005-02-03'); INSERT INTO reservation VALUES (150,3600,70,'double',DATE'2005-03-14',DATE'2005-03-24'); INSERT INTO reservation VALUES (140,4300,80,'double',DATE'2004-04-12',DATE'2004-04-30'); INSERT INTO reservation VALUES (160,4100,70,'single',DATE'2004-04-12',DATE'2004-04-15'); INSERT INTO reservation VALUES (170,4400,150,'suite',DATE'2004-09-01',DATE'2004-09-03'); INSERT INTO reservation VALUES (180,3100,120,'double',DATE'2004-12-23',DATE'2005-01-08'); INSERT INTO reservation VALUES (190,4300,140,'double',DATE'2004-11-14',DATE'2004-11-17'); |
Acapella DB поддерживает сложные условия выборок: JOIN, ORDER BY, агрегации, алиасы. Сделаем несколько выборок.
Выберем все отели в Нью-Йорке, отсортированные по названию:
1 2 3 4 5 | SELECT h.name, h.id, h.address FROM hotel h JOIN city c ON h.zip = c.zip WHERE c.name = 'New York' ORDER BY h.name; |
результат:
+---------------+------------+----------------+ | name | id | address | +---------------+------------+----------------+ | Eighth Avenue | 40 | 112 8th Avenue | | Midtown | 80 | 12 Barnard St. | +---------------+------------+----------------+
Выберем среднюю цену за комнату:
1 | SELECT AVG(price) AS "avg" FROM room; |
результат:
+---------------------+ | avg | +---------------------+ | 201.5789473684211 | +---------------------+
Выберем количество свободных комнат по отелям, отсортируем отели по названию:
1 2 3 4 | SELECT h.name, SUM(r."free") AS "sum" FROM hotel h JOIN room r ON h.id = r.hotel_id GROUP BY h.name; |
результат:
+---------------+---------------------+ | name | sum | +---------------+---------------------+ | Congress | 65 | | Regency | 27 | | Indian Horse | 165 | | Long Island | 23 | | Lake Michigan | 292 | | Sunshine | 250 | | Eighth Avenue | 55 | | Beach | 35 | | Star | 489 | | Long Beach | 167 | | River Boat | 97 | | Airport | 69 | | Empire State | 15 | | Atlantic | 12 | | Midtown | 39 | +---------------+---------------------+
Заключение
Мы рассмотрели Acapella DB со стороны классических SQL баз данных: подключились через JDBC, создали реляционную схему данных, выполнили запросы с использованием джоинов и агрегаций. Но мы ещё далеки от уровня MySQL или PostgreSQL. Поддержка SQL позволяет попробовать Acapella DB без серьёзных изменений в стеке технологий.
Мы рассказали только про SQL, но в Acapella DB есть ещё много интересного: распределение данных по узлам, поддержка консистентности в распределённых транзакциях.
Подробнее об этом мы расскажем в следующих статьях, которые будут в ближайшее время.
Ответить
Want to join the discussion?Feel free to contribute!