从视图中的postgres访问Lob属性

时间:2013-01-30 11:15:40

标签: spring hibernate postgresql view lob

我有一个标准的Spring Framework(v3.1.2)java(v1.6)数据库支持(postgres v9.1)Web应用程序,它运行在Apache Tomcat(v6.0)上。请注意我使用的是Hibernate 3.6.10.Final和Spring Data JPA 1.2.0.RELEASE。

我有两个数据库实体类 - Chapter和ChapterText - 它们之间有一对一的关系......

@Entity @Table(name="chapter")
public class Chapter implements Comparator<Chapter> {

    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="CHAPTER_SEQ")
    @SequenceGenerator(name="CHAPTER_SEQ", sequenceName="chapter_seq", allocationSize=1)
    @Column(name="id")
    private Long id;

    @OneToOne(cascade=CascadeType.ALL, optional=false, fetch=FetchType.LAZY, orphanRemoval=true) @PrimaryKeyJoinColumn
    private ChapterText chapterText;

    // other properties plus setters and getters
}

@Entity @Table(name="chapterText")
public class ChapterText {

    @Id
    @GeneratedValue(generator="foreign")
    @GenericGenerator(name="foreign", strategy="foreign", parameters={ @Parameter(name="property", value="parent") })
    @Column(name="id")
    private Long id;

    @OneToOne(mappedBy="chapterText", optional=false)
    private Chapter parent;

    @Column(name="body") @Lob
    private String body;

    // setters and getters
}

现在,由于ChapterText包含一个@Lob属性,它可能包含大量文本,我在Chapter类中标记了chapterText属性,以便它将被延迟加载。

我有OpenEntityManagerInViewFilter设置和配置,所以我可以在模型中添加章实体(名称为“chapter”),然后在我的JSPX文件中我应该可以这样做...

${chapter.chapterText.body}

这应该懒得加载ChapterText实体,并在为调用浏览器生成的XHTML页面中包含body属性的值。

这是一种显示数据库信息的标准方式,我已经使用了多年。但是,这是我第一次使用Postgres的@Lob属性。当我这样做时,我会看到以下堆栈跟踪......

org.apache.jasper.JasperException: javax.servlet.ServletException: javax.servlet.jsp.JspException: javax.servlet.jsp.JspException: javax.el.ELException: Error reading 'body' on type project.vo.db.ChapterText_$$_javassist_5
.
.
.
javax.servlet.ServletException: javax.servlet.jsp.JspException: javax.servlet.jsp.JspException: javax.el.ELException: Error reading 'body' on type project.vo.db.ChapterText_$$_javassist_5
.
.
.
javax.servlet.jsp.JspException: javax.el.ELException: Error reading 'body' on type project.vo.db.ChapterText_$$_javassist_5
.
.
.
javax.el.ELException: Error reading 'body' on type project.vo.db.ChapterText_$$_javassist_5
.
.
.
org.hibernate.exception.GenericJDBCException: could not load an entity: [project.vo.db.ChapterText#1]
.
.
.
org.postgresql.util.PSQLException: Large Objects may not be used in auto-commit mode.

根据我的能力,Posgres要求通过自动提交设置为false的事务访问大对象。

令人讨厌的是,我能够想到解决这个问题的唯一方法是创建一个存储库方法,该方法获取@Lob属性,使用@Transactional标记它并将值加载到专门为显示目的创建的bean中。虽然这确实有效,但似乎有点不合适。

有没有人对替代方法有任何想法?

1 个答案:

答案 0 :(得分:2)

首先,我想您可能想重新考虑一下您的设计。如果文本低于1GB,并且您不必在其中进行搜索,那么使用文本字段而不是LOB可能会更好。这样更容易处理和管理。如果数据在每行1GB到2GB之间,则由于大小,您可能需要使用LOB。如果你需要能够查询,分块(即通过偏移寻找),那么LOB是合适的。如果这些都不合适,则TEXTBYTEA字段更可取。请注意,PostgreSQL会自动将大型属性移动到二级存储中,因此您不会通过使用大量内联数据来减慢扫描速度(基本上,任何超过4kb的内容都必须移动到二级存储),所以如果这是您的问题,那么我不会担心它。 TEXT字段更易于管理,因此它们将是我的首选。同样对于文本数据,除非你正在分块,否则LOB的编码会使网络流量比TEXT字段更差。

现在,如果这是不可接受的,您可以使用lo_read()阅读lob并在视图中显示为bytea