Java – explains the behavior of automatically incrementing a composite ID sequence using hibernate mapping

I have a table

CREATE TABLE `SomeEntity` (
     `id` int(11) NOT NULL AUTO_INCREMENT,`subid` int(11) NOT NULL DEFAULT '0',PRIMARY KEY (`id`,`subid`),

I have an entity class with an autoincrement field I want to read the auto increment ID when it is persistently assigned to it

The getter notes are as follows

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;
  }

I want to have an entity

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

SubID is the default value of 0 in the database. I add updates to this row programmatically I tried this so solution JPA – returning an auto generated ID after persist()

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

Now, outside of this transaction, I try to get the assigned auto increment ID

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

I called this from the network service

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

The update method is as follows

@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);
  }

I send n concurrent updates from n threads. The entity ID is 1. The other attributes are as follows

SomeEnity entity = new SomeEntity();

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

Case 1 has @ ID annotation on @ ID and Idid and "entitymanager. Persist" in the update. When I run 300 threads, some failures and connection exceptions "too many connections" database status is

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

The subsystem is always incremental, and the competitive condition is defined as active only because of the competitive condition

Case 2 with @ ID annotation on @ ID and Idid and "entitymanager. Merge" in update

id 1 subid 0 id 1 subid 0 id 2 subid 0 .. …. ID 151 subID 0 (maybe it's just a common point that one thread is more successful than another?)

Case 3 annotates subID and entitymanager with @ generatedvalue and @ ID and * * no @ ID Persist in update * * exception - separate entity passed to persistence

Case 3 use @ generatedvalue and @ ID to annotate ID and * * no @ ID in subID and entitymanager Merge is updating * * if the update sequence runs, the database status is

id 1 subid 0

After next update

id 1 subid 1

After each update, the same row is updated (only one row at a time)

id 1 subid 2

Case 4 is the same as case 3. If concurrent updates are run at the same time (there are 300 threads), I get the following exception

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

The database status is ID 1 subID 2 (only one thread will succeed, but the subID is updated from 0 to 2 due to competitive conditions)

Case 5 failed to create the ID and @ ID annotation on subID using @ generatedvalue and @ ID hibernate. Propertyaccessexception: someentity of setter is called when illegalargumentexception occurs id

Please explain why Javadoc from the method I know

Persistence - enables an instance to be managed and persisted

Merge – merges the state of a given entity into the current persistence context

My question is more about how hibernate manages annotations If the session is not closed, why is there a detached entity exception in case 3? Why is there an illegalargumentexception in this case?

I am using hibernate 3.6, MySQL 5 and spring 4. Please also suggest a method to implement such incremental IDs and subIDs (using a custom selectgenerator, with demonstration implementation or any other way, without column concat)

Solution

Because the ID field is unique and automatically incremented, you do not need a composite ID in this case, so your entity looks like this:

@Id
@Column(name = "id")
public long getId() {
    return id;
}

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

Entities can use the entity manager by ID:

entityManager.find(MyEntity.class,entityId);

Alternatively, you can use a query with both ID and subID to obtain the entity:

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

Hibernate also has a selectgenerator that can get ID from database columns, which is very useful when the database uses triggers to generate ID

Unfortunately, it doesn't apply to combined IDS, so you'll write down your own extended selectgenerator or use a single string ID_ sub_ ID column, which combines ID and sub ID into a varchar column:

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

You must write database triggers using database specific stored procedures to update the two columns and assemble the two columns into varchar stored procedures Then, map the aggregate column to the string field using the standard 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;
}
The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>