Java не хранит точную дату в базе данных MySQL - PullRequest
0 голосов
/ 31 октября 2018

Я писал программу для преобразования строки в объект java.util.Date, а затем сохранения ее в базе данных, программа работает правильно, без ошибок. Но в MySql дата хранится неправильно, java хранит дату, которая является вчерашней датой по отношению к дате, записанной в строке. Пример - если я напишу «2018-11-10», он хранит «2018-11-09». Мой код -

import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class Demo {

    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Connection con;
        Class.forName("com.mysql.cj.jdbc.Driver");
        Date date = Date.valueOf("2018-11-20"); 
        con = DriverManager.getConnection("jdbc:mysql://localhost:9090/ProjectScheduler", "root", "tiger");
        PreparedStatement prepare = con.prepareStatement("insert into SchedulerDB(Date) values(?)");
        prepare.setDate(1, date);
        prepare.executeUpdate();
    }
}

В MySql workbench я создал таблицу как

create table SchedulerDB(Date date)

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

select * from SchedulerDB

Тогда под столбцом «Дата» в таблице «SchedulerDB» я получил 2018-11-19. Но я хочу 2018-11-20, как это то, что я написал в коде Java. Пожалуйста, помогите мне в решении этой проблемы.

1 Ответ

0 голосов
/ 01 ноября 2018

ТЛ; др

myPreparedStatement.setObject(
    … ,
    LocalDate.parse( "2018-11-20")
) ;

Подробнее

Вы используете ужасно разработанный класс java.sql.Date. Этот класс, к сожалению, является подклассом java.util.Date, хотя документация странным образом говорит нам игнорировать этот факт наследования. Таким образом, в то время как java.sql.Date делает вид, что представляет только дату, на самом деле это момент, дата с временем суток, установленным на полночь в некоторой зоне и затем настроенным на UTC. Это ужасный дизайн, и это одна из многих причин, по которым никогда не следует использовать устаревшие классы даты и времени.

Для столбца DATE в SQL используйте современный класс LocalDate.

LocalDate

Класс LocalDate действительно представляет значение только для даты, без времени суток и без часового пояса или смещения от UTC .

Для столбца базы данных типа, подобного стандарту SQL DATE, используйте класс LocalDate в Java.

LocalDate ld = LocalDate.parse( "2018-11-20" );

JDBC 4.2

Начиная с JDBC 4.2, мы можем напрямую обмениваться объектами java.time с базой данных.

myPreparedStatement.setObject( … , ld ) ;

индексирование:

LocalDate ld = myResultSet.getObject( … , LocalDate.class ) ;

Без учета часового пояса полученное значение будет таким же 2018-11-20, которое вы сохранили.

Пример приложения

Вот полный пример приложения, использующего H2 Database Engine . В качестве демонстрации я настроил запись в базу данных в памяти, а не на сохранение в реальном хранилище.

Мы создаем базу данных с одной таблицей, с двумя столбцами:

  • первичный ключ с порядковым номером с именем pkey_
  • a DATE столбец с именем when_

Мы вставляем пару LocalDate объектов, а затем извлекаем строки для выгрузки в консоль.

package com.basilbourque.example;

import java.sql.*;
import java.time.LocalDate;
import java.util.List;

public class EventDate {
    public static void main ( String[] args ) {
        EventDate app = new EventDate();
        app.doIt();
    }

    private void doIt ( ) {
        final String driverName = "org.h2.Driver";
        final String catalogName = "event_demo_db";
        final String jdbcPath = "jdbc:h2:mem:" + catalogName + ";DB_CLOSE_DELAY=-1";  // Set delay to keep in-memory database even after last connection closed.

        // Verify JDBC driver.
        try {
            Class.forName( driverName );
        } catch ( ClassNotFoundException e ) {
            e.printStackTrace();
        }

        // Connect, and create database.
        try (
                Connection conn = DriverManager.getConnection( jdbcPath ) ;
        ) {
            String sql = null;

            // Create table.
            try ( Statement stmt = conn.createStatement() ; ) {
                sql = "CREATE TABLE " + "event_" + " ( \n" +
                        " pkey_ IDENTITY PRIMARY KEY , \n" +
                        " when_ DATE NOT NULL \n" +
                        ") ; \n";
                System.out.println( "TRACE - SQL:\n" + sql );
                stmt.execute( sql );
            }
            System.out.println( "TRACE - Created table `event_`." );

            // Add rows
            sql = "INSERT INTO event_ ( when_ ) \n" +
                    "VALUES ( ? ) " +
                    "; ";

            List < LocalDate > dates = List.of( LocalDate.parse( "2018-11-10" ) , LocalDate.parse( "2018-12-31" ) );
            System.out.println( "Inserting list of LocalDate objects: " + dates );
            try (
                    PreparedStatement ps = conn.prepareStatement( sql ) ;
            ) {
                for ( LocalDate localDate : dates ) {
                    ps.setObject( 1 , localDate );
                    ps.executeUpdate();
                }
            }

            // Retrieve rows
             sql = "SELECT * FROM " + "event_" + " ;";
            try (
                    Statement stmt = conn.createStatement() ;
                    ResultSet rs = stmt.executeQuery( sql ) ;
            ) {
                while ( rs.next() ) {
                    int pkey = rs.getInt( "pkey_" );
                    LocalDate when = rs.getObject( "when_" , LocalDate.class );
                    System.out.println( "Row pkey_: " + pkey + " when_: " + when );
                }
            }


        } catch ( SQLException e ) {
            e.printStackTrace();
        }

    }
}

При запуске.

Вставка списка объектов LocalDate: [2018-11-10, 2018-12-31]

Строка pkey_: 1 когда_: 2018-11-10

Строка pkey_: 2 когда_: 2018-12-31


О java.time

Платформа java.time встроена в Java 8 и более поздние версии. Эти классы вытесняют проблемные старые устаревшие классы даты и времени, такие как java.util.Date, Calendar, & SimpleDateFormat.

Проект Joda-Time , теперь в режиме обслуживания , рекомендует выполнить переход на классы java.time .

Чтобы узнать больше, см. Oracle Tutorial . И поиск переполнения стека для многих примеров и объяснений. Спецификация JSR 310 .

Вы можете обмениваться java.time объектами напрямую с вашей базой данных. Используйте драйвер JDBC , совместимый с JDBC 4.2 или более поздней версии. Нет необходимости в строках, нет необходимости в java.sql.* классах.

Где получить классы java.time?

Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Здесь вы можете найти некоторые полезные классы, такие как Interval, YearWeek, YearQuarter и more .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...