Postgresql JPA与许多孩子建立父母/孩子关系

Postgresql JPA与许多孩子建立父母/孩子关系,postgresql,ejb,postgis,jpa-2.1,hibernate-spatial,Postgresql,Ejb,Postgis,Jpa 2.1,Hibernate Spatial,我正在尝试使用JPA方法create将实体Track与子实体TrackPoints一起存储。但是,与子项一起存储轨迹点的时间非常长,大约30秒。我尝试了GenerationType.Identity和GenerationType.SEQUENCE。如果我还有Hibernate Spatial(Postgis)列,它会持续更长的时间——大约60秒来存储父级和所有子级。JPA依次发送insert。我如何优化它?谁能告诉我主要的问题是什么 技术: Wildfly 8.1、JPA2.1(hiberna

我正在尝试使用JPA方法create将实体Track与子实体TrackPoints一起存储。但是,与子项一起存储轨迹点的时间非常长,大约30秒。我尝试了GenerationType.IdentityGenerationType.SEQUENCE。如果我还有Hibernate Spatial(Postgis)列,它会持续更长的时间——大约60秒来存储父级和所有子级。JPA依次发送insert。我如何优化它?谁能告诉我主要的问题是什么

技术:

  • Wildfly 8.1、JPA2.1(hibernate)、hibernate Spatial、EJB、JTA
  • PostgreSQL 9.3+PostGis-默认设置(仅从Ubuntu软件包安装)
Track.java

@Entity
@Table(name = "TRACKS")
public class Track implements Serializable {    
    @Id
    @Column(name = "track_id", nullable = false, unique = true)
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;

    @NotNull
    @NotEmpty
    @Size(min = 1, max = 100)
    @Column(nullable = false, length = 100)
    private String name;

    @Size(max = 200)
    @Column(nullable = false, length = 200)
    private String description;

    @OneToOne(optional = false)
    @JoinColumn(name = "userId", nullable = false)
    private User userOwner;

    @NotNull
    @NotEmpty
    @Column(nullable = false, length = 55)
    private String type;

    @NotNull
    private Boolean isShared;

    @OneToMany(mappedBy = "track")
    private List<TrackPoint> trackPoints;
}
@Entity
@Table(name = "TRACK_POINTS")
public class TrackPoint implements Serializable {

    private static final long serialVersionUID = 8089601593251025235L;

    @Id
    @Column(name = "trackpoint_id", nullable = false, unique = true)
    @GeneratedValue(generator = "track_point_sequence", strategy = GenerationType.SEQUENCE)
    @SequenceGenerator(name = "track_point_sequence", sequenceName = "track_point_sequence", allocationSize = 1000)
    private Long id;

    @NotNull
    private int trackSegment;

    @NotNull
    private double elevation;

    @NotNull
    @Temporal(TemporalType.TIMESTAMP)
    private Date timeStamp;

    @NotNull
    @ManyToOne(optional = false, fetch = FetchType.EAGER)
    @JoinColumn(name = "track_id")
    private Track track;

    /*Hibernate Spatial - Postgis field.
    @NotNull
    @Column(nullable = false)
    @Type(type = "org.hibernate.spatial.GeometryType")
    private Geometry location;*/
}
@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class TracksService implements ITracksService {

    @Inject
    private IDaoService dao;

    @Override
    public Long createTrack(GpxType gpx, String userId, String name, String desc) {
        // Map GPX to Track, TrackPoint object.
        track = dao.create(track);

    int batch_size = 50;

    int i = 0;

        for(TrackPoint point: track.getTrackPoints()) {
            dao.create(point);
            if(i++ % batch_size == 0) {
                dao.flush();
                dao.clear();
            }
        }

        return track.getId();

}
@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class DaoService implements IDaoService {

    @PersistenceContext()
    private EntityManager em;

    @Override
    public <T extends Serializable> T create(T t) {
        em.persist(t);
        return t;
    }
}
TrackService.java

@Entity
@Table(name = "TRACKS")
public class Track implements Serializable {    
    @Id
    @Column(name = "track_id", nullable = false, unique = true)
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;

    @NotNull
    @NotEmpty
    @Size(min = 1, max = 100)
    @Column(nullable = false, length = 100)
    private String name;

    @Size(max = 200)
    @Column(nullable = false, length = 200)
    private String description;

    @OneToOne(optional = false)
    @JoinColumn(name = "userId", nullable = false)
    private User userOwner;

    @NotNull
    @NotEmpty
    @Column(nullable = false, length = 55)
    private String type;

    @NotNull
    private Boolean isShared;

    @OneToMany(mappedBy = "track")
    private List<TrackPoint> trackPoints;
}
@Entity
@Table(name = "TRACK_POINTS")
public class TrackPoint implements Serializable {

    private static final long serialVersionUID = 8089601593251025235L;

    @Id
    @Column(name = "trackpoint_id", nullable = false, unique = true)
    @GeneratedValue(generator = "track_point_sequence", strategy = GenerationType.SEQUENCE)
    @SequenceGenerator(name = "track_point_sequence", sequenceName = "track_point_sequence", allocationSize = 1000)
    private Long id;

    @NotNull
    private int trackSegment;

    @NotNull
    private double elevation;

    @NotNull
    @Temporal(TemporalType.TIMESTAMP)
    private Date timeStamp;

    @NotNull
    @ManyToOne(optional = false, fetch = FetchType.EAGER)
    @JoinColumn(name = "track_id")
    private Track track;

    /*Hibernate Spatial - Postgis field.
    @NotNull
    @Column(nullable = false)
    @Type(type = "org.hibernate.spatial.GeometryType")
    private Geometry location;*/
}
@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class TracksService implements ITracksService {

    @Inject
    private IDaoService dao;

    @Override
    public Long createTrack(GpxType gpx, String userId, String name, String desc) {
        // Map GPX to Track, TrackPoint object.
        track = dao.create(track);

    int batch_size = 50;

    int i = 0;

        for(TrackPoint point: track.getTrackPoints()) {
            dao.create(point);
            if(i++ % batch_size == 0) {
                dao.flush();
                dao.clear();
            }
        }

        return track.getId();

}
@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class DaoService implements IDaoService {

    @PersistenceContext()
    private EntityManager em;

    @Override
    public <T extends Serializable> T create(T t) {
        em.persist(t);
        return t;
    }
}
DaoService.java

@Entity
@Table(name = "TRACKS")
public class Track implements Serializable {    
    @Id
    @Column(name = "track_id", nullable = false, unique = true)
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;

    @NotNull
    @NotEmpty
    @Size(min = 1, max = 100)
    @Column(nullable = false, length = 100)
    private String name;

    @Size(max = 200)
    @Column(nullable = false, length = 200)
    private String description;

    @OneToOne(optional = false)
    @JoinColumn(name = "userId", nullable = false)
    private User userOwner;

    @NotNull
    @NotEmpty
    @Column(nullable = false, length = 55)
    private String type;

    @NotNull
    private Boolean isShared;

    @OneToMany(mappedBy = "track")
    private List<TrackPoint> trackPoints;
}
@Entity
@Table(name = "TRACK_POINTS")
public class TrackPoint implements Serializable {

    private static final long serialVersionUID = 8089601593251025235L;

    @Id
    @Column(name = "trackpoint_id", nullable = false, unique = true)
    @GeneratedValue(generator = "track_point_sequence", strategy = GenerationType.SEQUENCE)
    @SequenceGenerator(name = "track_point_sequence", sequenceName = "track_point_sequence", allocationSize = 1000)
    private Long id;

    @NotNull
    private int trackSegment;

    @NotNull
    private double elevation;

    @NotNull
    @Temporal(TemporalType.TIMESTAMP)
    private Date timeStamp;

    @NotNull
    @ManyToOne(optional = false, fetch = FetchType.EAGER)
    @JoinColumn(name = "track_id")
    private Track track;

    /*Hibernate Spatial - Postgis field.
    @NotNull
    @Column(nullable = false)
    @Type(type = "org.hibernate.spatial.GeometryType")
    private Geometry location;*/
}
@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class TracksService implements ITracksService {

    @Inject
    private IDaoService dao;

    @Override
    public Long createTrack(GpxType gpx, String userId, String name, String desc) {
        // Map GPX to Track, TrackPoint object.
        track = dao.create(track);

    int batch_size = 50;

    int i = 0;

        for(TrackPoint point: track.getTrackPoints()) {
            dao.create(point);
            if(i++ % batch_size == 0) {
                dao.flush();
                dao.clear();
            }
        }

        return track.getId();

}
@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class DaoService implements IDaoService {

    @PersistenceContext()
    private EntityManager em;

    @Override
    public <T extends Serializable> T create(T t) {
        em.persist(t);
        return t;
    }
}
@无状态
@TransactionAttribute(TransactionAttributeType.REQUIRED)
公共类DaoService实现IDaoService{
@PersistenceContext()
私人实体管理者;
@凌驾
公共T创建(T){
em.t;
返回t;
}
}
persistence.xml

<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xsi:schemaLocation=
                     "http://xmlns.jcp.org/xml/ns/persistence
                          http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">

    <persistence-unit name="postgisTourbookPU" transaction-type="JTA">

        <description>PostgresSQL database with PostGIS extension</description>
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <jta-data-source>${tourbook.datasource.postgresql.jndi-name}</jta-data-source>
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <shared-cache-mode>NONE</shared-cache-mode>

        <properties>
            <!-- JPA properties -->
            <property name="javax.persistence.schema-generation.database.action"
                      value="drop-and-create"/>

            <!--            <property name="javax.persistence.schema-generation-target"
                                  value="database"/>-->

            <!-- Creation Schema Properties -->
            <property name="javax.persistence.schema-generation.create-source"
                      value="metadata"/>

            <!--            &lt;!&ndash; DDL Script location, when script is used &ndash;&gt;
                        <property name="javax.persistence.schema-generation.create-script-source"
                                    value="META-INF/create-script.sql"/>-->

            <!-- Drop Schema Properties -->
            <property name="javax.persistence.schema-generation.drop-source"
                      value="metadata"/>
            <!--            <property name="javax.persistence.schema-generation.drop-script-source"
                                  value="META-INF/drop-script.sql"/>-->

            <property name="javax.persistence.sql-load-script-source"
                                  value="META-INF/load-script.sql"/>

            <!-- JPA driver information -->
            <property name="javax.persistence.jdbc.driver"
                      value="org.postgresql.Driver"/>

            <!-- Hibernate properties -->
            <property name="hibernate.connection.characterEncoding"
                      value="UTF-8"/>

            <property name="hibernate.dialect"
                      value="org.hibernate.spatial.dialect.postgis.PostgisDialect"/>

            <property name="hibernate.default_schema"
                      value="public"/>

            <property name="hibernate.show_sql"
                      value="true"/>

            <property name="hibernate.jdbc.batch_size" value="50"/>

            <property name="hibernate.jdbc.fetch_size"
                      value="50"/>

            <property name="hibernate.order_inserts"
                      value="true"/>

            <property name="hibernate.order_updates"
                      value="true"/>

            <property name="hibernate.cache.use_query_cache"
                      value="false"/>

            <!-- Hibernate caching -->

        </properties>
    </persistence-unit>
</persistence>

具有PostGIS扩展的PostgresSQL数据库
org.hibernate.jpa.HibernatePersistenceProvider
${tourbook.datasource.postgresql.jndi name}
假的
没有一个
已编辑


所以我尝试过,在Hibernate中批量插入,但我仍然有30秒的时间来保存2000点。

您正在插入一个包含所有子项的父项。在这种情况下,HibernateJPA确实会很慢,但是有一些技巧可以提高性能 -检查hibernate批处理指南 -我使用了hibernate.jdbc.batch_size参数(设置为例如50)

祝你好运
Gabriel

您是否将所有内容都存储在一个事务中?此外,您还可以使用SequenceGenerator,它不会在每次需要新的oneHi时要求数据库提供新id,我在一个事务中完成所有操作。这是个问题吗?我也试过这一批,但没用。嗨,我终于解决了。我在Wildfly中启用了org.hibernate上的记录器。谢谢你的帮助。嗨,加布里埃尔。我试过批量插入,但运气不好。现在,2000个轨迹点大约需要30-35秒。我已附加修改后的代码。