Reputation: 526
EDIT After your advices, the code and the errors. I got an error "ORA-00955: name is already used by an existing object" now. The sequences creation create this error each time a DataStoreManager constructor is called.
Here is the code now :
public class DataStoreManager {
private Connection connection;
private PreparedStatement lookForAccount;
private PreparedStatement addAccount;
private PreparedStatement updaterBalance;
private PreparedStatement reachOperation;
public DataStoreManager(String url, String user, String password) throws DataStoreException, SQLException {
try {
connection = DriverManager.getConnection(url,user,password);
connection.setAutoCommit(false);
this.createDB();
lookForAccount = connection.prepareStatement("SELECT * FROM accounts WHERE account_id = ?");
addAccount = connection.prepareStatement("INSERT INTO accounts (account_id, balance) VALUES (? , 0.0)");
updaterBalance = connection.prepareStatement("UPDATE accounts SET balance = ? WHERE account_id = ?");
reachOperation = connection.prepareStatement("SELECT * FROM operations WHERE account_id = ? AND (date BETWEEN ? AND ?)");
} catch (SQLException error) {
error.printStackTrace();
throw error;
}
}
public void createDB() throws DataStoreException {
try {
Statement statmnt = connection.createStatement();
statmnt.executeUpdate("DROP TABLE operations");
statmnt.executeUpdate("DROP TABLE accounts");
statmnt.executeUpdate("CREATE TABLE accounts ( account_id INTEGER, balance DOUBLE PRECISION)");
statmnt.executeUpdate("CREATE TABLE operations ( operation_id INTEGER, account_id INTEGER, amount DOUBLE PRECISION, mydate DATE NOT NULL)");
//implement primary Key constraint.
statmnt.executeUpdate("ALTER TABLE accounts ADD CONSTRAINT accounts_PK PRIMARY KEY ( account_id )");
//implement foreign Key constraint
statmnt.executeUpdate("ALTER TABLE operations ADD CONSTRAINT accountID FOREIGN KEY ( account_id )"
+ "REFERENCES accounts ( account_id )");
// implement sequence for auto implement.
statmnt.executeUpdate("CREATE SEQUENCE operationID MINVALUE 1 START WITH 1 INCREMENT BY 1 CACHE 10");
statmnt.executeUpdate("CREATE SEQUENCE logID MINVALUE 1 START WITH 1 INCREMENT BY 1 CACHE 10");
// implement balance always positive constraint
statmnt.executeUpdate("ALTER TABLE accounts ADD CONSTRAINT balance_must_be_positive CHECK (balance >= 0)");
// Auto operation.
statmnt.executeUpdate("CREATE TRIGGER addingOrder BEFORE UPDATE ON accounts FOR EACH ROW BEGIN"
+ " INSERT INTO operations(operation_id, account_id, amount, mydate) "
+ " VALUES (operationID.nextval, :OLD.account_id, :NEW.amount - :OLD.amount, SYSDATE) END");
connection.commit();
} catch (Exception error) {
error.printStackTrace();
}
}
public boolean createAccount(int number) throws DataStoreException, SQLException {
try {
lookForAccount.setInt(1, number);
Boolean result = lookForAccount.execute();
if(result == true)
{
addAccount.setInt(1, number);
addAccount.executeUpdate();
connection.commit();
return true;
}
else
{ return false;}
} catch (SQLException error) {
error.printStackTrace();
throw error;
}
}
Here are my errors :
java.sql.SQLException: ORA-00955: name is already used by an existing object
at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:134)
at oracle.jdbc.ttc7.TTIoer.processError(TTIoer.java:289)
at oracle.jdbc.ttc7.Oall7.receive(Oall7.java:590)
at oracle.jdbc.ttc7.TTC7Protocol.doOall7(TTC7Protocol.java:1973)
at oracle.jdbc.ttc7.TTC7Protocol.parseExecuteFetch(TTC7Protocol.java:1119)
at oracle.jdbc.driver.OracleStatement.executeNonQuery(OracleStatement.java:2191)
at oracle.jdbc.driver.OracleStatement.doExecuteOther(OracleStatement.java:2064)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:2989)
at oracle.jdbc.driver.OracleStatement.executeUpdate(OracleStatement.java:891)
at services.DataStoreManager.createDB(DataStoreManager.java:105)
at services.DataStoreManager.<init>(DataStoreManager.java:55)
at application.SimpleTest.main(SimpleTest.java:145)
Running single-user tests...
Running multi-users tests...
java.sql.SQLException: ORA-00955: name is already used by an existing object
at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:134)
at oracle.jdbc.ttc7.TTIoer.processError(TTIoer.java:289)
at oracle.jdbc.ttc7.Oall7.receive(Oall7.java:590)
at oracle.jdbc.ttc7.TTC7Protocol.doOall7(TTC7Protocol.java:1973)
at oracle.jdbc.ttc7.TTC7Protocol.parseExecuteFetch(TTC7Protocol.java:1119)
at oracle.jdbc.driver.OracleStatement.executeNonQuery(OracleStatement.java:2191)
at oracle.jdbc.driver.OracleStatement.doExecuteOther(OracleStatement.java:2064)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:2989)
at oracle.jdbc.driver.OracleStatement.executeUpdate(OracleStatement.java:891)
at services.DataStoreManager.createDB(DataStoreManager.java:105)
at services.DataStoreManager.<init>(DataStoreManager.java:55)
at application.SimpleTest.main(SimpleTest.java:160)
user#0[services.DataStoreManager@e00c09]: starting
user#0[services.DataStoreManager@e00c09]: exiting
java.sql.SQLException: ORA-00955: name is already used by an existing object
at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:134)
at oracle.jdbc.ttc7.TTIoer.processError(TTIoer.java:289)
at oracle.jdbc.ttc7.Oall7.receive(Oall7.java:590)
at oracle.jdbc.ttc7.TTC7Protocol.doOall7(TTC7Protocol.java:1973)
at oracle.jdbc.ttc7.TTC7Protocol.parseExecuteFetch(TTC7Protocol.java:1119)
at oracle.jdbc.driver.OracleStatement.executeNonQuery(OracleStatement.java:2191)
at oracle.jdbc.driver.OracleStatement.doExecuteOther(OracleStatement.java:2064)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:2989)
at oracle.jdbc.driver.OracleStatement.executeUpdate(OracleStatement.java:891)
at services.DataStoreManager.createDB(DataStoreManager.java:105)
at services.DataStoreManager.<init>(DataStoreManager.java:55)
at application.SimpleTest.main(SimpleTest.java:160)
user#1[services.DataStoreManager@111f9b]: starting
user#1[services.DataStoreManager@111f9b]: exiting
java.sql.SQLException: ORA-00955: name is already used by an existing object
at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:134)user#2[services.DataStoreManager@1363271]: starting
user#2[services.DataStoreManager@1363271]: exiting
at oracle.jdbc.ttc7.TTIoer.processError(TTIoer.java:289)
at oracle.jdbc.ttc7.Oall7.receive(Oall7.java:590)
at oracle.jdbc.ttc7.TTC7Protocol.doOall7(TTC7Protocol.java:1973)
at oracle.jdbc.ttc7.TTC7Protocol.parseExecuteFetch(TTC7Protocol.java:1119)
at oracle.jdbc.driver.OracleStatement.executeNonQuery(OracleStatement.java:2191)
at oracle.jdbc.driver.OracleStatement.doExecuteOther(OracleStatement.java:2064)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:2989)
at oracle.jdbc.driver.OracleStatement.executeUpdate(OracleStatement.java:891)
at services.DataStoreManager.createDB(DataStoreManager.java:105)
at services.DataStoreManager.<init>(DataStoreManager.java:55)
at application.SimpleTest.main(SimpleTest.java:160)
java.sql.SQLException: ORA-00955: name is already used by an existing object
at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:134)
at oracle.jdbc.ttc7.TTIoer.processError(TTIoer.java:289)
at oracle.jdbc.ttc7.Oall7.receive(Oall7.java:590)
at oracle.jdbc.ttc7.TTC7Protocol.doOall7(TTC7Protocol.java:1973)
at oracle.jdbc.ttc7.TTC7Protocol.parseExecuteFetch(TTC7Protocol.java:1119)
at oracle.jdbc.driver.OracleStatement.executeNonQuery(OracleStatement.java:2191)
at oracle.jdbc.driver.OracleStatement.doExecuteOther(OracleStatement.java:2064)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:2989)
at oracle.jdbc.driver.OracleStatement.executeUpdate(OracleStatement.java:891)
at services.DataStoreManager.createDB(DataStoreManager.java:105)
at services.DataStoreManager.<init>(DataStoreManager.java:55)
at application.SimpleTest.main(SimpleTest.java:160)
user#3[services.DataStoreManager@114f313]: starting
user#3[services.DataStoreManager@114f313]: exiting
java.sql.SQLException: ORA-00955: name is already used by an existing object
at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:134)user#4[services.DataStoreManager@d767dc]: starting
user#4[services.DataStoreManager@d767dc]: exiting
at oracle.jdbc.ttc7.TTIoer.processError(TTIoer.java:289)
at oracle.jdbc.ttc7.Oall7.receive(Oall7.java:590)
at oracle.jdbc.ttc7.TTC7Protocol.doOall7(TTC7Protocol.java:1973)
at oracle.jdbc.ttc7.TTC7Protocol.parseExecuteFetch(TTC7Protocol.java:1119)
at oracle.jdbc.driver.OracleStatement.executeNonQuery(OracleStatement.java:2191)
at oracle.jdbc.driver.OracleStatement.doExecuteOther(OracleStatement.java:2064)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:2989)
at oracle.jdbc.driver.OracleStatement.executeUpdate(OracleStatement.java:891)
at services.DataStoreManager.createDB(DataStoreManager.java:105)
at services.DataStoreManager.<init>(DataStoreManager.java:55)
at application.SimpleTest.main(SimpleTest.java:160)
Upvotes: 0
Views: 2331
Reputation: 3138
You will have problems in your createDB()
method, if any of your SQL statements generate an error (for example if a table doesn't exist and you try to drop it). At that point your code will jump into the catch
block and none of your database objects will be created. You need to wrap each DROP statement in a try/catch block so that any error can be caught and handled (or in your case it's probably safe to ignore) and then the CREATE
statements will run.
You also are only running DROP
statements for your tables. You need to do the same for your sequences and trigger.
Your trigger is also invalid. The accounts table only has columns for account_id
and balance
. You can't reference :old
or :new
values for the columns in the operations table. So :old.amount
and :new.amount
are invalid, and :old.account_id
is the account_id from the accounts table (which turns out to be the same as the account_id
in the operations
table since it's a foreign key). You're also missing two semicolons. It should look like this:
statmnt.executeUpdate("CREATE TRIGGER addingOrder BEFORE UPDATE ON accounts FOR EACH ROW BEGIN"
+ " INSERT INTO operations(... columns ...) "
+ " VALUES (... values ...); END;");
The way you have things coded, you are trying to do some cleanup first by DROPPING
everything, then you CREATE
everything. When your test is done you will be left with all of your database objects in place. I would suggest that you reverse your order so that your create your objects when your test starts, and then do a tear down at the end in which you DROP
everything so that your database stays clean.
Upvotes: 1