How to create multiple schema connections at runtime? - java

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;
}
}

Related

JDBC table existence check issue on MySQL

Using the many solutions online I have implemented the following method to check whether the table exists on database or not:
private static boolean tableExists( Connection connection, String schema, String tableName ) throws SQLException {
DatabaseMetaData meta = connection.getMetaData();
ResultSet resultSet = meta.getTables( null, schema, tableName, new String[]{"TABLE"} );
return resultSet.next();
}
This works fine for SQL Server and PostgreSQL, but has a very weird issue with MySQL: if I create two databases that are accessed by the same user, e.g. like this:
create user 'test_user'#'localhost' identified by '123456';
create database first_db;
grant all privileges on first_db.* to 'test_user'#'localhost' with grant option;
create database second_db;
grant all privileges on second_db.* to 'test_user'#'localhost' with grant option;
and add a table for example test_table inside first_db, but do not create it inside second_db (so second_db is empty and first_db has test_table table inside it)
And then make a Connection to the second_db (jdbc:mysql://localhost:3306/second_db) and call my method to see whether it has a table with name test_table (it shouldn't). But the response is true! If I access second_db with another user, the method seems to work correctly though.
Is there something I'm doing wrong? Obviously I can just use separate users if I have multiple databases with the same tables but I would like to understand what causes this behaviour.

How can I display, using Java, my databases?

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)

can I set autocommit to ON while using savepoints

I am a newbiee to Java database programming.
Recently during my project, I have got stuck in a concept, which I searched a lot but not getting any solution to satisfy my query, which may help me to get out of my problem.
Actually the problem is:
I have three table, let say one main (which contains common fields of actual data) table and two child table(which contains other different fields according to some criteria). Main table contain some part of information, and rest of information, depending on some criteria, will be saved in only one of the child table.
Now the scenario is like this, I have set autocommit off, then firing one insert query. So, when the insert query will be fired, database will give it a unique ID, in mysql, since the ID feild is autoIncrement. Now firing a Select Query, I want to extract that ID from main table. So, here is my question, Will SELECT QUERY BE ABLE TO EXTRACT THE ID OF THAT PARTICLULAR RECORD I HAVE JUST SAVED? Please remember that autocommit is set to false, and I have not committed yet.
I am doing this because I want that unique ID to be inserted in one of the child tables so that I can relate the information between table. So, After finding the ID, I have again fired a new INSERT query to save rest of the data in one of the child tables, now with the unique ID with rest of the data. And then on successful insertion, I have committed the connection.
Also, I want that either the information is saved in both (main and one of the child) tables or the details does not saves completely if any failure occur, so that I do not lose the partial information.
Please Help me in this. If you can explain what is relation between autocommit, savepoints. When to use, what things are to be remembered. Please provide some genuine resources, if you can, which demonstrate their nature,how they work under different circumstances, etc. I have googled but didn't got any such useful information. I want to get deep knowledge about it.
Thanks in advance :)
It looks like you want to get the ID when the record is added to the table. This is available when you insert the record if you use the getGeneratedKeys(). The autocommit cannot be used to return this.
The following code shows how this can be done.
/**
* Insert to database using JDBC 3.0 + which will return the key of the new row.
*
* #param sql is the sql insert to send to the database
* #return the key for the inserted row
* #throws DBSQLException
*/
public static int insertAndReturnKey(Connection dbConnection, String sql, List<SqlField> params) throws DBSQLException
{
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
String paramList = null;
try {
preparedStatement = dbConnection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
// Setup your parameters
int result = preparedStatement.executeUpdate();
resultSet = preparedStatement.getGeneratedKeys();
if (resultSet.next()) {
return (resultSet.getInt(1));
} else {
// throw an exception from here
throw new SQLException("Failed to get GeneratedKey for [" + sql + "]");
}
} catch (SQLException ex) {
throw new DBSQLException(buildErrorMessage(ex, sql, params));
} finally {
DBConnector.closeQuietly(preparedStatement);
DBConnector.closeQuietly(resultSet);
}
}

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.

Categories

Resources