Is there a cross database platform way to get the primary key of the record you have just inserted?
I noted that this answer says that you can get it by Calling SELECT LAST_INSERT_ID() and I think that you can call SELECT ##IDENTITY AS 'Identity'; is there a common way to do this accross databases in jdbc?
If not how would you suggest I implement this for a piece of code that could access any of SQL Server, MySQL and Oracle?
Copied from my code:
pInsertOid = connection.prepareStatement(INSERT_OID_SQL, Statement.RETURN_GENERATED_KEYS);
where pInsertOid is a prepared statement.
you can then obtain the key:
// fill in the prepared statement and
pInsertOid.executeUpdate();
ResultSet rs = pInsertOid.getGeneratedKeys();
if (rs.next()) {
int newId = rs.getInt(1);
oid.setId(newId);
}
Hope this gives you a good starting point.
extraneon's answer, although correct, doesn't work for Oracle.
The way you do this for Oracle is:
String key[] = {"ID"}; //put the name of the primary key column
ps = con.prepareStatement(insertQuery, key);
ps.executeUpdate();
rs = ps.getGeneratedKeys();
if (rs.next()) {
generatedKey = rs.getLong(1);
}
Have you tried the Statement.executeUpdate() and Statement.getGeneratedKeys() methods? There is a developerWorks article that mentions the approach.
Also, in JDBC 4.0 Sun added the row_id feature that allows you to get a unique handle on a row. The feature is supported by Oracle and DB2. For sql server you will probably need a third party driver such as this one.
Good luck!
for oracle, Hibernate uses NEXT_VALUE from a sequence if you have mapped a sequence for PKEY value generation.
Not sure what it does for MySQL or MS SQL server
Spring provides some useful support for this operation and the reference guide seems to answer your question:
There is not a standard single way to
create an appropriate
PreparedStatement (which explains why
the method signature is the way it
is). An example that works on Oracle
and may not work on other platforms
is...
I've tested this example on MySQL and it works there too, but I can't speak for other platforms.
For databases that conform to SQL-99, you can use identity columns:
CREATE TABLE sometable (id INTEGER GENERATED ALWAYS AS IDENTITY(START WITH 101) PRIMARY KEY, ...
Use getGeneratedKeys() to retrieve the key that was just inserted with executeUpdate(String sql, int autoGeneratedKeys). Use Statement.RETURN_GENERATED_KEYS for 2nd parameter to executeUpdate()
Just declare id column as id integer not NULL primary key auto_increment
after this execute this code
ResultSet ds=st.executeQuery("select * from user");
while(ds.next())
{
ds.last();
System.out.println("please note down your registration id which is "+ds.getInt("id"));
}
ds.close();
the above code will show you the current row's id
if you remove ds.last() than it will show all values of id column
Related
I'm using jOOQ (3.14.11) to manage a table defined (in H2 or MYSQL) as:
CREATE TABLE example_one (
group_id VARCHAR(36) NOT NULL,
pawn_id INT UNSIGNED AUTO_INCREMENT NOT NULL,
some_unimportant_attribute INT UNSIGNED DEFAULT 0 NOT NULL,
another_uniportant_attribute VARCHAR(36),
CONSTRAINT pk_example_one PRIMARY KEY (group_id, pawn_id)
)
Note that in this SQL, the primary key specifies the (group, pawn) IDs in that order but it is the pawn_id, the second one, which is the auto-increment/identity column.
It appears that jOOQ doesn't like this arrangement. When I try to use the Record objects to insert a new row, it will not return back to me the "pawnID" value:
ExampleOneRecord r = create.newRecord(EXAMPLE_ONE);
r.setGroup("a group identity");
r.store();
assert r.getPawnId() != null; // <---- FAILS test
Diving into the code, the suspect seems to be in AbstractDMLQuery.java method executeReturningGeneratedKeysFetchAdditionalRows which has this bit of logic:
// Some JDBC drivers seem to illegally return null
// from getGeneratedKeys() sometimes
if (rs != null)
while (rs.next())
list.add(rs.getObject(1));
The call to rs.getObject(1) seems to be assuming that the generated column will always be the first column of the primary key.
Is there any way to convince jOOQ otherwise?
This is a bug in jOOQ 3.15.1 for H2: https://github.com/jOOQ/jOOQ/issues/12192
It has been fixed in jOOQ 3.16.0 for H2 2.0.202, which now supports the powerful data change delta table syntax, allowing for much easier fetching of generated values from a DML statement (it was implemented before that H2 version, but had a significant bug: https://github.com/h2database/h2database/issues/2502)
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 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
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.
I'm busy on a piece of code to get alle the column names of a table from an Oracle database. The code I came up with looks like this:
DriverManager.registerDriver (new oracle.jdbc.driver.OracleDriver());
Connection conn = DriverManager.getConnection(
"jdbc:oracle:thin:#<server>:1521:<sid>", <username>, <password>);
DatabaseMetaData meta = conn.getMetaData();
ResultSet columns = meta.getColumns(null, null, "EMPLOYEES", null);
int i = 1;
while (columns.next())
{
System.out.printf("%d: %s (%d)\n", i++, columns.getString("COLUMN_NAME"),
columns.getInt("ORDINAL_POSITION"));
}
When I ran this code to my surprise too many columns were returned. A closer look revealed that the ResultSet contained a duplicate set of all the columns, i.e. every column was returned twice. Here's the output I got:
1: ID (1)
2: NAME (2)
3: CITY (3)
4: ID (1)
5: NAME (2)
6: CITY (3)
When I look at the table using Oracle SQL Developer it shows that the table only has three columns (ID, NAME, CITY). I've tried this code against several different tables in my database and some work just fine, while others exhibit this weird behaviour.
Could there be a bug in the Oracle JDBC driver? Or am I doing something wrong here?
Update: Thanks to Kenster I now have an alternative way to retrieve the column names. You can get them from a ResultSet, like this:
DriverManager.registerDriver (new oracle.jdbc.driver.OracleDriver());
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:#<server>:1521:<sid>", <username>, <password>);
Statement st = conn.createStatement();
ResultSet rset = st.executeQuery("SELECT * FROM \"EMPLOYEES\"");
ResultSetMetaData md = rset.getMetaData();
for (int i=1; i<=md.getColumnCount(); i++)
{
System.out.println(md.getColumnLabel(i));
}
This seems to work just fine and no duplicates are returned! And for those who wonder: according to this blog you should use getColumnLabel() instead of getColumnName().
In oracle, Connection.getMetaData() returns meta-data for the entire database, not just the schema you happen to be connected to. So when you supply null as the first two arguments to meta.getColumns(), you're not filtering the results for just your schema.
You need to supply the name of the Oracle schema to one of the first two parameters of meta.getColumns(), probably the second one, e.g.
meta.getColumns(null, "myuser", "EMPLOYEES", null);
It's a bit irritating having to do this, but that's the way the Oracle folks chose to implement their JDBC driver.
This doesn't directly answer your question, but another approach is to execute the query:
select * from tablename where 1 = 0
This will return a ResultSet, even though it doesn't select any rows. The result set metadata will match the table that you selected from. Depending on what you're doing, this can be more convenient. tablename can be anything that you can select on--you don't have to get the case correct or worry about what schema it's in.
In the update to your question I noticed that you missed one key part of Kenster's answer. He specified a 'where' clause of 'where 1 = 0', which you don't have. This is important because if you leave it off, then oracle will try and return the ENTIRE table. And if you don't pull all of the records over, oracle will hold unto them, waiting for you to page through them. Adding that where clause still gives you the metadata, but without any of the overhead.
Also, I personally use 'where rownum < 1', since oracle knows immediately that all rownums are past that, and I'm not sure if it's smart enough to not try and test each record for '1 = 0'.
In addition to skaffman's answer -
use the following query in Oracle:
select sys_context( 'userenv', 'current_schema' ) from dual;
to access your current schema name if you are restricted to do so in Java.
This is the behavior mandated by the JDBC API - passing nulls as first and second parameter to getColumns means that neither catalog name nor schema name are used to narrow the search.
Link to the documentation . It is true that some other JDBC drivers have different behavior by default (e.g MySQL's ConnectorJ by default restricts to the current catalog), but this is not standard, and documented as such