JavaRush /Курсы /Модуль 4. Работа с БД /Согласование типов данных в JDBC

Согласование типов данных в JDBC

Модуль 4. Работа с БД
7 уровень , 3 лекция
Открыта

Типы данных

Давай обратим внимание на таблицу:

"C:\Program Files\Java\jdk-17.0.3.1\bin\java.exe…
id java.lang.Integer INT 4
name java.lang.String VARCHAR 12
level java.lang.Integer INT 4
created_date java.sql.Date DATE 91
Process finished with exit code 0

В третьей колонке мы видим типы: INT, VARCHAR, DATE. Это типы SQL-сервера. Значит сервер отдает данные с теми типами, о которых он знает. Как же эти типы преобразовываются в типы Java?

Это как раз и есть одна из вещей, которая была стандартизирована вместе с JDBC. Создатели JDBC начали с того, что зафиксировали список SQL-типов. Есть специальный класс с константами:


class java.sql.Types {
   public static final int CHAR         =   1;
   public static final int NUMERIC    	=   2;
   public static final int DECIMAL     	=   3;
   public static final int INTEGER      =   4;
   public static final int FLOAT        =   6;
   public static final int REAL         =   7;
  …
}

Число — это не порядковый номер в классе, а ID-тип в списке SQL-типов в спецификации SQL. Именно эти числа ты видел в примере в начале лекции.

Также в классе ResultSet есть методы, которые умеют преобразовывать одни типы данных в другие. Не все типы можно преобразовать друг в друга, но логика достаточно понятна. Вот тебе хорошая таблица на первое время:

Метод Тип данных SQL
int getInt() NUMERIC, INTEGER, DECIMAL
float getFloat() NUMERIC, INTEGER, DECIMAL, FLOAT, REAL
double getDoublel() NUMERIC, INTEGER, DECIMAL, FLOAT, REAL
Date getDate() DATE, TIME, TIMESTAMP
Time getTime() DATE, TIME, TIMESTAMP
Timestamp getTimestamp() DATE, TIME, TIMESTAMP
String getString() CHAR, VARCHAR

Среди всех SQL-типов можно явно выделить некоторые группы:

  • числа
  • время
  • строки
  • байтовые объекты

Кстати, а ты обратил внимание на метод getInt()?

JDBC и NULL

Ты обратил внимание, что не так с методом getInt() у класса ResultSet? Давай еще раз посмотрим на его сигнатуру:


int getInt(column)

Это метод возвращает int, а не Integer. Потому что во время создания JDBC-типа Integer еще не было. Ладно, допустим. Тогда у меня вопрос:

У меня есть таблица в базе дaнных, которая имеет колонку с типом INT NULL, которая может принимать значения INT, но также может быть и NULL. Как мне получить значение null из этой колонки?

Не волнуйся, все за тебя уже придумали.

Решение первое. Если SQL-тип в Java представлен ссылочным типом, таким как Date или String, то проблемы нет. Переменные этого типа могут принимать значения null.

Решение второе. Примитивные типы не могут принимать значения null, поэтому методы типа getInt() будут просто возвращать значение по умолчанию. Для int это 0, для float = 0.0f, для double = 0.0d и тому подобное.

А как тогда понять, что было в колонке: 0 или NULL? И на этот вопрос у партии есть ответ.

Решение третье. У класса ResultSet есть специальный метод wasNull(), который возвращает true, если только что вместо NULL метод вернул другое значение.

Все работает именно так, как я тут написал. Пример:


ResultSet results = statement.executeQuery("SELECT * FROM user");
results.next();
int level = results.getInt("level");
 
if (results.wasNull()) {
  System.out.println("Level is null");
} else {
  System.out.println("Level is " + level);
}

Если при обращению к методу getInt() он должен был вернуть null, то метод wasNull() вернет true, иначе метод wasNull() вернет false.

Это работает не только для примитивных типов:


ResultSet results = statement.executeQuery("SELECT * FROM user");
results.next();
String name = results.getString("name");
 
if (results.wasNull()) {
  System.out.println("Name is null");
} else {
  System.out.println("User name is " + name);
}

Это конечно костыль. Зато никаких проблем с NullPointerException. Надо во всем видеть положительные стороны :)

Что не так с типами данных в JDBC?

Продолжаем тест на внимательность. Посмотри внимательно на метод getDate(column)? Что с ним не так? Этот метод имеет вот такой тип результата:


java.sql.Date

Он может хранить null, и это уже неплохо. Но все-таки с ним что-то не так. Подсказка! Вот как выглядит правильный тип Date:


java.util.Date

У них разные пакеты! Это вообще разные типы данных. А причина вот в чем…

Базы данных еще с 70-х годов 20-го века поддерживают 3 типа данных для хранения времени:

  • DATE – хранит дату: год, месяц, день.
  • TIME – хранит время: часы, минуты, секунды.
  • TIMESTAMP – хранит конкретный момент времени: дата, время и миллисекунды.

Язык Java первые 10 лет своего существования имел только один тип данных —– java.util.Date, который хранил момент времени в формате UNIX TIME: количество миллисекунд, которое прошло с начала 1970 года.

Поэтому создатели стандарта JDBC добавили в Java еще три типа данных — специально для JDBC:

  • java.sql.Date
  • java.sql.Time
  • java.sqlTimestamp

И поэтому методы интерфейса ResultSet содержат фиксированные типы данных:

SQL TYPE Java Type Метод
DATE java.sql.Date java.sql.Date getDate()
TIME java.sql.Time java.sql.Time getTime()
TIMESTAMP java.sql.Timestamp java.sql.Timestamp getTimestamp()

И именно этот тип вы видите тут:

"C:\Program Files\Java\jdk-17.0.3.1\bin\java.exe…
id java.lang.Integer INT 4
name java.lang.String VARCHAR 12
level java.lang.Integer INT 4
created_date java.sql.Date DATE 91
Process finished with exit code 0

Догадался, чего тут не хватает? Типов данных, которые появились в Java DateTime API:

  • LocalDate
  • LocalTime
  • LocalDateTime
1
Задача
Модуль 4. Работа с БД, 7 уровень, 3 лекция
Недоступна
Метод wasNull
Метод wasNull
Комментарии (13)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Олег Уровень 106 Expert
25 сентября 2024
Что-то я поплыл, ребятки.
Ольга Николенко Уровень 109 Expert
23 мая 2024
Четвертое решение: типизированный метод Float weight = resultSet.getObject("weight", Float.class);
Николай Уровень 109
9 марта 2024
Пошел на рекорд 14 попыток) не заметил что написал weit 🤪
Aleksey Protasov Уровень 20
23 февраля 2023
ResultSet results = staatement.executeQuery("SELECT * FROM user");
Андрей Уровень 96
20 февраля 2023
"У меня есть таблица в базе денных"
finedefinition Уровень 28
3 февраля 2023
И на этот вопрос у партии есть ответ. Какая партия имеется ввиду? Очень интересно...
bprint Уровень 41
21 февраля 2023
Коммунистическая, конечно же!
Daniel Уровень 51
15 июля 2023
Одобряю!
Виталий Уровень 107 Expert
16 ноября 2023
Большого Брата
Andrey Vysotsky Уровень 32
9 апреля 2024
если у теб возникает вопрос "какая" по отношению к слову партия, то ты уже автоматически изменник родины. Партия она одна, единая, все остальные - предатели. Стыдно такое не знать конечно, проследуйте в воронок, товарищ
Maksim Tebenkov Уровень 51
7 января 2023
staatement.executeQuery("SELECT * FROM user"); очепятка правильнее будет: statement.executeQuery("SELECT * FROM user");
Михаил Уровень 108 Expert
9 ноября 2022
В разделе JDBC и NULL в листинге кода после первой строки разве не нужно было добавить results.next(), чтобы перевести указатель на первую строчку ответа?
Stas S Уровень 108 Expert
16 ноября 2022
Нужно было, иначе получим: java.sql.SQLException: Before start of result set