Java和PostgreSQL数据库SQL数组映射问题

Hibernate自定义类型允许映射各种数据库特定的列类型,比如IP地址、JSON列、位集或SQL数组。定义定制Hibernate类型有两种方法: UserType接口和 Java and SQL descriptorsJava and SQL descriptors是首选的,因为它允许更好地分离 Java-to-JDBCJDBC-to-SQL 类型处理。在本文中,我们将了解如何将PostgreSQL数据库中的数组映射到它们的Java对应对象中。


SQL映射到JPA 

首先我们在postgreSQL数据库中创建如下含有Array列的test表:

~~~sql

create table array_test (

   id int8 not null,

   version int4,

   sensor_names text[],

   sensor_values integer[],

   primary key (id)

)

~~~

我们希望使用JPA和Hibernate映射这个表。但是,JPA和Hibernate默认都不支持SQL数组,我们希望将这些数组分别映射到字符串和int Java数组。

这个数据库表的JPA实体映射如下(string-array和int-array是自定义类型,实现SQL数组与java数组转换):

~~~java

@Entity(name = "ArrayTestEntity")

@Table(name = "array_test")

@TypeDefs({

   @TypeDef(name = "string-array", typeClass = StringArrayType.class),

   @TypeDef(name = "int-array", typeClass = IntArrayType.class)

})

~~~

~~~sql

public class ArrayTestEntity {

   @Id  

   private Long id;

   @Version

   private int version;

   @Type( type = "string-array" )

   @Column(name = "sensor_names",columnDefinition = "text[]")

   private String[] sensorNames;

   @Type( type = "int-array" )

   @Column(name = "sensor_values", columnDefinition = "int[]")

   private int[] sensorValues;

   //Getters and setters omitted for brevity

}

~~~

接下来完成自定义StringArrayType类与IntArrayType类,需要继承AbstractSingleColumnStandardBasicType类并完成定义 Java and SQL descriptors:

~~~java

public class StringArrayType

       extends AbstractSingleColumnStandardBasicType<String[]>

       implements DynamicParameterizedType {

   public StringArrayType() {

       super(

           ArraySqlTypeDescriptor.INSTANCE,

           StringArrayTypeDescriptor.INSTANCE

       );

   }

   public String getName() {

       return "string-array";

   }

   @Override

   protected boolean registerUnderJavaType() {

       return true;

   }

   @Override

   public void setParameterValues(Properties parameters) {

       ((StringArrayTypeDescriptor)

           getJavaTypeDescriptor())

           .setParameterValues(parameters);

   }

}

public class IntArrayType

       extends AbstractSingleColumnStandardBasicType<int[]>

       implements DynamicParameterizedType {

   public IntArrayType() {

       super(

           ArraySqlTypeDescriptor.INSTANCE,

           IntArrayTypeDescriptor.INSTANCE

       );

   }

   public String getName() {

       return "int-array";

   }

   @Override

   protected boolean registerUnderJavaType() {

       return true;

   }

   @Override

   public void setParameterValues(Properties parameters) {

       ((IntArrayTypeDescriptor)

           getJavaTypeDescriptor())

           .setParameterValues(parameters);

   }

}

~~~

接下来还有最后一步就是descriptor的定义,从前面两个自定义数组类提到的Hibernate类型中可以看出,两个数组类共享用于处理jdbc到sql类型映射的相同SqlTypeDescriptor,那么可以写一个公用的实现SqlTypeDescriptor类如下所示:

~~~java

public class ArraySqlTypeDescriptor

   implements SqlTypeDescriptor {

   public static final ArraySqlTypeDescriptor INSTANCE =

       new ArraySqlTypeDescriptor();

   @Override

   public int getSqlType() {

       return Types.ARRAY;

   }

   @Override

   public boolean canBeRemapped() {

       return true;

   }

   @Override

   public <X> ValueBinder<X> getBinder(

       JavaTypeDescriptor<X> javaTypeDescriptor) {

       return new BasicBinder<X>( javaTypeDescriptor, this) {

           @Override

           protected void doBind(

                   PreparedStatement st,

                   X value,

                   int index,

                   WrapperOptions options

               ) throws SQLException {

               AbstractArrayTypeDescriptor<Object> abstractArrayTypeDescriptor =

                   (AbstractArrayTypeDescriptor<Object>)

                       javaTypeDescriptor;

               st.setArray(

                   index,

                   st.getConnection().createArrayOf(

                       abstractArrayTypeDescriptor.getSqlArrayType(),

                       abstractArrayTypeDescriptor.unwrap(

                           value,

                           Object[].class,

                           options

                       )

                   )

               );

           }

           @Override

           protected void doBind(

                   CallableStatement st,

                   X value,

                   String name,

                   WrapperOptions options

               ) throws SQLException {

               throw new UnsupportedOperationException(

                   "Binding by name is not supported!"

               );

           }

       };

   }

   @Override

   public <X> ValueExtractor<X> getExtractor(

       final JavaTypeDescriptor<X> javaTypeDescriptor) {

       return new BasicExtractor<X>(javaTypeDescriptor, this) {

           @Override

           protected X doExtract(

                   ResultSet rs,

                   String name,

                   WrapperOptions options

               ) throws SQLException {

               return javaTypeDescriptor.wrap(

                   rs.getArray(name),

                   options

               );

           }

           @Override

           protected X doExtract(

                   CallableStatement statement,

                   int index,

                   WrapperOptions options

               ) throws SQLException {

               return javaTypeDescriptor.wrap(

                   statement.getArray(index),

                   options

               );

           }

           @Override

           protected X doExtract(

                   CallableStatement statement,

                   String name,

                   WrapperOptions options

               ) throws SQLException {

               return javaTypeDescriptor.wrap(

                   statement.getArray(name),

                   options

               );

           }

       };

   }

}

~~~

基本上,ArraySqlTypeDescriptor定义了Hibernate如何使用JDBC语句处理Statement.setArray 和ResultSet. 

StringArrayTypeDescriptor

StringArrayTypeDescriptor很简单,因为大部分逻辑都封装在AbstractArrayTypeDescriptor中。StringArrayTypeDescriptor定义了期望的Java类型(如String[])和postgreSQL底层数据库数组类型(如text[])。

~~~java

public class StringArrayTypeDescriptor

       extends AbstractArrayTypeDescriptor<String[]> {

   public static final StringArrayTypeDescriptor INSTANCE =

       new StringArrayTypeDescriptor();

   public StringArrayTypeDescriptor() {

       super( String[].class );

   }

   @Override

   protected String getSqlArrayType() {

       return "text";

   }

}

~~~

IntArrayTypeDescriptor

IntArrayTypeDescriptor也是一样,因为它定义了预期的Java类型(例如int[])和底层数据库数组类型(例如int[])。

~~~java

public class IntArrayTypeDescriptor

       extends AbstractArrayTypeDescriptor<int[]> {

   public static final IntArrayTypeDescriptor INSTANCE =

       new IntArrayTypeDescriptor();

   public IntArrayTypeDescriptor() {

       super( int[].class );

   }

   @Override

   protected String getSqlArrayType() {

       return "integer";

   }

}

~~~

这样就可以实现Java数组与postgreSQL数据库数组列之间的映射。同理也可以完成其他数组的映射,已测试通过就不放了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,492评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,048评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,927评论 0 358
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,293评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,309评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,024评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,638评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,546评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,073评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,188评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,321评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,998评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,678评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,186评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,303评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,663评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,330评论 2 358

推荐阅读更多精彩内容

  • 小编费力收集:给你想要的面试集合 1.C++或Java中的异常处理机制的简单原理和应用。 当JAVA程序违反了JA...
    八爷君阅读 4,596评论 1 114
  • pyspark.sql模块 模块上下文 Spark SQL和DataFrames的重要类: pyspark.sql...
    mpro阅读 9,459评论 0 13
  • 一. Java基础部分.................................................
    wy_sure阅读 3,812评论 0 11
  • 设计模式分类 总体来说设计模式分为三大类:创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原...
    lifeline丿毅阅读 1,225评论 0 2
  • 没有一个期末这么难熬,效率低,内心抗拒,整天感觉也没干啥,就是浑身乏力,碎觉的次数和吃饭的次数一样多,甚至会更多,...
    马尾木头_dfeb阅读 120评论 0 0