How can I display, using Java, my databases? - java

I'm programming a Java utility to make security copies of all my databases in my PC. I know how to program the time and I know to work with tables, but no to list all my DB in my program using a JList or a JTable.
How could I do it?
Thanks all!

Not sure what DB? most db has jdbc connections (google for open source solutions, the db name and jdbc). https://en.wikipedia.org/wiki/Java_Database_Connectivity
And with jdbc connections you can always create your own data structure from the queries... and put it in a jtable.
Another tip (but if you want to make a generic solution with nice interfcae): Have a look at swingx and jxtables? have some nice features...
https://java.net/projects/swingx/
they have some nice interfaces for databases, to connect and than show them in tables (and open source):
https://java.net/projects/databinding/sources/svn/content/trunk/src/java/org/jdesktop/dataset/DataConnection.java?rev=421
As Andreas states, using the default jdbc classes and functions will help. most open source jdbc has nice descriptions.
Some tips of unknown but very nice jdbc connections:
csv jdbc (has a lot of unit tests with examoples in it hoiw to get
table data and meta info): http://csvjdbc.sourceforge.net/ or the code in git: https://sourceforge.net/projects/csvjdbc/ see the test to see how things work. e.g. test metadata to see how things work: https://sourceforge.net/p/csvjdbc/code/ci/master/tree/src/test/java/org/relique/jdbc/csv/TestCsvDriver.java
h2 db http://www.h2database.com/html/main.html see this metadata overview: http://www.h2database.com/javadoc/org/h2/jdbc/JdbcDatabaseMetaData.html
They have both nice examples and tests (csv jdbc) to show how it works (just google), same counts for other type of jdbc connections
You can find the code in above, but as requested in the remark, here an example of how to get the table names from the h2 db (most jdbc work the same):
public ArrayList<String> getTableNames(boolean withSystemTables)
throws SQLException {
// Note: system table are tables like Catalogue
ArrayList<String> tables = new ArrayList<String>();
DatabaseMetaData metadata = getMetaData();
String tableNamePattern = null;
String catalog = null;
String schemaPattern = null;
String[] types = { "TABLE" };
if (withSystemTables) {
types = null;
}
ResultSet rs = metadata.getTables(catalog, schemaPattern,
tableNamePattern, types);
if (rs == null) {
return tables;
}
boolean debugFunction=false;
while (rs.next()) {
String table = rs.getString("TABLE_NAME");
tables.add(table);
if (debugFunction){
String tableType=rs.getString("TABLE_TYPE");
String msg=table+" : "+tableType;
//System.out.println(msg);
log.fine(msg);
}
}
rs.close();
return tables;
}
Note: the code above can be shorter, I splitted things out for readability and understanding.

To query the database schema in a database agnostic way, call Connection.getMetaData() to get a DatabaseMetaData object, then use the various methods, such as:
getCatalogs()
getSchemas(String catalog, String schemaPattern)
getTables(String catalog, String schemaPattern, String tableNamePattern, String[] types)
getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern)

Related

How can I check that Java JDBC code uses the right column names?

I have a test suite of end-to-end tests. They are supposed to catch typos in SQL statements, bad table or column names (anything where DB schema and Java code disagree), or missing DB permissions. I don't want to rely on data in the database (too complicated to set up); this is just a basic test.
import java.sql.*;
import org.junit.Test;
public class TypoTest {
private Connection getConnection() throws Exception {
String connectionString = "jdbc:postgresql://127.0.0.1:5432/db";
String driverClassName = "org.postgresql.ds.PGConnectionPoolDataSource";
Class.forName(driverClassName).newInstance();
return DriverManager.getConnection(connectionString, "robert", "");
}
#Test
public void runQuery() throws Exception {
try (Connection connection = getConnection();
PreparedStatement ps = connection.prepareStatement("SELECT relname FROM pg_catalog.pg_class");
ResultSet data = ps.executeQuery()) {
while (data.next()) {
data.getString("relname");
}
}
}
}
When I run the above test, it fails if I have a typo in the SELECT statement. (Good.) If I have a typo in the column name in data.getString("typo here"), that won't get caught if the table queried does not have data because then the loop is never entered. To keep the test (setup) simple, I don't want to insert data into my tables first.
I guess I could make the column names into constants and DRY up my code and get rid of the problem.
However, I am wondering if there is an easier way... I am lazy and don't want to edit all my queries. Is there a better way to unit-test my SQL?
I am using Postgres 9.5 and JDBC 4.
I guess you already have the answer you seek but just for the sake of answering, you can try using result-set-metadata by using a select * from table and then checking the column names against your query (you'd have to parse the query string I guess...).
I believe it will work for empty tables as well but do note that I have not tested the empty table scenario.

Need to sync two tables from different databases in java

Usually to sync a table with in the network I can write a simple sql query and run it to sync the tables, but what if the source database is different(could be db2, mssql, mysql, oracle - from where I can get the data in to destination table).
How should I go about writing the code in java to achieve this?. I know I can create dblinks in java to fetch data from external network database but dblinks works only with database of same type. I am not able to figure out the implementation in my head. Please point me in the right direction so I can take baby steps and learn the same as I am new to java
You can do this with plain JDBC. Code example, not tested:
void migrate() throws SQLException {
Connection connA = DriverManager.getConnection("jdbc:oracle:thin:#myhost:1521:orcl");
Connection connB = DriverManager.getConnection("jdbc:mysql://192.168.1.33/test");
PreparedStatement stmA = connA.prepareStatement("select * from product where 1=1");
PreparedStatement stmB = connB.prepareStatement("insert into prod values(?,?,?,?)");
ResultSet rs = stmA.executeQuery();
while (rs.next()) {
for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) {
stmB.setObject(i + 1, rs.getObject(i + 1));
}
stmB.executeUpdate();
}
connA.close();
connB.close();
}
Data Migration If you want to migrate data from one database to another database of different types,
Suppose you have A and B two different database, you have to export data from A database in XML format, table name is XML parent node (create structure as per your database).
Then parse that XML's and create objects of each table present in A, after that use any XML parser which will parse your XML, using hibernate save() api put each object in another database manage if tables has relationships in them then insert master table data first then insert child items data.
By this approach you no need to be dependent on destination (B) database each time, with the help of hibernate you can easily change your database.

Java DB Database, check for all table names

I've got an embedded Derby Database in my java application, and have multiple table's (that are created and deleted, so nothing is set in stone). I wanted to be able to return a list of names of all the tables currently in the database as I have to display the list in the application as well as get all the information from them.
Easiest way to do so? I don't need code just a method or methods. I'm a terrible google-fu user.
Currently my code works by grabbing a ResultSet from a specific table name entered, but it's only for testing purposes and I need to be able to display the full list of tables I have.
EDIT: My current workaround is actually different than posted. I simply have another table that holds all the table names created and updates when one is created/deleted. Obviously not the best approach but it works for me right now.
DatabaseMetaData metaData = connection.getMetaData();
ResultSet resultSet = metaData.getTables(null, "schenaName", "%" ,new String[] {"TABLE"} );
while (resultSet.next()) {
System.out.println(resultSet.getString(3));
}
Adding new answer:
Connection connection = getDBConnection();
DatabaseMetaData dbMetaData = connection.getMetaData();
//getting catalogs for mysql DB, if it is not working for your DB, try dbMetaData.getSchemas();
ResultSet catalogs = dbMetaData.getCatalogs();
while(catalogs.next()){
String catalogName = catalogs.getString(1);
//excluding table names from "mysql" schema from mysql DB.
if(!"mysql".equalsIgnoreCase(catalogName)){
ResultSet tables = dbMetaData.getTables(catalogName, null, null, null);
while(tables.next()){
System.out.println(catalogName + "::"+tables.getString(3));
}
}
}
Using metadata is the (somewhat) more portable solution. Note that you don't need the catalog stuff with Derby, as there are no catalogs. You can issue dmd.getTables(...) directly with null for the catalog. If all the tables you track are in a single schema, (and there aren't any other tables in that schema), getTables(null, "schemaName", null, null) should do the trick.
If need more fancy querying and you're not concerned about portability, you can check out
the dataBaseMetaData tool which gives you access to metadata as tables so that you can perform joins and other sophisticated queries on them.
Try this:
select tableName from sys.systables
You should get all the tables your system.

How to create multiple schema connections at runtime?

I have a a project name drop-down list, and based on the selected value a schema drop-down list is generated.
After the schema list is generated, there is a 'choose file' option where a script name is chosen which is to be run on multiple schemas.
Both the project list values and the schema list values are stored in the database. There is another table in the database where the schema credentials are stored.
I want to know that how create connections on those multiple schemas, and how to run a script in multiple schemas selected from that schema drop-down list.
I have executed the code in one schema using iBatis framework using scriptrunner method.
Table 1: ProjectName
PROJECT_PK,
PROJECT_CODE,
PROJECT_NAME
Table2: ComponentName
COMPONENT_PK,
COMPONENT_CODE,
COMPONENT_NAME,
PROJECT_PK
Table 3: SchemaName (This table contains the credentials of Other Schemas)
SCHEMA_PK,
SCHEMA_NAME,
PASSWORD,
ORACLE_SID,
HOST_NAME,
PORT_ID
Table 4: PROJECT_DETAIL
PROJECT_DETAIL_PK,
COMPONENT_PK,
SCHEMA_PK
Table5: COMPONENT_DETAILS
COMPONENT_DETAILS_PK,
PROJECT_PK,
SCHEMA_PK
I am attaching the scenario image.
I propose you create a 'super-schema' with the appropiate grants on every other schema, and create your JDBC connection for this 'super-schema'. This will make you need some tampering with the sql script - you will need to write it with some marker to easily substitute the schema, something like
ALTER TABLE ${SCHEMA_MARKER}.INVOICES ADD CLIENT_ADRRESS Varchar2(35);
And your java code would substitute it for the schema you are targeting. With some imagination you can extend this idea to execute bulk DDL scripts on all your schemas.
By the way, I understand by your question that you have many schemas with the same structure. I was forced once to work with such a legacy structure, and so I know there is a lot of momentum in corporate structures; nonetheless I must recommend you to redesign such system. Think for example in creating materialized views on your super-schema, replicating your schema structure but with a new field in every table primary key (this new field would fill the gap that made whomever did it separe the data in many schemas for starters).
This will surely make your query cache suffer a lot less, and will make easier the development of any new software that needs to work with that 'distributed' data.
In Oracle, a schema is basically a user. So to create a table FOO in the schema SX, you just login as user SX and execute create table FOO (...) (without specifying a schema). The user == schema convention in Oracle will make sure this works.
To login as user SX, get hold of your DataSource and use getConnection(String username, String password) instead of the default getConnection()
Alternative ways are to add placeholders in your script that you process to generate valid SQL first. See the answer by Jorge_B for an example.
Lastly, you can change the default schema using ALTER SESSION (see Default Schema in Oracle Connection URL). The problem with this approach is that you must restore the schema before closing the connection when using a web container with a DataSource - in this scenario, connections are never really closed, so the next piece of code asking for a connection will get one with an unexpected default schema -> hard to find errors.
Here is the DAO class to create multiple schema connection on the same database at run time.
We need to enter the schema names at run time through and call that in some servlet.
The schema details i.e username, password,host Id,port Id and SID are to be stored in the database tables though which the connections will be created.
The created connections are stored here in the list which can be used at a later point of time.
The credential DTO here is the object which maps to the database tables in the database and then
Connection conn=DBUtil.getConnection(constants.DB_DS_NAME);
Statement stmt=null;
stmt=conn.createStatement();
ResultSet rs= null;
Connection [] con=new Connection[schemaname.length];
int i,j;
String [] url=new String[schemaname.length];
String [] username=new String[schemaname.length];
String [] password=new String[schemaname.length];
List<CredentialDTO> creDTOlist=new ArrayList<CredentialDTO>();
String query1="insert into dba_project_master VALUES(9,'abc','abc','abc','abc',40)";
String query2="CREATE TABLE EMP(EMPNO NUMBER(4,0) NOT NULL ENABLE,ENAME VARCHAR2(10 BYTE),JOB VARCHAR2(9 BYTE), SAL NUMBER(7,2),DEPTNO NUMBER(2,0))";
try
{
for(i=0;i<schemaname.length;i++){
String query=" select * from dba_schema_details where schema_name="+DBUtil.enquoteString(schemaname[i]);
rs=stmt.executeQuery(query);
while(rs.next()){
CredentialDTO creDTO=new CredentialDTO();
creDTO.setSCHEMA_PK(rs.getString("SCHEMA_PK"));
creDTO.setSCHEMA_NAME(rs.getString("SCHEMA_NAME"));
creDTO.setPASSWORD(rs.getString("PASSWORD"));
creDTO.setORACLE_SID(rs.getString("ORACLE_SID"));
creDTO.setHOST_NAME(rs.getString("HOST_NAME"));
creDTO.setPORT_ID(rs.getString("PORT_ID"));
creDTOlist.add(creDTO);
}
}
System.out.println("creDTOlist size:"+creDTOlist.size());
//create URL for the schema name
int m=creDTOlist.size();
Iterator<CredentialDTO> LItr= creDTOlist.iterator();
String [] username1=new String[m];
String [] password1=new String[m];
i=0;
while(LItr.hasNext()){
System.out.println("iteration "+i);
CredentialDTO temp = LItr.next();
String URL="jdbc:oracle:thin:#"+temp.getHOST_NAME()+":"+temp.getPORT_ID()+":"+temp.getORACLE_SID();
System.out.println("URL:"+URL);
username1[i]=temp.getSCHEMA_NAME();
System.out.println("iteartion "+i+" username="+username1[i]);
password1[i]=temp.getPASSWORD();
System.out.println("iteartion "+i+" password="+password1[i]);
Class.forName("oracle.jdbc.OracleDriver");
con[i]=DriverManager.getConnection(URL, username1[i], password1[i]);
System.out.println("Connection Name:" +con[i]);
Statement st1=con[i].createStatement();
con[i].setAutoCommit(false);
st1.addBatch(query1);
st1.addBatch(query2);
int [] update=st1.executeBatch();
i++;
}
}
catch(Exception ex){
ex.printStackTrace();
}finally
{
if (conn != null) try{conn.close();} catch(SQLException ignore) {}
if (stmt!= null) try{stmt.close();} catch(SQLException ignore) {}
if (rs != null) try{rs.close();} catch(SQLException ignore) {}
}
return creDTOlist;
}
}

Java SQL PreparedStatement UPDATE with optional attributes

I'm writing a Java GUI application which uses a MySQL database. In this application the users can see a JTable with the rows of DB's table and modify the attributes of a selected row with a form. I'd like to update only the modified attributes of the row. I know I have to specify every SQL table's column in the String command if I use PreparedStatement and placeholders
String command = "UPDATE table SET attr0 = ?, attr1 = ? WHERE id = ?";
PreparedStatement statement = connection.prepareStatement(command);
but It's not what I'm looking for. Moreover, my DB's table has many columns, so I can't use different String commands for every combination of attributes.
Can someone help me? Thanks.
Unfortunately with straight JDBC, the best you can do is build the SET clause dynamically (see rough code sample below). JDBC can't handle optional parameters and will throw an Exception if not all parameters are bound before executing.
`
// 'columns' assumed a Map
// 'id' to be a String
List<String> setClauses = new ArrayList<String>();
for (String key : columns.keySet()) {
setClauses.add(String.format("%s=?", key));
}
// StringUtils is from Apache Commons Lang
// although it's pretty easy to build your own join routine.
String command = String.format("UPDATE table SET %s WHERE id=?"
, StringUtils.join(setClauses, ",")
);
PreparedStatement statement = connection.prepareStatement(command);
int p = 1;
for (String key : columns.keySet()) {
statement.setString(p++, columns.get(key));
}
statement.setString(p++, id);
`
JDBC also doesn't have named parameters either so this is why you have to do the incrementing. If you are able to do it, I would recommend investigating Hibernate (which allows to work with JavaBeans) or Spring JDBCTemplate (which does have named parameters).

Categories

Resources