查询以 JDBC 默认格式 (yyyy-mm-dd) 可视化。
不,没有“JDBC 默认格式”这样的东西。 LocalDate::toString生成的文本是标准的ISO 8601格式,YYYY-MM-DD.这与JDBC无关。
您的代码还有其他问题。所以请继续阅读。
使用智能对象,而不是哑字符串
假设您的数据库列的类型类似于 SQL 标准类型 DATE,使用与 JDBC 4.2 或更高版本兼容的 JDBC 驱动程序检索该值作为 LocalDate 对象。停止思考文本。考虑智能对象,而不是哑字符串。
LocalDate localDate = myResultSet.getObject( … , LocalDate.class ) ;
同样,向数据库发送适当的对象而不是纯文本。 Use a prepared statement 和 ? 占位符。
myPreparedStatement.setObject( … , localDate ) ; // Send object to database, to be written into row in table.
将检索与格式化/表示分开
只有稍后您才应该考虑格式化数据以呈现给用户。通常最好将数据的检索与数据的格式化/表示分开。首先将您的数据收集到对象中,然后生成用于演示的文本。
随着即将到来的,将数据收集到对象中变得更加容易和简单记录功能 previewed in Java 14 和 arriving in Java 15。构造函数、getter 方法、toString、equals & hashCode 等等都是在后台自动合成的。
record Order ( UUID id , String description , LocalDate whenPlaced ) {} // That is all the code you need. Constructor, getter methods, `toString`, `equals` & `hashCode`, and so on are all synthesized automatically behind the scenes.
以标准的ISO 8601 格式生成代表对象内值的文本。请注意,LocalDate 对象没有文本,也没有“格式”。这样的对象知道如何解析文本,并知道如何生成文本,是不是本身的文字。
String output = localDate.toString() ;
让java.time生成文本时自动本地化。
Locale locale = Locale.CANADA_FRENCH ; // or Locale.US, Locale.ITALY, etc.
DateTimeFormatter f =
DateTimeFormatter
.ofLocalizedDate( FormatStyle.MEDIUM )
.withLocale( locale ) ;
String output = localDate.format( f ) ; // Generate text representing the value of this object, while automatically localizing.
或者,如果您坚持,请指定您自己的自定义格式设置模式。
DateTimeFormatter f = DateTimeFormatter.ofPattern( "MM/dd/uuuu" ) ;
String output = localDate.format( f ) ;
例子
这是一个完整示例的源代码。
此示例使用 H2 Database Engine。我们选择 in-memory database 选项,当 JVM 关闭时它会消失。
首先,建立一个DataSource对象。
// Establish `DataSource`.
org.h2.jdbcx.JdbcDataSource dataSource = new JdbcDataSource();
// Set `DB_CLOSE_DELAY` to `-1` to keep in-memory database in existence after connection closes.
dataSource.setURL( "jdbc:h2:mem:pstmt_localdate_example_db;DB_CLOSE_DELAY=-1" );
dataSource.setUser( "scott" );
dataSource.setPassword( "tiger" );
在第一次连接时,数据库是隐式创建的。该名称来自我们上面DataSource 的 URL 字段。然后我们执行SQL创建表order_。我们使用尾部下划线来避免命名冲突,因为 SQL 标准承诺永远不会以这种方式命名关键字。
顺便说一句,当 text blocks feature 到达 Java 15 (previewed in Java 14) 时,在 Java 中嵌入 SQL 代码会容易得多。
// Create database implicitly upon connection, and create first table.
try (
Connection conn = dataSource.getConnection() ;
Statement stmt = conn.createStatement() ;
)
{
String sql =
"DROP TABLE IF EXISTS order_ ;
"
+
"CREATE TABLE IF NOT EXISTS
" +
" order_
" +
" (
" +
" pkey_ UUID NOT NULL DEFAULT RANDOM_UUID() PRIMARY KEY ,
" +
" description_ VARCHAR NOT NULL ,
" +
" when_placed_ DATE NOT NULL
" +
" )
" +
";";
System.out.println( "sql =
" + sql );
stmt.execute( sql );
}
catch ( SQLException e )
{
e.printStackTrace();
}
我们插入一行。
// Insert row.
try (
Connection conn = dataSource.getConnection() ;
Statement stmt = conn.createStatement() ;
)
{
String sql = "INSERT INTO order_ ( description_ , when_placed_ )
";
sql += "VALUES ( ? , ? )
";
sql += ";";
System.out.println( "sql = " + sql );
try (
PreparedStatement pstmt = conn.prepareStatement( sql , Statement.RETURN_GENERATED_KEYS ) ;
)
{
pstmt.setString( 1 , "blah" );
pstmt.setObject( 2 , LocalDate.now( ZoneId.of( "America/Montreal" ) ) );
pstmt.executeUpdate();
ResultSet rs = pstmt.getGeneratedKeys();
System.out.println( "INFO - Reporting generated keys." );
while ( rs.next() )
{
UUID uuid = rs.getObject( 1 , UUID.class );
System.out.println( "generated keys: " + uuid );
}
}
}
catch ( SQLException e )
{
e.printStackTrace();
}
将行转储到控制台。如果您进一步查看这段代码,您将看到我们如何使用自动本地化生成文本。我们使用自定义格式化程序生成文本。我建议通常通过硬编码的自定义格式进行本地化。
// Dump all rows.
try (
Connection conn = dataSource.getConnection() ;
Statement stmt = conn.createStatement() ;
)
{
System.out.println( "INFO - Reporting all rows in table `order_`." );
String sql = "SELECT * FROM order_ ; ";
System.out.println( "sql = " + sql );
try ( ResultSet rs = stmt.executeQuery( sql ) ; )
{
while ( rs.next() )
{
UUID pkey = rs.getObject( "pkey_" , UUID.class );
String description = rs.getString( "description_" );
LocalDate whenPlaced = rs.getObject( "when_placed_" , LocalDate.class );
// Dump to console.
System.out.println( "-----------------" );
System.out.println( "pkey = " + pkey );
System.out.println( "description = " + description );
System.out.println( "whenPlaced = " + whenPlaced ); // Standard ISO 8601 format.
// Localized.
Locale locale = new Locale( "fr" , "DZ" ); // French language, Algeria culture.
DateTimeFormatter formatterLocalized = DateTimeFormatter.ofLocalizedDate( FormatStyle.SHORT ).withLocale( locale );
String outputLocalized = whenPlaced.format( formatterLocalized );
System.out.println( "whenPlaced (localized): " + outputLocalized );
// Custom format.
DateTimeFormatter formatterCustom = DateTimeFormatter.ofPattern( "dd/MM/uuuu" );
String outputCustom = whenPlaced.format( formatterCustom );
System.out.println( "whenPlaced (custom-format): " + outputCustom );
System.out.println( "-----------------" );
}
}
}
catch ( SQLException e )
{
e.printStackTrace();
}
运行时。
-----------------
pkey = a4388a40-738b-44bd-b01a-2c487c7e08bf
description = blah
whenPlaced = 2020-06-20
whenPlaced (localized): 20/06/2020
whenPlaced (custom-format): 20/06/2020
-----------------
顺便说一下,养成使用分号来终止 SQL 语句的习惯。在某些情况下您可以忽略它,但在其他情况下会导致问题。