How To Fetch Updated Rows In JDBC [duplicate] - java

I'm using Java 8 with Spring's JdbcTemplate and Oracle 12.1,
I want to update record and get the exact time record was updated
jdbcTemplate.update(UPDATE_SQL, null);
Currently it returns (int) the number of rows affected, but I want the exact updated date
Must I send a new request to get current time which may be inaccurate?
More exact will be to save in column updated date, but then to execute another SQL
Is there another option to get updated date in one query?
Obviously, I don't want to use get date from code also (as new Date()) also because server time is/can be different than DB Time

You decided to use JDBCTemplate most probably to simplify the code in comparison to plain JDBC.
This particular problem IMHO makes the plain JDBC solution as proposed in other answer much simpler, so I'd definitively recommend to get the database connection from JDBCTemplate and make the insert in a JDBC way.
The simplest solution using JDBCTemplate that comes to my mind is to wrap the insert in a PROCEDURE and return the timestamp as an OUT parameter.
Simple example (Adjust the time logik as required)
create procedure insert_with_return_time (p_str VARCHAR2, p_time OUT DATE) as
BEGIN
insert into identity_pk(pad) values(p_str);
p_time := sysdate;
END;
/
The call is done using SimpleJdbcCall
SimpleJdbcCall jdbcCall = new SimpleJdbcCall(jdbcTemplate).withProcedureName("insert_with_return_time");
SqlParameterSource params = new MapSqlParameterSource().addValue("p_str", str);
Map<String, Object> out = jdbcCall.execute(params);
The Map contains the returned value e.g. [P_TIME:2019-10-19 11:58:10.0]
But I can only repeat, in this particular use case is IMHO JDBC a rescue from JDBCTemplate;)

You're right that passing new Date() would store the server time rather than the DB time.
To store the DB time you can set your timestamp to the DB system timestamp systimestamp then you could run a query to retrieve that row and its updated timestamp.
If you want to update the row and get the updated timestamp in a single execution then you could do the following using RETURNING INTO where TimestampUpdated is your column name:
Connection con = ...;
String sql = "UPDATE TableName SET <updates> , TimestampUpdated = systimestamp RETURNING TimestampUpdated INTO ?";
CallableStatement statement = con.prepareCall(sql);
statement.registerOutParameter(1, Types.TIMESTAMP);
int updateCount = statement.executeUpdate();
Timestamp timestampUpdated = statement.getInt(1);
System.out.println("Timestamp Updated = " + timestampUpdated);
Here is a related link doing this with JdbcTemplate

Related

HQL query ignores time portion of the Date object

I have problem with HQL where I am setting the query parameters. One of them is Date. When I debug the code there is Date with time entering the method. I set the parameter using setParameter(timestamp, new Timestamp(date.getTime())) or query.setTimestamp...etc etc I used many combinations...
When I use p6spy to examine the SQL comming from app to the DB there is only '29-Jan-21' or other date without time.
I am using hibernate 5.1.0 final and postgre DB. I'll be glad for any help.
Example:
Query query = getSessionFactory().getCurrentSession().createQuery("SELECT user FROM UserEntity cr WHERE user.userStatus.id = :statusId AND :timestamp >= user.valid_to");
This is how I tried to set the timestamp parameter:
query.setParameter("timestamp", new Timestamp(date.getTime()));
query.setParameter("timestamp", date, TimestampType.INSTANCE);
query.setTimestamp("timestamp", date);
query.setTimestamp("timestamp", new Timestamp(date.getTime()));
Problem is that the generated SQL replace timestamp by '29-Jan-21' or other date I choose but without time. The date parameter comes to the method from UI and it contains full date with time.

Oracle - update record and return updated date in same query

I'm using Java 8 with Spring's JdbcTemplate and Oracle 12.1,
I want to update record and get the exact time record was updated
jdbcTemplate.update(UPDATE_SQL, null);
Currently it returns (int) the number of rows affected, but I want the exact updated date
Must I send a new request to get current time which may be inaccurate?
More exact will be to save in column updated date, but then to execute another SQL
Is there another option to get updated date in one query?
Obviously, I don't want to use get date from code also (as new Date()) also because server time is/can be different than DB Time
You decided to use JDBCTemplate most probably to simplify the code in comparison to plain JDBC.
This particular problem IMHO makes the plain JDBC solution as proposed in other answer much simpler, so I'd definitively recommend to get the database connection from JDBCTemplate and make the insert in a JDBC way.
The simplest solution using JDBCTemplate that comes to my mind is to wrap the insert in a PROCEDURE and return the timestamp as an OUT parameter.
Simple example (Adjust the time logik as required)
create procedure insert_with_return_time (p_str VARCHAR2, p_time OUT DATE) as
BEGIN
insert into identity_pk(pad) values(p_str);
p_time := sysdate;
END;
/
The call is done using SimpleJdbcCall
SimpleJdbcCall jdbcCall = new SimpleJdbcCall(jdbcTemplate).withProcedureName("insert_with_return_time");
SqlParameterSource params = new MapSqlParameterSource().addValue("p_str", str);
Map<String, Object> out = jdbcCall.execute(params);
The Map contains the returned value e.g. [P_TIME:2019-10-19 11:58:10.0]
But I can only repeat, in this particular use case is IMHO JDBC a rescue from JDBCTemplate;)
You're right that passing new Date() would store the server time rather than the DB time.
To store the DB time you can set your timestamp to the DB system timestamp systimestamp then you could run a query to retrieve that row and its updated timestamp.
If you want to update the row and get the updated timestamp in a single execution then you could do the following using RETURNING INTO where TimestampUpdated is your column name:
Connection con = ...;
String sql = "UPDATE TableName SET <updates> , TimestampUpdated = systimestamp RETURNING TimestampUpdated INTO ?";
CallableStatement statement = con.prepareCall(sql);
statement.registerOutParameter(1, Types.TIMESTAMP);
int updateCount = statement.executeUpdate();
Timestamp timestampUpdated = statement.getInt(1);
System.out.println("Timestamp Updated = " + timestampUpdated);
Here is a related link doing this with JdbcTemplate

Timestamp insert issue in Mysql from Oracle

I am trying to insert the timestamp value from oracle to mysql timestamp column.
oracle value is 2017-09-01 11:35:22.495000000 but while getting value from result set its giving 2017-09-01 11:35:22.495.
its stored in oracle using oracle.sql.timestamp and i cannot insert the value in mysql.so getting stringvalue or timestamp value from oracle.sql.timestamp API.
But mysql storing the value is 2017-09-01 11:35:22.000495 and datatype defined as timestamp (6) and am not sure why its inserting the value like this?
How i can store the value in mysql similar to oracle ?
Using JDBC you should be able to directly copy a timestamp from one database to another doing something like this:
try(Connection oracleConnection = getOracleConnection();
Connection mysqlConnection = getMySQLConnection();
PreparedStatement oracleStmt = oracleConnection.prepareStatement("SELECT my_time FROM oracle_table");
PreparedStatement mysqlStmt = mysqlConnection.prepareStatement("INSERT INTO mysql_table VALUES (?)");
ResultSet rs = oracleStmt.executeQuery()) {
while(rs.next) {
mysqlStmt.setTimestamp(1, rs.getTimestamp("my_time"));
mysqlStmt.execute();
}
}
Timestamps are essentially numeric datatypes. Different DBMS's can have different precisions and different ways of handling timezones, but you shouldn't need any database specific API's to interact with them in most cases.
If you need to format a Timestamp you can use SimpleDateFormat on what you get back from getTimestamp() to format the string any way you need to.

Insert Date in Access DB - zero date

I'm making a library project in Java that is supposed to record data about members, books, users and borrowings. When I create a new object of the class Borrowing the system automatically notes the IssueDate.
The problem happens when I try to make a record of the book being returned with and UPDATE SQL QUERY and record the ReturnDate.The query works but in DB in the corresponding field I always get 30/12/1899 as a ReturnDate.
The SQL query goes like this:
UPDATE Booking SET Returned = 1, ReturnDate = "+ sdf.format(getReturnDate()) +" WHERE BookingID =" + getBookingID()
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
setReturnDate(new Date());
I decided to format it to String and format dd/mm/yyyy because that is the format Access recognizes when I enter it manually and it worked with all other queries (like creating a new Booking and IssueDate) in the project and it enters the real date.
I have already tried using java.sql.Date instead, switching to the US format (mm/dd/yyyy) and using # (hash marks) at the beginning and the end of the date string and none of those worked.
Do you have any other ideas?
Consider using a PreparedStatement instead, see Using Prepared Statements for more details
Instead of setting the "text" of the query, use setDate of the PreparedStatement and let the JDBC driver work it out

Return Timestamp With Prepared Statement

I have an auto generated timestamp that is created each time a record is inserted or updated in a mysql table. Is there a way to return this timestamp in a way similar to how I would use a keyholder to return a newly created id?
KeyHolder keyHolder = new GeneratedKeyHolder();
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
//Insert Contact
jdbcTemplate.update(new PreparedStatementCreator() {
#Override
public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
PreparedStatement preparedStatement = connection.prepareStatement(SQL_ADD, Statement.RETURN_GENERATED_KEYS);
preparedStatement.setString(1, contact.getFirstName());
preparedStatement.setString(2, contact.getLastName());
preparedStatement.setInt(3, contact.getOrganizationId());
preparedStatement.setString(4, contact.getType());
preparedStatement.setInt(5, contact.getUserId());
return preparedStatement;
}
}, keyHolder);
//Use keyholder to obtain newly created id
contact.setId(keyHolder.getKey().intValue());
Is there some way to also return the new timestamp without having to requery the table? I have been looking for ways to return it along with the id as a key in the keyholder, but it doesn't seem to be returned as a key?
Not very satisfying, but I think "no" is the answer to your question. I don't know any of the Spring stuff, but I think this is due to the basic JDBC that it's wrapping. See http://docs.oracle.com/javase/6/docs/api/java/sql/Statement.html#getGeneratedKeys%28%29
You only option would be to create a stored procedure on MySQL that has an out parameter and call that. See http://dev.mysql.com/doc/refman/5.0/en/call.html.
There are few options for solving this issue on the MySQL database server side. You could start with creating a TRIGGER on the table. As TRIGGER has a restriction and cannot return data, you can set the TIMESTAMP value to a variable:
DEMILITER //
CREATE TRIGGER ai_tbl_name AFTER INSERT ON tbl_name
FOR EACH ROW
BEGIN
SET #TimeStamp = NEW.timestamp_column;
END;//
DELIMITER ;
To retrieve this timestamp value, run the following command:
SELECT #TimeStamp;
Since the variables are stored in the memory, there will be no need to open any tables again.
You go even further. You could create a STORED PROCEDURE in MySQL to automate all the above (sample code, as I do not know your table's details):
DELIMITER //
DROP PROCEDURE IF EXISTS sp_procedure_name //
CREATE PROCEDURE sp_procedure_name (IN col1_val VARCHAR(25),
IN col2_val VARCHAR(25),
IN col3_val INT)
BEGIN
INSERT INTO tbl_name (col1, col2, col3)
VALUES (col1_val, col2_val, col3_val);
SELECT #TimeStamp;
END; //
DELIMITER ;
You can run this procedure with the following code:
CALL sp_procedure_name(col1_val, col2_val, col3_val);
As I'm not familiar with the Java, you'll need to finish it up with your side of code.
It seems that the variable contact is an instance for the newly inserted record. As it contains the newly generated id (primary key) field value, you can execute a new query to return the required timestamp field value for this new id.
The query may look like this:
select timestamp_field from my_table where id=?
Use PreparedStatement to input new id value and execute it to fetch required timestamp field value.
GeneratedKeyHolder also has two methods: getKeyList() that returns Map<String,Object> of generated fields; and getKeyList() that produces a list of generated keys for all affected rows.
See java doc of GeneratedKeyHolder and Spring tutorial of auto generated keys
In addition Spring's SimpleJdbcInsert has methods for generated key retrieval. See also method SimpleJdbcInsert#usingGeneratedKeyColumns
There are 2 methods in java.sql.Connection class causing PreparedStatement execution to return selected key columns :
PreparedStatement prepareStatement(String sql,
int[] columnIndexes)
throws SQLException
PreparedStatement prepareStatement(String sql,
String[] columnNames)
throws SQLException
You don't need to use Spring KeyHolder & JDBCTemplate to do this.
The give hope you could number/name your timestamp column. But the javadoc doesn't require or suggest that any JDBC implementation can return non-key columns, so your out of luck with this approach:
Creates a default PreparedStatement object capable of returning the auto-generated keys
designated by the given array. This array contains the names of the columns in the target
table that contain the auto-generated keys that should be returned.
As suggested in another answer, can switch to a stored procedure that does exactly what you want (CallableStatement is actually a PreparedStatement that executes storedprocedures - i.e. a subclass).
Can populate the timestamp column within the prepared statement via new Timestamp(new Date()) - but you should have in place a mechanism to sync times across your various servers (which is often used in windows and *nix environments). Your trigger could set the timestamp only if a value wasn't already provided.
As part of your app & DB design, you need to commit to a philosophy of where certain operations occur. If the DB derives needed data, the app needs to refresh data - you must pay the price of separate query executions or a combined stored proc that inserts & retrieves.

Categories

Resources