【问题标题】:select nextval for every row inserted with hibernate为使用休眠插入的每一行选择 nextval
【发布时间】:2015-01-14 23:20:57
【问题描述】:

这是我第一次使用 Hibernate,当我在循环中插入多行时,hibernate 会为插入的每一行打印以下内容

Hibernate: select nextval ('hibernate_sequence')

对循环中的所有数据执行此操作后,它开始插入数据

Hibernate: insert into user_data (age, location, sent_count, user_id, username, id) values (?, ?, ?, ?, ?, ?)

hibernate 总是这样运行的吗?数据库不可能处理序列吗?我觉得这真的减慢了插入行的过程。我正在为我的数据库使用 PostgreSQL。

这是我的相关代码 用户数据

@Entity
@Table(name = "user_data")
public class UserData
{
  @Id @GeneratedValue
  @Column(name = "id")
  private int id;

  @Column(name = "user_id")
  private String userid;

  @Column(name = "username")
  private String username;

  @Column(name = "age")
  private int age;

  @Column(name = "location")
  private int location;

  @Column(name = "sent_count")
  private int sentCount;

    public int getId()
    {
        return id;
    }

    public void setId(int id)
    {
        this.id = id;
    }

    public String getUserid()
    {
        return userid;
    }

    public void setUserid(String userid)
    {
        this.userid = userid;
    }

    public String getUsername()
    {
        return username;
    }

    public void setUsername(String username)
    {
        this.username = username;
    }

    public int getAge()
    {
        return age;
    }

    public void setAge(int age)
    {
        this.age = age;
    }

    public int getLocation()
    {
        return location;
    }

    public void setLocation(int location)
    {
        this.location = location;
    }

    public int getSentCount()
    {
        return sentCount;
    }

    public void setSentCount(int sentCount)
    {
        this.sentCount = sentCount;
    }
}

我的 Hibernate 助手类

public class HibernateUtil
{
    static SessionFactory       sessionFactory;
    static ServiceRegistry  serviceRegistry;

    static
    {
        try
        {
            Configuration configuration = new Configuration();
            configuration.setProperty("hibernate.temp.use_jdbc_metadata_defaults", "false");
            configuration.configure();
            serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
            sessionFactory = configuration.buildSessionFactory(serviceRegistry);
        }
        catch (Throwable ex)
        {
            // Make sure you log the exception, as it might be swallowed
            System.err.println("Initial SessionFactory creation failed." + ex);
            closeSessionFactory();
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory()
    {
        return sessionFactory;
    }

    public static void closeSessionFactory()
    {
        sessionFactory.close();
    }

}

以及插入行的相关部分

    Session session = HibernateUtil.getSessionFactory().openSession();
    session.beginTransaction();

    for (String memberId : memberIds)
    {
        System.out.println(memberId);
        UserData user = new UserData();
        user.setUserid(memberId);
        session.save(user);
    }

    session.getTransaction().commit();
    session.close();
    HibernateUtil.closeSessionFactory();

【问题讨论】:

    标签: java hibernate postgresql


    【解决方案1】:

    当您调用session.save() 时,您还没有向数据库中插入任何内容。您只是将对象注册到会话缓存,Hibernate 会在其中跟踪最终需要在数据库中插入/更新的所有对象。但是 Hibernate 立即需要的是新对象的标识符,因此它可以连接其他通过外键引用它的对象。

    默认情况下,Hibernate 将使用由本机 DB 序列支持的简单 ID 生成器,从该序列中为每个保存的对象获取一个 ID。只要您不进行批量插入(在同一事务中插入很多东西),这将正常工作。不过,你的 for 循环确实让它看起来就像你正在做的那样。

    如果您在执行批量插入时需要良好的性能,则需要处理许多问题(四处搜索),但在这里我将针对您的直接问题提出解决方案:优化的序列生成器。这是我使用的:

    @GenericGenerator(name = "optimized-sequence", strategy = "enhanced-sequence", parameters = {
        @Parameter(name = "prefer_sequence_per_entity", value = "true"),
        @Parameter(name = "optimizer", value = "hilo"),
        @Parameter(name = "increment_size", value = "50") })
    package org.example.myproject;
    
    import org.hibernate.annotations.GenericGenerator;
    import org.hibernate.annotations.Parameter;
    

    以上内容必须保存在名为package-info.java 的文件中。它实现的是在名称 optimized-sequence 下定义一个包范围的自定义 ID 生成器。你可以这样使用它:

    @Id @GeneratedValue(generator = "optimized-sequence") public long id;
    

    这将为您带来一个本地序列支持的 ID 生成器,但它只需要为每 50 个(可配置的)保存的对象碰撞 DB 序列一次。它改变了底层序列的语义,例如,currval = 1 意味着当前的 Hibernate 会话已经为自己保留了 ID 范围 1-50。是的,这会在您的 ID 空间中创建“漏洞”,但是有 264 存在,您不应该很快开始担心这个问题。

    【讨论】:

      【解决方案2】:

      您的 id 设置为 @GeneratedValue 但您尚未设置生成策略。看起来它默认为一个序列。我建议设置:

      @GeneratedValue(strategy = GenerationType.IDENTITY)
      

      您需要有一个 serial 类型的列作为您的 id 列。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-03
        • 1970-01-01
        • 2011-04-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多