挿入およびフェッチの方法 Java.timeLocalDate
などのタイプ [〜#〜] jdbc [〜#〜]H2 Database Engine ?などのSQLデータベースに
PreparedStatement::setDate
および ResultSet::getDate
を使用する古い方法は、レガシー Java.sql.Date
タイプで機能します。これらの面倒な古い日時クラスの使用は避けたいと思います。
JDBCドライバー を介してJava.time型を送信するための最新の方法は何ですか?
JDBCを介してJava.timeオブジェクトを交換する方法は2つあります。
Java.util.Date
、Java.util.Calendar
などの従来の日時クラス、およびJava.sql
などの関連するJava.sql.Date
クラスはひどい混乱です。不十分に設計されたハッキングされたアプローチで構築されており、欠陥があり、面倒で、混乱を招くことが証明されています。可能な限りそれらを避けてください。現在、Java.timeクラスに取って代わられています。
H2用の組み込みJDBCドライバー(2017-03現在)はJDBC4.2に準拠しているようです。
準拠ドライバーは、Java.timeタイプを認識するようになりました。しかし、JDBC委員会はsetLocalDate
/getLocalDate
の種類のメソッドを追加するのではなく、 setObject
getObject
メソッド。
データベースにデータを送信するには、Java.timeオブジェクトをPreparedStatement::setObject
に渡すだけです。渡された引数のJavaタイプはドライバーによって検出され、適切なSQLタイプに変換されます。AJava LocalDate
はSQL DATE
タイプ。これらのマッピングのリストについては、 JDBC Maintenance Release 4.2 PDFドキュメントのセクション22を参照してください。
myPreparedStatement.setObject ( 1 , myLocalDate ); // Automatic detection and conversion of data type.
データベースからデータを取得するには、ResultSet::getObject
を呼び出します。結果のObject
オブジェクトをキャストする代わりに、受け取ると予想されるデータ型の Class
という追加の引数を渡すことができます。期待されるクラスを指定することにより、 type-safety が [〜#〜] ide [〜#〜] およびコンパイラによってチェックおよび検証されます。
LocalDate localDate = myResultSet.getObject ( "my_date_column_" , LocalDate.class );
これは、H2データベースにLocalDate
値を挿入して選択する方法を示す実用的なサンプルアプリ全体です。
package com.example.h2localdate;
import Java.sql.*;
import Java.time.LocalDate;
import Java.time.ZoneId;
import Java.util.UUID;
/**
* Hello world!
*/
public class App {
public static void main ( String[] args ) {
App app = new App ( );
app.doIt ( );
}
private void doIt ( ) {
try {
Class.forName ( "org.h2.Driver" );
} catch ( ClassNotFoundException e ) {
e.printStackTrace ( );
}
try (
Connection conn = DriverManager.getConnection ( "jdbc:h2:mem:trash_me_db_" ) ;
Statement stmt = conn.createStatement ( ) ;
) {
String tableName = "test_";
String sql = "CREATE TABLE " + tableName + " (\n" +
" id_ UUID DEFAULT random_uuid() PRIMARY KEY ,\n" +
" date_ DATE NOT NULL\n" +
");";
stmt.execute ( sql );
// Insert row.
sql = "INSERT INTO test_ ( date_ ) " + "VALUES (?) ;";
try ( PreparedStatement preparedStatement = conn.prepareStatement ( sql ) ; ) {
LocalDate today = LocalDate.now ( ZoneId.of ( "America/Montreal" ) );
preparedStatement.setObject ( 1, today.minusDays ( 1 ) ); // Yesterday.
preparedStatement.executeUpdate ( );
preparedStatement.setObject ( 1, today ); // Today.
preparedStatement.executeUpdate ( );
preparedStatement.setObject ( 1, today.plusDays ( 1 ) ); // Tomorrow.
preparedStatement.executeUpdate ( );
}
// Query all.
sql = "SELECT * FROM test_";
try ( ResultSet rs = stmt.executeQuery ( sql ) ; ) {
while ( rs.next ( ) ) {
//Retrieve by column name
UUID id = rs.getObject ( "id_", UUID.class ); // Pass the class to be type-safe, rather than casting returned value.
LocalDate localDate = rs.getObject ( "date_", LocalDate.class ); // Ditto, pass class for type-safety.
//Display values
System.out.println ( "id_: " + id + " | date_: " + localDate );
}
}
} catch ( SQLException e ) {
e.printStackTrace ( );
}
}
}
実行時。
id_:e856a305-41a1-45fa-ab69-cfa676285461 |日付_:2017-03-26
id_:a4474e79-3e1f-4395-bbba-044423b37b9f |日付_:2017-03-27
id_:5d47bc3d-ebfa-43ab-bbc2-7bb2313b33b0 |日付_:2017-03-28
H2の場合、上記のコードは私が推奨する道です。ただし、参考までに、JDBC 4.2にまだ準拠していない他のデータベースについては、Java.timeタイプとJava.sqlタイプを簡単に変換する方法を紹介します。この種の変換コードは、以下に示すように確かにH2で実行されますが、上に示したより単純なアプローチがあるため、これを行うのはばかげています。
データベースにデータを送信するには、その古いクラスに追加された新しいメソッドを使用して、LocalDate
を Java.sql.Date
オブジェクトに変換します。
Java.sql.Date mySqlDate = Java.sql.Date.valueOf( myLocalDate );
次に、PreparedStatement::setDate
メソッドに渡します。
preparedStatement.setDate ( 1, mySqlDate );
データベースから取得するには、ResultSet::getDate
を呼び出してJava.sql.Date
オブジェクトを取得します。
Java.sql.Date mySqlDate = myResultSet.getDate( 1 );
次に、すぐにLocalDate
に変換します。 Java.sqlオブジェクトはできるだけ簡単に処理する必要があります。 Java.time型のみを使用して、すべてのビジネスロジックおよびその他の作業を実行します。
LocalDate myLocalDate = mySqlDate.toLocalDate();
これは、H2データベースでのJava.timeタイプでのJava.sqlタイプの使用を示すサンプルアプリ全体です。
package com.example.h2localdate;
import Java.sql.*;
import Java.time.LocalDate;
import Java.time.ZoneId;
import Java.util.UUID;
/**
* Hello world!
*/
public class App {
public static void main ( String[] args ) {
App app = new App ( );
app.doIt ( );
}
private void doIt ( ) {
try {
Class.forName ( "org.h2.Driver" );
} catch ( ClassNotFoundException e ) {
e.printStackTrace ( );
}
try (
Connection conn = DriverManager.getConnection ( "jdbc:h2:mem:trash_me_db_" ) ;
Statement stmt = conn.createStatement ( ) ;
) {
String tableName = "test_";
String sql = "CREATE TABLE " + tableName + " (\n" +
" id_ UUID DEFAULT random_uuid() PRIMARY KEY ,\n" +
" date_ DATE NOT NULL\n" +
");";
stmt.execute ( sql );
// Insert row.
sql = "INSERT INTO test_ ( date_ ) " + "VALUES (?) ;";
try ( PreparedStatement preparedStatement = conn.prepareStatement ( sql ) ; ) {
LocalDate today = LocalDate.now ( ZoneId.of ( "America/Montreal" ) );
preparedStatement.setDate ( 1, Java.sql.Date.valueOf ( today.minusDays ( 1 ) ) ); // Yesterday.
preparedStatement.executeUpdate ( );
preparedStatement.setDate ( 1, Java.sql.Date.valueOf ( today ) ); // Today.
preparedStatement.executeUpdate ( );
preparedStatement.setDate ( 1, Java.sql.Date.valueOf ( today.plusDays ( 1 ) ) ); // Tomorrow.
preparedStatement.executeUpdate ( );
}
// Query all.
sql = "SELECT * FROM test_";
try ( ResultSet rs = stmt.executeQuery ( sql ) ; ) {
while ( rs.next ( ) ) {
//Retrieve by column name
UUID id = ( UUID ) rs.getObject ( "id_" ); // Cast the `Object` object to UUID if your driver does not support JDBC 4.2 and its ability to pass the expected return type for type-safety.
Java.sql.Date sqlDate = rs.getDate ( "date_" );
LocalDate localDate = sqlDate.toLocalDate (); // Immediately convert into Java.time. Mimimize use of Java.sql types.
//Display values
System.out.println ( "id_: " + id + " | date_: " + localDate );
}
}
} catch ( SQLException e ) {
e.printStackTrace ( );
}
}
}
楽しみのために別のものを試してみましょう。今回は 接続を取得するためのDataSource
実装を使用 。そして今回は LocalDate.MIN
を試してみました。これは、ISO 8601、-999999999-01-01で約10億年前の定数です。
package work.basil.example;
import Java.sql.*;
import Java.time.LocalDate;
import Java.time.ZoneId;
import Java.util.UUID;
public class LocalDateMin
{
public static void main ( String[] args )
{
LocalDateMin app = new LocalDateMin();
app.doIt();
}
private void doIt ()
{
org.h2.jdbcx.JdbcDataSource ds = new org.h2.jdbcx.JdbcDataSource();
ds.setURL( "jdbc:h2:mem:localdate_min_example_db_;DB_CLOSE_DELAY=-1" );
ds.setUser( "scott" );
ds.setPassword( "tiger" );
try (
Connection conn = ds.getConnection() ;
Statement stmt = conn.createStatement() ;
)
{
String tableName = "test_";
String sql = "CREATE TABLE " + tableName + " (\n" +
" id_ UUID DEFAULT random_uuid() PRIMARY KEY ,\n" +
" date_ DATE NOT NULL\n" +
");";
stmt.execute( sql );
// Insert row.
sql = "INSERT INTO test_ ( date_ ) " + "VALUES (?) ;";
try ( PreparedStatement preparedStatement = conn.prepareStatement( sql ) ; )
{
LocalDate today = LocalDate.now( ZoneId.of( "America/Montreal" ) );
preparedStatement.setObject( 1 , LocalDate.MIN ); // MIN =
preparedStatement.executeUpdate();
}
// Query all.
sql = "SELECT * FROM test_";
try ( ResultSet rs = stmt.executeQuery( sql ) ; )
{
while ( rs.next() )
{
//Retrieve by column name
UUID id = rs.getObject( "id_" , UUID.class ); // Pass the class to be type-safe, rather than casting returned value.
LocalDate localDate = rs.getObject( "date_" , LocalDate.class ); // Ditto, pass class for type-safety.
//Display values
System.out.println( "id_: " + id + " | date_: " + localDate );
}
}
} catch ( SQLException e )
{
e.printStackTrace();
}
}
}
id_:4b0ba138-d7ae-469b-854f-5cbe7430026f | date _:-999999999-01-01
Java.time フレームワークはJava 8以降に組み込まれています。これらのクラスは、厄介な古い legacy date-timeクラスに取って代わります。 Java.util.Date
、 Calendar
、& SimpleDateFormat
。
Joda-Time プロジェクトは現在 メンテナンスモード であり、 Java.time クラスへの移行をアドバイスします。
詳細については、 Oracleチュートリアル を参照してください。そして、StackOverflowで多くの例と説明を検索してください。仕様は JSR 31 です。
Java.timeクラスはどこで入手できますか?
ThreeTen-Extra プロジェクトは、追加のクラスでJava.timeを拡張します。このプロジェクトは、Java.timeに将来追加される可能性のある試験場です。 Interval
、 YearWeek
、 YearQuarter
などの便利なクラスがここにあります。 、および more 。