java – 解释使用Hibernate映射自动递增复合id序列的行为

前端之家收集整理的这篇文章主要介绍了java – 解释使用Hibernate映射自动递增复合id序列的行为前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一张桌子
CREATE TABLE `SomeEntity` (
     `id` int(11) NOT NULL AUTO_INCREMENT,`subid` int(11) NOT NULL DEFAULT '0',PRIMARY KEY (`id`,`subid`),

我有一个实体类,其中有一个自动增量字段.我想要读取自动递增id,当它被持久化分配给它

吸气剂的注释如下

private long id;
   private int subid;
  @Id
  @GeneratedValue **//How do i correct this to have multiple rows with same id and different subid**
  @Column(name = "id")
  public long getId() {
    return id;
  }

  @Id
  @Column(name = "subid")
  public int getSubid() {
    return subid;
  }

我想要有实体

id 1 subid 0 
id 1 subid 1
id 1 subid 2
id 2 subid 0

subid在数据库中是默认值0,我以编程方式增加对该行的更新.
我试过这个SO SO的解决方
JPA – Returning an auto generated id after persist()

@Transactional
  @Override
  public void daoSaveEntity(SomeEntity entity) {
    entityManager.persist(entity);
  }

现在在这个事务之外,我试图获得分配的自动递增ID

@Override
      public long serviceSaveEntity(SomeEntity entity) {
        dao.daoSaveEntity(entity);
        return entity.getId();
      }

我从网络服务中呼叫这个

@POST
  @Produces(MediaType.APPLICATION_JSON)
  @Consumes(MediaType.APPLICATION_JSON)
  public Response createEntity(SomeEntity entity) {

更新方法如下

@Transactional
  public void updateReportJob(SomeEntity someEntity) {

    Query query =
        entityManager
.createQuery("UPDATE SomeEntity SET state=:newState WHERE id = :id");
    query.setParameter("newState","PASSIVE");
    query.setParameter("id",id);
    query.executeUpdate();
    double rand = Math.random();
    int i = (int) (rand * 300);
    try {
      Thread.sleep(i);  //only to simulate concurrency issues
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    List<Integer> resList =
        entityManager.createQuery("select max(subid) from SomeEntity WHERE id = :id")
            .setParameter("id",jobId).getResultList();
    // Increment old subid by 1
    int subid = resList.get(0);
    SomeEntity.setsubid(subid + 1);
    SomeEntity.setState("ACTIVE");
    // entityManager.merge(SomeEntity);
    entityManager.persist(SomeEntity);
  }

我从N线程发送N个并发更新,实体为Id 1,其他几个属性如下

SomeEnity entity = new SomeEntity();

entity.setId(1);
  long num = Thread.currentThread().getId();
  entity.setFieldOne("FieldOne" + num);
  entity.setFieldTwo("" + i);
  entity.setFieldThree("" + j);
  i++;
  j++;

案例1具有@Id和idid上的@Id注释和更新中的“entityManager.persist”
当我运行300线程一些失败与连接异常“太多的连接”数据库状态是

id 1 subid 0 
   id 1 subid 1
   id 1 subid 2
   ..  ....
   id 1 subid 150

子系统总是增量,竞争条件只是因为竞争条件而被定义为ACTIVE

案例2带有@Id和idid上的@Id注释和更新中的“entityManager.merge”

id 1 subid 0
id 1 subid 0
id 2 subid 0
.. ….
id 151 subid 0(也许只是一个共同点,一个线程比一个线程成功?)

案例3使用@GeneratedValue和@Id在id和** NO @Id注释在subid和entityManager.persist在更新**
异常 – 分离实体传递到持久化

情况3使用@GeneratedValue和@Id对id和** NO @Id注释在subid和entityManager.merge在更新**
如果更新顺序运行,则数据库状态为

id 1 subid 0

下次更新后

id 1 subid 1

在每次更新之后,相同的行被更新(一次只导致一行)

id 1 subid 2

案例4与案例3相同,并发更新
如果同时运行(有300个线程),我得到以下异常

org.hibernate.HibernateException: More than one row with the given identifier was found: 1

数据库状态是
id 1 subid 2(只有一个线程将成功,但由于竞争条件更新subid从0到2)

案例5使用@GeneratedValue和@Id对idid和@Id注释在subid上
创建也失败与subid org.hibernate.PropertyAccessException:IllegalArgumentException发生时调用setter的SomeEntity.id

请解释原因.从我知道的方法的javadoc

持久化 – 使一个实例被管理和持久化.

merge – 将给定实体的状态合并到当前持久性上下文中.

我的问题更多的是Hibernate如何管理注释.
如果会话未关闭,为什么在情况3中有一个脱离实体异常?
为什么在这种情况下有一个IllegalArgumentException异常?

我正在使用hibernate 3.6 MysqL 5和spring 4
还请建议一种实现这样的增量id和subid的方法(使用自定义SelectGenerator,具有演示实现或任何其他方式,而不做列concat)

解决方法

因为id字段已经是唯一的并且自动递增,所以在这种情况下你不需要一个复合的id,所以你的实体看起来像这样:
@Id
@Column(name = "id")
public long getId() {
    return id;
}

@Column(name = "subid")
public int getSubid() {
    return subid;
}

实体可以通过id使用实体管理器:

entityManager.find(MyEntity.class,entityId);

或者您可以使用同时具有id和subid的查询获取实体:

MyEntity myEntity = entityManager.createTypeQuery("select me from MyEntity where id = :id and subid = :subid",MyEntity.class)
    .setParameter("id",entityId) 
    .setParameter("subid",entitySubId) 
    .getSingleResult();

Hibernate还有一个可以从数据库获取id的SelectGenerator,当数据库使用触发器生成ID时,这是非常有用的.

不幸的是,它不适用于组合ids,所以你会写下你自己的扩展的SelectGenerator或使用单个字符串id_sub_id列,将id和sub-id组合成一个VARCHAR列:

'1-0'
'1-1'
'2-0'
'2-1'

您必须使用数据库特定的存储过程编写数据库触发器来更新两列,并将两列集合到VARCHAR存储过程中.然后,使用标准SelectGenerator将聚合列映射到字符串字段:

@Id
@Column(name = "id_sub_id")
@GeneratedValue( strategy = "trigger" )
@GenericGenerator( 
    name="trigger",strategy="org.hibernate.id.SelectGenerator",parameters = {
        @Parameter( name="keys",value="id_sub_id" )
    }
)
public String getId() {
    return id;
}

猜你在找的Java相关文章