Single thread writing to different database with different connection parameters - java

I am working on a project in which I have three tables in a different database with different schemas. So that means I have three different connection parameters for those three tables to connect using JDBC-
Let's suppose-
For Table1-
Username:- A
Password:- B
URL: C
Columns-
ID1 String
Account1 String
For Table2-
Username:- P
Password:- Q
URL:- R
Columns-
ID2 String
Account2 String
For Table3-
Username:- T
Password:- U
URL:- V
Columns-
ID3 String
Account3 String
And I am supposed to insert in all the three tables or any one of them using JDBC.
Below are the three use cases I have-
From the command prompt if suppose I am passing Table1 only, then I am suppose to insert only in Table1 columns by making connection to
Table1.
And if I am passing Table1, Table2 from the command prompt then I am suppose to insert in both Table1 and Table2 columns by making
connection to Table1 and Table2.
And if I am passing Table1, Table2 and Table3 then I am suppose to enter in all the three tables using there respective connection
parameter
I am not able to understand how to write code for the above particular scenario in such a cleaner way so that it can be extended in near future as well if I come up with four tables. I can have a one constant file which can store the SQL that needs to be executed for any of the three tables and some other constant thing as well.
public static void main(String[] args) {
}
class Task implements Runnable {
private Connection dbConnection = null;
private PreparedStatement preparedStatement = null;
public Task() {
}
#Override
public void run() {
dbConnection = getDbConnection();
//prepare the statement and execute it
}
}
private Connection getDBConnection() {
Connection dbConnection = null;
Class.forName(Constants.DRIVER_NAME);
dbConnection = DriverManager.getConnection( , , );
return dbConnection;
}
Can anyone provide some thoughts on this how should I proceed forward?
Note:-
Column in each table will differ a lot. Like in some tables, column can be 10 and in some other table, column can be 20.

Create databases.properties file with content like this:
# Table 1
table1.url: jdbc:mysql://localhost:3306/garden
table1.user: gardener
table1.password: shavel
table1.table: fruits
table1.column.id: fruitID
table1.column.color: fruitColor
table1.column.weight: fruitWeight
# ... More fruit columns here ...
# Table 2
table2.url: jdbc:mysql://otherhost:3306/forest
table2.user: forester
table2.password: axe
table2.table: trees
table2.column.id: treeID
table2.column.height: treeHeight
# ... More tree columns here ...
# ... More tables here ...
Then do something like this:
public static void main (String [] args)
{
Properties databasesProperties = new Properties ();
databasesProperties.load ("databases.properties");
for (String arg: args)
{
String url = databasesProperties.get (arg + ".url");
String user = databasesProperties.get (arg + ".user");
String password= databasesProperties.get (arg + ".password");
String table = databasesProperties.get (arg + ".table");
String columnPrefix = arg + ".column."
Map <String, String> columns = new HashMap <String, String> ();
for (String key: databasesProperties.stringPropertyNames ())
{
if (key.startsWith (columnPrefix))
columns.put (
key.substring (columnPrefix.length ()),
databasesProperties.get (key));
}
doInsert (url, user, password, table, columns);
}
}
Later you can always add more tables into your databases.properties file.

Save your Database properties in a class file DBPropery.java.
final class DBProperty
{
static String[] urls = {
"C",
"R",
"V"
}; //You can add more URLs here.
static String[] driver= {
"Driver1",
"Driver2",
"Driver3"
};//You can add more drivers string
static String[] table = {
"Table1",
"Table2",
"Table3"
};//You can add more table names here According to URLs mentioned in urls array.
static String[] user = {
"A",
"P",
"T"
};//You can add more user names here according to URls mentioned in urls array.
static String[] pwd = {
"B",
"Q",
"U"
};//You can add more Password here according to URls mentioned in urls array.
static String[] queries = {
"Query for Table1",
"Query for Table2",
"Query for Table3",
};//You can add more queries here for more tables according to URls mentioned in urls array.
static int[] columns ={
2,
2,
2
};//You can change the column numbers according to need . 0th index belongs to Table1 , 1 to table2....so on.
//If you add more tables , add corresponding columns count to next index.
static String[] columnValues ={
"1^John",
"34^Vicky",
"65^Ethen"
};//String at each index represents a row in corresponding table in table[] array. each column is seperated by delimiter "^".
}
Make all Changes in DBProperty.java file.
Then proceed with following class file
import java.sql.*;
import java.util.*;
class MultiTableInsert implements Runnable
{
Map<String,Integer> columnsInTable;
Map<String,String> tableDriver;
Map<String,String> rowForTable;
Map<String,String> queryForTable;
Map<String,String> urlForTable;
Map<String,String> userForTable;
Map<String,String> pwdForTable;
String[] tables ;
public MultiTableInsert(String... tables)//Loading all Database Settings here..
{
this.tables = tables;
columnsInTable = new LinkedHashMap<String,Integer>();
rowForTable = new LinkedHashMap<String,String>();
tableDriver = new LinkedHashMap<String,String>();
urlForTable = new LinkedHashMap<String,String>();
userForTable= new LinkedHashMap<String,String>();
pwdForTable = new LinkedHashMap<String,String>();
for (int i = 0 ; i < DBProperty.urls.length ; i++ )
{
try
{
tableDriver.put(DBProperty.table[i],DBProperty.driver[i]);
queryForTable.put(DBProperty.table[i],DBProperty.queries[i]);
columnsInTable.put(DBProperty.table[i],DBProperty.columns[i]);
rowForTable.put(DBProperty.table[i],DBProperty.columnValues[i]);
urlForTable.put(DBProperty.table[i],DBProperty.urls[i]);
userForTable.put(DBProperty.table[i],DBProperty.user[i]);
pwdForTable.put(DBProperty.table[i],DBProperty.pwd[i]);
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
}
#Override
public void run()
{
insertIntoTable(tables);
}
private void insertIntoTable(String... tables)
{
for (String tble : tables )
{
Connection con = null;
PreparedStatement pStmt = null;
try
{
Class.forName(tableDriver.get(tble));
con = DriverManager.getConnection(urlForTable.get(tble),userForTable.get(tble),pwdForTable.get(tble));
pStmt = con.prepareStatement(queryForTable.get(tble));
int columns = columnsInTable.get(tble);
String sRow = rowForTable.get(tble);
StringTokenizer tokenizer = new StringTokenizer(sRow,"^");
for (int i = 0; i < columns ; i++)
{
pStmt.setString(i+1,(String)tokenizer.nextElement());
}
pStmt.execute();
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
try
{
con.close();
}catch (Exception ex){}
try
{
pStmt.close();
}catch (Exception ex){}
}
}
}
public static void main(String[] args)
{
int length = args.length;
int THREAD_COUNTS = 10;//Number of threads you want to start.
switch (length)
{
case 0:
System.out.println("Usage: javac MultiTableInsert Table1/Table2/Table3 <Table1/Table2/Table3> <Table1/Table2/Table3>");
System.exit(0);
case 1:
for (int i = 0 ; i < THREAD_COUNTS ; i++)
{
MultiTableInsert mti = new MultiTableInsert(args[0]);
Thread th = new Thread(mti,"Thread"+i);//Create New Thread
th.start(); //Start Thread
}
break;
case 2:
for (int i = 0 ; i < THREAD_COUNTS ; i++)
{
MultiTableInsert mti = new MultiTableInsert(args[0],args[1]);//Create New Thread
Thread th = new Thread(mti,"Thread"+i); //Start Thread
th.start();
}
break;
default:
for (int i = 0 ; i < THREAD_COUNTS ; i++)
{
MultiTableInsert mti = new MultiTableInsert(args[0],args[1],args[2]);//Create New Thread
Thread th = new Thread(mti,"Thread"+i); //Start Thread
th.start();
}
break;
}
}
}

Related

Can we Replace a portion of String in Java which has symbol in the start and end to Identify?

I have a String SELECT *FROM USERS WHERE ID = '#userid#' AND ROLE = '#role#'
Now i have replace any string between #...# , with a actual value .
Expected output SELECT *FROM USERS WHERE ID = '4' AND ROLE = 'Admin'
This replace will happen from a method , i have written this logic
public String replaceQueryKeyWithValueFromKeyValues(String query, int reportId) {
try {
REPMReportDao repmReportDao = new REPMReportDao();
int Start = 0;
int end;
if (query.contains("#")) {
boolean specialSymbolFound = false;
for (int i = 0; i < query.length(); i++) {
if (query.charAt(i) == '#') {
if (!specialSymbolFound) {
Start = i + 1;
specialSymbolFound = true;
} else {
specialSymbolFound = false;
end = i;
query = query.replace(query.substring(Start - 1, end + 1), repmReportDao.getReportManagerKeyValue(query.substring(Start - 1, end + 1).replaceAll("#", ""), reportId));
}
}
}
return query;
} else {
return query;
}
} catch (Exception e) {
logger.log(Priority.ERROR, e.getMessage());
return e.getMessage();
}
}
It works fine , but in the case if a single '#' symbol exist instead of start and end it will fail.
Like :
SELECT *FROM USERS WHERE emailid = 'xyz#gmail.com' AND ROLE = '#role#'
Here it should replace the only role '#role#' and should left email as it is.
Expected Output => SELECT *FROM USERS WHERE emailid = 'xyz#gmail.com' AND ROLE = 'Admin'
Complete example with mocked data returned by getReportManagerKeyValue:
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class StackOverflow54842971 {
private static Map<String, String> map;
public static void main(String[] args) {
// preparing test data
map = new HashMap<>();
map.put("role", "Admin");
map.put("userid", "666");
// original query string
String query = "SELECT * FROM USERS WHERE ID = '#userid#' AND emailid = 'xyz#gmail.com' AND ROLE = '#role#' ";
// regular expression to match everything between '# and #' with capture group
// omitting single quotes
Pattern p = Pattern.compile("'(#[^#]*#)'");
Matcher m = p.matcher(query);
while (m.find()) {
// every match will be replaced with value from getReportManagerKeyValue
query = query.replace(m.group(1), getReportManagerKeyValue(m.group(1).replaceAll("#", "")));
}
System.out.println(query);
}
// you won't need this function
private static String getReportManagerKeyValue(String key) {
System.out.println("getting key " + key);
if (!map.containsKey(key)) {
return "'null'";
}
return map.get(key);
}
}
It's considered very bad practice to use string substitution to generate database queries, because you leave your code open to SQL Injection attacks. I can't tell from the small code sample you've provided, but the vast majority of large-scale Java projects use the Spring Framework, which allows you to use either JdbcTemplate or (my preference) NamedParameterJdbcTemplate. Both will allow you to substitute variables in a safe manner.

Insert Multiple Rows realm android

Hello ive been trying to insert multiple rows to my realm database using values from arraylists , whenever i try to insert through a for loop it only adds the last one, if you need something else (code, xml) pls let me know
here is my code:
realm.executeTransactionAsync(new Realm.Transaction() { //ASYNCHRONOUS TRANSACCION TO EXECUTE THE QUERY ON A DIFFERENT THREAD
#Override
public void execute(Realm bgRealm) {
// increment index
Invoices inv = bgRealm.createObject(Invoices.class, RealmController.autoincrement(bgRealm, Invoices.class)); //METHOD THAT GIVES US THE AUTONINCREMENTE FUNCTION
//inv.id = nextId; //THE 2ND PARAMETER IN CREATE OBJECTE DEFINES THE PK
//...
//realm.insertOrUpdate(user); // using insert API
inv.number = n;
inv.serial = s;
inv.client = c;
inv.subtotal = sub;
inv.tax = tax;
inv.total = tot;
Invoice_lines invl = bgRealm.createObject(Invoice_lines.class, RealmController.autoincrement(bgRealm, Invoice_lines.class));//ID FROM ANOHTER TABLE (ROW)
for(int i=0; i<price.size(); i++) {
invl.description = description.get(i);
invl.price = price.get(i);
invl.quantity = quantity.get(i);
invl.invoice = inv;
bgRealm.insert(invl);
}
}
}
I'm not sure. You create only one realm object in this line:
Invoice_lines invl = bgRealm.createObject(Invoice_lines.class, RealmController.autoincrement(bgRealm, Invoice_lines.class));//ID FROM ANOHTER TABLE (ROW)
And in cycle you change invl fields, but don't insert new objects.
Try to create objects inside cycle.
Because what you wanted to do is
Invoice_lines invl = new Invoice_lines(); // unmanaged object
for(int i = 0; i < price.size(); i++) {
inv1.setId(RealmController.autoincrement(bgRealm, Invoice_lines.class));//ID FROM ANOHTER TABLE (ROW)
invl.description = description.get(i);
invl.price = price.get(i);
invl.quantity = quantity.get(i);
invl.invoice = inv;
bgRealm.insert(invl);
}

returning 2 different values

i'm working with java in eclipse.I am trying to take 2 variables from my database and write it to an excel.My only problem is returning 2 different values(an integer and a string) from db reader method and send it to excel writer method which are in different classes.
Here is my db reader class:
public class DbConnection {
public void createConnection(String choice) {
try {
String myDriver = "com.mysql.jdbc.Driver";
String db = "jdbc:mysql://localhost/digiturkschema";
Class.forName(myDriver);
Connection conn = DriverManager.getConnection(db, "root",
"*****");
Statement st = conn.createStatement();
switch (choice) {
case "write":
ResultSet rs = st.executeQuery("SELECT * FROM channelstable");
while (rs.next()) {
int channelId = rs.getInt("channelNo");
String channelName = rs.getString("channelName");
}
}
} catch (Exception exception) {
System.out.print(exception.getStackTrace());
}
}
}
I need to return "channelId" and "channelName" from this method to this method:
public class WritingToExcel {
public void Write() throws IOException {
try {
JFileChooser f = new JFileChooser();
f.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
f.showSaveDialog(null);
System.out.println(f.getCurrentDirectory());
System.out.println(f.getSelectedFile());
String direction = f.getSelectedFile().toString() + "\\DigiTurkKanalListesi.xls";
WritableWorkbook workbook = Workbook.createWorkbook(new File(direction));
WritableSheet sheet = workbook.createSheet("Kanal Listesi", 0);
Label label = new Label(0, 0, "A label record");
sheet.addCell(label);
Number number = new Number(2, 1, 3.1459);
sheet.addCell(number);
workbook.write();
workbook.close();
} catch (WriteException e) {
e.getStackTrace();
}
}}
I know that writingToExcel class is not completed and it's ok,i can finish it if i can take these two variables to this class.By the way i am using MVC pattern so i have a controller class between them.I can write it too if it's necessary.
As #Ascalonian said, you can use Map or HashMap.
for example:
Map<Integer, String> channelInfo = new HashMap<Integer, String>();
You can also (but should not):
Create a new class with the values you need and return that class. (You will be doing extra work which you don't really need to.)
Create setter methods for those variables and use it before calling the method to write to excel. (requires caution as you can end up with undesired values if you mess the code)
There are multiple options
ArrayList<Objects> : During Iterating the resultSet prepare temporary List say tempList insert items into tempList and then after each iteration add tempList to Main List , Since ArrayList is a sequential list. So, insertion and retrieval order is the same. So you can return this from your dbReader() method .Then use them wherever you want
Your Arraylist will look like this
[ [1,Channel 1] , [2,Channel 2] , [3,Channel 3] ]
Map if order is important prefer LinkedHashMap if order is not your primary concern then opt for HashMap

compare two arrayList and stock the result in a thirth arrayList

i want compare 2 arrayList when i stock in them the result of a class java of telnet
this class it's to telnet about a router and gives all of interfaces of this routers then stock them in the arrayList
so i stock the interfaces for the router1 in myData1 and the second in myData2
and i will compare if the interface of the first aray it's the same in the second just add one of them in the array of result myData
but it gives me anthing the code
public class Test {
public static void main(String[] args) {
Connection conn = null;
try {
conn = DriverManager.getConnection("jdbc:mysql://localhost/mohammedia", "root", "123456");
String sql = "SELECT * FROM router;";
Telnet_Interface telnet = new Telnet_Interface();
Telnet_Interface telnet1 = new Telnet_Interface();
Telnet_Interface telnet2 = new Telnet_Interface();
PreparedStatement prest = conn.prepareStatement(sql);
ResultSet res=prest.executeQuery();
while(res.next()){
telnet1.Config(res.getString(1), "user", "passwd", res.getString(1));
telnet2.Config(res.getString(2), "user", "passwd", res.getString(2));
}
ArrayList myData=new ArrayList();
ArrayList myData1=telnet1.getMyData();
ArrayList myData2=telnet2.getMyData();
boolean bool=false;
for(int i=0;i<myData1.size();i++)
{
for(int j=0;j<myData2.size();j++)
{
if (myData2.get(j).equals(myData1.get(i)))
{
bool=true;
//System.out.print("sdfsd");
}
if(!bool)
{
myData.add(myData2.get(j));
//System.out.print("sdsd");
}
}
}
for(int x=0;x<myData.size();x++)
{
System.out.print(myData.get(x));
}
} catch (SQLException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
what's the problem ??
thank you
You can just use ArrayList.retainAll method like this
list1.retainAll(list2)
after this method list1 will containt only the data which are available in list2.
(Not an answer) Separate all. Use logging and handle the exceptions.
If it is not a kind of dictionary attack, first do the SQL retrieving users with passwords.
Close result set, statement and connection.
Check the results.
Then get the telnet data.
Check the results.
Then do the comparison.
I hope you can see the deleted answer of #StinePike; he basically proposes list1.retainAll(list2) to remove all element in list1 that occur in list2.
I think you want to do the following. Outcommented is non-looping alternative.
// Add all myData2 and myData1 elements but not twice to myData.
// (1) Add myData2
myData.addAll(myData2);
// (2) Add myData1 when not in myData2
//myData1.removeAll(myData1);
//myData.addAll(myData1);
for (int i = 0; i < myData1.size(); i++)
{
boolean found = false;
for (int j = 0; j < myData2.size(); j++)
{
if (myData2.get(j).equals(myData1.get(i)))
{
found = true;
break;
}
}
if (!found)
{
myData.add(myData1.get(i));
}
}

Iterartor - How to traverse for specific records

I have executed a query using JDBC and traversing the resultset I have stored all fields in List in java.
List<String> dataList=new ArrayList<String>();
while(res.next())
{
dataList.add(res.getString(1));
dataList.add(res.getString(2));
dataList.add(res.getString(3));
dataList.add(res.getString(4));
dataList.add(res.getString(5));
dataList.add(res.getString(6));
dataList.add(res.getString(7));
}
Iterator<String> it= dataList.iterator();
As I have added directly into list so how can I get this 7 fields while traversing the iterator.
Means:
while(it.hasNext())
{
String f1=it.next();
}
Like wise everytime I want 7 fields at a time
and next 7, next 7....... so on
Using this while loop how can I get those 7 fields (one row in table having 7 field) at a time.
I get little bit confuse here. Please help me.
Thanks
What you want to do is actually create another object that stores all seven of the values.
Then create a list of these entries so that you can access one row at a time, which is what I think you are asking.
First create a class for the row.
private static class Entry {
String[] row;
public Entry ( ResultSet r ) {
row = new String [ 7 ];
for (int i = 1; i <= 7; i++) {
row[i] = r.getString(i);
}
}
}
Using that, you can then create a list of Entry objects.
List<Entry> entryList = new ArrayList <Entry> ();
while(res.next())
{
entryList.add ( new Entry ( res ) );
}
Then, you can go ahead and loop through entryList and get any specific entry you would want.
Of course, if you have specific values, it might be wise to create instance variables of type String for Entry rather than an array of Strings.
By that I mean you could do this:
private static class Entry {
String column1; // rather than name column1 use what the column semantically represents
String column2;
// ...
public Entry ( ResultSet r ) {
column1 = r.getString(1);
// ...
}
This way, you can also calls like r.getInt(i) for certain columns which have an different type other than String.
Good luck!
I think your List declaration should be
List<Any DAO Object> instead of List<String>
While fetching from resultset, create a DAO object, add all fetched data into that object and then add that object into the list.
Then you can iterate and get each DAO object at each iteration.
You can use DatabaseMetaData class,
private static final String DRIVER = "com.mysql.jdbc.Driver";
private static final String URL = "jdbc:mysql://localhost/testdb";
private static final String USERNAME = "root";
private static final String PASSWORD = "";
public static void main(String[] args) throws Exception {
Class.forName(DRIVER);
Connection connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);
DatabaseMetaData metadata = connection.getMetaData();
ResultSet resultSet = metadata.getColumns(null, null, "users", null);
while (resultSet.next()) {
String name = resultSet.getString("COLUMN_NAME");
String type = resultSet.getString("TYPE_NAME");
int size = resultSet.getInt("COLUMN_SIZE");
System.out.println("Column name: [" + name + "]; type: [" + type + "]; size: [" + size + "]");
}
connection.close();
}

Categories

Resources