数据库
首页 > 数据库> > Spring JDBC Postgres SQL Java 8 – 从/向LocalDate的转换

Spring JDBC Postgres SQL Java 8 – 从/向LocalDate的转换

作者:互联网

我正在使用Postgres SQL 9.2,Spring JDBC 4.0.5版和Java 8.
Java 8引入了新的日期/时间API,我想使用它,但是我遇到了一些困难.
我创建了表TABLE_A:

CREATE TABLE "TABLE_A"
(
  new_date date,
  old_date date
)

我正在使用Spring JDBC与数据库进行通信.我创建了Java类,它对应于这个表:

public class TableA
{
    private LocalDate newDate;
    private Date oldDate;
    //getters and setters

}

这是我的代码,它可以插入新行:

public void create(TableA tableA)
{
    BeanPropertySqlParameterSource parameterSource = new BeanPropertySqlParameterSource(tableA);
    final String sql = "INSERT INTO public.TABLE_A (new_date,old_date) values(:newDate,:oldDate)";
    namedJdbcTemplate.update(sql,parameterSource);

}

当我执行这个方法时,我得到了异常:

org.postgresql.util.PSQLException: Can't infer the SQL type to use for an instance of java.time.LocalDate. Use setObject() with an explicit Types value to specify the type to use.

所以我更新了BeanPropertySqlParameterSource的创建:

BeanPropertySqlParameterSource parameterSource = new BeanPropertySqlParameterSource(tableA);
parameterSource.registerSqlType("newDate", Types.DATE); 

在那次改变后,我能够插入行.但接下来,我想从数据库中获取行.这是我的方法:

public List<TableA> getAll()
{
    final String sql = "select * from public.TABLE_A";
    final BeanPropertyRowMapper<TableA> rowMapper = new BeanPropertyRowMapper<TableA>(TableA.class);
    return namedJdbcTemplate.query(sql,rowMapper);
}

当然我得到例外:

...
at org.springframework.beans.BeanWrapperImpl.convertIfNecessary(BeanWrapperImpl.java:474)
at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:511)
at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:1119)
at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:902)
at org.springframework.jdbc.core.BeanPropertyRowMapper.mapRow(BeanPropertyRowMapper.java:255)
...
Caused by: java.lang.IllegalStateException: Cannot convert value of type [java.sql.Date] to required type [java.time.LocalDate] for property 'newDate': no matching editors or conversion strategy found.

所以我更新了我的代码,这次是BeanPropertyRowMapper,我已经将转换服务添加到bean包装器,它能够执行从java.sql.Date到java.time.LocalDate的转换

public List<TableA> getAll()
{
    final String sql = "select * from public.TABLE_A";
    final BeanPropertyRowMapper<TableA> rowMapper = new BeanPropertyRowMapper<TableA>(TableA.class)
    {
        @Override
        protected void initBeanWrapper(BeanWrapper bw) {
            super.initBeanWrapper(bw);
           bw.setConversionService(new ConversionService() {
               @Override
               public boolean canConvert(Class<?> aClass, Class<?> aClass2) {
                   return aClass == java.sql.Date.class && aClass2 == LocalDate.class;
               }

               @Override
               public boolean canConvert(TypeDescriptor typeDescriptor, TypeDescriptor typeDescriptor2) {
                   return canConvert(typeDescriptor.getType(), typeDescriptor2.getType());
               }

               @Override
               public <T> T convert(Object o, Class<T> tClass) {
                   if(o instanceof Date && tClass == LocalDate.class)
                   {
                       return (T)((Date)o).toLocalDate();
                   }

                   return null;


       }

           @Override
           public Object convert(Object o, TypeDescriptor typeDescriptor, TypeDescriptor typeDescriptor2) {
               return convert(o,typeDescriptor2.getType());
           }
       });
    }
}   ;

return namedJdbcTemplate.query(sql,rowMapper);

现在一切正常,但它很复杂.
是否更容易实现这一目标?
一般来说,我想在我的Java代码中运行LocalDate,因为它更方便,并且能够将它持久化到数据库.我希望默认情况下应该启用它.

解决方法:

新日期& JDBC的日期API支持由JEP 170: JDBC 4.2定义.Postgres download page与JDBC 4.2的兼容性仅从Postgres版本9.4开始,因此使用旧版驱动程序的新API会弹出一些兼容性挑战.

甚至setObject(1,new java.util.Date());被Postgres中的相同约束(MySQL很乐意接受)拒绝,而不仅仅是像LocalDate这样的新API.一些行为将依赖于实现,因此只有java.sql.*才能得到保证(粗略地说).

对于Spring JDBC框架,我认为重写它的行为可以解决它,而不会后悔.对于你已经做过的事情,我建议采用略有不同的方法:

>扩展BeanPropertySqlParameterSource行为以使用新日期& time API,以及与参数输入相关的其他类(如果需要)(我不熟悉Spring API).
>将已经被覆盖的BeanPropertyRowMapper行为提取到另一个类以获取操作.
>使用工厂模式或实用程序类将其全部包装起来,这样您就不必再次查看它了.

这样,如果API得到支持,您可以增强未来的重构功能,并减少开发期间所需的代码量.

您还可以查看一些DAO方法.

标签:spring-jdbc,java,java-8,spring,postgresql
来源: https://codeday.me/bug/20191007/1869242.html