I am using spring , hibernate. I need that when update a status to "A", an event executes after a day.
My question is: How to create the event from Java and?
I have been doing this:
Date endDate = cal.getTime();
Timestamp time = new Timestamp(endDate.getTime());
String sql = "CREATE EVENT EVENT_POLL ON SCHEDULE AT " + time +
" DO UPDATE POLL SET STATUS = 'F' WHERE ID = " + dto.getId();
System.out.println("SQL: " + sql);
springHibernateDao.getSession().createSQLQuery(sql).executeUpdate();
I got this error:
ERROR: org.hibernate.engine.jdbc.spi.SqlExceptionHelper - No value specified for parameter 1
Please help!
As far as I know this is not possible.
An alternative method is to create an event from the command line in the following structure:
Create an event that runs every minute/hour etc according to what your hibernate code was creating except that this event runs at a regular interval and not just once;
Create a table in which you place your run instruction with the scheduled time it should run;
Use hibernate to insert the instruction into that table;
Let your event check that table and run the code from there.
Related
I want to create MySQL Event programmatically with Query Method (#Query) in spring data. And my code like this:
#Query(value="CREATE EVENT :name ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 30 MINUTE ON COMPLETION NOT PRESERVE ENABLE"
+ " DO BEGIN"
+ " END", nativeQuery=true)
void createEventTestOpen(#Param("name") String name);
But i get error like this:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use
near ''my_sample_name' ON SCHEDULE AT CURRENT_TIMESTAMP +
INTERVAL 30 MINUTE ON ' at line 1
How can I make a MySQL event with using the query method in Spring with variable event name?
I have a program in JAVA which creates a table in a database and then I insert rows in this table.
The table is created as below:
String sql = "CREATE TABLE IF NOT EXISTS weather (\n"
+ " city string,\n"
+ " temp real,\n"
+ " feels_like real,\n"
+ " temp_min real,\n"
+ " temp_max real,\n"
+ " pressure integer,\n"
+ " humidity integer\n"
+ ");";
When I add rows, I don't want to have duplicates for the field named "city".
So, for example, if I already have London with its data, I don't want to add it again, even though that all its data may have changed. I want to have it only once in my table.
I have this query for insertion :
String sql = "INSERT INTO weather VALUES(?,?,?,?,?,?,?);";
and I want to modify it so I don't insert city duplicates.
Can anyone help me please? Thanks!
If the version of SQLite you use is 3.24.0+ and there is a unique constraint for the column city, you can use upsert which gives you an option to do NOTHING or UPDATE the table if a unique constraint violation occurs.
In this case:
String sql =
"INSERT INTO weather VALUES(?,?,?,?,?,?,?) " +
"ON CONFLICT DO NOTHING";
if you try to insert a row with an existing city, the statement will fail without an error.
But if the new row contains up to date data for the other columns and you want the row updated, you can do this:
String sql =
"INSERT INTO weather VALUES(?,?,?,?,?,?,?) " +
"ON CONFLICT(city) DO UPDATE SET "
"temp = excluded.temp, " +
"feels_like = excluded.feels_like, " +
"temp_min = excluded.temp_min, " +
"temp_max = excluded.temp_max, " +
"pressure = excluded.pressure, " +
"humidity = excluded.humidity";
and the other 6 columns will be overwritten by the new values you supplied.
If there isn't a unique constraint defined for city and you don't want to or can't define one, then you can avoid inserting the same city twice with NOT EXISTS like this:
String sql =
"INSERT INTO weather SELECT ?,?,?,?,?,?,? " +
"WHERE NOT EXISTS (SELECT 1 FROM weather WHERE city = ?);
In this case you will have to pass in your Java code as an additional 8th parameter the value of the city again.
There is no way to do this in 'effectively standard SQL'*.
But, each individual DB engine does usually have some way of accomplishing this goal.
The concept is called merging or upserting - those are terms you can search the web for. Just search for 'how to postgres upsert' for example. It's called upsert because the more general application is: If some subset of the values I am inserting doesn't exist yet in the DB, INSERT a new row with this data. Otherwise, find the row with the same values for this subset, and then update all the other values with it. For example: "Find the student with ID 12345, and then change the name to 'Joe Bloggs'. If there is no row with that, then make it".
make ALL the values 'the key' and you've reduced your 'insert, ignore if it is already there' to a standard UPSERT.
In psql, you can do ON CONFLICT. searching for 'mysql upsert' gets you to blog posts that give you varying tactics depending on your exact needs, from using INSERT IGNORE (I advice against this, this ignores any and all errors, vs only ignoring the 'already in here' error only), ON DUPLICATE KEY UPDATE (better idea, this), or using REPLACE.
Similar blog posts will be found for any db engine you are using here.
*) Defined not as 'as per some version of the SQL standard', but defined as: 'works in the majority of existing DB engines'.
You can now use on conflict. This requires that you have a unique index/constraint on city but it is already defined as the primary key. Check.
insert into weather ( . . . )
values ( . . . )
on conflict (city) ignore;
SQLite also allows this shorthand:
insert or ignore into weather ( . . . )
values ( . . . );
My code is performing the following update at a given time in my mysql database:
" UPDATE client_registration " +
" SET registration_date = NOW() " +
" WHERE cycle <= str_to_date(\"" + now + "\",'%d/%m/%Y %H:%i') ";
However I have a unit test that tries to perform this update on the HSQL database and I receive the following error message: user lacks privilege or object not found: STR_TO_DATE.
Some way to execute the condition WHERE cycle_start <= str_to_date(\"" + now + "\",'%d/%m/%Y %H:%i') for the mysql database and the hsql database?
You have to re-write your query for HSQL:
" UPDATE client_registration " +
" SET registration_date = NOW() " +
" WHERE cycle <= current_timestamp";
How to do "select current_timestamp" in hsqldb?
If you want to run the exact same query on both MySQL and HSQLDB, you need to create the STR_TO_DATE function on HSQLDB. You also need to use the single-quote character in your query: str_to_date('" + now + "','%d/%m/%Y %H:%i') (this quoting follows the SQL Standard).
It is easier if you use the SQL Standard format 'YYYY-MM-DD hh:mm:ss' (e.g '2020-07-21 14:30:00') for your 'now' variable and the format string you use with MySQL. In this case the HSQLDB function is simply created as:
CREATE FUNCTION STR_TO_DATE(STR VARCHAR(30), FORMAT VARCHAR(40) )
RETURNS TIMESTAMP
RETURN CAST(STR AS TIMESTAMP);
Execute the CREATE FUNCTION statement once when you connect to the database and you can use it in all your queries and upade statements.
A SQL query comparing timestamps works in MySQL, but fails when using an H2 database.
As an example, this is the query that produces the exception:
SELECT * FROM table WHERE time >= '2019-02-01T10:59:12.632Z' AND time <= '2019-04-12T10:59:12.632Z'
The query is created dynamically using Java code, and the timestamps above are of type java.time.Instant.
I have even tried using other types of date/time objects, with the same outcome.
This query executes fine using MySQL, but throws the following error using an H2 DB:
org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement
"SELECT * FROM table WHERE time>= 2019-04-10T13[*]:31:19.498Z AND time <= 2019-04-07T13:31:19.498Z";
SQL statement:
SELECT * FROM table WHERE time >= 2019-04-10T13:31:19.498Z AND time<= 2019-04-07T13:31:19.498Z
I find it puzzling that using colon-separated timestamps cause this issue, especially since the H2 docs use similar timestamps
try converting date string properly
SELECT * FROM table WHERE time >= str_to_date('2019-02-01 10:59:12.632 ', '%Y-%m-%d %T.%f')
AND time <= str_to_date( '2019-04-12 10:59:12.632 ' , '%Y-%m-%d %T.%f')
I am using Spring Boot's JdbcTemplate and creating my queries as follows:
jdbcTemplate.query("SELECT * FROM table WHERE time >= " + startTime + " AND " + " time <= " + endTime, (rs, i) -> Accessor.readFromResultSet(rs));
with the date Strings passed in as Instant objects.
The solution, thanks to #OleV.V's comment, was to pass the date objects in as an Object argument:
jdbcTemplate.query("SELECT * FROM table WHERE time >= ? AND time <= ?", new Object[]{startTime, endTime}, (rs, i) -> Accessor.readFromResultSet(rs));
I have a spring application which reads data from the Database and sends it to system 'X'. I am using task executors to spin up threads, so there are like 5 threads which are reading the database for rows at the same time. For each thread I need to make sure that unique records are selected.
To achieve this I am using JdbcTemplate and "select for update"
I have written the code but in the logs I am able to see 2 threads picking up the same rows. I am not able to figure out the root cause of this issue.
Does anyone has a suggestion
try {
List<Map<String, Object>> rows = getJdbcTemplate().queryForList(
SELECT_FOR_UPDATE,
new Object[] {a,b,c,d});
for (Map<String,Object> row : rows) {
Header a = new Header();
a.setMailID(((BigDecimal)row.get("mailID")).intValue());
a.setVersion(((BigDecimal)row.get("version")).intValue());
// some other parameters to get
getJdbcTemplate().update(UPDATE_MSG_STATE_VERSION_N_ORIG_MSG_STAT,
x,
a.getVersion()+1,
y),
a.getMailID(),
a.getVersion());
headers.add(a);
}
}
UPDATE_MSG_STATE_VERSION_N_ORIG_MSG_STAT = update MESSAGE set MSG_STAT_CD = ?, VERSION_NBR = ?, ORIG_MSG_STAT_CD=?, LAST_UPD_TS=SYSTIMESTAMP where MESSAGE.MAIL_ID = ? and VERSION_NBR = ?
String SELECT_FOR_UPDATE = "select m.MAIL_ID mailID, m.VERSION_NBR version, m.MSG_STAT_CD state,"
+ "from message m "
+ "and m.MSG_STAT_CD in ('Nerwerw')"
+ " and m.create_ts > (sysdate - ?)"
+ " and mod(mail_id,?) = ?"
+ " and ROWNUM <= ?"
+ " order by mt.MSG_PRIORITY FOR UPDATE";
You need to annotate your class with #Repostitory tag and the #Transactional tag to make sure that all the actions in the same call are handled in one transaction.
If they are not handled in the same transaction then each SELECT_FOR_UPDATE will happen on a different transaction and thus your threads queries will not be syncronized and your select_for_update does not matter.
Have you had transaction control properly set up?
If not, the transaction will only happen for the duration of the update statement, and will be committed automatically (You are using Oracle I believe, base on your syntax).
That means, although you acquired the lock of those records, they are released right-away.
Do you have access to modify the database? If I understand your question correctly I recently had a similar problem and implemented a scheme like this:
Add a new column to your database like "thread_number" or something like that. Set it to some default value like 0. Give each thread a unique identifier. Then you "claim" a record in the database by updating its "thread_number" to the identifier of the thread processing it. Then the other threads will not find it when querying if you include "where thread_number = 0" in the SQL.
I know it's kind of broad, but I hope it helps.