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

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.

Related

JAVA: concurrent sequence

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)
)

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.

Hibernate Batch Save Nested Objects

I have the below class structure:
class A{
int id;
List<B> blist;
List<C> clist;
List<D> dlist;
}
I get a json as an input which is mapped to object A by a mapper. Now, i have object A which has the list of B,C and D objects. I want to use batching to save the insert time taken. I went through the documentation which describes the solution if I want to save multiple parent objects. How would I use the batching capability in my case which has nested list of objects of multiple type.
I have enabled batch inserts using
<property name="hibernate.jdbc.batch_size">50</property>
This by itself doesnt give me any batching unless I clear and flush the session. Any suggestions on how do I go about with this?
The problem is that you're using IDENTITY strategy.
Whenever you save a new entity, Hibernate will place it into the Session's 1LC; however, in order to do that the identifier must be known. The problem with IDENTITY strategy is that Hibernate must actually perform the insert to determine the identifier value.
In the end, batch insert capabilities are disabled.
You should either try to load your data using business key values that are known up front or worse case use SEQUENCE generation type with a sequence optimizer to minimize the database hit. This will allow batch inserts to work.
UPDATE
For situations where you have no business key that defines the uniqueness for a row and your database doesn't have SEQUENCE support, you could manage the identifiers yourself. You can either elect to do this using a custom identifier generator or just doing this in your loop as code.
The caveat here is that this solution is not thread-safe. You should guarantee that at no point would you ever be running this logic in two threads simultaneously, which is typically not something one does anyway with bulk data loads.
Define a variable to store your identifier in. We will need to initialize this variable based on the existing max value of the identifier in the database. If no rows in the database exist, we likely will want to initialize it as 1.
Long value = ... // createQuery ( "SELECT MAX(id) FROM YourEntity" )
value = ( value == null ? 1L : value + 1);
The next step is to change the #Id annotated field. It should not be marked as #GeneratedValue since we're going to allow the application to provide the value.
For each row you're going to insert, simply call your #setId( value ) method with the value variable generated from step 1.
Increment your value variable by 1.

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