1.9.0 i what to do this key-next trigger validation in java
i what something like this but in java adf
protected PreparedStatement createStatementADF(String query)
{
PreparedStatement statement=null;
try {
/*create transaction for current statemtnt*/
DBTransaction dbTransaction = (DBTransaction) this.getTransaction();
statement= dbTransaction.createPreparedStatement(query, 0);
} catch (SQLException e)
{
throw new JboException(e);
}
return statement;
}
/*Executes single query*/
protected ResultSet executeQueryADF (String query, Object[] bindVars)
{
PreparedStatement statement=null;
ResultSet ret=null;
try {
/*create transaction for current statemtnt and resuse it*/
statement=createStatementADF(query);
if ((bindVars != null)&&(statement!=null)) {
// 2. Loop over values for the bind variables passed in, if any
for (int z = 0; z < bindVars.length; z++) {
// 3. Set the value of each bind variable in the statement
statement.setObject(z + 1, bindVars[z]);
}
}
// 4. Execute the statement
ret=statement.executeQuery();
} catch (SQLException e) {
throw new JboException(e);
} finally {
if (statement != null) {
try {
// 5. Close the statement
statement.close();
} catch (SQLException e) {
}
}
}
return ret;
}
public void getUsrStatus()
{
ResultSet rs = null;
Object[] bindVars = new Object[]{"TestUser"};
try {
rs = executeQueryADF("SELECT account_status FROM dba_users WHERE username = ?", bindVars );
while(rs.next())
{
//..... process data
}
} catch (Exception e)
{
}
}
where i can use valueChangeListener,i what to validate the password and call the procedure to validate the password,i have to validate based on the enterd useid
public void labelListener(ValueChangeEvent valueChangeEvent)
{ UIComponent c = valueChangeEvent.getComponent();
//This step actually invokes Update Model phase for this
//component
c.processUpdates(FacesContext.getCurrentInstance());
//Jump to the Render Response phase in order to avoid
//the validation
FacesContext.getCurrentInstance().renderResponse();
}
Create a View Object (VO) which uses following query:
SELECT account_status
FROM dba_users
WHERE username = :p_username
Where p_username is a bind variable and add the VO to your Application Module (AM)
In your AM you will need to create a new method which gets the VO,
set the bind variable and execute the VO. Here you do the validations by checking the number of rows and see if the status etc is correct.
Depending on your use case you should expose the method in your AM (which probably returns a boolean or string). Add that method to your bindings and execute it when the user does some action (click a button). With the result of your method you could do some navigation or show an error. (Throwing an exception could also be a option).
Edit:
You can move your PL/SQL into a function/procedure and execute it from your AM. Very nice ex: http://www.baigzeeshan.com/2010/05/calling-plsql-procedure-and-function-in.html
Related
I'm using PostgreSQL to save a form in three tables, one for the name and id, another one for the fields to populate, and a third to store values for the fields.
private static final String REMOVE_FORM = "DELETE FROM forms WHERE name = ?";
private PreparedStatement removeFormQuery;
public boolean connect() throws SQLException{
this.connection = DriverManager.getConnection(URL);
this.removeFormQuery = this.connection.prepareStatement(REMOVE_FORM);
}
public void close() throws SQLException {
if(null != this.connection) {
this.connection.close();
}
if(null != this.removeFormQuery) {
this.removeFormQuery.close();
}
}
private void removeForm(String form) {
try {
removeFormQuery.setString(1, form);
int execute = removeFormQuery.executeUpdate();
System.out.println(execute);
ResultSet generatedKeys = removeFormQuery.getGeneratedKeys();
while (generatedKeys.next()) {
int anInt1 = generatedKeys.getInt("id");
removeFieldQuery.setInt(1, anInt1);
if (removeFieldQuery.execute())
System.out.println("remove field failed");
else
System.out.println("remove field success");
ResultSet generatedFieldsKeys = removeFieldQuery.getGeneratedKeys();
while (generatedFieldsKeys.next()) {
int anInt = generatedFieldsKeys.getInt("id");
removeListItemQuery.setInt(1, anInt);
if (removeListItemQuery.execute())
System.out.println("remove listItem failed");
else
System.out.println("remove listItem success");
}
}
} catch (SQLException e) {
e.printStackTrace();
}
}
The code doesn't generate keys after the remove query is executed, am I missing something?
While you haven't told us what queries you are running, if they are deletes then you wouldn't expect any generated keys.
From the Javadoc for Statement.getGeneratedKeys():
* Retrieves any auto-generated keys created as a result of executing this
* Statement object. If this Statement object did
* not generate any keys, an empty ResultSet
* object is returned.
Keys may be auto generated when you insert into a table, creating a new row which needs a primary key, but when you delete a row no key generation occurs.
In my JavaFX program I want to dynamically generate a tree using the live data set from my database (I'm using MariaDB, but it could be any SQL database).
I had searched a bunch and could not find a direct answer to my question, so I spent some time learning how JDBC ResultSet's work, how the next() method works, and how while loops work. A few trial-and-error attempts finally led me to the result I wanted, so I thought I would share it in case anyone else finds themselves in my position.
See my answer below.
edit It seems I’ve designed the overall program poorly in not using threading to isolate the GUI from the JDBC query. I think this can be fixed using JavaFX concurrency, but I’ve never used it so until I can update the code below, just ignore the stuff outside the while loop.
Firstly, I'm using following versions of MariaDB (10.4.12), Java (13.0.2.8), JavaFX (13.0.2), and MariaDB JDBC (2.6.0). I don't think any of this will make a difference, but just in case.. I'm using FXML, which is why you won't see any UI formatting in there anywhere.
This is the full method that generates the TreeView in my JavaFX program. It's then called from a separate class shortly after generating the Stage and Scene objects.
They key part is the while loop, which was a struggle for me to get right. I initially thought I needed a nested while(rs.next()) loop, but then I realised that this was causing rows to be skipped because each rs.next() call is related to the previous one, not to the while loop in which it is used.
Note also that the SQL statement is important. If the statement gives results out of order the method doesn't work correctly.
public void generateTree(DataSource dataSource) {
source = null;
this.source = dataSource;
Connection con = null;
Statement stmt = null;
TreeItem<String> rootTreeItem = new TreeItem<String>("EMT");
rootTreeItem.setExpanded(true);
emtTree.setRoot(rootTreeItem);
TreeItem<String> site = null;
TreeItem<String> plant = null;
try {
con = source.getConnection();
try {
stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT sites.siteid, sites.longname, plants.plantid, plants.siteplantid, plants.shortname FROM sites INNER JOIN plants ON plants.siteid=sites.siteid ORDER BY sites.longname ASC, plants.siteplantid ASC");
String site1 = ""; //It's not possible for the site name to be "" in the result set because the database design prevents it.
//Steps through the result set from first row item to last row item.
while(rs.next()) {
//This bit prevents repeating the same first level items multiple times.
//I only want each site to appear once, and under each site is a list
//of plants.
if (!site1.equals(rs.getString("sites.longname"))) {
site = new TreeItem<String>(rs.getString("sites.longname"));
rootTreeItem.getChildren().add(site);
site1 = rs.getString("sites.longname");
}
//This section is never skipped and will add all the plants to a given
//site until the next site is reached in the result set, then the if
//is triggered again and the process for the new site.
plant = new TreeItem<String>(rs.getInt("plants.siteplantid") + " " + rs.getString("plants.shortname"));
site.getChildren().add(plant);
}
} catch (SQLException e) {
System.out.println("Statement Error");
System.err.println("SQL State: " + ((SQLException)e).getSQLState());
System.err.println("Error Code: " + ((SQLException)e).getErrorCode());
System.err.println("Message: " + ((SQLException)e).getMessage());
System.err.println("Cause: " + ((SQLException)e).getCause());
return;
}
} catch (SQLException e) {
e.printStackTrace();
return;
} finally {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
I'll probably find ways to improve it in future, but for now I'm just happy to have it working. Ignore the messy exception handling - its a work in progress!
Here is my try how to do it with not blocking the UI Thread:
public class YourClassName {
ArrayList<ResultBean> fetchedData = null;
public void createTree() {
// run in other thread fetching the data
Task task = new Task<Void>() {
#Override
protected Void call() throws Exception {
// show loading pane -> you can use the one from import org.controlsfx.control.MaskerPane
// https://github.com/controlsfx/controlsfx/wiki/ControlsFX-Features
loadingPane.setVisible(true);
// get data
fetchedData = generateTreeData(yourDataSource);
return null;
}
#Override
protected void succeeded() {
// the data has been fetched, now is safe to build your tree
super.succeeded();
buildTreeFromTheData(fetchedData);
}
};
new Thread(task).start();
}
}
Fetch the data from your database:
public ArrayList<ResultBean> getTreeData(DataSource dataSource) {
ArrayList<ResultBean> resultBeans = new ArrayList<>();
source = null;
this.source = dataSource;
Connection con = null;
Statement stmt = null;
try {
con = source.getConnection();
try {
stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT " +
"sites.siteid, " +
"sites.longname, " +
"plants.plantid, " +
"plants.siteplantid, " +
"plants.shortname " +
"FROM sites " +
"INNER JOIN plants ON plants.siteid=sites.siteid " +
"ORDER BY sites.longname ASC, plants.siteplantid ASC");
while (rs.next()) {
ResultBean resBean = new ResultBean();
resBean.setSiteId(rs.getString("sites.siteid"));
//....
//....
// set all values and add it to the result array
resultBens.add(resBean);
}
} catch (SQLException e) {
e.printStackTrace();
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return resultBens;
}
ResultBean:
public class ResultBean {
private int siteid;
private String longname;
private int plantid;
private int siteplantid;
private String shortname;
// setters
....
// getters
....
}
And finally, build the tree with your logic:
public void buildTreeFromTheData(ArrayList<ResultBean> treeData) {
// do you logic here, loop over treeData ArrayList in while loop
TreeItem<String> rootTreeItem = new TreeItem<String>("EMT");
rootTreeItem.setExpanded(true);
emtTree.setRoot(rootTreeItem);
TreeItem<String> site = null;
TreeItem<String> plant = null;
//This bit prevents repeating the same first level items multiple times.
//I only want each site to appear once, and under each site is a list
//of plants.
//if (!site1.equals(rs.getString("sites.longname"))) {
// site = new TreeItem<String>(rs.getString("sites.longname"));
// rootTreeItem.getChildren().add(site);
// site1 = rs.getString("sites.longname");
// }
//This section is never skipped and will add all the plants to a given
//site until the next site is reached in the result set, then the if
//is triggered again and the process for the new site.
// plant = new TreeItem<String>(rs.getInt("plants.siteplantid") + " " + rs.getString("plants.shortname"));
// site.getChildren().add(plant);
// finally, hide the loading pane
maskerPane.setVisible(false);
}
The result set that I'm trying to retrieve from another class returns null, even though the query works.I'm trying to initialize my object based on the records kept in databases,which means if there is initially a record in sqlite,I retrieve the one with latest date.Else,I try to retrieve the earliest one from mysql database. The code that is supposed to retrieve result set from mysql database is like this:
public ResultSet lowestDate() throws SQLException {
ResultSet rs1 = null;
String resultQuery = "SELECT * FROM alarm ORDER BY `timestamp` ASC LIMIT 1";
rs1 = stmt.executeQuery(resultQuery);
return rs1;
}
Statement is initialized globally.And I call this in another class like this:
public void setLastAlarm() throws SQLException, ParseException {
String liteQuery = "SELECT * FROM alarm_entries ORDER BY date(`timestamp`) DESC LIMIT 1";
conn.connectLite();
Connection getCon = conn.getLiteConnection();
try {
stmt = getCon.createStatement();
} catch (SQLException e) {
e.printStackTrace();
}
try {
rs = stmt.executeQuery(liteQuery);
if (rs.next()) {
//while (rs.next()) {
nuDate = rs.getString("timestamp");
newDate = format.parse(nuDate);
lastAlarm.setBacklogId(rs.getBytes("backlog_id"));
lastAlarm.setTimestamp(newDate);
//}
}
else{
rsq=mysqlConnection.lowestDate();
lastAlarm.setTimestamp(format.parse(rsq.getString("timestamp")));
lastAlarm.setBacklogId(rsq.getBytes("backlog_id"));
}
}catch (Exception e){
e.printStackTrace();
}
}
public void run() {
try {
setLastAlarm();
You never call ResultSet#next() on the result set being returned from the lowestDate() helper method. Hence, the cursor is never being advanced to the first (and only) record in the result set. But I think it is a bad idea to factor your JDBC code in this way. Instead, just inline your two queries like this:
try {
rs = stmt.executeQuery(liteQuery);
if (rs.next()) {
nuDate = rs.getString("timestamp");
newDate = format.parse(nuDate);
lastAlarm.setBacklogId(rs.getBytes("backlog_id"));
lastAlarm.setTimestamp(newDate);
}
else {
String resultQuery = "SELECT * FROM alarm ORDER BY timestamp LIMIT 1";
rs = stmt.executeQuery(resultQuery);
if (rs.next()) {
String ts = rs.getString("timestamp");
lastAlarm.setTimestamp(format.parse(ts));
lastAlarm.setBacklogId(rs.getBytes("backlog_id"));
}
}
} catch (Exception e){
e.printStackTrace();
}
I'm trying to execute method which should create a new object with fields from database, and everytime i run this code im getting SQLException: ResultSet closed.
public DatabasedClient getDatabaseClient(int clientDatabaseid){
if(DatabaseClientUtil.isInDatabase(clientDatabaseid)){
return DatabaseClientUtil.getDBClient(clientDatabaseid);
}else{
try{
System.out.println("Trying to find user in db");
ResultSet rs = fbot.getStorage().query("select * from database_name where clientDBId = " + clientDatabaseid);
System.out.println("deb " + rs.getString("nick"));
while (rs.next()) {
DatabasedClient databasedClient = new DatabasedClient(clientDatabaseid);
databasedClient.setUid(rs.getString("uid"));
databasedClient.setNick(rs.getString("nick"));
databasedClient.setLastConnect(rs.getLong("lastConnected"));
databasedClient.setLastDisconnect(rs.getLong("lastDisconnect"));
databasedClient.setTimeSpent(rs.getLong("timeSpent"));
databasedClient.setLongestConnection(rs.getLong("longestConnection"));
return databasedClient;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return null;
}
}
Im using hikari, here are methods from AbstractStorage class
#Override
public void execute(String query) throws SQLException {
try (Connection connection = getConnection()){
connection.prepareStatement(query).executeUpdate();
}
}
#Override
public ResultSet query(String query) throws SQLException {
try (Connection connection = getConnection()) {
return connection.prepareStatement(query).executeQuery();
}
}
Screenshot from error
I hope someone will help me with this.
I think the exact error you are seeing is being caused by the following line of code:
System.out.println("deb " + rs.getString("nick"));
You are trying to access the result set before you advance the cursor to the first record. Also, your method getDatabaseClient is returning a single object which conceptually maps to a single expected record from the query. Hence, iterating once over the result set would seem to make sense. Taking all this into consideration, we can try the following:
try {
System.out.println("Trying to find user in db");
ResultSet rs = fbot.getStorage().query("select * from database_name where clientDBId = " + clientDatabaseid);
// do not access the result set here
if (rs.next()) {
DatabasedClient databasedClient = new DatabasedClient(clientDatabaseid);
databasedClient.setUid(rs.getString("uid"));
databasedClient.setNick(rs.getString("nick"));
databasedClient.setLastConnect(rs.getLong("lastConnected"));
databasedClient.setLastDisconnect(rs.getLong("lastDisconnect"));
databasedClient.setTimeSpent(rs.getLong("timeSpent"));
databasedClient.setLongestConnection(rs.getLong("longestConnection"));
return databasedClient;
}
} catch (SQLException e) {
e.printStackTrace();
}
first time posting so sorry if my question is slightly strange.
So I have a project in school that requires us to create java classes using netbeans that open up a window with three options, check stock, purchase item and update stock.
We had a class called stockdata that held the details of 5 different items for us to use in our three classes to check, purchase and update items. The latest stage of our coursework requires us to create a derby database and enter the items into a table.
I have done this with no issues but I am having a problem getting the items from the table back into my classes to use. We were given the following code but I can't get it to work, even using the commented hints.
package stock;
// Skeleton version of StockData.java that links to a database.
// NOTE: You should not have to make any changes to the other
// Java GUI classes for this to work, if you complete it correctly.
// Indeed these classes shouldn't even need to be recompiled
import java.sql.*; // DB handling package
import java.io.*;
import org.apache.derby.drda.NetworkServerControl;
public class StockData {
private static Connection connection;
private static Statement stmt;
static {
// standard code to open a connection and statement to an Access database
try {
NetworkServerControl server = new NetworkServerControl();
server.start(null);
// Load JDBC driver
Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
//Establish a connection
String sourceURL = "jdbc:derby://localhost:1527/"
+ new File("UserDB").getAbsolutePath() + ";";
connection = DriverManager.getConnection(sourceURL, "use", "use");
stmt = connection.createStatement();
} // The following exceptions must be caught
catch (ClassNotFoundException cnfe) {
System.out.println(cnfe);
} catch (SQLException sqle) {
System.out.println(sqle);
} catch (Exception e) {
System.out.println(e);
}
}
// You could make methods getName, getPrice and getQuantity simpler by using an auxiliary
// private String method getField(String key, int fieldNo) to return the appropriate field as a String
public static String getName(String key) {
try {
// Need single quote marks ' around the key field in SQL. This is easy to get wrong!
// For instance if key was "11" the SELECT statement would be:
// SELECT * FROM Stock WHERE stockKey = '11'
ResultSet res = stmt.executeQuery("SELECT * FROM Stock WHERE stockKey = '" + key + "'");
if (res.next()) { // there is a result
// the name field is the second one in the ResultSet
// Note that with ResultSet we count the fields starting from 1
return res.getString(2);
} else {
return null;
}
} catch (SQLException e) {
System.out.println(e);
return null;
}
}
public static double getPrice(String key) {
// Similar to getName. If no result, return -1.0
return 0;
}
public static int getQuantity(String key) {
// Similar to getName. If no result, return -1
return 0;
}
// update stock levels
// extra is +ve if adding stock
// extra is -ve if selling stock
public static void update(String key, int extra) {
// SQL UPDATE statement required. For instance if extra is 5 and stockKey is "11" then updateStr is
// UPDATE Stock SET stockQuantity = stockQuantity + 5 WHERE stockKey = '11'
String updateStr = "UPDATE Stock SET stockQuantity = stockQuantity + " + extra + " WHERE stockKey = '" + key + "'";
System.out.println(updateStr);
try {
stmt.executeUpdate(updateStr);
} catch (SQLException e) {
System.out.println(e);
}
}
// close the database
public static void close() {
try {
connection.close();
} catch (SQLException e) {
// this shouldn't happen
System.out.println(e);
}
}
}
Sorry if this seems a stupid question but I am fairly new to Java and was making good progress until this roadblock.
Thanks in advance!
Alex
Searching for "java sql" on Google delivers this link: https://docs.oracle.com/javase/tutorial/jdbc/basics/processingsqlstatements.html
From a connection you can create a statement (you can find this in the link and in your code) , then fetch a result set and loop over that with rs.next(). That should get your started.
Of course you have to make sure that the driver and database are there/running, just saying...
Here netbeans has nothing to do with database. This is a Java-based integrated development environment(IDE) that will help you to reduce syntactic error.
public void dataAccess(){
try {
String connectionUrl = "suitable connection url as per your database";
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
Class.forName("JDBC driver name as per your database");
con = DriverManager.getConnection(connectionUrl, userName, password);
String SQL = "SQL query as per your criteria";
stmt = con.createStatement();
rs = stmt.executeQuery(query);
while (rs.next()) {
// look into ResultSet api and use method as per your requirement
}
rs.close();
}
catch (Exception e) {
//log error message ;
}
}