当前位置: 首页 > 知识库问答 >
问题:

将java.time.LocalDate对象插入/从SQL数据库(如H2)中获取

毕浩渺
2023-03-14

使用PreparedStatement::SetDateResultSet::GetDate的旧方法适用于遗留的java.sql.date类型。我想避免使用这些麻烦的旧日期时间类。

通过JDBC驱动程序发送java.time类型的现代方式是什么?

共有1个答案

鲍钊
2023-03-14

我们有两种通过JDBC交换java.time对象的途径:

  • JDBC 4.2兼容驱动程序
    如果您的JDBC驱动程序符合JDBC 4.2规范或更高版本,则可以直接处理java.time对象。
  • JDBC 4.2之前的旧驱动程序
    如果您的JDBC驱动程序还不符合JDBC 4.2或更高版本,那么您可以简单地将java.time对象转换为等效的java.sql类型,反之亦然。查看添加到旧类中的新转换方法。

遗留的日期时间类,如java.util.datejava.util.Calendar,以及相关的java.sql.date类,如java.sql.date非常混乱。它们是用设计不佳的黑客方法构建的,事实证明它们是有缺陷的、麻烦的和令人困惑的。尽可能避开他们。现在被java.time类所取代。

myPreparedStatement.setObject ( 1 , myLocalDate ); // Automatic detection and conversion of data type.
LocalDate localDate = myResultSet.getObject ( "my_date_column_" , LocalDate.class ); 
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_:a4474e79-3e1f-4395-bbba-044423b37b9f日期_:2017-03-27

ID_:5D47BC3D-EBFA-43AB-BBC2-7BB2313B33B0日期_:2017-03-28

对于H2,上面显示的代码是我建议您走的路。但是仅供参考,对于其他还不符合JDBC4.2的数据库,我可以向您展示如何在java.time和java.sql类型之间进行简单的转换。这种转换代码当然可以在H2上运行,如下所示,但现在我们有了上面所示的更简单的方法,这样做是愚蠢的。

java.sql.Date mySqlDate = java.sql.Date.valueOf( myLocalDate );
preparedStatement.setDate ( 1, mySqlDate );
java.sql.Date mySqlDate = myResultSet.getDate( 1 );
LocalDate myLocalDate = mySqlDate.toLocalDate();
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 ( );
        }
    }
}
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();
        }
    }
}

Java.time框架内置在Java8和更高版本中。这些类取代了麻烦的旧的遗留日期时间类,如java.util.dateCalendar、&SimpleDateFormat

要了解更多信息,请参阅Oracle教程。并搜索堆栈溢出的许多例子和解释。规范是JSR310。

现在处于维护模式的Joda-Time项目建议迁移到java.Time类。

    null
    null
    null
 类似资料:
  • 我试图将选中的项目从checkedlistbox保存到我的SQL数据库,并从同一个SQL数据库填充我的checkedlistbox,到目前为止,我能够从checkedlistbox中获取选中项的文本,并将其保存为字符串,然后使用标签显示是否获取选中项的文本及其工作情况,但当我尝试在数据库中插入选中的数据时,我收到一个错误“连接属性尚未初始化”关于ExecuteNonQuery()方法。 这个错误

  • 我有一个SQL函数,它返回一个对象。 上面返回一个对象,比如 我需要从对象中获取单独的值。

  • 问题内容: 我想初始化一个H2数据库,但是我不确定记录是否存在。如果它们不存在,我什么都不愿做,但是如果它们不存在,我想写默认值。 像这样的东西: 问题答案: 以下内容适用于MySQL,PostgreSQL和H2数据库:

  • 问题内容: 我正在尝试使用H2的runscript运行sql脚本。 该表之一包含一个长文本类型,该类型存储了一个xml文档(来自SAP数据库) 因此,Insert语句包含XML的长文本(大约200行XML),虽然很难看,但仍然可以使用。 在SQL解析期间,H2因ArrayOutOfBoundException而崩溃。 插入语句接受的长度是否有限制? 在nsert中,我使用刻度(如mysql中所使用

  • 我正在inMemory数据库中插入数据,当插入数据时,我得到了一个问题, 使用boot、JPA、H2db在内存中插入数据的示例程序 > 创建Pojo并使用JPA注释进行注释 > 配置在app.prop:中 在data.sql文件中添加了给定表 为data.sql中提到的转换添加了名称。 在哪里配置;在Springboot中? 波乔 控制器 错误原因:对名为'in memorydatabaseShu

  • 我有一个CSV文件,如 我正在尝试使用函数将此文件读入数据库,如下所示 出于某种原因,我一直得到< code>SQL错误,指出列数不匹配。 该表是使用Hibernate / GORM创建的,并包含我尝试插入的字段。 select本身似乎可以工作,或者至少在单独执行时不会导致任何错误。我的说法有什么问题?