I am using ServiceStack and OrmLite.Oracle. I connect to an old Oracle 7.3 instance using ODBC Driver for Oracle on a Windows Server 2012 x64. ODBC is setup as an ODBC32.
I connect and query the database from my repo like this:
using (IDbConnection db = _context.DbFactory.OpenDbConnection())
{
return db.Select<T>();
}
The _context hold the OrmLiteConnectionFactory which was created like this:
DbFactory= new OrmLiteConnectionFactory(conInfo.ConnectionString,false, ServiceStack.OrmLite.Oracle.OracleDialect.Provider);
My service is running just fine and I can access and query the database, no problem.
But after a certain period of time (30 minutes or so), the connection is lost and I have to restart my service (hosted in a Windows Service) because the call to Open the connection will give me this error: unable to allocate an environment handle.
It might be a normal thing to release the handle to the connection after a while but why it simply doesn't reconnect to it? From OrmLite code, I can see that OpenDbConnection should return a new instance of its connection when the AutoDisposeConnection is set to True or if the internal ormLiteConnection is null. I guess my connection is not null but not quite alive...
private OrmLiteConnection ormLiteConnection;
private OrmLiteConnection OrmLiteConnection
{
get
{
if (ormLiteConnection == null)
{
ormLiteConnection = new OrmLiteConnection(this);
}
return ormLiteConnection;
}
}
public IDbConnection OpenDbConnection()
{
var connection = CreateDbConnection();
connection.Open();
return connection;
}
public IDbConnection CreateDbConnection()
{
if (this.ConnectionString == null)
throw new ArgumentNullException("ConnectionString", "ConnectionString must be set");
var connection = AutoDisposeConnection
? new OrmLiteConnection(this)
: OrmLiteConnection;
return connection;
}
I have tried to set the AutoDisposeConnection to True but when I do, I always get an AccessViolationException saying "Attempted to read or write protected memory. This is often an indication that other memory is corrupt.". What does that mean? Is this an OS, ODBC or OrmLite error? Any idea why this is happening?
I have to say that because I am using Oracle 7.3, I had to recompile the ServiceStack.OrmLite.Oracle.dll so it uses the System.Data.Odbc rather than System.Data.OracleClient (only compatible with v8+).
I really want to avoid to test if the connection is alive or not at every call, so any help to make this work is greatly appreciated. Thanks
Related
I am working on a multithreaded wpf application I get "AccessViolationException" saying Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
in my ConnectionOpen().
my code is as follows.
public class DatabaseServices
{
static SQLiteConnection connection;
static object conLock = new object();
static object conCloseLock = new object();
public static SQLiteDataReader ConnectionOpen(string Query)
{
lock (conLock)
{
if (connection != null && connection.State != System.Data.ConnectionState.Open)
{
connection = new SQLiteConnection("Data Source=Database/abc.sqlite");
connection.Open();
}
else if (connection == null)
{
connection = new SQLiteConnection("Data Source=Database/abc.sqlite");
connection.Open();
}
SQLiteCommand mycommand = new SQLiteCommand(Query, connection);
SQLiteDataReader sqlite_datareader = mycommand.ExecuteReader();
return sqlite_datareader;
}
}
public static void ConnectionClose()
{
lock (conCloseLock)
{
connection.Close();
}
}
}
I've used lock as well for thread safe code but its not working.why?
The SQLiteConnection is not thread safe. Like all other database connections, you are supposed to open one per thread. The fact that your code has a few parts that won't work even if it were thread safe, does not help either. For example, anybody can close a connection, while somebody else is just querying on it.
Keep to the well-established patterns. Do not use database connections across threads. Do not write your own connection caching. Open a conection, do your work and then close it. If you definetly need connection caching, look into the documentation of your database and find out how the inbuilt mechanism works.
SQLite does not support Multiple Active ResultSets (MARS)
So you cannot have multiple DataReaders served by the same connection.
After connecting (and dropping the lock) you hand out a DataReader. I assume the client code calls this ConnectionOpen method twice resulting (or rather attempting) to re-use the same connection.
Create a connection per DataReader.
When you use connection pooling:
Data Source=c:\mydb.db;Version=3;Pooling=True;Max Pool Size=100;
connections will be recycled/pooled when closed properly. This will lessen the overhead of the creation and opening of the connections.
I am trying to connect to an Oracle Database using the java.sql.DriverManager in a JSF application. I am using a Tomcat v7 with ojdbc5.jar.
I have a very simple sample project that consists of nothing else than this piece of java code:
String url = "jdbc:oracle:thin:#DBSERV:DBPORT:DBSID";
String user = "account_admin";
String password = "my_assword";
Connection connection = null;
try {
Class.forName("oracle.jdbc.OracleDriver");
connection = DriverManager.getConnection(url, user, password);
connection.close();
} catch ..
...
Executed I get the following error:
java.lang.NoClassDefFoundError: Could not initialize class oracle.jdbc.driver.OracleDriver
Infact the class specified there "oracle.jdbc.driver.OracleDriver" is deprecated...and I can't change the Tomcat configuration. Therefore I specified "oracle.jdbc.OracleDriver" which loads just fine.
So the question is: Why does the DriverManager tries to load the "wrong" oracle driver, although I am loading another one?
I also tried as an alternative to Class.forName the following:
DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
That does not change anything though. I also checked for the registered drivers in the following way:
Enumeration<Driver> driverList = DriverManager.getDrivers();
while(driverList.hasMoreElements()){
Driver driver = driverList.nextElement();
System.out.println(driver.getClass().toString());
}
The output:
class sun.jdbc.odbc.JdbcOdbcDriver
class oracle.jdbc.OracleDriver
So the desired driver seems to be registered, no trace of the deprecated "oracle.jdbc.driver.OracleDriver".
Thank you for any help
My problem just disappeared when I restarted the container. I can't explain why that is though.
In my page consists of a repeater and bind some data using store procedure from SQL Server 2008.
rptTour.DataSource = GetData();
rptTour.DataBind();
Data binding GetData()
SqlCommand cmdSelectAllMatch = new SqlCommand("sp_sel_Tour", Global.conn);
SqlDataReader dtrSelectAllMatch = null;
Collection<TourBO> TourData = new Collection<TourBO>();
try
{
Global.connD2W.Open(); //error here, line 23
cmdSelectAllMatch.CommandType = System.Data.CommandType.StoredProcedure;
dtrSelectAllMatch = cmdSelectAllMatch.ExecuteReader();
while (dtrSelectAllMatch.Read())
{
TourBO Tour = new TourBO();
TourID = Convert.ToInt16(dtrSelectAllMatch[dtrSelectAllMatch.GetOrdinal("ID")]);
Tour.Name = dtrSelectAllMatch[dtrSelectAllMatch.GetOrdinal("Name")].ToString();
TourData.Add(Tour);
}
}
catch(Exception ex)
{
Global.Log(ex.ToString());
}
finally
{
Global.connD2W.Close();
}
if (dtrSelectAllMatch != null)
{
dtrSelectAllMatch.Close();
}
return TourData;
This is the sqlconnection that will be share among the entire application.
public static SqlConnection connD2W = new SqlConnection(ConfigurationManager.ConnectionStrings["D2WConnectionString"].ConnectionString);
It just read through all the data from data reader and assign into a custom collection and pass back to the repeater.
Everything working fine when i test by myself.
But when i run the Lost Test using Visual Studio (20 users and run for 2 minutes), i received errors below in my error log file(same error keep repeat)
Log Entry : 9:59:05 AM Thursday, November 07, 2013
:System.InvalidOperationException: The connection was not closed. The connection's current state is connecting.
at System.Data.ProviderBase.DbConnectionBusy.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
at System.Data.SqlClient.SqlConnection.Open()
at TourDAL.GetAllScheduledMatch() in c:\Documents\Visual Studio 2010\WebSites\test\App_Code\DAL\TourDAL.cs:line 23
Does it means this function not allowed multiple user to access it at the same time?
Any way to solve this?
If you're using a global connection (e.g. defined as a global variable or a static variable), that won't work in an environment where you have multiple threads running at the same time (e.g. in a web server).
The reason for it is all threads will go through the same code. The first one will open the connection and it will stay open for all the others as well.
It's best to define a connection locally, open and close it as soon as the job is done.
So, I recently inherited a large project that uses the following data access pattern; unfortunately, this is resulting in a massive number of timeout exceptions related to connection pooling.
Timeout expired. The timeout period elapsed prior to obtaining a
connection from the pool. This may have occurred because all pooled
connections were in use and max pool size was reached"
It clear that the connections are leaking and not getting closed properly.
So, the framework has a DataAccess class with the method GetDataReader.
When the data reader is referenced, it is placed inside a using block, but connections are still leaking.
Does the fact that the connection is not explicitly closed or placed in a using block the reason why the connections are getting leaked?
Normally, I would wrap the connection in a using block AND wrap the data reader in a using block.
Obviously, this framework is very flawed, but would somehow using the option CommandBehavior.CloseConnection for the data reader resolve this issue?
None the external code accesses the SqlConnection directly and has to go through this DataAccess class.
public IDataReader GetDataReader(QueryDto dto)
{
DateTime current = DateTime.Now;
Database db = DatabaseFactory.CreateDatabase(dto.DatabaseName);
DbCommand cmd = db.GetStoredProcCommand(dto.StoredProcedureName);
if (dto.Params.Length > 0)
{
cmd = db.GetStoredProcCommand(dto.StoredProcedureName, dto.Params);
}
dto.Command = cmd;
cmd.CommandTimeout = dto.Timeout;
cmd.Connection = db.CreateConnection();
try
{
cmd.Connection.Open();
}
catch (SqlException ex)
{
// Handle Exception here...
throw;
}
return rdr;
}
Usage in some static repository class:
var query = new QueryDto
{
DatabaseName = "SomeDatabase",
Params = parms,
StoredProcedureName = "StoredProcedureName"
};
using (IDataReader dr = dataAccess.GetDataReader(query))
{
while (dr.Read())
{
// do stuff here
}
}
I think your problem is that the using statement is around a function that has open resources embedded in it. The using will not dispose of the connection that is opened inside GetDataReader. I think your are correct that the Connection itself needs to be in a using block. The using statement only calls Dispose on the object that is passed in, not any nested resources.
Having this simple code I get "Cannot drop database "test_db" because it is currently in use" (CleanUp method) as I run it.
[TestFixture]
public class ClientRepositoryTest
{
private const string CONNECTION_STRING = "Data Source=.;Initial Catalog=test_db;Trusted_Connection=True";
private DataContext _dataCntx;
[SetUp]
public void Init()
{
Database.SetInitializer(new DropCreateDatabaseAlways<DataContext>());
_dataCntx = new DataContext(CONNECTION_STRING);
_dataCntx.Database.Initialize(true);
}
[TearDown]
public void CleanUp()
{
_dataCntx.Dispose();
Database.Delete(CONNECTION_STRING);
}
}
DataContext has one property like this
public DbSet<Client> Clients { get; set; }
How can force my code to remove database?
Thanks
The problem is that your application probably still holds some connection to the database (or another application holds connection as well). Database cannot be deleted where there is any other opened connection. The first problem can be probably solved by turning connection pooling off (add Pooling=false to your connection string) or clear the pool before you delete the database (by calling SqlConnection.ClearAllPools()).
Both problems can be solved by forcing database to delete but for that you need custom database initializer where you switch the database to single user mode and after that delete it. Here is some example how to achieve that.
I was going crazy with this! I have an open database connection inside SQL Server Management Studio (SSMS) and a table query open to see the result of some unit tests. When re-running the tests inside Visual Studio I want it to drop the database always EVEN IF the connection is open in SSMS.
Here's the definitive way to get rid of Cannot drop database because it is currently in use:
Entity Framework Database Initialization
The trick is to override InitializeDatabase method inside the custom Initializer.
Copied relevant part here for the sake of good DUPLICATION... :)
If the database already exist, you may stumble into the case of having
an error. The exception “Cannot drop database because it is currently
in use” can raise. This problem occurs when an active connection
remains connected to the database that it is in the process of being
deleted. A trick is to override the InitializeDatabase method and to
alter the database. This tell the database to close all connection and
if a transaction is open to rollback this one.
public class CustomInitializer<T> : DropCreateDatabaseAlways<YourContext>
{
public override void InitializeDatabase(YourContext context)
{
context.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction
, string.Format("ALTER DATABASE [{0}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE", context.Database.Connection.Database));
base.InitializeDatabase(context);
}
protected override void Seed(YourContext context)
{
// Seed code goes here...
base.Seed(context);
}
}
This is a really aggressive database (re)initializer for EF code-first with migrations; use it at your peril but it seems to run pretty repeatably for me. It will;
Forcibly disconnect any other clients from the DB
Delete the DB.
Rebuild the DB with migrations and runs the Seed method
Take ages! (watch the timeout limit for your test framework; a default 60 second timeout might not be enough)
Here's the class;
public class DropCreateAndMigrateDatabaseInitializer<TContext, TMigrationsConfiguration>: IDatabaseInitializer<TContext>
where TContext: DbContext
where TMigrationsConfiguration : System.Data.Entity.Migrations.DbMigrationsConfiguration<TContext>, new()
{
public void InitializeDatabase(TContext context)
{
if (context.Database.Exists())
{
// set the database to SINGLE_USER so it can be dropped
context.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, "ALTER DATABASE [" + context.Database.Connection.Database + "] SET SINGLE_USER WITH ROLLBACK IMMEDIATE");
// drop the database
context.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, "USE master DROP DATABASE [" + context.Database.Connection.Database + "]");
}
var migrator = new MigrateDatabaseToLatestVersion<TContext, TMigrationsConfiguration>();
migrator.InitializeDatabase(context);
}
}
Use it like this;
public static void ResetDb()
{
// rebuild the database
Console.WriteLine("Rebuilding the test database");
var initializer = new DropCreateAndMigrateDatabaseInitializer<MyContext, MyEfProject.Migrations.Configuration>();
Database.SetInitializer<MyContext>initializer);
using (var ctx = new MyContext())
{
ctx.Database.Initialize(force: true);
}
}
I also use Ladislav Mrnka's 'Pooling=false' trick, but I'm not sure if it's required or just a belt-and-braces measure. It'll certainly contribute to slowing down the test more.
None of those solutions worked for me. I ended up writing an extension method that works:
private static void KillConnectionsToTheDatabase(this Database database)
{
var databaseName = database.Connection.Database;
const string sqlFormat = #"
USE master;
DECLARE #databaseName VARCHAR(50);
SET #databaseName = '{0}';
declare #kill varchar(8000) = '';
select #kill=#kill+'kill '+convert(varchar(5),spid)+';'
from master..sysprocesses
where dbid=db_id(#databaseName);
exec (#kill);";
var sql = string.Format(sqlFormat, databaseName);
using (var command = database.Connection.CreateCommand())
{
command.CommandText = sql;
command.CommandType = CommandType.Text;
command.Connection.Open();
command.ExecuteNonQuery();
command.Connection.Close();
}
}
I try adding Pooling=false like Ladislav Mrnka said but always got the error.
I'm using Sql Server Management Studio and even if I close all the connection, I get the error.
If I close Sql Server Management Studio then the Database is deleted :)
Hope this can helps
I got the same error. In my case, I just closed the connection to the database and then re-connected once the in my case the new model was added and a new controller was scaffolded. That is however a very simple solution and not recommended for all scenarios if you want to keep your data.
I got the same problem back then. Turns out the solution is to close the connection in Server Explorer tab in Visual Studio. So maybe you could check whether the connection is still open in the Server Explorer.
Its simple because u're still using the same db somewhere, or a connection is still open.
So just execute "USE master" first (if exist, but usually is) and then drop the other db. This always should work!
Grz John