I m writing junit test cases for JDBC connection for Oracle (OJDBC6.jar). Below is my code
public void insertCard(){
Properties prop= new Properties();
properties.put("user","user");
properties.put("password","password");
properties.put("driver","com.oracle.OracleDriver")
Connection con = DriverManager.getConnection (
"jdbc:oracle:thin:#localhost:1521:orcl",properties);
PreparedStatement insertCardValues = con.prepareStatement(
"insert into card values(?,?,?)");
insertCardValues.setInt(1,123);
insertCardValues.setName(2,"Raja");
insertCardValues.setAddress(3, "Lucknow");
insertCardValues.executeUpdate();
}
}
Can someone help me to test below code
Connection con = DriverManager.getConnection (
"jdbc:oracle:thin:#localhost:1521:orcl","properties);
Please, first of all I'd suggest to you to separate concerns.
Create a separate object which it should be the responsible of returning to you a Connection. Maybe you could create your own Connection wrapper object to deal with the SQL Connection
Then the class which is using the responsible of inserting the card, can retrieve an opened connection in order to create statements.
Do not forget also to have a method to release the connection once the insertCard logic is finished (no matter if it was succeeded or not, is dangerous to leave opened connections against a database)
Once you have refactored your code, you could easily cover it with unit tests using Mockito. But firstly I think you need to do a refactor, testing otherwise will be painful
Related
Can anyone please provide advice on how to enlist in an MVCC session from SSIS?
Reading from an Ingres DB, we have a requirement to enable MVCC and specify the isolation level from within an SSIS 2008 R2 package.
An existing application exists over this database, that DOES NOT use MVCC, and hence it is not appropriate to simply enable MVCC on the existing DBMS. The reason we want our reads to enlist in MVCC is to ensure we do not cause locks and break this existing application (as is currently periodically happening when we do not use MVCC to perform these reads).
DB version is Ingres II 10.0.0 (su9.us5/132)
ADO.NET driver version is Ingres.Client.IngresConnection, Ingres.Client, Version=2.1.0.0 driver,
We have a similar requirement to do so programmatically from within Tibco BusinessWorks, and interactively via eg SQL Squirrel, and meet this need by issuing the following commands via direct SQL execution (via JDBC):
SET LOCKMODE SESSION WHERE LEVEL = MVCC;
SET SESSION ISOLATION LEVEL READ COMMITTED;
In SSIS we can set the session isolation level using the IsolationLevel property of the task/sequence. But I can find no means of issuing the MVCC command directly.
I have attempted to issue the command via an Exceute SQL Task step, but I encounter the following error:
Syntax error on line 1. Last symbol read was: 'SET LOCKMODE'
What I've tried, to no avail:
With or without the terminating ;
Execute step placed within or outside of a sequence
Enabled the DelayValidation property, at both the sequence and step level
Various TransactionOption settings at the sequence and task level (in case they mattered!)
Setting the lockmode via a windows environment variable ING_SET = "SET LOCKMODE SESSION WHERE LEVEL = MVCC". But my testing shows this is not honoured by the ADO.NET driver we're using in SSIS (nor, incidentally, is it honoured by the JDBC driver we use for SQL Squirrel or Tibco). I believe this is probably an ODBC feature.
Issuing the command from within an ADO.NET source step within a dataflow. Same syntax error.
[UPDATE] Had also tried wrapping the SET ... commands in an Ingres procedure, but this resulted in syntax errors suggesting the SET ... command is not valid anywhere within a procedure.
Can anyone please provide advice on how to enlist in an MVCC session from SSIS?
At this stage (I believe) we're constrained to the ADO.NET driver, but if there's no other option that to go with ODBC then so be it.
Answering my own question here.
Two possible approaches were conceived.
1. Use a Script Component (within a Data Flow step)
From within a script component, I was able to issue the SET ... commands directly via ADO.NET.
The problem with this approach was that I wasn't able to retain the connection on which these commands had been run, for subsequent (or parallel, within the same dataflow) ADO.NET source components.
Attempting to work via a specific connection via transactions was no good, because these commands must be issued outside of an ongoing transaction.
So ultimately I had to also issue the source select from within this component, which even then is less than ideal as the subsequent destination insert operation could then not enlist in the same transaction as the source select.
The solution using this approach ended up being:
- Using MVCC, copy the data from a source view, into a temp staging table on the source system.
- Then using a transaction, read from the source staging table into the destination system.
Code looks something like this (NB had to explicitly add a reference to Ingres .NET Data Provider\v2.1\Ingres.Client.dll
/* Microsoft SQL Server Integration Services Script Component
* Write scripts using Microsoft Visual C# 2008.
* ScriptMain is the entry point class of the script.*/
using System;
using System.Data;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using Microsoft.SqlServer.Dts.Runtime.Wrapper;
using Ingres.Client;
using System.Collections.Generic;
[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
public class ScriptMain : UserComponent
{
private bool debug = true;
private IDTSConnectionManager100 cm;
private IngresConnection conn;
public override void AcquireConnections(object Transaction)
{
// The connection manager used here must be configured in the Script Component editor's "Connection Managers" page.
// "Connection" is the (default) strongly typed name for the first connection added.
// In this case, it needs to be a reference to the xxxxx connection manager (by convention it should be "xxxxx_ADONET").
cm = this.Connections.Connection;
conn = (IngresConnection)cm.AcquireConnection(Transaction);
}
public override void PreExecute()
{
debugMessage("PreExecute", "Started");
base.PreExecute();
string viewName = Variables.vViewName;
IngresCommand cmdSetSessionLockMode = conn.CreateCommand();
IngresCommand cmdSetSessionIsolationLevel = conn.CreateCommand();
IngresCommand cmdReaderQuery = conn.CreateCommand();
List<string> sqlCommandStrings = new List<string>();
if (Variables.vUseIngresMVCC)
{
sqlCommandStrings.Add("SET LOCKMODE SESSION WHERE LEVEL = MVCC");
}
sqlCommandStrings.Add("SET SESSION ISOLATION LEVEL READ COMMITTED");
sqlCommandStrings.Add(String.Format("MODIFY {0}_STAGING TO TRUNCATED", viewName));
sqlCommandStrings.Add(String.Format("INSERT INTO {0}_STAGING SELECT * FROM {0}", viewName));
foreach (string sqlCommandString in sqlCommandStrings)
{
debugMessage("PreExecute", "Executing: '{0}'", sqlCommandString);
IngresCommand command = conn.CreateCommand();
command.CommandText = sqlCommandString;
int rowsAffected = command.ExecuteNonQuery();
string rowsAffectedString = rowsAffected >= 0 ? rowsAffected.ToString() : "No";
debugMessage("PreExecute", "Command executed OK, {0} rows affected.", rowsAffectedString);
}
debugMessage("PreExecute", "Finished");
}
public override void CreateNewOutputRows()
{
// SSIS requires that we output at least one row from this source script.
Output0Buffer.AddRow();
Output0Buffer.CompletedOK = true;
}
public override void PostExecute()
{
base.PostExecute();
// NB While it is "best practice" to release the connection here, doing so with an Ingres connection will cause a COM exception.
// This exception kills the SSIS BIDS designer such that you'll be unable to edit this code through that tool.
// Re-enable the following line at your own peril.
//cm.ReleaseConnection(conn);
}
private void debugMessage(string method, string messageFormat, params object[] messageArgs)
{
if (this.debug)
{
string message = string.Format(messageFormat, messageArgs);
string description = string.Format("{0}: {1}", method, message);
bool fireAgain = true;
this.ComponentMetaData.FireInformation(0, this.ComponentMetaData.Name, description, "", 0, ref fireAgain);
}
}
}
Answering my own question here.
Two possible approaches were conceived.
2. Set up a dedicated MVCC-enabled process of the Ingres DBMS over the existing database, and connect via this
This is the approach we're currently pursuing (as it is supported, and ideally transparent). I will update with details once they are known.
using:
Python 2.7.3
SQLAlchemy 0.7.8
PyODBC 3.0.3
I have implemented my own Dialect for the EXASolution DB using PyODBC as the underlying db driver. I need to make use of PyODBC's output_converter function to translate DECIMAL(x, 0) columns to integers/longs.
The following code snippet does the trick:
pyodbc = self.dbapi
dbapi_con = connection.connection
dbapi_version = dbapi_con.getinfo(pyodbc.SQL_DRIVER_VER)
(major, minor, patch) = [int(x) for x in dbapi_version]
if major >= 3:
dbapi_con.add_output_converter(pyodbc.SQL_DECIMAL, self.decimal2int)
I have placed this code snippet in the initialize(self, connection) method of
class EXADialect_pyodbc(PyODBCConnector, EXADialect):
Code gets called, and no exception is thrown, but this is a one time initialization. Later on, other connections are created. These connections are not passed through my initialization code.
Does anyone have a hint on how connection initialization works with SQLAlchemy, and where to place my code so that it gets called for every new connection created?
This is an old question, but something I hit recently, so an updated answer may help someone else along the way. In my case, I was trying to automatically downcase mssql UNIQUEIDENTIFIER columns (guids).
You can grab the raw connection (pyodbc) through the session or engine to do this:
engine = create_engine(connection_string)
make_session = sessionmaker(engine)
...
session = make_session()
session.connection().connection.add_output_converter(SQL_DECIMAL, decimal2int)
# or
connection = engine.connect().connection
connection.add_output_converter(SQL_DECIMAL, decimal2int)
I am using hibernate to connect to a mysql database.
My saveOrUpdate method is :
public void saveOrUpdate(T t){
Session session = HibernateUtil.getSession();
Transaction transaction = session.beginTransaction();
session.saveOrUpdate(t);
transaction.commit();
}
I used this method actually for about half year, it worked well.
But now when I do junit test using this method, it seems suck.
I do saveOrUpdate first and then use Criteria to query, it gets the result seems to be right, but in database nothing actually changed.
Could anyone please give me any hint about what's happening here?
Thank you very much.
What is your JUnit configuration set to for transactions? I believe it is set to rollback all the transactions in the test. It should rightly be so, as after a test the database should be put back into a consistent/known state. The correctness of your code should rely on how you write the test and not the records being physically present in the database.
This is a sample code I'd like to run:
for i in range(1,2000):
db = create_engine('mysql://root#localhost/test_database')
conn = db.connect()
#some simple data operations
conn.close()
db.dispose()
Is there a way of running this without getting "Too many connections" errors from MySQL?
I already know I can handle the connection otherwise or have a connection pool. I'd just like to understand how to properly close a connection from sqlalchemy.
Here's how to write that code correctly:
db = create_engine('mysql://root#localhost/test_database')
for i in range(1,2000):
conn = db.connect()
#some simple data operations
conn.close()
db.dispose()
That is, the Engine is a factory for connections as well as a pool of connections, not the connection itself. When you say conn.close(), the connection is returned to the connection pool within the Engine, not actually closed.
If you do want the connection to be actually closed, that is, not pooled, disable pooling via NullPool:
from sqlalchemy.pool import NullPool
db = create_engine('mysql://root#localhost/test_database', poolclass=NullPool)
With the above Engine configuration, each call to conn.close() will close the underlying DBAPI connection.
If OTOH you actually want to connect to different databases on each call, that is, your hardcoded "localhost/test_database" is just an example and you actually have lots of different databases, then the approach using dispose() is fine; it will close out every connection that is not checked out from the pool.
In all of the above cases, the important thing is that the Connection object is closed via close(). If you're using any kind of "connectionless" execution, that is engine.execute() or statement.execute(), the ResultProxy object returned from that execute call should be fully read, or otherwise explicitly closed via close(). A Connection or ResultProxy that's still open will prohibit the NullPool or dispose() approaches from closing every last connection.
Tried to figure out a solution to disconnect from database for an unrelated problem (must disconnect before forking).
You need to invalidate the connection from the connection Pool too.
In your example:
for i in range(1,2000):
db = create_engine('mysql://root#localhost/test_database')
conn = db.connect()
# some simple data operations
# session.close() if needed
conn.invalidate()
db.dispose()
I use this one
engine = create_engine('...')
with engine.connect() as conn:
conn.execute(text(f"CREATE SCHEMA IF NOT EXISTS...")
engine.dispose()
In my case these always works and I am able to close!
So using invalidate() before close() makes the trick. Otherwise close() sucks.
conn = engine.raw_connection()
conn.get_warnings = True
curSql = xx_tmpsql
myresults = cur.execute(curSql, multi=True)
print("Warnings: #####")
print(cur.fetchwarnings())
for curresult in myresults:
print(curresult)
if curresult.with_rows:
print(curresult.column_names)
print(curresult.fetchall())
else:
print("no rows returned")
cur.close()
conn.invalidate()
conn.close()
engine.dispose()
I've got an app that uses EF CTP5.
In this particular situation, i need to degrade to some classic ADO.NET (in order to read multiple result sets in a stored procedure, which EF does not support).
As such, im trying to use the existing connection string from the EntityConnection object, like this:
var ctx = (this as IObjectContextAdapter).ObjectContext;
var efCon = ((EntityConnection) (ctx.Connection)).StoreConnection;
var con = new SqlConnection(efCon.ConnectionString);
con.Open(); // exception thrown
When i debug, i see that the ConnectionString does not contain the password, only the data source, username, database, etc.
Is this a security thing why they've removed it? Does EF hide the password somewhere and only use it when it executes stored procedures itself?
The EF connection string is not like classic ADO.NET connection strings, as it has metadata info.
So it looks like im going to have to strip out the part of the connection string that i need, put that in the web.config and pass it through to the Repository.
Surely there must be a better way!
Try adding "Persist Security Info=True;" to the context connection string. This worked for me.