will nested sessions work? I.e. will a child session commit be auto-ignored?

258 views
Skip to first unread message

Simon

unread,
Aug 15, 2010, 7:05:58 PM8/15/10
to mybatis-user
Dear Gurus,

If one DAO calls another, are the transactions nested or treated as
separate?

e.g. below the PlayerDAO wants to use AccountDAO to create a new
dependant object. If AccountDAO succeeds, it calls commit. Does this
commit actuall happen on the DB at this point? i.e. the code fails in
PlayerDAO after the call of AccountDAO, will it roll back BOTH? Or
will I end up with a stranded account with no player in the example?
Obviosly I could have a layer of business logic above the DAO which
calls both DAOs, but this would have a worse issue as it would not
have access to any transaction control. Im using the defaut
transaction manager (JDBC). I havent worked out how to specify
autocommit=false for everything, so i really hope the system is not
autocommiting by default.

public class AccountDAO{
public void create(Account account) {
SqlSession session =
SqlSessionFactoryFactory.getFactory().openSession();
try {
AccountMapper mapper = session.getMapper(AccountMapper.class);
mapper.insert(account);
session.commit();
} finally {
session.close();
}
assert (account.getId() > 0);
}

And now want to use it in DAO2:

public class PlayerDAO{
public void create(Player player) {
SqlSession session =
SqlSessionFactoryFactory.getFactory().openSession();
try {
AccountDao accountDAO = new accountDAO();
Account account = new Account();
accountDAO.create(account);

Player.setAccountId (account.getId());
PlayerMapper mapper = session.getMapper(PlayerMapper.class);
mapper.insert(player);
session.commit();
} finally {
session.close();
}
assert (player.getId() > 0);
}

Or even worse, will the commit from the AccountDAO in the middle of
the PlayerDAO commit any thing the PlayerDAO may have written and not
committed yet (I presumt not, but cant find nested transaction info in
the User guide).

Is there a public area where knowlege and examples like this can be
posted? A public wiki perhaps? If not, can I offer one?

fx bird

unread,
Aug 15, 2010, 11:01:48 PM8/15/10
to mybati...@googlegroups.com
Hi, if you use spring,  u can control and define the transaction boundary, like required,new etc.

Poitras Christian

unread,
Aug 16, 2010, 9:00:51 AM8/16/10
to mybati...@googlegroups.com
As an additional explanation, if you use JDBC transaction, nested SqlSession instances will not give you the result you desire. When the first SqlSession.commit() is called, the transaction will be commited.
If you use managed transaction (backed by Spring, Guice or wathever) calls to commit and rollback will be no-ops since commit and rollback are expected to be called elsewhere.
 
Christian


From: mybati...@googlegroups.com [mailto:mybati...@googlegroups.com] On Behalf Of fx bird
Sent: Sunday, August 15, 2010 11:02 PM
To: mybati...@googlegroups.com
Subject: Re: will nested sessions work? I.e. will a child session commit be auto-ignored?

Simon

unread,
Aug 16, 2010, 9:28:46 AM8/16/10
to mybatis-user
How would one control the transaction across two sessions, not using
Spring?

E.g. PlayerLogic.class:

public void create(String name) {
// some way of starting transaction.

Account account = new Account();
accountDAO.create(account); // this will do a commit, but we
dont want to to commit in this case.

Player p = new player(name, account.getId());

PlayerDAO.create(p); // this will do the wanted commit.

//some way of ending transaction.
}

One could create a session above the DAOs, and pass it in, but then
the first DAO will still do an unwanted commit.

One could change the DAOs to never commit, and pass in a session, then
have the logic above the DAOs do the commit, but this is also
horrible.

One could create a session above the DAOs, pass it to the DAOs, and
pass in a commit= true/false if that DAO should do the final commit.

One could write ones own nested transaction handling class, which
keeps a stack of commits, and only applies a single final commit.
However, this is rocket science to me - I dont think I could do it.

How does anyone else do this?

Thanks,

S.

Poitras Christian

unread,
Aug 16, 2010, 9:34:41 AM8/16/10
to mybati...@googlegroups.com
I usually use Guice.
Simone developed a nice plugin for Guice and MyBatis in ibaguice project.
http://code.google.com/p/ibaguice/

Spring did not supply any integration for MyBatis, so we are developping some integration mechanism.

If you don't plan to use Spring or Guice, then I would create the SqlSession instance in my service class and pass it to DAO as a parameter. Since the DAO did not create the SqlSession instance, the DAO should never call commit or rollback. It's the service's job!

Christian

-----Original Message-----
From: mybati...@googlegroups.com [mailto:mybati...@googlegroups.com] On Behalf Of Simon
Sent: Monday, August 16, 2010 9:29 AM
To: mybatis-user
Subject: Re: will nested sessions work? I.e. will a child session commit be auto-ignored?

Simon Hobbs

unread,
Aug 16, 2010, 9:55:03 AM8/16/10
to mybati...@googlegroups.com
Crikey - this is a show stopper then.  If we had know this I would not have chosen Mybaits.  I would never have dreamed there would be no nested transaction support in a persistence framework.

We are deliberately avoiding Spring and similar unnecessary frameworks as we all hate complex XML configurations which make the code un-followable, especially for novice programmers - we don't have time to learn yet another framework just to do a simple task (and we avoid dependency injection unless its absolutely necessary  having been burned in the past). 

We are really stuck now - we are too far down the line to start from scratch with hibernate or cayenne or similar.   Implementing a 3rd party transaction manager with the very little documentation and no examples is a daunting task which will involve a lot of additional trial and error and trips to the forums.

The only quick solution is to have lots of mappers and lots of objects in big DAO methods with a commit at the end.  Is this an approach which anyone uses?

Now I have to explain to the share holders why the project is going to be delayed by a couple of weeks.

Is there a publicly editable wiki where we can contribute this kind of knowledge?  If not can I supply one?

Simon.

Poitras Christian

unread,
Aug 16, 2010, 10:04:20 AM8/16/10
to mybati...@googlegroups.com
Contribution is always welcome. The wiki is here: http://code.google.com/p/mybatis/wiki/Welcome
 
I know that this might not seem to be the most appropriate approch for you. This change from iBATIS 2 (which separated transaction logic from statement execution logic) seemed weird to many.
Some of the developpers also miss the separation of transaction and statement execution and I think they are working on this. Still, I am unable to provide you with a fully operational transaction mechanism that depends only on MyBatis rigth now. I kown there are many good transaction managers for J2EE and I hope one will be appropriate and simple enough for you to use - I think that's why we don't provide one beside SqlSession instances.
 
Christian


From: mybati...@googlegroups.com [mailto:mybati...@googlegroups.com] On Behalf Of Simon Hobbs
Sent: Monday, August 16, 2010 9:55 AM

Poitras Christian

unread,
Aug 16, 2010, 10:10:32 AM8/16/10
to mybati...@googlegroups.com
I am sorry, my explanation about the change from iBATIS 2 to MyBatis 3 is incorrect.
The change from iBATIS 2 logic to MyBatis 3 which links transaction and statement execution was made because many people found that weird that they were not linked.
Still some people want more control over transaction and desire them to be separate. That is why some developpers are working on separating transaction and statement execution again.
Once this change will be made, You will be able to use nested transaction. Since I cannot say when this change will be made, I may be better for you to find an appropriate solution with our current version.
 
Christian


From: mybati...@googlegroups.com [mailto:mybati...@googlegroups.com] On Behalf Of Poitras Christian
Sent: Monday, August 16, 2010 10:04 AM
To: 'mybati...@googlegroups.com'
Subject: RE: will nested sessions work? I.e. will a child session commit be auto-ignored?

Simon Hobbs

unread,
Aug 16, 2010, 12:14:53 PM8/16/10
to mybati...@googlegroups.com
Thanks Christian, looks like your last suggestion is the sane way to go.

I looked at http://www.99soft.org/projects/ibaguice/1.0/dao.html which has a teasing     @com.googlecode.ibaguice.dao.Transactional at the bottom.  However, the page only has about half the information needed to construction a working example of this not knowing Guice.

For example, at the top of this page, they make the FooDAOImpl a singleton, which would be suicide for our app where say 100 people need to use the playerDAO.login() method, and I want it to create 100 DAO objects, not 1 (a singleton) which 100 have to queue up to use.  

And what should these lines actually be to work? 
Class<? extends Provider<DataSource>> dataSourceProviderClass = [...];
Class<? extends Provider<TransactionFactory>> txFactoryProviderClass = [...];
And can you inject just the special nested Transaction stuff without the other baggage such as the sqlSessionFactory?  How do you configure the dataSource?

As an aside, I find it amazing that developers will want to add the complexity of another framework and lots of hard to debug implicit Magic just to save a three lines of easy to read and write code in relation to the AbstractTransctionDao.  I value explicit simplicity over implicit complexity any time, but most of our developers just want to use new and/or clever stuff.  The problem then is the chain of dependencies, framework A needs framework B to work as needed, framework B only works if you use framework C to build or configure it etc.  In the end, a developer has to spend 6 months becoming en expert on every framework before he can write a basic webapp which goes to the DB.  Which is why I guess they invented ruby...

Simon Hobbs

unread,
Aug 16, 2010, 12:20:53 PM8/16/10
to mybati...@googlegroups.com

Simone Tripodi

unread,
Aug 16, 2010, 1:55:11 PM8/16/10
to mybati...@googlegroups.com
Hi Simon
very nice to meet you ;) Let me explain how the guice integration can
be useful for you:

1) a small working example can be found on the test[1] source code, it
will show you how to configure the module. PS don't take this code as
the absolute reference, you could load configurations from properties
file as well

2) AbstractTransactionalDao implementations are multi-threaded-safety
classes, you can reuse the same singleton instance to serve all the
requests.

IMHO MyBatis is a killer framework because doesn't require any
dependency at all; the Guice integration was thought to satisfy Guice
users (including myself :P ) to fill the missing integration between
both framework.

Feel free to ask more questions for every aspect is not clear!
All the best, good luck!
Simo

[1] http://code.google.com/p/ibaguice/source/browse/tags/1.0/samples/src/main/java/com/googlecode/ibaguice/samples/AbstractContactDao.java
[2] http://code.google.com/p/ibaguice/source/browse/tags/1.0/core/src/main/java/com/googlecode/ibaguice/core/dao/AbstractTransactionalDao.java

http://people.apache.org/~simonetripodi/
http://www.99soft.org/

Nathan Maves

unread,
Aug 16, 2010, 6:39:48 PM8/16/10
to mybati...@googlegroups.com
I am going to give you my person/professional opinion so take it for
what it is worth.

DAO's are dead. Part of the rewrite of MyBatis was to get rid of the
idea of a DAO and our old DAO framework. A mapper is really your dao.

DAO's when used should be a single unit of work. If you find yourself
calling one from the other you have done something wrong and rethink
it. If it is hard to unit test rethink it :)

Use a service layer class when you need to combine multiple units of
work together. Given your example I would create a AccountService
class that would use both the AccountMapper and the PlayerMapper.
Hand the transaction there.

DI is your friend. USE IT


Nathan

Poitras Christian

unread,
Aug 17, 2010, 9:11:19 AM8/17/10
to mybati...@googlegroups.com
I agree with Nathan. I've ditched the DAO layer since I couldn't find it usefull in combination with Mappers.

Christian

-----Original Message-----
From: mybati...@googlegroups.com [mailto:mybati...@googlegroups.com] On Behalf Of Nathan Maves
Sent: Monday, August 16, 2010 6:40 PM
To: mybati...@googlegroups.com
Subject: Re: will nested sessions work? I.e. will a child session commit be auto-ignored?

Tim

unread,
Aug 17, 2010, 9:24:37 AM8/17/10
to mybati...@googlegroups.com
Are you guys talking about the same thing?
The mapper interface IS my dao.
I've got myBatisImpl and hibernateImpl both using the same mapper interface.
The Mapper IS the definition of a dao interface.
DAOs are not useless. They are easier to manage and (especially with mybatis/hibernate) trivial to implement, even if you don't have different impls like I do.
In the future, I'll use the same mapper interface from mybatis to create my cacheImpl which will look up my datamodel from a caching layer.
And with the 'magic' of daos and a DI container (I'm using guice but you can use wtf you want including rolling your own) it just works.

Ellison Alves

unread,
Aug 17, 2010, 9:37:37 AM8/17/10
to mybati...@googlegroups.com
Tim, could you give us a example of your implementation ?
I'm using the structure proposed in user guide of myBatis.
So, i've a service layer that execute some mapped query. For example:

public class AccountService {
       private AccountMapper accountMapper;
       // follows a constructor here to init the acountMapper reference variable

      public int createAccount(Account account) {
        // myBatis code, session, mapper, execute interface method, close session ....
      }

}

Thanks, regards.


2010/8/17 Tim <che...@gmail.com>



--
Ellison Alves de Souza

Tim

unread,
Aug 17, 2010, 9:50:00 AM8/17/10
to mybati...@googlegroups.com
Yea np! I'll put some gists up.
What in particular were you looking for? Or did you want an example of using guice to inject different dao impls?
You might have to give me some time as I have to refactor them to remove any possibly sensitive information for a full example :P
If you want a small peek though you can look at:

It doesn't show the guice side of things but it's as easy as:

            bind(SqlSessionFactory.class).toInstance(mySessionFactory); 
            bind(FooMapper.class).to(MyBatisFooDaoImpl.class);
            bind(BarMapper.class).to(MyBatisBarDaoImpl.class);

There's a better way to bind the sessionfactory than using the straight instance but I'm always annoyed at how you get guice to construct 3rd party libraries so I just created an instance of it myself for now.
The impls are not actually named MyBatisXXX HibernateXXX. They reside in folders of that name.

Ellison Alves

unread,
Aug 17, 2010, 10:18:15 AM8/17/10
to mybati...@googlegroups.com
Hi tim, 
i'm looking for best pratices to improve my coding using myBatis.
So, i think that the example that i give to you above is pretty simple and i've to write the same thing everytime and won't to do it! I want to writeless.
I'm not using any framework about transaction manager, i'm just learning myBatis doing some projects and don't understand exactly what guice can do for me.

So, i think that's just a architecture doubt. =D

Thanks for help.

2010/8/17 Tim <che...@gmail.com>

Simon Hobbs

unread,
Aug 17, 2010, 11:00:12 AM8/17/10
to mybati...@googlegroups.com
Very good point.  i like it.  Ill rename all my xxDAOs to xxService and job done - no more feeling bad about calling different mappers from inside a method.  The only thing is then to avoid one service calling another.



I don't yet agree with DI being a friend though:
  1. It would appear that DI to manage modularitly is like designing a house with a replacable roof.  Great in theory, but noone ever replaces it.
  2. The extreme programming principal is to keep it as simple as possible, and to not implement functionality that is not needed now.
  3. in 20 years of developing large banking and gaming systems, I have never seen someone swap a major component.  E.g. we certainly add payment providers, (I've written more than 10), but they are always in addition to, not replacing the current one, and are chosen dynamically, not bound statically at compile or run time.
  4. The DI framework (spring/guice) etc. adds time (=cost) to the project, as everyone has to learn it, implement it, then get to know all the gotchas. 
  5. I think it makes the code a lot less readable because of all the indirection and hidden glue Magic. I look at guice examples and I dont have a clue whats going on.
  6. It adds complexity to code, you are never sure what object you are really dealing with or when/where it came from, especially with mutli-project inter-dependencies.  Makes it harder to debug.
  7. You can implement modular design without it (e.g. by using an interface possibly with a simple factory).
  8. The only time I can see it being an advantage is for mock objects & testing. However, I think mock objects are over rated and we dont use them, we test the real code.
  9. Give me a few extra lines of explicit code over a few less but with implicit magic behind the scenes any day.
  10. Guice singletons arent singletons at all.  Its too easy to create 2 of them, undermining the whole dependency injected object.
  11. Factories and singletons are easy to write and follow.

DI must have advantages which outweighs the disadvantages, but I haven't seen the light yet...

Simon.

Simone Tripodi

unread,
Aug 17, 2010, 2:04:43 PM8/17/10
to mybati...@googlegroups.com
Hi Nathan,
great explanation! I think the same, but I've been scared on saying it
to be taken as a crazy guy - and that's the reason why in the old
iBaGuice site I mentioned DAOs - but I feel now very happy since here
I can find a common way of thinking about it :)
Mappers are now the core of the development where mybatis plays the
leading role, DI is our friend and that's the reason why in the new
version of iBaGuice (aka mybatis-guice in the subprojects)
SqlSessionManager based Mappers instances will be automagically
injected.
All the best,
Simo

http://people.apache.org/~simonetripodi/
http://www.99soft.org/

Clinton Begin

unread,
Aug 17, 2010, 2:14:56 PM8/17/10
to mybati...@googlegroups.com
I agree with Nathan, but we need to redefine Unit of Work here to avoid confusion.  Usually Unit of Work is synonymous with Transaction... so to clarify what Nathan is saying, I'll just call it a "Statement".

Working from the bottom up:

* Statements is the smallest "piece of work" that may be part of a larger "unit of work"
* Mappers contain many statements
--- Mybatis ends here ----
* DAOs use abstract and collect many mappers and statements
* Service may call many DAOs
* A Transaction or "Unit of Work" may include and scope around many calls to many services, daos, mappers and statements.
* A Servlet/JSP request (or other UI event) may call many services

What I've found (and it seems others like Nathan have as well) is that the DAO is the most useless piece of this already deep layering.  

So I (like Nathan) have generally reduced my stack to (now reversing the example above):

Servlet / Controller / UI
    -> Transaction Scope
        -> Service
--------------MyBatis Begins Here--------------
           -> Mapper
                -> Statement

No DAO layer.  MyBatis ensures that coding your statements and Mappers essentially boils down to writing a Java Interface and some SQL.  The Service is your business logic.  Transactions are transparent with a servlet filter (or similar interceptor approach), and hopefully a good Servlet framework (like Stripes) makes the controller layer almost non-existent from a coding perspective (in stripes it's literally just a method).


Clinton

ooper

unread,
Oct 6, 2010, 3:06:15 PM10/6/10
to mybatis-user
So in a Struts world, I have an Action class that makes calls to
service classes. I currently have the transaction being started in the
service class, but this prevents me from being able to call other
service classes within my service classes. Would you suggest putting
the transaction logic, i.e., sqlSession creation, in the Action class,
or introduce a "transaction" layer of sorts between the Action and
Service classes? The latter seems like a waste, but just wanted to get
your take on this.

Clinton Begin

unread,
Oct 6, 2010, 9:50:44 PM10/6/10
to mybati...@googlegroups.com
I use a servlet filter to manage the lifecycle of the transaction.  An interceptor in your favourite web framework would work just as well.

Clinton
Reply all
Reply to author
Forward
0 new messages