I am trying to do things before processing Ingest to KIT DataManager (Code on GitHub, it runs on tomcat7) with a "Staging Processor" …
adding a custom Staging Processor
package edu.kit.dama.mdm.content.mets;
…
public class TryQuota extends AbstractStagingProcessor {
…
#Override
public final void performPreTransferProcessing(TransferTaskContainer pContainer) throws StagingProcessorException {
…
trying to get user data
… this works
UserData userResult = null;
try {
userResult = mdm.findSingleResult(
"Select u FROM UserData u WHERE u.email=?1",
new Object[]{"dama#kit.edu"},
standard email of admin user with userid 1
UserData.class
);
} catch (UnauthorizedAccessAttemptException e2) {
System.out.println("exception on extracting userid");
e2.printStackTrace();
}
try {
System.out.println("KIT DM ID: " + userResult.getUserId());
}catch(Exception e4) {
System.out.println("exception on output for userid");
e4.printStackTrace();
}
trying to get quota from UserQuota
and on the other hand, the corresponding implementation doesn't do the job here (that I want to get working)
Number UserQuota = null;
try {
UserQuota = mdm.findSingleResult(
//SQL would be: "SELECT quota FROM userquota WHERE uid=?;"
//JPQL is …
"Select q.quota FROM UserQuota q WHERE q.uid=?1",
new Object[]{1},
Number.class
);
} catch (UnauthorizedAccessAttemptException e2) {
System.out.println("exception on userquota");
e2.printStackTrace();
}
System.out.println("quota is: " + UserQuota );
UserQuota is still null here
DB is PostgreSQL, Table is:
CREATE SEQUENCE userquota_seq
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE;
CREATE TABLE userquota
(
id INTEGER NOT NULL DEFAULT nextval('userquota_seq'),
uid INTEGER NOT NULL DEFAULT 0,
quota DECIMAL NOT NULL DEFAULT 0,
CONSTRAINT uid_key UNIQUE (uid),
CONSTRAINT fk_uid FOREIGN KEY (uid) REFERENCES users(id)
);
This quota I want to get from db in the processor
INSERT INTO userquota (id, uid,quota) VALUES ( 0, 1, 1048576 );
So mainly I want to get the entry for the ingesting user (here 1) from db: 1048576 as a Long.
Any hints welcome on how to proceed on these things.
As stated in above comment, the following statement is invalid SQL syntax:
SELECT u FROM UserData u WHERE u.email=?1
Instead, according to above comment the correct syntax would be:
SELECT u.* FROM UserData u WHERE u.email='dama#kit.edu'
I found a solution by creating a class UserQuota1 so JPQL can work here.
As I did not find a way around, I first copied class UserData, dropped everything I had no use of and changed the members according to my database table userquota. This also means when extending the db table this class needs to be altered as well.
A very important part I had no clue about is that this new class also needs to be registered for tomcat7 in persistence.xml, also here copied over from the entry for UserData.
Related
this is the method Dao layer List,
public List<PortfolioMemberView> getPortfolioMemberViewByPid(Integer pid){
//check the portfolioId value in console
System.out.print(pid);
try {
Session session = sessionFactory.getCurrentSession();
String sql = "from PortfolioMemberView pv where pv.portfolioId = ?0";
Query query = session.createQuery(sql).setParameter(0, pid);
List<PortfolioMemberView> pmvl = query.list();
//check the result list by assetCode in console
for(PortfolioMemberView pv: pmvl){
System.out.print(pv.getAssetCode());
}
return pmvl;
}catch(Exception e){
logger.info("操作失败:" + e.getMessage() + ", " +e.getCause());
throw new RuntimeException();
}
I have a view(That I create) PortfolioMemberView in my database
and it has the following data
inmage
when I involke the method, the console print following result.
2
Hibernate: select portfoliom0_.portfolioId as portfoli1_8_,
portfoliom0_.assetId as assetId2_8_, portfoliom0_.accountType as accountT3_8_, portfoliom0_.assetCode as assetCod4_8_, portfoliom0_.assetLabel as assetLab5_8_, portfoliom0_.value_ as value_6_8_, portfoliom0_.annualReturn as annualRe7_8_, portfoliom0_.returnRate as returnRa8_8_ from PortfolioMemberView portfoliom0_ where portfoliom0_.portfolioId=?
CMPROP0121CMPROP0121CMPROP0121CMPROP0121CMPROP0121
The expected result should be CMPROP0121kckbGYck, because when portfolioId = 2, the assetCode of three object in the resulting list shoud be CMPROP0121,kckb,GYck.
I also copy the query hibenate generated and run it at mysql database, and the result is correct.
Hibernate: select portfoliom0_.portfolioId as portfoli1_8_,
portfoliom0_.assetId as assetId2_8_, portfoliom0_.accountType as accountT3_8_, portfoliom0_.assetCode as assetCod4_8_, portfoliom0_.assetLabel as assetLab5_8_, portfoliom0_.value_ as value_6_8_, portfoliom0_.annualReturn as annualRe7_8_, portfoliom0_.returnRate as returnRa8_8_ from PortfolioMemberView portfoliom0_ where portfoliom0_.portfolioId=?
not sure what's wrong, pls help!!!
I mapped portfolioId as primary Id, and primary Id cannot be duplicated. but obviously the primary key portfolioId is duplicated. I make aother primary key portfolioMemberId, and the problem solved
I am trying to write DAO method to update value in postgres table "accounts" with just two columns:
"id" string
"balance" int
public Account setAccountBalance(String id, Integer balance) {
Handle h = dbi.open();
try{
return h.createQuery("UPDATE accounts SET balance=" + balance.intValue() +
" WHERE id=\'" + id +"\';")
.mapTo(Account.class)
.first();
} finally {
h.close();
}
}
But on execute I see the following exception:
org.skife.jdbi.v2.exceptions.NoResultsException: Query did not have a result set, perhaps you meant update? [statement:"UPDATE accounts SET balance=20 WHERE id='1';", located:"UPDATE accounts SET balance=20 WHERE id='1';", rewritten:"UPDATE accounts SET balance=20 WHERE id='1';", arguments:{ positional:{}, named:{id:'1'}, finder:[]}]
Any idea if the problem is in query syntax, or use of DAO?
Looks like you are using JDBI. According to the documentation, SQL UPDATEs can be performed through Handle.execute(), as follows:
h.execute("UPDATE accounts SET balance=? WHERE id=?", balance.intValue(), id);
But the execute method doesn't return a result set and therefore cannot be used for creating an Account object. You would need to issue a separate query for doing that, maybe something like
return h.createQuery("SELECT id, balance FROM accounts WHERE id = :id")
.bind("id", id)
.mapTo(Account.class)
.first();
(source: hostingpics.net)
how can I add a new customer or supplier?, last time I was using this class for one table "customer":
Code:
public int addnewcustomer(){
int idcust;
DBConnection eConnexion = new DBConnection();
try {
//Statement state = eConnexion.getConnexion().createStatement();
String sql = "INSERT INTO customer(name_cust, num_cust, adress_cust, city_cust , tel_cust, ref_cust)";
sql+= "VALUES (?,?,?,?,?,?)";
PreparedStatement insertQuery = eConnexion.getConnexion().prepareStatement(sql);
insertQuery.setString(1,Name_cust);
insertQuery.setString(2,Num_cust);
insertQuery.setString(3,Adress_cust);
insertQuery.setString(4,City_cust );
insertQuery.setString(5,Tel_cust);
insertQuery.setString(6,Ref_cust);
insertQuery.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
//JOptionPane.showMessageDialog(null,"Erreur:the addition is not performed with Succee!");
idcust = 0;
}
eConnexion.closeConnection();
idcust= Services.getLastInsertedId("customer","id_customer");
return idcust;
}
Currently, I attach all tables with new table "person". All tables now extend "person", I tried to add new customer with super variables "person" but I'm stuck in filling foreign key "id_pers FK".
First you need to persist a person into your database. After a successful(!) persist, you can query for the id the database used to insert the data. Most databases also provide a method to directly retrieve the used id after an insert.
After you have successfully persisted the person you can use the id for the foreign key column.
You may consider using a transaction for these actions, as there should never be a person persisted without a customer/employee whatever extending the persons data.
With a transaction, you can rollback the previous actions, for example if something goes wrong during the insertion of the customer.
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
This question already has answers here:
How to get the insert ID in JDBC?
(14 answers)
Closed 7 years ago.
Is there any way of insert a row in a table and get the new generated ID, in only one statement? I want to use JDBC, and the ID will be generated by a sequence or will be an autoincrement field.
Thanks for your help.
John Pollancre
using getGeneratedKeys():
resultSet = pstmt.getGeneratedKeys();
if (resultSet != null && resultSet.next()) {
lastId = resultSet.getInt(1);
}
You can use the RETURNING clause to get the value of any column you have updated or inserted into. It works with trigger (i-e: you get the values actually inserted after the execution of triggers). Consider:
SQL> CREATE TABLE a (ID NUMBER PRIMARY KEY);
Table created
SQL> CREATE SEQUENCE a_seq;
Sequence created
SQL> VARIABLE x NUMBER;
SQL> BEGIN
2 INSERT INTO a VALUES (a_seq.nextval) RETURNING ID INTO :x;
3 END;
4 /
PL/SQL procedure successfully completed
x
---------
1
SQL> /
PL/SQL procedure successfully completed
x
---------
2
Actually, I think nextval followed by currval does work. Here's a bit of code that simulates this behaviour with two threads, one that first does a nextval, then a currval, while a second thread does a nextval in between.
public void checkSequencePerSession() throws Exception {
final Object semaphore = new Object();
Runnable thread1 = new Runnable() {
public void run() {
try {
Connection con = getConnection();
Statement s = con.createStatement();
ResultSet r = s.executeQuery("SELECT SEQ_INV_BATCH_DWNLD.nextval AS val FROM DUAL ");
r.next();
System.out.println("Session1 nextval is: " + r.getLong("val"));
synchronized(semaphore){
semaphore.notify();
}
synchronized(semaphore){
semaphore.wait();
}
r = s.executeQuery("SELECT SEQ_INV_BATCH_DWNLD.currval AS val FROM DUAL ");
r.next();
System.out.println("Session1 currval is: " + r.getLong("val"));
con.commit();
} catch (Exception e) {
e.printStackTrace();
}
}
};
Runnable thread2 = new Runnable(){
public void run(){
try{
synchronized(semaphore){
semaphore.wait();
}
Connection con = getConnection();
Statement s = con.createStatement();
ResultSet r = s.executeQuery("SELECT SEQ_INV_BATCH_DWNLD.nextval AS val FROM DUAL ");
r.next();
System.out.println("Session2 nextval is: " + r.getLong("val"));
con.commit();
synchronized(semaphore){
semaphore.notify();
}
}catch(Exception e){
e.printStackTrace();
}
}
};
Thread t1 = new Thread(thread1);
Thread t2 = new Thread(thread2);
t1.start();
t2.start();
t1.join();
t2.join();
}
The result is as follows:
Session1 nextval is: 47
Session2 nextval is: 48
Session1 currval is: 47
I couldn't comment otherwise I would have added to Vinko Vrsalovic's post:
The id generated by a sequence can be obtained via
insert into table values (sequence.NextVal, otherval)
select sequence.CurrVal
ran in the same transaction as to get a consistent view.
Updating de sequence after getting a nextval from it is an autonomous transaction. Otherwise another session would get the same value from the sequence. So getting currval will not get the inserted id if anothers sesssion has selected from the sequence in between the insert and select.
Regards,
Rob
The value of the auto-generated ID is not known until after the INSERT is executed, because other statements could be executing concurrently and the RDBMS gets to decide how to schedule which one goes first.
Any function you call in an expression in the INSERT statement would have to be evaluated before the new row is inserted, and therefore it can't know what ID value is generated.
I can think of two options that are close to what you're asking:
Write a trigger that runs AFTER INSERT, so you have access to the generated ID key value.
Write a procedure to wrap the insert, so you can execute other code in the procedure and query the last generated ID.
However, I suspect what you're really asking is whether you can query for the last generated ID value by your current session even if other sessions are also inserting rows and generating their own ID values. You can be assured that every RDBMS that offers an auto-increment facility offers a way to query this value, and it tells you the last ID generated in your current session scope. This is not affected by inserts done in other sessions.
The id generated by a sequence can be obtained via
insert into table values (sequence.NextVal, otherval)
select sequence.CurrVal
ran in the same transaction as to get a consistent view.
I think you'll find this helpful:
I have a table with a
auto-incrementing id. From time to
time I want to insert rows to this
table, but want to be able to know
what the pk of the newly inserted row
is.
String query = "BEGIN INSERT INTO movement (doc_number) VALUES ('abc') RETURNING id INTO ?; END;";
OracleCallableStatement cs = (OracleCallableStatement) conn.prepareCall(query);
cs.registerOutParameter(1, OracleTypes.NUMBER );
cs.execute();
System.out.println(cs.getInt(1));
Source: Thread: Oracle / JDBC Error when Returning values from an Insert
I couldn't comment, otherwise I would have just added to dfa's post, but the following is an example of this functionality with straight JDBC.
http://www.ibm.com/developerworks/java/library/j-jdbcnew/
However, if you are using something such as Spring, they will mask a lot of the gory details for you. If that can be of any assistance, just good Spring Chapter 11, which is the JDBC details. Using it has saved me a lot of headaches.