JAVA: concurrent sequence - java

in my application I have a table to store User informations as Name, Surname, Address, Type (Employee, Manager, Administrator), UniqueNumber.
I need to store in field UniqueNumber for each record in the table User a sequence number between 1 and 100 univocal for Type: so can exist a record with Type = 'Employee' and UniqueNumber=1 and a record with Type='Manager' and UniqueNumber=1 but cannot exist another record with Type='Employee' and UniqueNumber=1.
I was thinking to use a sequence of the database for each Type. This help me to manage concurrency where more users can be inserted a record at the same time.
Is this a good solution?
Is there an alternative?
I see AtomicInteger class but I don't understand how to use it for each Type of my table.
Thanks.

AtomicInteger just provides a thread-safe usage of Integer values.
Your problem has little to do with Java, unless you're creating every single User entity in one pass. If that's the case, you can declare 3 int values and increment them for each entity you're creating (or 3 static or local AtomicInteger values if you need to handle concurrency).
Best way to do it would be to create one sequence per Type, or get the next available value for a given Type using a Max query. --> Depends on your needs
What happens when you have more than 100 values for a Type ?

We can create such code in java, but that's unnecessarily complicated. It involves a Map and AtomicInteger() and you'd use the incrementAndGet() method quite frequently.
On the other hand, you can create two tables. One for UserTypes, another for users. Then the users table can have a foreign key to the types. Problem solved on the database level. This is cool because the database will enforce this constraint.
This is how you can do it with MS SQL Server:
CREATE TABLE UserTypes (
ID INT Identity(1, 1) NOT NULL,
TypeName VARCHAR(128) NOT NULL,
PRIMARY KEY (ID)
)
CREATE TABLE Usr (
ID INT Identity(1, 1) NOT NULL,
TypeId INT NOT NULL,
MoreData VARCHAR(256) NULL,
CONSTRAINT fk_types FOREIGN KEY (TypeId) REFERENCES UserTypes (ID)
)

Related

Inherited table with unique constraint is not generated as an UpdatableRecord

I have the following table definitions:
CREATE TABLE parent
(
id bigserial NOT NULL,
info text,
member_uuid uuid NOT NULL DEFAULT uuid_generate_v4(),
CONSTRAINT parent_pkey PRIMARY KEY (id)
);
CREATE TABLE child
(
-- Inherited from table parent: id bigint NOT NULL DEFAULT nextval('parent_id_seq"::regClass),
-- Inherited from table parent: info text
-- Inherited from table parent: member_uuid uuid NOT NULL DEFAULT uuid_generate_v4(),
member_info text,
CONSTRAINT child_member_uuid_unique UNIQUE (member_uuid)
)
INHERITS (parent);
I wish to generate the second table as a JOOQ POJO and be able to manipulate it. In particular, I wish to be able to do the following:
ChildRecord record = dslContext.newRecord(CHILD)
.setMemberInfo(...)
.insert();
record.getMemberUuid(); // autogenerated upon insert
However, in the above case with the given definition, JOOQ generates the following POJO:
public class ChildRecord extends TableRecordImpl<ChildRecord> implements Record4<Long, String, UUID, String>
Which is not an UpdatableRecord. This means that I am unable to call refresh() on this record and that the autogenerated UUID value is not available:
ChildRecord record = dslContext.newRecord(CHILD)
.setMemberInfo(...)
.insert();
record.getMemberUuid(); // null
There is a workaround, which is a bit dirty:
ChildRecord record = dslContext.newRecord(CHILD)
.setMemberInfo(...)
.setMemberUuid(UUID.randomUUID())
.insert();
record.getMemberUuid(); // available
However, there is no guarantee that the uuid_generate_v4() implementation is always going to be exactly the same as the java UUID.randomUUID() implementation.
Is this behaviour 'as expected'? Is there a workaround aside from what I have mentioned above?
After some more research, I read through the JOOQ docs, which state:
Any Record can be updatable, if
it represents a record from a table or view - a TableRecord
its underlying table or view has a "main unique key", i.e. a primary key or at least one unique key
As far as I can see, condition one is not fulfilled by my child table (due to the lack of a PK), while condition two is fulfilled. By the wording of the docs, I can surmise that both of these need to be true for the Record to be an UpdatableRecord. Insofar - this JOOQ behaviour is correct and as-expected.
Unfortunately this does not solve the issue of using values that should be autogenerated. One possible workaround might be to use an SQL statement like:
dslContext.update.<...>.setMemberUuid(select("select uuid_generate_v4()")).<...>
though this is extremely cumbersome and rather error-prone, and most likely will not solve the issue of the value not being refreshed. For now I will have to live with Java's UUID.randomUUID() method, until something better comes along.

jOOQ - update record based on unique key (not primary key)

I am using jOOQ to generate POJOs for my database tables. This works great.
I have a table with a primary key (identifier) and a unique key (name). When updating the record, jOOQ uses the primary key.
I would like to update the record by using the unique key instead of the primary key.
https://github.com/jOOQ/jOOQ/blob/master/jOOQ/src/main/java/org/jooq/impl/UpdatableRecordImpl.java
#Override
public final int update() {
return update(fields.fields.fields);
}
#Override
public int update(Field<?>... storeFields) throws DataAccessException, DataChangedException {
return storeUpdate(storeFields, getPrimaryKey().getFieldsArray());
}
In essence, I want to call storeUpdate with another key (second parameter). I tried extending the generated record, but storeUpdate is private.
Is there another way to update a record? I could first select the identifier before update(), but it introduces an extra query, which I would like to avoid.
From the comments, I understand that you want to:
Use the generated records as "ActiveRecords" holding data that is going to be stored / updated into a table
Use arbitrary "key" information as selective criteria for your update statement
There are two ways you can do this with jOOQ:
1. Override the primary key information in the code generator
You can specify a regular expression matching unique key names in your database, which should override primary keys in generated code:
<!-- All (UNIQUE) key names that should be used instead of primary keys on
generated UpdatableRecords, to be used with
- UpdatableRecord.store()
- UpdatableRecord.update()
- UpdatableRecord.delete()
- UpdatableRecord.refresh()
If several keys match, a warning is emitted and the first one encountered
will be used.
This flag will also replace synthetic primary keys, if it matches. -->
<overridePrimaryKeys>MY_UNIQUE_KEY_NAME</overridePrimaryKeys>
Note that this solution will affect all the calls to store(), update(), etc. From your comments, this might not be the desired behaviour... For more information, see the jOOQ manual
2. Use a regular UPDATE statement
You can pass the whole UpdatableRecord to an UPDATE statement and specify the selection criteria explicitly, such as:
MyTableRecord record = ...;
DSL.using(configuration)
.update(MY_TABLE)
.set(record)
.where(MY_TABLE.NAME.eq(record.getName())
.execute();

Hibernate Insert Options

I am trying to efficiently implement a Hibernate connection in Java and recently came across two ways of adding database rows using Hibernate which I would like to discuss:
Given are the following SQL Tables:
CREATE TABLE Customer (
customer_id INT NOT NULL AUTO_INCREMENT,
customer_name VARCHAR(255) NOT NULL UNIQUE KEY,
PRIMARY KEY (customer_id)
) ENGINE=InnoDB;
CREATE TABLE Orders (
order_id INT NOT NULL AUTO_INCREMENT,
customer_name VARCHAR(255) NOT NULL,
order_date DATETIME,
PRIMARY KEY(order_id),
FOREIGN KEY (customer_name) REFERENCES Customer(customer_name)
ON UPDATE CASCADE
ON DELETE CASCADE
) ENGINE=InnoDB;
Customer is parent table and Orders is child table, 1:n relationship.
When I want to insert new Orders for a certain customer, which is already in the database I know to options how to achieve it :
(1)
// Saving the child table
// Query the customer
Customer cu = (Customer) session.get(Customer.class, 1);
Orders od = new Orders(cu, new Date());
session.save(od);
// This seems to work fast and efficient
(2) Saving the parent table
// Due to bidirectional relationship one can also do:
Orders od = new Orders(cu, d);
cu.getOrderses().add(od);
session.save(cu);
// This is what is often shown in Hibernate tutorials, but seems to be really
// inefficient because the entire HashSet of the parent table needs to loaded //first,
//before the new object can be added.
Benchmark example : (1) 0 sec (2) 5 sec
Why is way (2) often shown in Tutorials even though it seems to be inefficient ?
Which option you should choose depents on your model. Do you have/need a collection of orders in the Customer? Then you have to add the object anyway and you should choose (2).
Take care of proper fetch configuration or otherwise Hibernate will load the whole collection even if you don't need it. For that case take a look at Hibernate - How to persist a new item in a Collection without loading the entire Collection.
If you don't have a collection in Customer then use option (1).
(2) is often shown in tutorials to show the capabilities of Hibernate/ORMs in general. It's also more object oriented but I would recomment to create a method Customer.addOrder() or even Customer.creatOrder() instead od directly manipulating the collection from outside.

How to make the primary key in JDBC MYSQL case sensitive?

I have a primary key defined as a string value. So two tuples with primary keys as "Hello" and "hello" cant exist because the primary key is case insensitive.
What will be the sql statement to create a table whose primary key is case insensitive?
You basically need a check constraint that uses a sub query. But since sub-queries are not permitted in check constraints you can write a function that runs the query and returns a
result: (Assuming your PK is called ID)
create or replace
FUNCTION check_id(ID_INPUT IN VARCHAR2)
RETURN NUMBER
IS count_id NUMBER;
Begin
SELECT count(*) INTO count_id FROM table WHERE UPPER(ID_INPUT) = UPPER(ID);
Return(Count_Id);
END;
Then use this function in your check constraint for your primary key
CHECK check_id(ID) = 0
Try this and let me know. Have not verified it for syntax.
Having a user defined function called by a constraint is one way to go. The drawbacks are that a complete table scan must be performed every time a row is inserted -- or whenever the key field is updated, I suppose, but that shouldn't be happening too often. Also, developing a udf that can be referenced by a constraint is not always easy. Even when it's allowed, the function has to meet strict requirements about being deterministic and not altering the data state. Some DBMSs make this relatively easy, others...do not.
Another option would be to define a "shadow" field. This field, populated by insert and update trigger(s), would be the contents of the ID field converted to all one case, upper or lower. A unique constraint on the shadow field would then serve the purpose you need. This could also be implemented as a computed column, where they exist, but triggers would be better. In case of duplicates, the triggers could then intercept the exception and throw their own, with the ID field instead of the shadow named as the culprit.
The drawback to this method is that you've doubled the space needed to contain your key data. That may or may not be significant.
Interestingly, Oracle 12c has introduced the "invisible" column. It acts just like any other column except it must be referenced explicitly, it doesn't show up in select * for example. This would be a perfect use for such an invisible column.

Hibernate - Get a row with only one value of a composite primary key?

I have a table (Oracle database) that looks like:
CREATE TABLE example
(
idEx INTEGER,
idAdh INTEGER,
date DATE,
PRIMARY KEY (idEx, idAdh)
)
I have generated the corresponding classes in Netbeans and I have two classes created for this table: Example.java and ExampleId.java, this last one containing the two values of my primary key.
Now let's say I have some records here and I would like to delete one using only one value of the primary key (idEx for example, which is unique too). So first I need to get that row, but I can't find a way to do this. Would it be possible to do something like this?
Example ex = (Example) session.get(Example.class, new ExampleId(?, idEx));
I'd need something to replace that ? that would act as a wildcard.
Or maybe this is absolutely not the way to go and in this case I'd really appreciate some advices.
You should be able to get the ex with a HQL query.
There is no way to get this without an HQL/JPQL/Criteria query, for good reason.
The get method returns a single object and automatically generates a query like select * from table where key = :key.
The only way you can guarantee that this query returns exactly one row is when you specify the entire key. If you don't have the full PK object available, the query will return a list of objects, at which point get is not appropriate anymore.

Categories

Resources