Hibernate Sequence Generator requests 2 values - java

I have found a strange case about Hibernate Sequence Generator. When I save the entity with repository Hibernate performs two queries.
select nextval ('some_sequence')
select nextval ('some_sequence')
Is is some Hibernate pre-caching behavior? Can it be tuned?
Here is the entity:
#Entity
#Getter
#Setter
#Table(name = "host_black_list")
public class RestrictedHost {
#Id
#GeneratedValue(
strategy = SEQUENCE,
generator = "restricted_host_generator"
)
#SequenceGenerator(
name = "restricted_host_generator",
sequenceName = "some_sequence"
)
#Column(name = "host_black_list_id")
private Long id;
#Column(name = "host_name")
#NotNull
private String name;
#Column(name = "msisdn_count")
#NotNull
private long msisdnCount;
}
And here is the test code:
final var id = transactionTemplate.execute(status -> {
RestrictedHost restrictedHost = new RestrictedHost();
restrictedHost.setName("some_name");
restrictedHost.setMsisdnCount(156);
final var host = restrictedHostRepository.saveAndFlush(restrictedHost);
return host.getId();
});
I use Testcontainers + PostgreSQL 9.6.8

Yes hibernate default way cache seq values.
Default cached values are 50. But I didn't think it run one seq query twice.
persistence.xml:
this settings said old style or new style seq usage
<property name="hibernate.id.new_generator_mappings" value="false"/>
If you use GenericGenerator, then it works without cache, so all persist fetch a seq value!
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "some_seq_generator")
#GenericGenerator(name = "some_seq_generator", strategy = "sequence", parameters = { #Parameter(name = "sequence", value = "some_seq") })

Related

How to setup Liquibase to use custom SequenceStyleGenerator

so I have custom IdGenerator like that:
#Service
public class IdGenerator extends SequenceStyleGenerator {
private final SequenceRepository sequenceRepository;
public IdGenerator(SequenceRepository sequenceRepository) {
this.sequenceRepository = sequenceRepository;
}
#Override
public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
BaseObject type = ((BaseObject) object);
return StringUtils.getNumberWithMaxRadix(sequenceRepository.getNext(type.sequenceName()));
}
}
And on Entity Id field Hibernate annotations:
#Id
#Column(name = "id", nullable = false, length = 18)
#SequenceGenerator(name = "location_road_seq", sequenceName = "location_road_seq", allocationSize = 10)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "location_road_seq")
#GenericGenerator(
name = "location_road_seq",
strategy = "com.wildtigerrr.bestgamebot.bin.service.base.IdGenerator",
parameters = {
#org.hibernate.annotations.Parameter(name = IdGenerator.VALUE_PREFIX_PARAMETER, value = "a0lr")
})
private String id;
When inserting objects from the code with Hibernate - works like a charm. But I need to insert initial data with Liquibase, and here I have issues inserting data from Liquibase changeset:
INSERT INTO location (id, system_name)
VALUES (nextval('location_seq'), 'TestLocation');
Returns simple values from sequence as Id.
Is there an option and how should I configure Liquibase to use my IdGenerator?
And if it's not possible, what's best practices/possible solutions for overcoming that issue? Any feedback would be appreciated!

Hibernate mapping if allocationSize exists id is 1 if not id is -48. How?

I have an entity mapped and I want to verbosely point it to its sequence. So I have the following mapping:
#Entity
#Table(schema = DbConstants.SCHEMA_PUBLIC, name =
DbConstants.PUBLIC_TABLE_TEST)
public class TestEntity implements Serializable {
private static final long serialVersionUID = 6284010266557287786L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "test")
#SequenceGenerator(schema = DbConstants.SCHEMA_PUBLIC, name = "test", sequenceName = "test_id_seq")
private Integer id;
}
The problem is that if I don't include allocationSize in the #SequenceGenerator annotation the entities seem to have an id of something along the lines of -49 + nextval('test_id_seq'::regclass). Adding a new entity also increments the test_id_seq. I've compared the sql that hibernate uses with or without the allocationSize and it's exactly the same.
1) How does this happen?
2) How do the database ids end up being so different with seemingly the same sql being used by hibernate?

Hibernate sequence generator always 0

I'm trying to configure a mapped class to use a sequence I defined in a postgres db. The ids are always zero when I try to persist any entities, if I use select nextval('item_seq'), I'll get 1 (or the next val). I used intellij to regenerate the classes. The version of hibernate in this project is 3.6.0, if that might be part of my problem?
#Entity
#Table(name = "item")
public class Item {
private int itemid;
...
#Basic
#Id
#SequenceGenerator(name = "item_seq", sequenceName = "item_seq", allocationSize = 1)
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "item_seq")
#Column(name = "itemid", unique = true, nullable = false, insertable = true, updatable = true)
public int getItemid() {
return itemid;
}
...
}
Usage
Item item = new Item();
item.setCreated(new Date());
item.setVendorId(vendorId);
save(item); // essentially is getHibernateTemplate().save(Item.class.getName(), item);
-- EDIT --
I've been trying the suggestions below and everything seems to keep generating 0 as an id or throw the exception 'ids for this class must be manually assigned before calling save()'. This is where I am now, as a last ditch effort I tried moving the annotations to the variable declaration instead of the getter. Didn't help.
#Entity
#Table(name = "item")
public class Item {
#Id
//#SequenceGenerator(name = "item_seq", sequenceName = "item_seq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.IDENTITY) //, generator = "item_seq")
#Column(name = "itemid", unique = true, nullable = false) //, insertable = true, updatable = true)
private Long itemid;
...
public Long getItemid() {
return itemid;
}
}
This always works for me (Hibernate 4.x though):
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Id makes the column a primary key (unique, no nulls), so you don't need the #Column(...) annotation. Is something setting your itemId somewhere? You can remove its setter if you have one (Hibernate doesn't require).
Try to provide database schema name for given table and sequence in you entity class.
Make sure your application user has privileges (grants) to the sequence.
-- update --
I think solution is here
I was having the same problem and here's what I did to solve the issue
I was using Hibernate tools to auto generate POJOs and all the annotations were being placed at the method level, however, Spring recommends (requires?) them at the field level. You can't just move the Id annotations to the field level either, because it's either one or the other (I got some other exceptions when I tried this). So I followed this answer to customize Hibernate tools to generate POJOs with the annotations all at the field level.
Now my code looks like this and it's using the database sequence sequence just fine.
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="my_seq")
#SequenceGenerator(name="my_seq",sequenceName="SPT_PROJECT_SEQ", allocationSize=1)
#Column(name = "PROJECT_ID", unique = true, nullable = false, precision = 10, scale = 0)
private long projectId;
Hope this helps
what database u are using?
can be possibly a database that does not support sequence??
try to use strategy=auto and see how does it work
since 'select nextval(...)' works, your database (postgresql) is supporting sequence. so thats not it
maybe for some reason hibernate is threating yout int == 0 as an id and it is trying to update it instead of inserting a new record ( deafult value for int =0 ) just change your id type to Integer and see if it solve the problem

Autoincrement column in oracle using hibernate

I am using hibernate annotations. I want to make a column as autoincremented. I have created a sequence in database(oracle) and mapped that sequence in java POJO class. Do I need to create trigger for that sequence too? I want to know how we can make a column autoincremented while using hibernate anotation? What changes i have to do in java and as well as database side? Please help me in this. Following is the part of code where I have mapped the sequence.
public class SimRuns implements Serializable {
private static final long serialVersionUID = 8698324570356602407L;
#Id #Column(name = "RUN_ID")
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq_run_id")
#SequenceGenerator(name="seq_run_id", sequenceName="seq_run_id")
private Long runId;
}
This works for me:
#Id
#GeneratedValue(generator = "nosicSeq")
#SequenceGenerator(name = "nosicSeq", sequenceName = "NOSIC_SEQ", allocationSize = 1)
#Column(name = "SID")
private BigDecimal sid;
no triggers in DB needed, just sequence.
Try removing the generator and setting to auto the generationType
#Id #Column(name = "RUN_ID")
#GeneratedValue(strategy=GenerationType.AUTO)
#SequenceGenerator(name="seq_run_id", sequenceName="seq_run_id")
private Long runId;
Hibernate is probably the only JPA Provider that selects the right Generationstrategy based on your databasetype. Using the GenerationType.AUTO statement hibernate will try to select the best strategy to implement an increasing row id.
In Oracle : It's no need for an Oracle trigger, but the sequence is must.
In pojo: you can use Annotations like this:
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="majorsSeq")
#SequenceGenerator(name="majorsSeq", sequenceName="MAJORS_SEQ", allocationSize = 1,initialValue = 1)
public int getId() {
return id;
}

auto creation of sequence using hibernate tool

I wanted to to generate sequence using hibernate tool ( pojo to sql). And definitely it works fine.
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seqid-gen")
#SequenceGenerator(name = "seqid-gen", sequenceName = "RTDS_ADSINPUT_SEQ" )
#Column(name="id")
public Long getId() {
return id;
}
This code generates below sql
create sequence RTDS_ADSINPUT_SEQ;
The problem is I wanted to specify properties like
INCREMENT BY,NOCACHE CYCLE
and the final ddl script should be some thing like below
CREATE SEQUENCE RTDS_ADSINPUT_SEQ MINVALUE 1 MAXVALUE
999999999999999999 INCREMENT BY 1 START WITH 1 NOCACHE ORDER CYCLE ;
But as far I saw hibernate only support name, sequncename,allocation,initialvalue
Please advice me if I can include those properties as annotation in the pojo.
I looked it up in the Hibernate sources (4.2.7). It is not possible to specify this with an annotation (neither JPA nor Hibernate).
However you can provide your own Dialect to achieve this.
public class MyOwnOracleDialect extends Oracle10gDialect {
#Override
protected String getCreateSequenceString(final String sequenceName, final int initialValue, final int incrementSize)
throws MappingException {
String createSequenceString = super.getCreateSequenceString(sequenceName, initialValue, incrementSize);
return createSequenceString + " NOCACHE ORDER CYCLE"; // modify this string as you like
}
}
Have an entity like this
#Entity
public class MyEntity {
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seqid-gen")
#SequenceGenerator(name = "seqid-gen", sequenceName = "RTDS_ADSINPUT_SEQ", allocationSize = 1, initialValue = 0)
#Column(name="id")
private Long id;
// ...
}
You can set your new Dialect as described in the Hibernate doc (http://docs.jboss.org/hibernate/orm/4.2/manual/en-US/html/ch03.html#configuration-optional-dialects)
I think you are looking for something like this
<id name="pk_field" column="column_name">
<generator class="sequence">
<param name="sequence">sequence_name</param>
<param name="parameters">START WITH 5 INCREMENT BY 10</param>
</generator>
</id>

Categories