Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Apa pengaturan Driver JDBC-mysql untuk penanganan DATETIME dan TIMESTAMP yang waras di UTC?

Solusinya adalah dengan mengatur parameter koneksi JDBC noDatetimeStringSync=true dengan useLegacyDatetimeCode=false . Sebagai bonus, saya juga menemukan sessionVariables=time_zone='-00:00' mengurangi kebutuhan untuk set time_zone secara eksplisit pada setiap koneksi baru.

Ada beberapa kode konversi zona waktu "cerdas" yang diaktifkan jauh di dalam ResultSet.getString() metode ketika mendeteksi bahwa kolom adalah TIMESTAMP kolom.

Sayangnya, kode cerdas ini memiliki bug:TimeUtil.fastTimestampCreate(TimeZone tz, int year, int month, int day, int hour, int minute, int seconds, int secondsPart) mengembalikan Timestamp salah menandai zona waktu default JVM, bahkan ketika tz parameter diatur ke sesuatu yang lain:

final static Timestamp fastTimestampCreate(TimeZone tz, int year, int month, int day, int hour, int minute, int seconds, int secondsPart) {
    Calendar cal = (tz == null) ? new GregorianCalendar() : new GregorianCalendar(tz);
    cal.clear();

    // why-oh-why is this different than java.util.date, in the year part, but it still keeps the silly '0' for the start month????
    cal.set(year, month - 1, day, hour, minute, seconds);

    long tsAsMillis = cal.getTimeInMillis();

    Timestamp ts = new Timestamp(tsAsMillis);
    ts.setNanos(secondsPart);

    return ts;
}

Kembalinya ts akan benar-benar valid kecuali ketika lebih jauh dalam rantai panggilan, itu diubah kembali menjadi string menggunakan toString() telanjang metode, yang merender ts sebagai String yang mewakili apa yang akan ditampilkan jam di zona waktu default-JVM, alih-alih representasi String dari waktu dalam UTC. Di ResultSetImpl.getStringInternal(int columnIndex, boolean checkDateTypes) :

                case Types.TIMESTAMP:
                    Timestamp ts = getTimestampFromString(columnIndex, null, stringVal, this.getDefaultTimeZone(), false);

                    if (ts == null) {
                        this.wasNullFlag = true;

                        return null;
                    }

                    this.wasNullFlag = false;

                    return ts.toString();

Menyetel noDatetimeStringSync=true menonaktifkan seluruh kekacauan parse/unparse dan hanya mengembalikan nilai string seperti yang diterima dari database.

Hasil pengujian:

0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0

useLegacyDatetimeCode=false masih penting karena mengubah perilaku getDefaultTimeZone() untuk menggunakan TZ server database.

Saat mengejar ini, saya juga menemukan dokumentasi untuk useJDBCCompliantTimezoneShift tidak benar, meskipun tidak ada bedanya:dokumentasi mengatakan [Ini adalah bagian dari kode tanggal-waktu lama, sehingga properti hanya memiliki efek ketika "useLegacyDatetimeCode=true." ], tapi itu salah, lihat ResultSetImpl.getNativeTimestampViaParseConversion(int, Calendar, TimeZone, boolean) .




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bagaimana cara menyimpan Java Instan di database MySQL

  2. Mysql WHERE masalah dengan daftar yang dipisahkan koma

  3. Bagaimana cara memilih entri dari hubungan ini?

  4. Dapatkan gaji tertinggi kedua untuk setiap orang di mysql

  5. Membandingkan Solusi Replikasi Dari Oracle dan MySQL