Industrial Programming Java - Lection Pack 03 - Relational Databases - Lavrentyev Fedor

Preview:

Citation preview

Реляционные базы данных

Модель предметной области

Модель предметной областиСовокупность сущностей и их отношений в

базе данныхОтражающая взаимосвязи между

реальными объектами предметной области

Цели проектирования модели П.О.Точно отразить реальные взаимосвязи

между сущностямиУпростить логическую структуру БДОбеспечить удобное использование БДОблегчить возможную эволюцию моделиОптимально использовать физические

возможности машины

Терминология реляционных БД

Терминология реляционных БДОтношение ( = таблица)Атрибут ( = столбец)Заголовок отношения ( = типы столбцов)Кортеж ( = строка, запись)Первичный ключ ( = идентификатор)Внешний ключ ( = связь, отношение)

НормализацияПроектирование начинается с одной

условной супертаблицы (отношения)Нормализация - декомпозиция отношения с

выделением меньших отношений и связей между ними

Выделяют не менее 5 нормальных формЗадача - свести исходное отношение к

приемлемой нормальной форме

ИдентификаторыПервичный ключ (Primary Key)

Неявный ключСуррогатный ключЕстественный ключSequence / Serial / Identity

Вторичный ключ (Secondary Key)Композитный ключФункциональный ключУникальный ключ

ИндексФизическая реализация вторичного ключаКомпактно организованная структураОсуществляет поиск записи по значению

ключа - помогает ускорить запросыОсуществляет проверку условия

(constraint) на пространстве ключей

Реализация индексаКак правило, физически хранится отдельно от

таблицыСодержит только данные ключа и ссылки на

соответствующие записиОрганизован в виде структуры поиска -

дерево поиска, хеш-таблица, гистограммаМожет храниться в памяти или на диске, в

зависимости от этого - разные реализации

ВзаимосвязьТермин - внешний ключ (Foreign Key)Столбец-ссылка, указывает на ключ в

другой таблицеФизически реализуется в виде ссылки на

индекс в другой таблицеИспользование ссылок позволяет СУБД

переходить сразу к нужной записи

Типы взаимосвязи1:(0..1) “Один к одному”. Вспомогательная

таблица либо дополнительные столбцы1:* - “Один к многим”. Внешний ключ.*:* - “Многие ко многим”. Промежуточная

таблица с двумя внешними ключами.

Планирование запросовСУБД составляет план выполнения

каждого запроса с учетом физической организации данных

В плане выполнения задействуются индексы и связи между таблицами

При проектировании нужно убедиться, что планы выполнения наиболее важных запросов выстраиваются оптимально

Эффект от индексовНа построение и обновление индекса

тратится время - замедляется вставка, удаление и модификация

Можно быстро перейти к записи по значению вторичного ключа

При работе с внешними ключами часть операций можно производить на индексе

Результат проектированияСписок таблиц с заголовкамиМеханизмы генерации идентификаторовЗапланированные индексы (с типами)Связи между таблицамиСводный обзор планов выполнения

важнейших запросов

Подключение к базе данныхРеляционные базы данных

SQL CLIsql> create table animals (id integer, name varchar, weight decimal);sql> show tables;TABLE_NAME | TABLE_SCHEMAANIMALS | PUBLICsql> insert into animals values (1, 'kitten', 2.5);sql> select name from animals where weight < 3.0;NAMEkitten

JDBCOpen DataBase Connectivity (1992) -

унифицированное API SQL баз данныхJava DataBase Connectivity (1997) -

унифицированное Java API SQL БДИзначально JDBC просто оборачивало

ODBC, однако потом были написаны нативные реализации

Пример JDBCClass.forName("com.mysql.jdbc.Driver"); // Загрузка драйвераString url = "jdbc:mysql://localhost:3306/db_name";Connection conn = DriverManager.getConnection(url, user, pass);Statement stmt = conn.createStatement();ResultSet rs = stmt.executeQuery("SELECT * FROM users");while (rs.next()) { // Process row}stmt.close();

Проблема - слишком много буквРучное управление подключениямиРучное управление запросами к базеРучное управление транзакциямиОтсутствие конкурентного доступаОпасности при закрытии ресурсовНизкоуровневое API для данныхСложная работа с исключениями

Решение - Spring JDBCРасширение Spring FrameworkУправляет подключениями и запросамиВовремя закрывает дескрипторыТесно интегрировано с JTA и Spring

Transactions (см далее)Каноничная иерархия исключенийВысокоуровневое API для запросов

Пример Spring JDBCJdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);int updated = jdbcTemplate.update( "insert into animals " + "(id, name, weight) " + "values (1, 'kitten', 2.5)");List<String> names = jdbcTemplate.queryForList( "select name from animals " + "where weight < 3.0", String.class);jdbcTemplate.execute("alter table animals " + "add column (height decimal)");

Реляционные базы данных

Устройство Spring JDBC

DataSource<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /></bean>

DataSource@Beanpublic DataSource dataSource( @Value("${jdbc.url}") String url, @Value("${jdbc.username}") String username, @Value("${jdbc.password}") String password) { return new DriverManagerDataSource(url, username, password);}

Connection PoolingSpring DataSource на каждый запрос

открывает новые подключенияВыгодно многократно переиспользовать

созданные подключенияЭто сложная задача с массой нюансовЕсть готовые реализации - C3P0, DBCP,

BoneCP

<bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close"> <property name="driverClassName" value="${jdbc.driver}" /> <property name="jdbcUrl" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /></bean>

Пример BoneCP Datasource

JDBC TemplateJdbcTemplate - класс-фасад, центральный

класс Spring JDBCПредоставляет методы для упрощенной

работы с JDBCСоздается вокруг конкретного DataSourceJdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

Методы JDBC TemplatejdbcTemplate.execute( “alter table users add column (last_login timestamp)”);int count = jdbcTemplate.queryForObject( “select count(*) from table”, Integer.class);String userName = jdbcTemplate.queryForObject( “select name from users where uid = 1”, String.class);List<String> admins = jdbcTemplate.queryForList( “select name from users where is_admin = 1”, String.class);Map<String, Object> row3 = jdbcTemplate.queryForMap( “select * from rows where row = 3”);

Методы JDBC Templateint inserted = jdbcTemplate.update( “insert into animals (id, name, weight) ” + “values (1, ‘kitten’, 2.5)”);int updated = jdbcTemplate.update( “update animals set is_heavy = 1 where weight > 50”);int deleted = jdbcTemplate.update( “delete from animals where is_heavy = 0”);

Реляционные базы данных

Возможности Spring JDBC

Row MapperList<Animal> animals = jdbcTemplate.query( "select * from animals", new RowMapper<Animal>() { public Animal mapRow(ResultSet rs, int rowNum) throws SQLException { Animal animal = new Animal(); animal.setId(rs.getInt("id")); animal.setName(rs.getString("name")); animal.setWeight(rs.getDouble("weight")); return animal; }});

Row MapperList<Animal> animals = jdbcTemplate.query( "select * from animals", (rs, rowNum) -> { Animal animal = new Animal(); animal.setId(rs.getInt("id")); animal.setName(rs.getString("name")); animal.setWeight(rs.getDouble("weight")); return animal;});

Row Callbackclass MeanCallback implements RowCallbackHandler { double sum = 0; int count = 0; public double getMean() { return sum/count; }

public void processRow(ResultSet rs) { sum += rs.getDouble(1); count += 1; }}

Row CallbackMeanCallback callback = new MeanCallback();String sql = "select weight from animals where in_zoo = 1";jdbcTemplate.query(sql, callback);double mean = callback.getMean();

Стандартизация исключенийВ JDBC фигурирует checked SQLExceptionУ каждого вендора свой подход к ошибкамИсключения в транзакционной среде

требуют внимательной обработкиSpring берет на себя разбор исключений Он использует свою unchecked иерархиюМаппинги пишутся отдельно к каждому

вендору (много доступно из коробки)

Prepared StatementСтадии обработки SQL-запроса:

Передача текста запросаПарсинг в синтаксическое деревоПостроение плана выполненияВыполнение (вжжжж!)

Для массовых однотипных запросов “планировочные” стадии несут оверхед

Есть возможность избежать этого

Prepared StatementЗапрос с Placeholder’ами:

select count(*) from animals where weight >= ? and weight < ? and country_id = 4;

Отправим запрос на сервер:Передача текста запросаПарсинг в синтаксическое деревоПостроение плана выполнения

Запомним ID запроса

Prepared StatementДля запроса достаточно отправить только

ID и значения Placeholder’овЭкономия на передаче данных, парсинге

текста и построении планаДля легких запросов это >50% времени

Prepared Statementstatic ANIMAL_ROW_MAPPER = new RowMapper<Animal>() {...}

for (int animalId : animalIds) { Animal animal = jdbcTemplate.queryForObject( "select * from animals where id = ? ", animalId, ANIMAL_ROW_MAPPER); animalsInZoo.add(animal); jdbcTemplate.update( "update animals set in_zoo = 1 where id = ? ", animalId);}

Batch UpdateList<Object[]> batchArgs = new ArrayList<>();batchArgs.add(new Object[] {2, "Panther", 200.0});batchArgs.add(new Object[] {3, "Leon", 250.0});batchArgs.add(new Object[] {4, "Tiger", 300.0}); jdbcTemplate.batchUpdate( "insert into animals values (?, ?, ?)", batchArgs);

Ручные Statement Setter’ыList<Animal> animals = ...;int batchSize = ...;String query = "insert into animals values (?, ?, ?)";jdbcTemplate.batchUpdate(query, animals, batchSize, new ParameterizedPreparedStatementSetter<Animal>() { public void setValues(PreparedStatement ps, Animal animal) throws SQLException { ps.setInt(1, animal.getId()); ps.setString(2, animal.getName()); ps.setDouble(3, animal.getWeight()); }});

Ручные Statement Setter’ыList<Animal> animals = ...;int batchSize = ...;String query = "insert into animals values (?, ?, ?";jdbcTemplate.batchUpdate(query, animals, batchSize, (ps, animal) -> { ps.setInt(1, animal.getId()); ps.setString(2, animal.getName()); ps.setDouble(3, animal.getWeight()); });

Maven dependencies<dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>4.0.6.RELEASE</version></dependency><dependency> <groupId>com.jolbox</groupId> <artifactId>bonecp</artifactId> <version>0.8.0.RELEASE</version></dependency>

Рекомендуемая литература

Рекомендуемая литература

Кристофер Дейт.Введение в системы баз данных.Восьмое (!) издание.