java.util.Date не может быть передан в java.sql.Date [дубликат]

Симон Моурир дал этот пример :

object o = null;
DateTime d = (DateTime)o;  // NullReferenceException

, где unboxing преобразование (литье) из object (или из одного из классов System.ValueType или System.Enum или из типа интерфейса) - тип значения (кроме Nullable<>) сам по себе дает NullReferenceException.

В другом направлении конверсия бокса из a Nullable<>, которая имеет HasValue, равную false , на ссылочный тип, может дать ссылку null, которая затем может привести к NullReferenceException. Классический пример:

DateTime? d = null;
var s = d.ToString();  // OK, no exception (no boxing), returns ""
var t = d.GetType();   // Bang! d is boxed, NullReferenceException

Иногда бокс происходит по-другому. Например, с помощью этого не общего метода расширения:

public static void MyExtension(this object x)
{
  x.ToString();
}

следующий код будет проблематичным:

DateTime? d = null;
d.MyExtension();  // Leads to boxing, NullReferenceException occurs inside the body of the called method, not here.

Эти случаи возникают из-за специальных правил, используемых во время выполнения при боксе Nullable<> экземпляров.

453
задан Jonas 7 December 2010 в 18:56
поделиться

5 ответов

Поздравляем, вы поразили мою любимую пизду с помощью JDBC: обработка класса даты.

В основном базы данных обычно поддерживают как минимум три формы полей даты и времени, которые являются датой, временем и меткой времени. Каждый из них имеет соответствующий класс в JDBC, и каждый из них расширяется java.util.Date . Быстрая семантика каждого из этих трех выглядит следующим образом:

  • java.sql.Date соответствует SQL DATE, что означает, что он хранит лет, месяцев и дней , в то время как час, минута, секунда и миллисекунда игнорируются. Кроме того, sql.Date не привязан к часам.
  • java.sql.Time соответствует SQL TIME, и, как должно быть очевидно, содержит только информацию о часах, минутах, секундах
  • java.sql.Timestamp соответствует SQL TIMESTAMP, который является точной датой на наносекунду (примечание [8], что util.Date поддерживает только миллисекунды! ) с настраиваемой точностью.

Одной из наиболее распространенных ошибок при использовании драйверов JDBC в отношении этих трех типов является то, что типы обрабатываются некорректно. Это означает, что sql.Date является специфичным для часового пояса, sql.Time содержит текущий год, месяц и день и т. Д.

Наконец: какой из них использовать?

Зависит от SQL тип поля, действительно. PreparedStatement имеет сеттеры для всех трех значений, #setDate() является тем, который для sql.Date, #setTime() для sql.Time и #setTimestamp() для sql.Timestamp.

Обратите внимание, что если вы используете ps.setObject(fieldIndex, utilDateObject); вы можете дать нормальный util.Date большинству драйверов JDBC, которые будут счастливо пожирать его, как если бы он был правильного типа, но когда вы запрашиваете данные позже, вы можете заметить, что на самом деле у вас отсутствует материал.

Я действительно говорю, что ни один из Дат не должен использоваться вообще.

Я говорю, что сохраняйте миллисекунды / наносекунды как простые длинные и конвертируйте их в любые объекты, которые вы используете ( обязательный шлейф joda-времени ). Один хакерский способ, который можно сделать, - сохранить компонент даты как один длинный и временной компонент как другой, например, сейчас будет 20100221 и 154536123. Эти магические числа могут использоваться в SQL-запросах и будут переносимыми из базы данных в другую и позволит вам избежать этой части API JDBC / Java Date: s полностью.

542
ответ дан indivisible 28 August 2018 в 11:20
поделиться

LATE EDIT: Начиная с Java 8, вы не должны использовать ни java.util.Date, ни java.sql.Date, если можете вообще избежать этого, и вместо этого предпочитаете использовать пакет java.time (на основе Joda) а не что-либо другое. Если вы не на Java 8, вот исходный ответ:


java.sql.Date - когда вы вызываете методы / конструкторы библиотек, которые его используют (например, JDBC). Не иначе. Вы не хотите вводить зависимости к библиотекам баз данных для приложений / модулей, которые явно не имеют отношения к JDBC.

java.util.Date - при использовании библиотек, которые его используют. В противном случае, как можно меньше, по нескольким причинам:

  • Это изменчиво, что означает, что вы должны сделать защитную копию этого файла каждый раз, когда вы передаете его или возвращаете его из метода.
  • Он не очень хорошо справляется с датами, которые, как и ваши, действительно напоминают людям, считают классы обработки даты.
  • Теперь, поскольку j.u.D не делает работу очень хорошо, были введены ужасные классы Calendar.
  • Существуют лучшие альтернативы, такие как Joda Time API (который, в свою очередь, может быть изменен и ужасен для работы, и его следует избегать, если у вас нет выбора. может даже превратиться в Java 7 и стать новым официальным API обработки дат - быстрый поиск говорит, что он не будет).

Если вы чувствуете, что это слишком много, ввести новую зависимость, такую ​​как Joda, long s, не так уж плохо использовать для полей timestamp в объектах, хотя я сам обычно обертываю их в juD при их передаче, для безопасности типов и документации.

52
ответ дан Community 28 August 2018 в 11:20
поделиться

У меня была такая же проблема, самый простой способ, которым я нашел вставку текущей даты в подготовленный оператор, следующий:

preparedStatement.setDate(1, new java.sql.Date(new java.util.Date().getTime()));
9
ответ дан Israelm 28 August 2018 в 11:20
поделиться

Класс java.util.Date в Java представляет определенный момент времени (e, .g., ноябрь 25 16:30:45 до миллисекунды), но тип данных DATE в БД представляет собой только дату (например, 2013 25 ноября). Чтобы вы не предоставили объекту java.util.Date DB по ошибке, Java не позволяет вам установить параметр SQL прямо в java.util.Date:

PreparedStatement st = ...
java.util.Date d = ...
st.setDate(1, d); //will not work

Но он все еще позволяет сделать это с помощью силы / намерения (тогда часы и минуты будут игнорироваться драйвером БД). Это делается с помощью класса java.sql.Date:

PreparedStatement st = ...
java.util.Date d = ...
st.setDate(1, new java.sql.Date(d.getTime())); //will work

Объект java.sql.Date может хранить момент времени (так что его легко создать из java.util.Date) но будет генерировать исключение, если вы попробуете задать ему часы (чтобы обеспечить соблюдение его концепции только даты). Ожидается, что драйвер DB распознает этот класс и просто будет использовать 0 для часов. Попробуйте следующее:

public static void main(String[] args) {
  java.util.Date d1 = new java.util.Date(12345);//ms since 1970 Jan 1 midnight
  java.sql.Date d2 = new java.sql.Date(12345);
  System.out.println(d1.getHours());
  System.out.println(d2.getHours());
}
2
ответ дан Kent Tong 28 August 2018 в 11:20
поделиться

Единственный раз, когда использовать java.sql.Date - в PreparedStatement.setDate. В противном случае используйте java.util.Date. Он говорит, что ResultSet.getDate возвращает java.sql.Date, но его можно назначить непосредственно на java.util.Date.

17
ответ дан saravanakumar 28 August 2018 в 11:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: