My Grails application is not using GORM but instead uses my own SQL and DML code to read and write the database (The database is a huge normalized legacy one and this was the only viable option).
So, I use the Groovy Sql Class to do the job. The database calls are done in Services that are called in my Controllers.
Furthermore, my datasource is declared via DBCP in Tomcat - so it is not declared in Datasource.groovy.
My problem is that I need to write some transaction code, that means to open a transaction and commit after a series of successful DML calls or rollback the whole thing back in case of an error.
I thought that it would be enough to use groovy.sql.Sql#commit() and groovy.sql.Sql#rollback() respectively.
But in these methods Javadocs, the Groovy Sql documentation clearly states
If this SQL object was created from a DataSource then this method does nothing.
So, I wonder: What is the suggested way to perform transactions in my context?
Even disabling autocommit in Datasource declaration seems to be irrelevant since those two methods "...do nothing"
The Groovy Sql class has withTransaction
http://docs.groovy-lang.org/latest/html/api/groovy/sql/Sql.html#withTransaction(groovy.lang.Closure)
public void withTransaction(Closure closure)
throws java.sql.SQLException
Performs the closure within a transaction using a cached connection. If the closure takes a single argument, it will be called with the connection, otherwise it will be called with no arguments.
Give it a try.
Thanks James. I also found the following solution, reading http://grails.org/doc/latest/guide/services.html:
I declared my service as transactional
static transactional = true
This way, if an Error occurs, the previously performed DMLs will be rolled back.
For each DML statement I throw an Error describing the message. For example:
try{
sql.executeInsert("""
insert into mytable1 (col1, col2) values (${val1}, ${val2})
""")
catch(e){
throw new Error("you cant enter empty val1 or val2")
}
try{
sql.executeInsert("""
insert into mytable2 (col1, col2) values (${val1}, ${val2})
""")
catch(e){
throw new Error("you cant enter empty val1 or val2. The previous insert is rolledback!")
}
Final gotcha! The service when called from the controller, must be in a try catch, as follows:
try{
myService.myMethod(params)
}catch(e){
//http://jts-blog.com/?p=9491
Throwable t = e instanceof UndeclaredThrowableException ? e.undeclaredThrowable : e
// use t.toString() to send info to user (use in view)
// redirect / forward / render etc
}
Related
I'm writing a small, simple web app in go using the gorm ORM.
Since the database can fail independently of the web application, I'd like to be able to identify errors that correspond to this case so that I can reconnect to my database without restarting the web application.
Motivating example:
Consider the following code:
var mrs MyRowStruct
db := myDB.Model(MyRowStruct{}).Where("column_name = ?", value).First(&mrs)
return &mrs, db.Error
In the event that db.Error != nil, how can I programmatically determine if the error stems from a database connection problem?
From my reading, I understand that gorm.DB does not represent a connection, so do I even have to worry about reconnecting or re-issuing a call to gorm.Open if a database connection fails?
Are there any common patterns for handling database failures in Go?
Gorm appears to swallow database driver errors and emit only it's own classification of error types (see gorm/errors.go). Connection errors do not currently appear to be reported.
Consider submitting an issue or pull request to expose the database driver error directly.
[Original]
Try inspecting the runtime type of db.Error per the advice in the gorm readme "Error Handling" section.
Assuming it's an error type returned by your database driver you can likely get a specific code that indicates connection errors. For example, if you're using PostgreSQL via the pq library then you might try something like this:
import "github.com/lib/pq"
// ...
if db.Error != nil {
pqerr, ok := err.(*pq.Error)
if ok && pqerr.Code[0:2] == "08" {
// PostgreSQL "Connection Exceptions" are class "08"
// http://www.postgresql.org/docs/9.4/static/errcodes-appendix.html#ERRCODES-TABLE
// Do something for connection errors...
} else {
// Do something else with non-pg error or non-connection error...
}
}
I have a .NET web application that frequently executes queries to get data from a local database.
In situations where the query doesn't run (due to an exception) or the query returns an unexpected set of data (such as an empty set). I want to be able to rebuild the query (replacing it's #parameters with the values actually used) and store the complete query in the database along with the exception.
I'm aware that I can do this through standard code but I was wondering whether it would be safer to do via Elmah?
Also would doing this via Elmah give me the ability to be able to view the executed sql through elmah.axd (when access is enabled)?
Unless the thrown exception includes the query with the actual values, ELMAH doesn't help you there other than logging the exception. You can catch the exception yourself and do a custom logging to ELMAH using the ErrorSignal.Raise method as explained here: How to use ELMAH to manually log errors?
I log SQL exceptions by passing the exception and the actual command to a new Exception class. The class wraps the SqlException and the System.Data.Common.DbCommand objects. Using that information I can create a message to provide the sql command details:
public override string Message
{
get
{
StringBuilder message = new StringBuilder("");
StringBuilder sql = new StringBuilder("");
sql.AppendFormat(" {0} ", Command.CommandText);
foreach (SqlParameter param in Command.Parameters)
{
sql.AppendFormat(" {0} - {1}", param.ParameterName,
param.Value.ToString());
}
message.AppendFormat("Error: {0} SQL: {1} User: {2}", SqlEx.Message,
sql, Username);
return message.ToString();
}
}
Finally, I use the ErrorSignal Raise method to log the message in Elmah:
Elmah.ErrorSignal.FromCurrentContext().Raise(new DetailSqlException(e.Exception as SqlException, e.Command, user));
I am trying to use Wix DTF custom action to write MSI runtime session values to registry.
This i wanted to achieve by adding temporary record to "Registry" table in the database.
Since c++ had a WcaAddTempRecord method to achieve this, really wanted to know is there any equivalent method in DTF.
Note: I tried using Session.Database.OpenView to insert the record, but consistently i am getting update failed error, due to session database readonly property.
Can someone please suggest the best approach for this situation?
The MSI database is read-only during the installation. So you cannot add permanent rows. However, you can insert temporary rows. Once you get the View back from the Session.Database.OpenView() then use the InsertTemporary() method on the View object to add temporary rows.
That's how WcaAddTempRecord() gets the Temp in its name. :)
This is my "go to" helper method:
private static void InsertTempRecord(Session session, string tableName, Object[] objects)
{
Database db = session.Database;
string sqlInsertSring = db.Tables[tableName].SqlInsertString + " TEMPORARY";
session.Log("SqlInsertString is {0}", sqlInsertSring);
View view = db.OpenView(sqlInsertSring);
view.Execute(new Record(objects));
view.Close();
}
For more information see:
Dynamic Windows Installer UI
This question is a bit of a dupe, but I still don't understand the best way to handle flushing.
I am migrating an existing code base, which contains a lot of code like the following:
private void btnSave_Click()
{
SaveForm();
ReloadList();
}
private void SaveForm()
{
var foo = FooRepository.Get(_editingFooId);
foo.Name = txtName.Text;
FooRepository.Save(foo);
}
private void ReloadList()
{
fooRepeater.DataSource = FooRepository.LoadAll();
fooRepeater.DataBind();
}
Now that I am changing the FooRepository to Nhibernate, what should I use for the FooRepository.Save method? Should the FooRepository always flush the session when the entity is saved?
I'm not sure if I understand your question, but here is what I think:
Think in "putting objects to the session" instead of "getting and storing data". NH will store all new and changed objects in the session without any special call to it.
Consider this scenarios:
Data change:
Get data from the database with any query. The entities are now in the NH session
Change entities by just changing property values
Commit the transaction. Changes are flushed and stored to the database.
Create a new object:
Call a constructor to create a new object
Store it to the database by calling "Save". It is in the session now.
You still can change the object after Save
Commit the changes. The latest state will be stored to the database.
If you work with detached entities, you also need Update or SaveOrUpdate to put detached entities to the session.
Of course you can configure NH to behave differently. But it works best if you follow this default behaviour.
It doesn't matter whether or not you explicitly flush the session between modifying a Foo entity and loading all Foos from the repository. NHibernate is smart enough to auto-flush itself if you have made changes in the session that may affect the results of the query you are trying to run.
Ideally I try to use one session per "unit of work". This means one cohesive piece of work which may involve several smaller steps. If you feel that you do not have a seam in your architecture where you can achieve this, then managing the session inside the repository will also work. Just be aware that you are missing out on some of the power that NHibernate provides you.
I'd vote up Stefan Moser's answer if I could - I'm still getting to grips with Nh myself but I think it's nice to be able to write code like this:
private void SaveForm()
{
using (var unitofwork = UnitOfWork.Start())
{
var foo = FooRepository.Get(_editingFooId);
var bar = BarRepository.Get(_barId);
foo.Name = txtName.Text;
bar.SomeOtherProperty = txtBlah.Text;
FooRepository.Save(foo);
BarRepository.Save(bar);
UnitOfWork.CommitChanges();
}
}
so this way either the whole action succeeds or it fails and rolls back, keeping flushing/transaction management outside of the Repositories.
What's the best practice for handling exceptions in NHibernate?
I've got a SubjectRepository with the following:
public void Add(Subject subject)
{
using (ISession session = HibernateUtil.CurrentSession)
using (ITransaction transaction = session.BeginTransaction())
{
session.Save(subject);
transaction.Commit();
}
}
And a Unit Test as follows:
[Test]
public void TestSaveDuplicate()
{
var subject = new Subject
{
Code = "En",
Name = "English"
};
_subjectRepository.Add(subject);
var duplicateSubject = new Subject
{
Code = "En",
Name = "English1"
};
_subjectRepository.Add(duplicateSubject);
}
I got to the point of handling the error generated by the unit test and got a bit stuck. This fails as expected, though with a GenericADOException, I was expecting a ConstraintViolationException or something similar (there is a uniqueness constraint on the subject code at database level).
The ADOException wraps a MySQL Exception that has a sensible error message but I don't want to start breaking encapsulation by just throwing the inner exception. Particularly as MySQL isn't finalised as the back end for this project.
Ideally I'd like to be able to catch the exception and return a sensible error to the user at this point. Are there any documented best practice approaches to handling NHibernate Exceptions and reporting back up to the user what went wrong and why?
Thanks,
Matt
I would handle it in the Add method as such:
public void Add(Subject subject)
{
using (ISession session = HibernateUtil.CurrentSession)
using (ITransaction transaction = session.BeginTransaction())
{
try
{
session.Save(subject);
transaction.Commit();
}
catch (Exception ex)
{
transaction.Rollback();
// log exception
throw;
}
}
}
In the catch block, you should first rollback the transaction and log the exception. Then your options are:
Rethrow the same exception, which is what my version does
Wrap it in your own exception and throw that
Swallow the exception by doing nothing, which is very rarely a good idea
You don't have any real options for handling the exception in this method. Assuming that the UI calls this method, it should call it in its own try..catch and handle it by displaying a meaningful error message to the user. You can make your unit test pass by using the ExpectedException(type) attribute.
To answer your question directly, you should create your own "sensible error" by extending Exception and throw that with the original exception as its InnerException. That's the exception wrapping technique I listed in (2).
All the Nhibernate exceptions are non recoverable, you could revisit the design of the app/data layer if you are trying to recover from nhibernate exceptions .
You can also Take a look at spring.net 's exception translation implementaion
Also you manually handling transactions on exceptions is tedious and error prone, take a look at nhibernate's contextual sessions .
Spring.net also has some nice helpers around nhibernate .
The general question is going to be, what do you want to tell the user, and who is the user?
If the user will sometimes be another computer (i.e., this is a web service), then you would want to use the appropriate mechanism to return a SOAP Fault or HTTP error.
If the user will sometimes be a UI of some sort, then you may want to display a message to the user, but what would you tell the user so he can do something about it? For instance, most web sites will say, "sorry, we had an unexpected error", no matter what the reason. That's because there's usually nothing the user could do about the error.
But in either case, the choice of how to tell "the user" is a matter for the Presentation layer (UI tier), not for the DAL. You should possibly wrap exceptions from the DAL in another exception type, but only if you're going to change the message. You don't need your own exception class, unless your callers would do something different if it's a data access exception rather than some other kind.
I'd probably validate the input before saving the object; that way you can implement whatever validation you like (e.g. check the length of the Subject Code as well as the fact that there aren't any duplicates), and pass back meaningful validation errors back to the user.
The logic is as follows; exceptions are used to indicate exceptional circumstances that your program doesn't cater for. A user entering a duplicate Subject Code in your example above is something your program should be catering for; so, rather than handling an exception because a DB constraint gets violated (which is an exceptional event and shouldn't be occurring), you'd want to handle that scenario first and only attempt to save the data when you know that the data you're saving is correct.
The advantage with implementing all validation rules in your DAL is that you can then ensure that the data going into your DB is valid as per your business processes in a consistent manner, rather than relying on the constraints in your DB to catch those for you.