I am new to Derby and to databases in general for that matter. How can I create a prepared statment for an embedded derby database? Im not sure because the database is embedded.
My String is:
final String updateString = "create table " + TABLE_NAME_TBL_IPS + " (" +
TABLE_COLUMN_COMPANY + " " + TABLE_COLUMN_COMPANY_DATA_TYPE+ "," +
TABLE_COLUMN_IP + " " + TABLE_COLUMN_IP_DATA_TYPE + ")";
Also what is the benefit of using this as a stored procedure instead of a prepared statement call?
It doesn't really matter if the database is embedded or not, as long as it has JDBC connectivity. In your case, Derby does provide you to the connection information.
Your code may look something like this:-
// much easier to read with String.format()... in my opinion
final String updateString = String.format("create table %s (%s %s, %s %s)",
TABLE_NAME_TBL_IPS,
TABLE_COLUMN_COMPANY,
TABLE_COLUMN_COMPANY_DATA_TYPE,
TABLE_COLUMN_IP,
TABLE_COLUMN_IP_DATA_TYPE);
Connection con = null;
try {
con = DriverManager.getConnection("jdbc:derby:yourDatabaseName");
PreparedStatement ps = con.prepareStatement(updateString);
ps.executeUpdate();
ps.close();
}
catch (SQLException e) {
e.printStackTrace();
}
finally {
try {
con.close();
}
catch (Exception ignored) {
}
}
Regarding your question whether to do so using a stored procedure or a PreparedStatement, there are bunch of information out there you are easily search. You generally use a stored procedure to group bunch of SQL statements whereas a PreparedStatement only allows you to execute one SQL statement. It is a good idea to use stored procedures if you intend to expose that API to allow your users to execute it regardless of technology (Java, .NET, PHP). However, if you are writing this SQL statement only for your Java application to work, then it makes sense to just use PreparedStatement.
Related
I'm currently creating a Java application which uses MySQL.
I have read that in certain situations you should use a prepared statement to prevent SQL injection.
By now I don't use prepared statements and I'm actually a bit worried that my Code might be vulnerable to SQL injection.
Situations where MySQL queries are executed:
Direct query from inside the application(all variables used are defined in the application)
API call (another application makes a MySQL query --> All variables used are defined inside the application which makes the call)
MySQL code:
public static void Update(final String qry) {
try {
Statement stnt = connection.createStatement();
stnt.executeUpdate(qry);
} catch (SQLException e) {
e.printStackTrace();
}
}
public static ResultSet Query(String qry) {
final ResultSet rs;
try {
Statement stnt = connection.createStatement();
rs = stnt.executeQuery(qry);
} catch (Exception e) {
e.printStackTrace();
}
return rs;
}
Depending on other factors, your application may remain vulnerable to SQL injection attack from someone with access to your application's environment.
For example, if the variables defined inside your code obtain their values from a configuration file, and later become part of SQL query, an attacker with access to your configuration files can execute a SQL injection attack by altering the content of your configuration file. Same goes for the other application: if there is a way to alter the content of the variables that go into the construction of your SQL query, it is likely possible to execute a successful SQL injection attack.
Using prepared statements provides catch-all defense against injection. The added complexity is well worth the trouble, though, because you plug a huge security hole with a relatively straightforward fix.
Can you post an example of String qry?
In general, it could be vulnerable if you execute a query with values defined not inside the program but defined from outside.
For example:
If you have a String name = null; and name is user-defined and you push in the database that name, this could be potentially a vulnerability.
You could avoid injection with preparedStatement because you set parameters with methods that process the value to strings.
Example:
try (Connection con = DriverManager.getConnection(JDBC_URL, JDBC_USERNAME, JDBC_PASSWORD)){
try (PreparedStatement pst = con.prepareStatement(
"INSERT INTO " + TABLE_NAME
+ "(id, date, ip, name) "
+ "VALUES (?,?,?,?)")) {
pst.clearParameters();
pst.setInt(1, objectID);
pst.setDate(2, (Date) objectDate);
pst.setString(3, objectIP.getHostAddress());
pst.setString(4, object.getName());
int n = pst.executeUpdate();
System.out.println("Inserted " + n + " rows.");
} catch (SQLException e) {
System.out.println("Error in insertion: " + e.getMessage());
}
} catch (SQLException e){
System.out.println("Problem with connection to db:" + e.getMessage());
}
With TABLE_NAME as a static string variable.
An SQL Injection attempted on the name, for example, would pass through pst.setString, so the DB will not see that as a query but simply as a value to insert in the database.
Not sure which is your question, but yes, you might be vulnerable to sql injection, since you have scenarios in which query params are coming from outside your application (as you explain).
You might not be vulnerable anyway, if you are already doing checks when building your query string (or before) to prevent this scenario, even if you are not using prepared statements.
But i would strongly suggest to use prepared statements with bind variables
Consider this scenario: During development, I want to use MySQL and in production I will be using derby.
To get connection, I have this method from java tutorial :
public Connection getConnection() throws SQLException {
Connection conn = null;
Properties connectionProps = new Properties();
connectionProps.put("user", this.userName);
connectionProps.put("password", this.password);
if (this.dbms.equals("mysql")) {
conn = DriverManager.getConnection(
"jdbc:" + this.dbms + "://" +
this.serverName +
":" + this.portNumber + "/",
connectionProps);
} else if (this.dbms.equals("derby")) {
conn = DriverManager.getConnection(
"jdbc:" + this.dbms + ":" +
this.dbName +
";create=true",
connectionProps);
}
System.out.println("Connected to database");
return conn;
}
Here is some more code that involves querying the db (again from java tutorial):
public static void viewTable(Connection con, String dbName)
throws SQLException {
Statement stmt = null;
String query = "select COF_NAME, SUP_ID, PRICE, " +
"SALES, TOTAL " +
"from " + dbName + ".COFFEES";
try {
stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
String coffeeName = rs.getString("COF_NAME");
int supplierID = rs.getInt("SUP_ID");
float price = rs.getFloat("PRICE");
int sales = rs.getInt("SALES");
int total = rs.getInt("TOTAL");
System.out.println(coffeeName + "\t" + supplierID +
"\t" + price + "\t" + sales +
"\t" + total);
}
} catch (SQLException e ) {
JDBCTutorialUtilities.printSQLException(e);
} finally {
if (stmt != null) { stmt.close(); }
}
}
I am wondering if I need to change my query construction depending on what database I use at backend.
For example, MySQL and PostgreSql seems to have some key differences in queries. (In the above example it might not make any difference).
I have django framework background, where ORM is designed to handle any kind of database. same code works fine with any database plugged in.
Since you are directly writing the SQL statements when using JDBC, these are inherently tied to the database you are using. The only way around this is to use only SQL constructs which are supported by all target databases. There is nothing shielding you from the differences between databases.
Your code can have both DB-independent and DB-dependent parts.
Database-dependent parts: The JDBC URLs, SQL statements (the syntax) are database-dependent in general. With some effort, it is possible to write SQL syntax which is recognized by all Databases, but this may not be possible in all cases.
Database-independent parts: The Java code used to get the connections, run statements, managing connections, creating data sources, connection pooling etc. are (as far as I think) common to all database systems that are JDBC compliant.
Strictly speaking, the 'JDBC' code is mostly independent of the database. What changes with every database is the statement syntax (but JDBC does not specify the syntax in the first place)
I agree with the other posters that if you use standard sql, then it should be simple to switch database vendor.
There are lots of ORM's and mappers that create standard sql. My favorite is sormula (I'm the author). I recently worked on a project using sormula where test server used HSQLDB and production server used PostgreSQL.
I have a web application which is based on SQL Server 2012, and I use Java to update data in the database. (Windows Server 2008, JSP, Tomcat7, Java7)
The relevant code is as follows:
public static synchronized int execute(String dsName, String packageAndFunction, List fields) {
// prepare insertStr
String executeStr = buildStatement(dsName, packageAndFunction, null, fields);
dbConn = DBConnection.getInstance();
Connection conn = dbConn.getConnection();
CallableStatement stmt = null;
int result = RESULT_FAILED;
try {
stmt = conn.prepareCall(executeStr);
// fill statement parameters (each ?)
fillStatement(stmt, fields);
stmt.execute();
result = stmt.getInt(fields.size());
} catch(SQLException e) {
Log.getInstance().write("Exception on executeGeneral (" + packageAndFunction + ") " + e.toString());
} finally {
try {
stmt.close();
dbConn.returnConnection(conn);
} catch(SQLException e) {
Log.getInstance().write("Exception on executeGeneral (" + packageAndFunction + ") " + e.toString());
}
}
return result;
}
About 90% of the time, the code works great. The rest of the time there is some kind of lock on the table which will disappear by itself in perhaps half an hour or so. The lock prevents even simple SELECT queries on the table from executing (in SQL Server Management Studio). In severe cases it has prevented the entire application from working.
I had an idea to use stmt.executeUpdate() instead of stmt.execute(), but I have tried to research this and I do not see any evidence that using stmt.execute() for updating causes locks.
Can anyone help?
Thanks!
It's difficult to diagnose with that code. The next time that it happens, pull up your activity monitor on the SQL server and see what sql command is holding the lock.
I'm connecting to an Access database with a jdbc:odbc bridge.
I then select a large amount of data from the database (~2 million rows).
The first time I run the code after a restart it is very slow, taking over 6 minutes to retrieve the data.
On subsequent runs, it takes only 1.5 mins to do the same thing.
This is the code I'm using to connect to the database:
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
String url = "jdbc:odbc:Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=" + databaseLocation + databaseName + ";selectMethod=cursor; READONLY=true; TYPE=FASTLOAD";
con = DriverManager.getConnection(url);
System.out.println("Connected to " + databaseName);
} catch (SQLException e) {
System.out.println("SQL Exception: " + e.toString());
} catch (ClassNotFoundException cE) {
System.out.println("Class Not Found Exception: " + cE.toString());
}
After much Googling I've tried adding parameters such as
selectMethod=cursor
READONLY=true
TYPE=FASTLOAD
As far as I can see, none of these made a difference.
I then select the data like so:
String SQL = "SELECT ADDRESS_MODEL.ADDR_LINE_1, ADDRESS_MODEL.ADDR_LINE_2, LOCALITIES.NAME, ADDRESS_MODEL.SECONDARY_LOCALITY, TLANDS.NAME, ADDRESS_MODEL.POST_TOWN, ADDRESS_MODEL.COUNTY FROM ((ADDRESS_MODEL LEFT JOIN BUILDINGS ON ADDRESS_MODEL.BUILDING_ID = BUILDINGS.BUILDING_ID) LEFT JOIN LOCALITIES ON BUILDINGS.LOCALITY_ID = LOCALITIES.LOCALITY_ID) LEFT JOIN TLANDS ON BUILDINGS.TLAND_ID = TLANDS.TLAND_ID WHERE BUILDINGS.COUNTY_ID = " + county_ID;
PreparedStatement prest = con.prepareStatement(SQL);
ResultSet result = prest.executeQuery();
I tried using a prepared statement but I'm not sure I did it right.
After storing the data I close the ResultSet:
result.close();
Later in the program, I close the connection as follows:
try{
stmt.close();
con.close();
System.out.println("Connection to " + databaseName + " closed");
} catch (SQLException e) {
System.out.println("SQL Exception: " + e.toString());
}
Unfortunately I am committed to using both Java and Access at this point.
Does anyone have any idea why it is slower the first time (or more why it is faster on subsequent runs)?
Also, are there any general things I could do better to make it faster?
Thanks for your time.
You say two million rows, but how large is the data? It's quite possible that it's reading it all in from disk the first time, then it's in the disk cache for subsequent runs. Even if the entire dataset doesn't fit in RAM at once, it's likely that key data structures will still be present.
I am trying to execute a BULK INSERT statement on SQL Server 2008 Express.
(It basically takes all fields in a specified file and inserts these fields into appropriate columns in a table.)
Given below is an example of the bulk insert statement--
BULK INSERT SalesHistory FROM 'c:\SalesHistoryText.txt' WITH (FIELDTERMINATOR = ',')
Given below is the Java code I am trying to use (but its not working)...Can someone tell me what I am doing wrong here or point me to a java code sample/tutorial that uses the Bulk Insert statement? --
public void insertdata(String filename)
{
String path = System.getProperty("user.dir");
String createString = "BULK INSERT Assignors FROM " + path + "\\" +filename+ ".txt WITH (FIELDTERMINATOR = ',')";
try
{
// Load the SQLServerDriver class, build the
// connection string, and get a connection
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
String connectionUrl = "jdbc:sqlserver://arvind-pc\\sqlexpress;" +
"database=test01;" +
"user=sa;" +
"password=password1983";
Connection con = DriverManager.getConnection(connectionUrl);
System.out.println("Connected.");
// Create and execute an SQL statement that returns some data.
String SQL = "BULK INSERT dbo.Assignor FROM " + path + "\\" +filename+ ".txt WITH (FIELDTERMINATOR = ',')";
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(SQL);
// Iterate through the data in the result set and display it.
while (rs.next())
{
//System.out.println(rs.getString(1) + " " + rs.getString(2));
System.out.println(" Going through data");
}
}
catch(Exception e)
{
System.out.println(e.getMessage());
System.exit(0);
}
}
I'd guess that your SQL string is missing the single quotes around the filename. Try the following:
String SQL = "BULK INSERT dbo.Assignor FROM '" + path + "\\" +filename+ ".txt' WITH (FIELDTERMINATOR = ',')";
EDIT in response to your comment: I wouldn't expect there to be anything in the ResultSet following a bulk insert, in much the same way that I wouldn't expect anything in a ResultSet following an ordinary INSERT statement. These statements just insert the data they are given into a table, they don't return it as well.
If you're not getting any error message, then it looks like your bulk insert is working. If you query the table in SQLCMD or SQL Server Management Studio, do you see the data?
INSERT, UPDATE, DELETE and BULK INSERT statements are not queries, so you shouldn't be using them with the executeQuery() method. executeQuery() is only intended for running SELECT queries. I recommend using the executeUpdate(String) method instead. This method returns an int, which is normally the number of rows inserted/updated/deleted.