I convert the DB from Oracle to MySQL.
I'm using both Java & Hibernate.
When I used oracle I had the following method that gave me a brand new and unused sequence value:
protected int getSequenceNextValue() {
Session session = sessionFactory.getCurrentSession();
Query query = session.createSQLQuery("select MY_SEQUENCE.NEXTVAL from DUAL");
return ((BigDecimal) query.uniqueResult()).intValueExact();
}
And I'm trying to refactor this method to work on MySQL DB.
I have a table in MySQL that I use as a sequence (through Hibernate):
create table MY_SEQUENCE(
next_val int(10) NOT NULL
);
Is there any thread safe way to get a new value from this table and in the same transction to increase it?
For most cases I use the Hibernate Generator to generate a new sequence using this table, but in several cases I need to do it manually.
The best solution for me will be a refactoring of the method above, in such way that threads that querying the table at the same time will not fail, but will wait for each other.
Thanks...
Have a look at the InnoDB table type and FOR UPDATE. An example similar to what you describe is in the MySQL manual here http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html
Related
I have a mariadb table with 2 cols: rowid int pk autogenerated and imagen blob.
By using "CallableStatement sentence = mariaConn.prepareCall(myinsert);" I'm able to add a new row with a blob into "imagen" BUT I can't get the autogenerated pk col "rowid".
By the other hand, using "Statement sentence = mariaConn.prepareStatement(myinsert);" I can get the autogenerated col "rowid" but I can't add a blob into "imagen" (only do if it is empty).
Is there a way to do both things at one call? (trying to avoid a Statement insert to get the pk and then a CallableStatement to update the blob).
Note: in Oracle is pretty simple using CallableStatement because Oracle's insert has a "returning" clause <= I'm trying to emulate it on mariadb.
Thanks in advance.
you do not need CallableStatement to insert blob, a simple prepared statement
insert into table(imagen) values(?)
works,and with that you can get autogenerated value if you use Statement.RETURN_GENERATED_KEYS during preparation, and Statement.getGeneratedKeys() after execution. You also can do
select last_insert_id()
any time, but this is less efficient.
There is no MariaDB 5.6 btw.
I have an update query which I am trying to execute through batchUpdate method of spring jdbc template. This update query can potentially match 1000s of rows in EVENT_DYNAMIC_ATTRIBUTE table which needs to be get updated. Will updating thousands of rows in a table cause any issue in production database apart from timeout? like, will it crash database or slowdown the performance of entire database engine for other connections...etc?
Is there a better way to achieve this instead of firing single update query in spring JDBC template or JPA? I have the following settings for jdbc template.
this.jdbc = new JdbcTemplate(ds);
jdbc.setFetchSize(1000);
jdbc.setQueryTimeout(0); // zero means there is no limit
The update query:
UPDATE EVENT_DYNAMIC_ATTRIBUTE eda
SET eda.ATTRIBUTE_VALUE = 'claim',
eda.LAST_UPDATED_DATE = SYSDATE,
eda.LAST_UPDATED_BY = 'superUsers'
WHERE eda.DYNAMIC_ATTRIBUTE_NAME_ID = 4002
AND eda.EVENT_ID IN
(WITH category_data
AS ( SELECT c.CATEGORY_ID
FROM CATEGORY c
START WITH CATEGORY_ID = 495984
CONNECT BY PARENT_ID = PRIOR CATEGORY_ID)
SELECT event_id
FROM event e
WHERE EXISTS
(SELECT 't'
FROM category_data cd
WHERE cd.CATEGORY_ID = e.PRIMARY_CATEGORY_ID))
If it is one time thing, I normally first select the records which needs to be updated and put in a temporary table or in a csv, and I make sure that I save primary key of those records in a table or in a csv. Then I read records in batches from temporary table or csv, and do the update in the table using the primary key. This way tables are not locked for a long time and you can have fixed set of records added in the batch which needs update and updates are done using primary key so it will be very fast. And if any update fails then you know which records got failed by logging out the failed records primary key in a log file or in an error table. I have followed this approach many time for updating millions of records in the PROD database, as it is very safe approach.
Database : Oracle
I have table in which there are 10 columns and i want sequence next value when insert row and also use that sequence number which inserted.
Now i have searched and find that KeyHolder of spring is useful but restrict for only less than 8 field so i can't use that.
How can i fire "select MySequence.nextval from dual" query and get sequence using jdbctemplate(NamedParameterJDBCTemplate) ?
Is other way to achieve for get inserted sequence value ?.
Using a jdbctemplate you can just mention the sequence generator as a value, e.g.
jdbcTemplate.update("INSERT INTO TABLE (id, data) VALUES (MySequence.nextval, ?)", new Object[] { data });
A note regarding the sequence generation: for versions before Oracle 12c you should have a trigger which will increment the sequence for you. From 12c you can use the auto-increment feature.
You can achieve this by using JdbcTemplate like this :
final SqlRowSet sqlRowSet = jdbcTemplate.queryForRowSet(NEXT_VALUE_QUERY);
sqlRowSet.next();// mandatory to move the cursor
sqlRowSet.getLong(1);// the value of the nextval
my code is written in java, and I am really new to java, so i hope my explanations are correct:
i have a java written web service that works with a data base.
the data base types can be PostgreSQL and mysql.
so my webservice works with the JDBC connection for both data bases.
one of my data base tables is table urls,
for postgressql it is created like this:
CREATE TABLE urls (
id serial NOT NULL primary key,
url text not null,
type integer not null);
for mysql it is creates like this:
CREATE TABLE IF NOT EXISTS URLS (
id INTEGER primary key NOT NULL AUTO_INCREMENT,
url varchar (1600) NOT NULL,
type INTEGER NOT NULL );
when I try inserting data to this table I use an entity called urls:
this entity has:
private BigDecimal id;
private String url;
private BigInteger type;
when I try to insert values to the urls table I assign values to the urls entity, while leaving the id as NULL since it is AUTO_INCREMENT for mysql and serial for postgres.
the query works for my sql, but fails for postgress.
in the postgres server log I can see the following error:
null value in column "id" violates not-null constraint
cause I sends NULL as the id value.
I found out that in order for the query to work I should use this query:
INSERT INTO URLS(ID, TYPE, URL) VALUES(DEFAULT, 1, 'DED'); or this one:
INSERT INTO URLS(TYPE, URL) VALUES(1, 'DED'); or this one:
instead of this one, that I use:
INSERT INTO URLS(ID, TYPE, URL) VALUES(NULL, 1, 'DED');
so my question is,
how do I assign the DEFAULT value to a BigDecimal value in java ?
is removing the id from my entity is the right way to go ?
how can I make sure that any changes I do to my code wont harm the mysql or any other data base that I will use ?
If you specify the column name in the insert query then postgres does not take the default value. So you should use your second insert query.
INSERT INTO URLS(TYPE, URL) VALUES(1, 'DED');
This syntax is correct for both postgres and MySQL.
This should resolve your question (1) and (3). For (2) DO NOT delete the id field from your entity. This id is going to be your link to the database row for a specific object of the entity.
1 - I think it is proper to use Long or long types instead of BigDecimal for id fields.
2 - Yes it generally helps, but it lowers portability. BTW, using an ORM framework like Hibernate may be a good choice.
3 - Integration testing usually helps and you may want to adopt TDD style development.
When using this statement:
INSERT INTO URLS(ID, TYPE, URL) VALUES(NULL, 1, 'DED');
you are telling the database that you want to insert a NULL value into the column ID and Postgres will do just that. Unlike MySQL, PostgreSQL will never implicitely replace a value that you supply with something totally different (actually all DBMS except MySQL work that way - unless there is some trigger involved of course).
So the only solution to is to actually use an INSERT that does not supply a value for the ID column. That should work on MySQL as well.
This question already has answers here:
How to get the insert ID in JDBC?
(14 answers)
Closed 7 years ago.
I have a database table A which stores records, A has a primary key (recordid) with auto_increment, each time i insert a record in to A, i get the inserted recordid and store it in another masterTable.
I am using a select statement as soon i do an insert into A to get the recordid like this:
select recordid from A order by recordid DESC LIMIT 1;
But i ran into a problem today, where in two records were inserted(by different threads) at the same time and i ended up storing wrong recordid in the master id( the same recordid for both the txns)
I heard about Statement.getGeneratedKeys(), I would like to know if that really helps resolve the issue. Or what is the best way to handle this.
You can use the getGeneratedKeys method. This forum post will help.
May I also recommend that you use an ORM tool like Hibernate. In Hibernate you would do something like this:
myTable = new myTable();
myTable.prop1 = prop1;
myTable.prop2 = prop2;
int id = session.save(myTable);
Hibernate will issue the appropriate SQL commands (depending on the database selected) and return you the auto-generated id.
The MySQL JDBC driver does support the getGeneratedKey() method. Have a look at the section 20.3.5.1.4. Retrieving AUTO_INCREMENT Column Values of the MySQL manual where:
we demonstrates the use of the new JDBC-3.0 method getGeneratedKeys() which is now the preferred method to use if you need to retrieve AUTO_INCREMENT keys.
In databases that don't support generatedKeys you may be able to get the ID into a return parameter. Oracle for example provides the RETURNING xxx INTO ? syntax where xxx is your column name.