Hibernate: How does native identifier generation strategy work - mysql

Hibernate has an identifier generation strategy called native that selects identity, sequence or hilo depending upon the capabilities of the underlying database. I used MySQL with hibernate.hbm2ddl.auto=update which generated id BIGINT(20) NOT NULL AUTO_INCREMENT for id property of Long Java data type.
I am trying to understand how did Hibernate choose AUTO_INCREMENT when it used SchemaExport tool. Is AUTO_INCREMENT the default primary key generation strategy for MySQL?
Could somebody help me understand it?

Hibernate when selecting the key generation mechanism in native mode, will try to choose the best mechanism available in the database. In the case of MySQL, auto increment is available and Hibernate uses it instead of a sequence, because the auto increment mechanism is slightly better altough sequences also work fine.
The reason why it's better is that it's possible in one single JDBC prepared statement, for example an insert, to do an insert AND retrieve the generated key without querying the database - see here for further details.
In the case of sequences, Hibernate has to first call the sequence at some point and then use the value or the result of it's use in a formula to populate the insert key and then issue the insert.
The autoincrement spares this extra roundtrip to the database needed to increment the sequence, and that is the reason why Hibernate prefers it in the case of MySQL.

Related

MySQL 8: Create Collections via DDL

I’d like to be able to create MySQL Document Store Collections via simple SQL DDL statements rather than using the X-Protocol clients.
Is there any way to do so?
Edit: I’ll try and clarify the question.
Collections are tables using JSON datatypes and functions. That much is clear.
I would like know how I can create a Collection without using the X-Protocol calls and make sure that the aforementioned collection is picked up as an actual Collection.
Judging from MySQL workbench, collection tables have a _id blob PK with an expression, a doc JSON column and a few other elements I do not recall at the moment (might be indexes, etc).
I have no means to tell via the Workbench whatever additional schema/metadata information is required for a table to be considered a Document Store Collection, or if the mere presence of an _id and doc columns are enough.
I hope this clears things up.
All "x-api" instructions are directly mapped to sql syntax. When you e.g. run db.createCollection('my_collection'), MySQL will literally just execute
CREATE TABLE `my_collection` (
`doc` json DEFAULT NULL,
`_id` varbinary(32) GENERATED ALWAYS AS
(json_unquote(json_extract(`doc`,_utf8mb4'$._id'))) STORED NOT NULL,
`_json_schema` json GENERATED ALWAYS AS (_utf8mb4'{"type":"object"}') VIRTUAL,
PRIMARY KEY (`_id`),
CONSTRAINT `$val_strict` CHECK (json_schema_valid(`_json_schema`,`doc`))
NOT ENFORCED
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
You can run the corresponding sql statements yourself if you follow that format.
The doc and _id (with their type and the given expression) are required, the _json_schema is optional, the check too (and only added since MySQL 8.0.17). Since MySQL 8, no additional columns are allowed, except generated columns that use JSON_EXTRACT on doc and which are supposed to be used in an index, see below (although they don't actually have to be used in an index).
Any table that looks like that - doc and _id with their correct type/expression and no other columns except an optional _json_schema and generated JSON_EXTRACT(doc,-columns - will be found with getCollections().
To add an index, the corresponding syntax for
my_collection.createIndex("age", {fields: [{field: "$.age", type: "int"}]})
would be
ALTER TABLE `test`.`my_collection` ADD COLUMN `$ix_i_somename` int
GENERATED ALWAYS AS (JSON_EXTRACT(doc, '$.age')) VIRTUAL,
ADD INDEX `age` (`$ix_i_somename`)
Obviously,
db.dropCollection('my_collection')
simply translates to
DROP TABLE `my_collection`
Similarly, all CRUD operations on documents have a corresponding sql DML syntax (that will actually be executed when you use them via x-api).

disabling auto-increment in datanucleus?

I have 2 my-sql databases (live-db, test-db). I need to transfer some tables from live-db to test-db in datanucleus jdo implementation.
The problem is, if primary-key is an auto-increment then it does not transfer same value, but it generates new value.
Is there any method disable the auto-increment in datanucleus as programmatically?
spent 5 min and cannot find the answer, so i think easiest way is to do the following:
1) add new INT column without AUTO_INCREMENT
2) copy column value
3) drop AUTO_INCREMENT column
So you could use one set of metadata for one datastore (with autoincrement) and one set for the other (without). JDO persistence is simply following your instructions in auto-increment

Unique constraints and Hibernate

I am working with Hibernate 3.6.4 and MySQL.
I have a table with unique constraints on four columns and 3 other columns. When the UI application create new instances of the corresponding Object it may create it with those four properties with values already in the table. the result, upon save, is, of course JDBC Exception of duplicate entry.
Is there a way to tell Hibernate to not insert new entry but update the rest of the three columns or upon each save I need to manually query the DB to see if exist and update accordingly?
Thanks.
The clean and database independent approach for this problem is to first check if such an instance exists and depending on that do an insert or update in your application logic.
That said, there might be a way to take advantage of the MySQL INSERT ... ON DUPLICATE KEY UPDATE feature documented here. In this case you must specify a custom SQL INSERT statement for your entity like described in this related question. But if this works depends on the way your entity IDs are generated to begin with. Take a look at this blog article concerning this issue.
Generally, you must deal with every aspect of the problem that Hibernate thinks a transient instance is persisted, when in fact a persistent instance is updated. This might be an issue with generated entity IDs, other generated entity values, entity versions, concurrency, expected insert/update row count, 2nd level and query cache, etc.
So, I think while this would be a nice thing to experiment with I would definitely not use this feature in a production application.
You must indeed explicitely get the entity with the four unique values, and then update it if it exists or create a new one if it does not. There is no way around that.
BTW, note that even with such a mechanism, you might end up with exceptions if two transactions get the entity concurrently, find that it doesn't exist, and both try to create a new one.

switching from NewID to Sequential NewID for a default PK value

I have a production database with few million rows all using randomly generated GUIDs using a default value of NewID() as the primary key.
I am thinking of using the Sequential NewIDs going forward.
How will SQL Server know while generating the GUIDs in sequence that it did not already create that GUID when it was randomly generating using NEWID()?
It sounds like you're considering using NEWSEQUENTIALID() as the new default value.
Don't worry about the scenario of duplicates. The PK constraint on that column guarantees that a collision isn't going to happen. You aren't guaranteed that a new sequential GUID will be 'higher' anyway:
Creates a GUID that is greater than any GUID previously generated by this function on a specified computer since Windows was started. After restarting Windows, the GUID can start again from a lower range, but is still globally unique.
Some relevant information that may help you at Microsoft Connect : NEWSEQUENTIALID() is Not Sequential

Why is it necessary to assign atleast one column in a table (in MySQL) as PRIMARY KEY for the table to accept UPDATE and INSERT statements via JDBC?

Also; can I add a negative INT inside a PRIMARY KEY column inside a table via JDBC?
There should be no reason why you can't have a negative number in a primary key field, unless you are using an unsigned integer as its data type.
When you don't have a primary key defined (or a unique index for that matter), the database server has no way of knowing that the rows are unique. Being able to tell one row from another is pretty fundamental when it comes to databases, and I think maybe the designers of MySQL probably are forcing this on you -- I don't know, since I don't use MySQL all that much... It's a problem that I've never ran into, to be honest, because pretty much every table that I ever create has a PK!
Why is it necessary to assign atleast one column in a table (in MySQL) as PRIMARY KEY for the table to accept UPDATE and INSERT statements via JDBC?
This is not a JDBC limitation. This is a database limitation. Consult DB-specific docs for answers.
Also; can I add a negative INT inside a PRIMARY KEY column inside a table via JDBC?
This is not a JDBC limitation. This is a database limitation. Consult DB-specific docs for answers.
To make things clear: JDBC is here just a simple tool to give you the ability to execute the SQL language using the Java language. If you get exceptions of java.sql package, then the problem more lies in the faulty SQL syntax used, or a limitation in the database in question, or in rare cases a bug in the DB-supplied JDBC driver, but it certainly isn't caused by the JDBC API in general as you seem to think.