Типы данных
Давай обратим внимание на таблицу:
"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
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ