Passing from glassfish3 to payara5 one piece of code stop waorking. Our code save a date to a set of record and the select those updated record. In glassfish3 work seamlessly, in payara5 the select return no record (seems like it does work in another transaction). If the result is different we throw an exception, so the data is never saved.
The transaction scope is READ_COMMITTED
try {
String whereClause = " where "
+ "em.mailboxToBeUsed =:mailbox "
+ "and em.lastSendResult is null "
+ "and (em.errorsNumber is null or em.errorsNumber<4) ";
Query updateQuery = em.createQuery("update EmailTobeSended em "
+ "set em.trysendsince=:dat " + whereClause);
updateQuery.setParameter("mailbox", mb);
updateQuery.setParameter("dat", key);
int modificate = updateQuery.executeUpdate();
em.flush();
TypedQuery<EmailTobeSended> emlocksel = em.createQuery(
"select em from EmailTobeSended em WHERE em.mailboxToBeUsed =:mailbox AND "
+ "em.trysendsince=:dat "
+ " order by em.emailId ", EmailTobeSended.class);
emlocksel.setParameter("mailbox", mb);
emlocksel.setParameter("dat", key);
res = emlocksel.getResultList();
if (modificate != res.size()) {
throw new java.lang.AssertionError("Lock error on select emailtobesended");
}
} catch (Exception ex) {
gotError = true;
res = null;
}
On glassfish3, after flushing, the second query find out the record updated. On payara5 no result
EDIT
we use eclipselink
WE solved the problem: it wasn't about persistence, it was about mysql versions (from 5.5 to 5.6)
The DATE field was interpreted differently between the two version: in 5.5 millisecond are ignored, in 5.6 are considered. Due to the field was not configured to accept millisecond, the date were saved without them, so in the second query (a select) the comparison were done answering with ".000" as millisecond, different from what were searched
Updating the field to DATE(3) solved the problem
Related
JdbcTemplate is returning an empty list when executing the "query" method.
public List<Loan> getLoanDAO(Employee employee, String s) {
final String SQL = "SELECT CTLPCODCIA, CTLPCODSUC, CTLPCODTRA, EMPNOMBRE, EMPAPATERN, EMPAMATERN, CTLPCODPRE, "
+ "CTLPTIPPRE, TIPDESPRE, CTLPMONEDA, CTLPESTADO, CTLPMONTOP, CTLPNROCUO, CTLPCUOTA, FLAGTIPOCUOTA, CTLGLOSA, CTLDIASFR, "
+ "CTLDOCADJ, CTLUSUCREA, CTLFECCREA "
+ "FROM HR_CTLPREC_SS INNER JOIN HR_EMPLEADO ON CTLPCODCIA=EMPCODCIA AND CTLPCODSUC=EMPCODSUC AND CTLPCODTRA=EMPCODTRA "
+ "INNER JOIN HR_TIPPRE ON CTLPCODCIA=TIPCODCIA AND CTLPCODSUC=TIPCODSUC AND CTLPTIPPRE=TIPCODPRE "
+ "WHERE TIPFLGEST = '1' AND TIPSELFSERVICE = '1' "
+ "AND CTLPCODCIA = ? AND CTLPCODSUC = ? AND EMPCODTRAJEF = ? AND CTLPESTADO = ? ";
List<Loan> loans = jdbcTemplate.query(SQL, new Object[] {
employee.getCTLPCODCIA(), employee.getCTLPCODSUC(), employee.getCTLPCODTRA(), s }, loanMapper);
return loans;
}
However, when replacing the "?" with the same parameters used in execution and executing in sqldeveloper, it returns 4 rows. I don't know what is wrong since I've been doing de data access code in the same way for all the other entities.
Problem solved
As stated by #Julian:
JdbcTemplate is a proved spring component used by a huge number of applications so in my opinion it must be a bug in your code.
It was not a problem from JdbcTemplate, neither my code. It was an issue from the IDE. I just build my project from scratch using maven console commands and the code worked as intended.
Thanks folks.
JdbcTemplate is a proved spring component used by a huge number of applications so in my opinion it must be a bug in your code.
Not sure what version of Spring you are using but jdbcTemplate.query would expect a Loan Mapper class as one of its arguments. There is no such a mapper present in your code.
I suggest you put a breakpoint just before the query and inspect the employee fields and see if they match the values you are playing in the sqldeveloper.
One other thing that it attracts my attention is the third one where u have EMPCODTRAJEF = ? in the query definition but you use employee.getCTLPCODTRA() as the argument. Obviously I don't know your data model but should it rather be employee.getEMPCODTRAJEF() or the other way around?
If this won't work double check your arguments.
final String SQL = "SELECT CTLPCODCIA, CTLPCODSUC, CTLPCODTRA, EMPNOMBRE, EMPAPATERN, EMPAMATERN, CTLPCODPRE, "
+ "CTLPTIPPRE, TIPDESPRE, CTLPMONEDA, CTLPESTADO, CTLPMONTOP, CTLPNROCUO, CTLPCUOTA, FLAGTIPOCUOTA, CTLGLOSA, CTLDIASFR, "
+ "CTLDOCADJ, CTLUSUCREA, CTLFECCREA "
+ "FROM HR_CTLPREC_SS INNER JOIN HR_EMPLEADO ON CTLPCODCIA=EMPCODCIA AND CTLPCODSUC=EMPCODSUC AND CTLPCODTRA=EMPCODTRA "
+ "INNER JOIN HR_TIPPRE ON CTLPCODCIA=TIPCODCIA AND CTLPCODSUC=TIPCODSUC AND CTLPTIPPRE=TIPCODPRE "
+ "WHERE CTLPCODCIA=? AND CTLPCODSUC = ? AND EMPCODTRAJEF = ? AND CTLPESTADO = ? "
+ "AND TIPFLGEST='1' AND TIPSELFSERVICE='1'";
Add this to application.properties to debug your query.
logging.level.org.springframework.jdbc.core = TRACE
I'm working on a simple java project that uses JavaDB and MySQL to introduce the use of databases. I'm trying to write a method for updating the scores of a game in a database.
public void setTeamsScore(int matchNumber, int hScore, int vScore) throws SQLException
{
Statement stmt = connection.createStatement();
String sqlStatement = "UPDATE Matches " +
"SET HomeTeamScore = " + hScore +
" WHERE " +
"MatchNumber = " + matchNumber;
stmt.executeUpdate(sqlStatement);
sqlStatement = "UPDATE Matches " +
"SET VisitorTeamScore = " + vScore +
" WHERE " +
"MatchNumber = " + matchNumber;
stmt.executeUpdate(sqlStatement);
}
I get no errors at runtime, and when I check the return value of the update statement, it returns 1 (which if I understand correctly, means that 1 row was updated in the database). However, the database doesn't get updated at all and keeps the same values from before.
At first, I thought that maybe auto-commit wasn't working, so I tried turning auto-commit off and using connection.comit() but that didn't solve the problem either.
Any guidance would be much appreciated.
First of all you have to check if the Auto-commit is set to true or false .
if false then you have to commit the connection after the SQL execution .
int rows = stmt.executeUpdate(sqlStatement);
System.out.println("Rows impacted : " + rows );
stmt.commit();
stmt.close();
You need to call both stmt.execute(sql) and stmt.executeUpdate(sql)
First check if your query returns a true result set or not.
Boolean ret = stmt.execute(sqlStatement);
Then update the records
int rows = stmt.executeUpdate(sqlStatement);
System.out.println("Rows impacted : " + rows );
If the data is still not updated check your connection object.
I'm getting a weird SQLException on a function I run against a database using JDBC.
SQLException: Column 'Message' not found.
I have this in my function:
st = con.prepareStatement("SELECT NotificationID,UserIDFrom,UserIDTo,Message,Timestamp,isNotified FROM notification WHERE UserIDTo=? AND isNotified=?");
st.setInt(1, _UserID);
st.setBoolean(2, false);
System.out.println("st is: " + st);
rs = st.executeQuery();
And I got that error, so I added this after the st.executeQuery() :
ResultSetMetaData meta = rs.getMetaData();
for (int index = 1; index <= meta.getColumnCount(); index++) {
System.out.println("Column " + index + " is named " + meta.getColumnName(index));
}
And when I run my code again this is what I get as a result:
Column 1 is named NotificationID
Column 2 is named UserIDFrom
Column 3 is named UserIDTo
Column 4 is named Message
Column 5 is named TimeStamp
Exception in thread "main" java.sql.SQLException: Column 'Message' not found.
Column 6 is named isNotified
And here is a screenshot of my table's design, from MySQL Workbench
And the data in the table
I really can't figure out what's going one here.... Anyone can help out?
EDIT
I've replaced the * in the SELECT statement just to add something to the question that I just noticed.
If I remove the Message column from the select then I get the same error for the TimeStamp column. And if I remove both columns I get no errors then.
EDIT2
OK,this is the part i get the errors, i get both on Message and Timestamp:
while (rs.next()) {
NotificationID = rs.getInt("NotificationID");
System.out.println("NotificationID: " + NotificationID);
SenderID = rs.getInt("UserIDFrom");
System.out.println("SenderID: " + SenderID);
From = findUserName(SenderID);
try {
body = rs.getString("Message");
System.out.println("body: " + body);
} catch (Exception e) {
System.out.println("Message error: " + e);
e.printStackTrace();
}
try {
time = rs.getString("Timestamp");
System.out.println("time: " + time);
} catch (Exception e) {
System.out.println("Timestamp error: " + e);
e.printStackTrace();
}
}
I get the error on the getString() methods for each column
StackTrace for TimeStamp(the same for Message):
java.sql.SQLException: Column 'TimeStamp' not found.
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1078)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:989)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:975)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:920)
at com.mysql.jdbc.ResultSetImpl.findColumn(ResultSetImpl.java:1167)
at com.mysql.jdbc.ResultSetImpl.getString(ResultSetImpl.java:5733)
at NotifyMe_Server.Database.getUnNotified(Database.java:444)
at tests.Tests.main(Tests.java:39)
If you observe your code
try {
time = rs.getString("Timestamp");
System.out.println("time: " + time);
} catch (Exception e) {
System.out.println("Timestamp error: " + e);
e.printStackTrace();
}
}
you have used "Timestamp" in this format but if you changed it to "TimeStamp" as specified in your database, hopefully it will work.
Change datatype of your isNotified column as TINYINT in database and retry to insert
isNotified TINYINT(1)
Bool, Boolean: These types are synonyms for TINYINT(1). A value of zero is considered false. Non-zero values are considered true.
Can you change
System.out.println("Column " + index + " is named " + meta.getColumnName(index));
to
System.out.println("Column " + index + " is named '" + meta.getColumnName(index) + "'");
so that we can see if there is whitespace in the "Message" column name?
The fact that the error message comes between column 5 and 6 is not important I think, because one is Standard Output and the other one Standard Error, these are not synchronized output streams.
(Also see the previous answer about Timestamp vs TimeStamp.)
It sounds like the table metadata is corrupt. You should be able to correct this by dropping and recreating the table, although if the metadata is really borked you may not be able to drop the table. If that's the case or you need to keep the data, backing up and restoring the whole database is the way to go, but check the SQL dump file before restoring and/or restore to another database name before dropping the broken database. Depending on exactly what's wrong, your problem columns may be missing from the dump.
If refreshing the database is not an option there are ways to perform targetted repairs, but I'm no expert so I can't advise you on that. Again, back up your database AND verify that the backup is complete (i.e. it has all your columns) before proceeding. If this is a production database, I would be very wary about taking advice from the internet on manipulating metadata. Minor differences in version, storage engine and environment can make or break you with this stuff, and given the nature of the problem you can't do a dry run.
Scenario: I came across some code that is mixing JPA with JDBC within a transaction. The JDBC is doing an INSERT into a table with basically a blank row, setting the Primary Key to (SELECT MAX(PK) + 1) and the middleName to a temp timestamp. The method is then selecting from that same table for max(PK) + that temp timestamp to check if there was a collision. If successful, it then nulls out the middleName and updates. The method returns the newly created Primary Key.
Question:
Is there a better way to insert an entity into the database, setting the PK to max(pk) + 1 and gaining access to that newly created PK (preferably using JPA)?
Environment:
Using EclipseLink and need to support several versions of both Oracle and MS SqlServer databases.
Bonus Background: The reason I'm asking this question is because I run into a java.sql.BatchUpdateException when calling this method as part of a chain when running integration tests. The upper part of the chain uses JPA EntityManager to persist some objects.
Method in question
#Override
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public int generateStudentIdKey() {
final long now = System.currentTimeMillis();
int id = 0;
try {
try (final Connection connection = dataSource.getConnection()) {
if (connection.getAutoCommit()) {
connection.setAutoCommit(false);
}
try (final Statement statement = connection.createStatement()) {
// insert a row into the generator table
statement.executeUpdate(
"insert into student_demo (student_id, middle_name) " +
"select (max(student_id) + 1) as student_id, '" + now +
"' as middle_name from student_demo");
try (final ResultSet rs = statement.executeQuery(
"select max(student_id) as student_id " +
"from student_demo where middle_name = '" + now + "'")) {
if (rs.next()) {
id = rs.getInt(1);
}
}
if (id == 0) {
connection.rollback();
throw new RuntimeException("Key was not generated");
}
statement.execute("update student_demo set middle_name = null " +
"where student_id = " + id);
} catch (SQLException statementException) {
connection.rollback();
throw statementException;
}
}
} catch (SQLException exception) {
throw new RuntimeException(
"Exception thrown while trying to generate new student_ID", exception);
}
return id;
}
First off: it hurts to answer this. But I know, sometimes you have to deal with the devil :(
So technically, it's not JPA, but if you are using Hibernate as JPA-Provider, you can go with
#org.hibernate.annotations.GenericGenerator(
name = “incrementGenerator”,
strategy = “org.hibernate.id.IncrementGenerator”)
#GeneratedValue(generator="incrementGenerator")
private Long primaryKey;
The Hibernate solution is "thread-safe", but not "cluster-safe", i.e. if you run your application on several hosts, this may fail. You may catch the appropriate exception and try again.
If you stick with your solution: close the ResultSet, Statement and the Connection. Sorry, didn't catch the try-with-resources initially.
The JDBC code is pathological, makes no sense, and will not work in a multi user environment.
I would strongly recommend fixing the code to use a sequence object, or sequence table.
In JPA you can just use sequencing.
See,
http://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#Sequencing
If you really want to do your own sequencing, you can either assign the Id yourself, use PrePersist to assign your own id, or in EclipseLink implement your own Sequence subclass that does whatever you desire. You will need to register this Sequence object using a SessionCustomizer.
See,
http://wiki.eclipse.org/EclipseLink/Examples/JPA/CustomSequencing
I am using jpa with hibernate to retrieve data objects with a MySql (InnoDB) database. Here is the workflow of my application.
User queries results
User modifies one of the results
The database "inactivates" the current row and runs an insert for the new value
Upon saving the modification the queried results are refreshed to show the changes.
For example:
1. Select * from example_table where example_type in(1,2,3,4,5) and status = "active"
2. On user update - "Update example_table set status = "inactive" where example_table_id = 123"
3. Insert into example_table(...) values(.. user_new_value)
4. on the refresh - Select * from example_table where example_type in(1,2,3,4,5) and status = "active"
When the refresh select runs it returns the results. However, the row that was set to inactive is still returned in the refresh query because the update hasn't been fully committed.
Since I am using jpa and hibernate - it is worth noting that I am using an explicitly written update query as opposed to entityManager.merge(). I do this to avoid executing a select statement followed by the update statement. Before when I used entityManager.merge to execute my updates - my "old data" problem occurred MUCH MORE frequently
What I am after is a way to force my select query to wait until all of the row commits have been made. I have used "SELECT...FROM..WHERE.. LOCK IN SHARE MODE" but have had no luck.
Sometimes the results DO come back with the correct results... and sometimes they do not. I just need a way to ensure that my select query will "wait" for all of the updates to be made...
EDIT HERE IS MY JPA-HIBERNATE code...
here is the jpa dao call for the select statement ran before and after the update:
public List<Tracking_Prv_Reln> getFirstNetRelnsByTrackingIds_TrackingPrvReln(List<Long> trackingIdList){
Map<String, Object>namedParams = new Hashtable<String, Object>();
namedParams.put("TRACKING_ID_LIST", trackingIdList);
return getJpaTemplate().findByNamedQueryAndNamedParams("getFirstNetRelnsByTrackingIds_TrackingPrvReln", namedParams);
}
Here is the namedQuery found in the Entity:
#NamedQuery(name="getFirstNetRelnsByTrackingIds_TrackingPrvReln",
query="SELECT tpr FROM Tracking_Prv_Reln tpr WHERE tpr.tracking_Id IN (:TRACKING_ID_LIST) " +
"AND tpr.unassign_Dt_Tm >= NOW() ",
hints=#QueryHint(name="org.hibernate.cacheable", value="false"))
Here is the update statement which accepts the passed entity ("Tracking_Prv_Reln"):
public void inactivateRow_TrackingPrvReln(Tracking_Prv_Reln tpr){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String query = "UPDATE Tracking_Prv_Reln SET unassign_Dt_Tm = STR_TO_DATE('" + sdf.format(tpr.getUnassign_Dt_Tm()) + "', '%Y-%m-%d %H:%i:%s'), " +
"updt_Dt_Tm = STR_TO_DATE('" + sdf.format(tpr.getUpdt_Dt_Tm()) + "', '%Y-%m-%d %H:%i:%s'), source_Flag = " + tpr.getSource_Flag() +
" WHERE tracking_Prv_Reln_Id = " + tpr.getTracking_Prv_Reln_Id();
executeQueryString(query);
}
public void executeQueryString(final String string){
getJpaTemplate().execute(new JpaCallback(){
public Object doInJpa(EntityManager em)throws PersistenceException {
String queryString = string;
Query query = em.createQuery(queryString);
return query.executeUpdate();
}
});
}
My hibernate query cache is turned on...