The Problem:
I am creating an application that requires the use of an integrated database but I am having issues getting my application to connect to the database/table. Unfortunately, my knowledge of Java connecting to databases is rather limited but everything I have read and watched seems to point to my code being correct.
My Code:
public static void main(String[] args) {
try{
Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
Connection con = DriverManager.getConnection("jdbc:derby:datahold;");
Statement stat = con.createStatement();
ResultSet rs = stat.executeQuery("select * from APP.DATASTORE");
ResultSetMetaData meta=rs.getMetaData();
int columnCount = meta.getColumnCount();
for (int x = 1; x <= columnCount; x++)
System.out.format("%20s",meta.getColumnName(x)+ " | ");
while (rs.next()){
System.out.println("");
for (int x = 1; x <= columnCount; x++) System.out.format("%20s", rs.getString(x)+ " | ");
}
if (stat != null) stat.close();
if (con != null) con.close();
} catch(Exception e) {
System.out.print(e);
}
}
The Error:
java.sql.SQLSyntaxErrorException: Table/View 'APP.DATASTORE' does not exist.BUILD
SUCCESSFUL (total time: 1 second)
My Data Base Setup:
I have tried removing the "APP." but this then results in the application not being able to find a table "ROOT.DATASTORE".
If anyone is able to help me out here that would be great!
UPDATE:
I can now see that when running the application, it is creating the database files in the root of the package. Therefore, the embedded driver connection must be working (at least that's the way I see it). My question is should the database be located here or should it be held in the "dist" folder?
I am assuming it is not able to see the table because it is looking in the wrong location.
You have put an semicolon there
DriverManager.getConnection("jdbc:derby:datahold;");
remove it
here is correct code
DriverManager.getConnection("jdbc:derby:datahold");
So the answer to this question is rather simple as I found out after HOURS of tinkering.
Netbeans kindly creates a persistent xml file that stores some data that the application uses when it starts up. More precisely, when the database starts up. One of these options is which connection to use.
All I had to do was change this connection to my embedded driver connection and it is now working.
Related
I am trying to figure out how to encrypt a sqlite database in non-android java.
It does not seem to be super straight forward, but I Willena jdbc crypt which does seem to be able to create an encrypted database, but I simply cannot figure out how to access a SQLCipher 4 encrypted database with it.
Here is my code.
String path = "jdbc:sqlite:C:\\Users\\User1\\Desktop\\testServer232.db";
Connection connection = null;
try
{
// create a database connection
connection = DriverManager.getConnection(path+"?cipher=sqlcipher&key=a");
Statement statement = connection.createStatement();
statement.setQueryTimeout(30); // set timeout to 30 sec.
statement.executeUpdate("drop table if exists person");
statement.executeUpdate("create table person (id integer, name string)");
statement.executeUpdate("insert into person values(3, 'leo1')");
statement.executeUpdate("insert into person values(4, 'yui1')");
ResultSet rs = statement.executeQuery("select * from person");
while(rs.next())
{
// read the result set
System.out.println("name = " + rs.getString("name"));
System.out.println("id = " + rs.getInt("id"));
}
}
catch(SQLException e)
{
// if the error message is "out of memory",
// it probably means no database file is found
System.err.println(e.getMessage());
}
finally
{
try
{
if(connection != null)
connection.close();
}
catch(SQLException e)
{
// connection close failed.
System.err.println(e.getMessage());
}
}
This code does work, but I don't think that it produces a SqlCipher 4 encrypted database. When I try to open it with DB browser for Sqlite, it does not allow me access when I put the password = a.
Where am I going wrong?
Ok, so I ended up finding the creator of the repository. And he solved it easily and answered really fast.
Here is the solution:
Here are a few things that could be tested:
Use version 3.31.1
Try to do the database connection using "jdbc:sqlite:file:C:\Users\User1\Desktop\test.db?cipher=sqlcipher&key=password123"as URI (notice the added "file:").
Try to add the legacy parameter for SQLCipher as available here (https://github.com/Willena/sqlite-jdbc-crypt#aes-256-bit-cbc---sha1sha256sha512-hmac-sqlcipher). The URI will become something like this: "cipher=sqlcipher&key=password123&legacy=4"
This is now working for me. I recommend that others use it if they are interested in an easy way to do sqlcipher version 4 similarly to how it is done in an android project.
I am trying to access a database from a different server , but no success so far. The event is, when I choose the object "ALL" in my combobox, the table will load all data from different servers.
The current code, which I only connected to the localhost, works fine. However, when I try to connect another server to load both of their data, I get a syntax error when trying to put 192.168.1.51.sales.items in the String sqlall. Also, I tried modifying the prepareStatement by writing cn.prepareStatement(sqlall) + cn1.prepareSatement("union Select * from 192.168.1.52.sales.items); I have no more idea on how to connect on both servers.
I would like to apologize beforehand if you find my coding a bit messy. Thank you. My code is as follows:
private void combobox_branchItemStateChanged(java.awt.event.ItemEvent evt) {
Object branch = combobox_branch.getSelectedItem();
try
{
// All is selected
if("All".equals(branch))
{
Connection cn = db.itemconnector.getConnection();
String sqlall = " Select * from sales2.items union Select * from sales1.items union Select * from sales.items " ; //I tried accessing multiple databases in my own localhost and worked.
PreparedStatement ps = cn.prepareStatement(sqlall);
ResultSet rs = ps.executeQuery();
DefaultTableModel tm = (DefaultTableModel)itemTable.getModel();
tm.setRowCount(0);
while(rs.next())
{
Object o[] = {rs.getInt("id"), rs.getString("location"), rs.getString("product_name"),rs.getString("product_category"),rs.getString("product_description"),rs.getInt("product_stock"), rs.getFloat("product_price"), rs.getString("product_status")};
tm.addRow(o);
}
}
catch (Exception e)
{
JOptionPane.showMessageDialog(null, e, "Connection Error", JOptionPane.ERROR_MESSAGE);
}
}
And I have a class in a different package and this is its code:
package db;
import java.sql.*;
public class itemconnector {
public static Connection getConnection() throws Exception
{
Class.forName("com.mysql.jdbc.Driver");
Connection cn = (Connection)
DriverManager.getConnection("jdbc:mysql://192.168.1.50:3306/sales","root","");
return cn;
}
It is not possible to query different databases on different servers in a single SQL query.
It is also not possible to get around this by "concatenating" prepared statements. (For a start, that is nonsensical Java!)
You need to open a separate Connection to each separate database server and query the relevant tables on that server. Then combine the information from the separate ResultSet objects in Java code.
The "combining" will be something like iterating the results in each result set and adding them to a Java data structure ...
I am following Java: How To Program - Chapter 24. The chapter deals with database implementation in Java. I followed the steps to setup "Derby", but I get the error java.sql.SQLException: Database 'books' not found..
I checked $PATH to make sure it includes $DERBY_HOME. $DERBY_HOME points to the correct folder(/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/db).
I checked $JAVA_HOME and it was also setup correctly(/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home).
I can use the tool ij and it shows me the database that is setup. I added derby.jar to the package in eclipse. The following is the code from the book, but when I compile it I get the error java.sql.SQLException: Database 'books' not found.
I looked it up online, and there were recommendations that I add //localhost:1527/books. But if I add that I get the java.sql.SQLException: No suitable driver found for jdbc:derby://localhost:1527/books error.
There was also suggestions that I use Class.forName("org.apache.derby.jdbc.ClientDriver").newInstance();, that didn't solve the problem either.
I have copy/pasted the books.sql database in the same package as the one that contains the source code.
Does anybody know how to solve the problem? I am running MacOS Sierra.
public class DisplayAuthors {
public static void main(String [] args) {
final String DATABASE_URL = "jdbc:derby:books";
final String SELECT_QUERY = "Select authorID, firstName, lastName from authors";
try(
Connection connection = DriverManager.getConnection(
DATABASE_URL, "deitel", "deitel");
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(SELECT_QUERY)){
ResultSetMetaData metaData = resultSet.getMetaData();
int numberOfCols = metaData.getColumnCount();
System.out.printf("Authors of table of Books databse:%n%n");
for(int i = 0; i < numberOfCols; i++)
System.out.printf("%-8s\t",metaData.getColumnName(i));
System.out.println();
while(resultSet.next()){
for (int i = 1; i <= numberOfCols; i++)
System.out.printf("%-8s\t",resultSet.getObject(i));
System.out.println();
}
}catch(SQLException ex){
ex.printStackTrace();
}
}
}
I figured the problem was. When the creating the database via ij I had to be in the same directory that the source file is. Now under eclipse I thought that this would mean I need to be under package folder(JAVAProject/src/package), but that was wrong. I had to be under (JAVAProject).
So a little background on my problem: I am trying to copy over a table on an Microsoft SQL system from an Oracle database. Besides giving password and user access to the table I cannot edit or do anything to the MSSQL database.
I successfully used the Oracle SQL Developer to connect and view the tables I want (using a third party JDBC driver), but I want to set up an automated copy-over into my Oracle database so I am attempting to use the same driver in some stored java code.
I have a java function that all it should do is go and count the number of entries in the table. So far my code looks like:
public static String getCount() {
Statement stmt = null;
Connection conn = null;
int rowCount = 0;
String message = "";
try {
Class.forName("net.sourceforge.jtds.jdbc.Driver");
}
catch(ClassNotFoundException e) {
System.err.println("Error loading driver: " + e);
message = message + e + " -ER1 \n";
}
try {
conn = DriverManager.getConnection("jdbc:jtds:sqlserver://site.school.edu:2000/ACCESS", "user", "password");
stmt = conn.createStatement();
String strSelect = "select 1 as field;";
ResultSet rset = stmt.executeQuery(strSelect);
while (rset.next()) {
++rowCount;
}
}
catch(SQLException ex) {
ex.printStackTrace();
message = message + ex.getSQLState() + " -ER2";
}
finally {
try {
if (stmt != null) stmt.close();
if (conn != null) conn.close();
} catch(SQLException ex) {
ex.printStackTrace();
message = message + ex.getSQLState() + "-ER3";
}
}
return message;
}
Which is being calling from a stored function :
CREATE OR REPLACE function Schema.java_testMessage return varchar2
as language java
name 'ConnectAndQuery.getCount() return java.lang.String';
Which I am calling from a script in TOAD:
set serveroutput on;
declare
words varchar2(400);
begin
words := KSL_ADMIN.java_testMessage;
dbms_output.put_line(words);
end;
However the result is that I'm getting:
java.lang.ClassNotFoundException: net/sourceforge/jtds/jdbc/Driver -ER1
08001 -ER2
PL/SQL procedure successfully completed.
I have the jar file within the class path, I can't think of any reason it shouldn't have the nessecary permissions to see the jar, and as far as I can tell I have everything spelled correctly.
Please help me figure out what I am doing wrong. Or if there is perhaps an easier way to go about connecting an Oracle DB to an MSSQL DB without really installing anything. Any knowledge on this is welcome as I am pretty new to a lot of this.
Oracle has its own internal java virtual machine and it does not use the system classpath. If you need external libraries you must “load” them into the internal JVM. You can do this using Oracle's loadjava tool.
See the Oracle's loadjava documentation (http://docs.oracle.com/cd/B28359_01/java.111/b31225/cheleven.htm#JJDEV10060)
I am building a web app with a single (not pooled) full time (jdbc) connection between static classes and the database. This is expected to be a low traffic site and the static methods are synchronized. In an effort to speed up access to product information, I am trying PreparedStatements for the first time. As I test, on localhost, sure that I'm the only one running the app., it seems clear to me that my the prepared statements are slower than the unprepared statements I use earlier in the process. This may not be a fair comparison. The unprepared statements get a single result set from one table and it's done. As you can see from the code below, what I'm doing with prepared statements involves three tables and multiple queries. But since this is my first time, I would appreciate review and comment. This does actually work; i.e. all data is retrieved as expected.
The first method below (initialize()) is called once from a servlet init() method when the application is first started. The second method (getItemBatch()) retrieves information about as many product items as match a product name (Titel). My little development / test database has less than 100 (total) items and only 1-3 items matching each name; most often only 1. The server app and database are on the same machine and I'm accessing from a browser via localhost. I'm surprised by the consistent perceptible wait for this detailed product data compared to fetching a master product list (all items) mentioned above.
public static boolean initialize (Connection connArg, String dbNameArg, String dbmsArg) {
con = connArg;
dbName = dbNameArg;
dbms = dbmsArg;
sqlserver_con = connArg;
ItemBatchStatement =
"select Cartnr, Hgrupp, Prisgrupp, Moms from dbo.Centralartregister " +
"where Titel = ?";
ForArtNrStatement =
"select Artnr, Antal from dbo.Artikelregister " +
"where Cartnr = ? and Antal > 0";
ItemHgruppStatement =
"select Namn from dbo.Huvudgrupper " +
"where Hgrupp = ?";
try {
con.setAutoCommit(false);
getItemBatch = con.prepareStatement(ItemBatchStatement);
getForArtNr = con.prepareStatement(ForArtNrStatement);
getItemHgrupp = con.prepareStatement(ItemHgruppStatement);
} catch (SQLException e) {
return(false);
} finally {
try {con.setAutoCommit(true);} catch (SQLException e) {}
}
return(true);
}
-
public static synchronized String getItemBatch (String Titel) throws SQLException {
String ret_xml;
ResultSet rs = null;
ResultSet rs1 = null;
ResultSet rs2 = null;
Titel = charChange(Titel);
ret_xml = "<ItemBatch Titel='" + Titel + "'>";
try {
con.setAutoCommit(false);
getItemBatch.setString(1,Titel);
rs = getItemBatch.executeQuery();
while (rs.next()) {
getForArtNr.setInt(1,rs.getInt("Cartnr"));
rs1 = getForArtNr.executeQuery();
getItemHgrupp.setInt(1,rs.getInt("Hgrupp"));
rs2 = getItemHgrupp.executeQuery();
if (rs1.next() && rs2.next()) {
ret_xml += "<item><Hgrupp>" + rs2.getString("Namn") + "</Hgrupp><Price>" + rs.getInt("Prisgrupp") + "</Price><Moms>" + rs.getInt("Moms") + "</Moms><Cartnr>" + rs.getInt("Cartnr") + "</Cartnr><Artnr>" + rs1.getInt("Artnr") + "</Artnr></item>";
}
}
ret_xml += "</ItemBatch>";
return(ret_xml);
} catch (SQLException e) {
return("SQLException: " + e);
} finally {
try {con.setAutoCommit(true);} catch (SQLException e) {}
if (rs != null) {rs.close();}
if (rs1 != null) {rs1.close();}
if (rs2 != null) {rs2.close();}
}
}
.
UPDATE: I'm still googling and looking for ways to do better. Let me add something for your consideration.
I'm closing the prepared statements via the servlet's destroy() method; the same servlet that calls the method "initialize()" above in order to create them. The idea is to create them once (and only once) and have them available forever for all users (i.e. until the app or server is shut down). I'm going for a kind-of a pseudo-stored procedure. I would just use stored procedures straight out, but the database exists to support another application (their in-house sales system) and I'm going to use it for Internet sales read-only ... avoiding any potential conflict with their maintenance efforts or agreements etc. by not doing anything to change their database set-up. I have suggested that my app use a new account limited to read-only privileges. And come to think of it, I haven't tested whether I can use Prepared Statements in that mode; just seems like it should work.
Each result set is closed in the finally block in the method where they are created. I guess that's ok? I reuse the same RS variable name for multiple result sets (on the second two) but close only once. But wait! Do I even need that? The ResultSets are declared within the scope of the method. If resetting them without closing the old ones doesn't cause leaks, then exiting the method should do just as well on its own. It is a static method, but the ResultSets will be reset every time it's used (at the very least). So, at most, there would just be a single set of ResultSet handles available for reuse; not run-away "leakage."
I'm wondering if I can send the two select requests in the loop both at the same time, simply by turning them into one prepared statement separated by ';'. Or just found "MultipleActiveResultSets=True"; document allowing SQL Server to process multiple transaction requests on a single connection ... still investigating this. Or is there another way to create a prepared statement that would fetch ALL the data via a single submission? (Seems to me like there are too many round trips.) Finally, I might get a boost from using connection pooling, which I haven't done yet. It's low priority in my project right now, but I might have to do it before we go online.
If you create web applicaton and use some web container like tomcat, jetty etc you always can use jdbc datasource and connection pool. It is simple. Good explanation gives here
If you don't want to use connection pool I suppose it would be better use Method Scope Connections described link above