Announcement Announcement Module
Collapse
No announcement yet.
@Transactional default on non transactional methods Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • @Transactional default on non transactional methods

    Hi,

    I'm moving from Spring 1.x declarative transaction style to @Transactional style.

    I have the feeling that this gives me a lesser fine grained control over which transactional behavior should be applied on which method.

    I happen to have few methods in my Services that don't deal with the persistent store at all. Since I have a @Transactional(readOnly=true) on my Service class, what will happen for these methods? Spring will open a transaction with the persistent storage where nothing will happen.
    How much of a waste is that?

    Is there ways to 'say' this method inside this @Transactional service is NOT transactional (not being annotate all the methods one by one instead of the class)

    thanks
    --------------
    Jean

  • #2
    Can't you just use PROPAGATION_SUPPORTS on the methods that you don't want to be transactional?
    http://www.springframework.org/docs/...ATION_SUPPORTS
    Last edited by karldmoore; Aug 21st, 2007, 07:09 AM.

    Comment


    • #3
      @Transactional annotation on method override annotation defined on class (see AbstractFallbackTransactionAttributeSource.java). So you need to annnotate class and that few methods with different behavior.

      Regards,
      Oleksandr

      Comment


      • #4
        Optimization: increasing concurrency level

        thanks for the quick answers guys.

        Karl, PROPAGATION_SUPPORTS is indeed very interesting. They specify that this is somewhat different from no Tx at all since it would synchronize (in my case) with the Hibernate Session object. Since using Hibernate Session IS accessing the persistent store in my case, then PROPAGATION_SUPPORTS is like having no Tx at all. So this is probably the best way to emulate No Tx behavior on a method.

        I'd like to widen a little bit the scope: I'm refactoring my transaction layer because we're having some lock problems in the DB (SQLServer) after 3 years in production. I used a pessimistic approach, which was very consistent, but not very concurrent. Now that we need more concurrency, I'm trying to make the transactional layer more flexible without going for optimistic locking (which would require as I understand adding a column to all the table in the db).
        External auditors advised to remove all the RO Tx saying they were not useful.
        So here's my problem. I read everywhere that any communication with the DB should occur within a transaction.
        Wouldn't any rdbms automatically open a transaction for any request anyway?
        And in this case, if default rdms behavior is suitable, why bother controlling Tx on a Java level?

        If not, is seems possible to me that reading *SOME* data would not require a transaction, but this would be decided based on the data nature and not on the method. So fine grained Transaction isolation tuning doesn't seem possible.

        Also I've read that in pessimistic locking approach the lowest acceptable isolation level should be TRANSACTION_REPEATABLE_READ (hibernate default indeed).

        So, even considering lowering isolation on some method (which doesn't seem safe anyway), I don't feel having much option here.

        I'm considering creating an Aspect in order to implement a retry on LockFailureException. And maybe moving to a JPA manager since I've heard Tx Timeouts were not very well implemented with HibernateTransactionManager.

        Do you have any experience in that type of optimization? What were your options?

        Regards,
        Jean

        Comment


        • #5
          Typically, you don't need any kind of transactions for read-only access. Pessimistic locking can be (very efficiently) done on read_commited isolation level (which is normally default) and manual locking of resources at appropriate places. Higher isolation levels work good on paper, but in practice lock far too much to be of any use.

          Comment


          • #6
            Hum, I'm confused...
            Hibernate docs states:
            No communication with the database can occur outside of a database transaction (this seems to confuse many developers who are used to the auto-commit mode). Always use clear transaction boundaries, even for read-only operations.
            I understand from it that it's cleaner to user Tx even for RO access but nevertheless not necessary. But then what does Hibernate's ReadOnly flag for Tx bring in the picture? What isolation level is used in case of RO TX?

            And what's the default Spring's isolation level (I can't find it in the doc)? Is it READ_COMMITED? Or does it uses Hibernate's hibernate.connection.isolation property? How can I control it?

            Anyway, I'd like to take what you say for granted (it would simplify a great deal my transaction policy) but it'd be better if I had a clean picture of what's happening in mind.

            cheers,
            jean

            Comment


            • #7
              Isolation level has nothing to do with read-only, they are orthogonal. A transaction can use any transaction isolation level and be read only or not.

              Spring default is "whatever the datasource does on it's own" - it's usually a server-wide configuration that can be overriden on the datasource level. If you use a Spring datasource to create a SessionFactory all "hibernate.connection.*" properties are ignored.

              The problem is that you have your auditors saying one thing and hibernate docs something else. I said that you don't _need_ the transaction for read-only stuff. The problem is that Hibernate people give no reasoning behind their advice and perhaps your auditors offered no deeper explanation. I'm sure both sides are right, in a certain context. The question is if the context is applying to you or not.

              Comment


              • #8
                yeah this is crazy, I spent hours doing some readings this afternoon and I'm still - if not more- in doubts.
                I read those fights dating back from 2004 between Juergen, Christian and gavin... just confused me...

                Anyway my conclusion - at this point in time - is that since, yes, in my case (SQLServer 2000, no MVCC) any communication with the DB occurs in a transaction, I'd better demarcate one even for the readOnly methods.

                And BTW, I can understand the concepts of readOnlyness and isolation Level are orthogonal, but they might influence each others: if you now the transaction is not gonna write anything, there's good chances that you can lower the isolation level (hum, not sure this is not non sense)

                Anyway, if I still think demarcating Ro Tx makes sense, I was about to lower my isolation level to read_commited (which means that writing Tx won't be blocked anymore by reading ones, which implies what?? hell, I really can't figure... ) using, you bet hibernate.connection.isolation.
                So what you just said just horrifies me... I'm creating my own c3p0 DS (com.mchange.v2.c3p0.ComboPooledDataSource) that I inject into the sessionFactory bean. Does it apply? What do'you mean exactly by 'Spring datasource' ? Where'd you read that anyway?

                If true, then what was my isolation level before? And how to set it properly? I just checked the c3p0 doc, and you have to implement a hook on each connection to manually 'force' the isolation level. This is most probably not the regular way.

                Comment


                • #9
                  Originally posted by Jean View Post
                  ...then PROPAGATION_SUPPORTS is like having no Tx at all. So this is probably the best way to emulate No Tx behavior on a method.
                  Honestly, it is not an emulation, it is just a way to say "this method is not interested in transaction. If one already exists let it be, if does not exist gooad as well".

                  [QUOTE]
                  I'd like to widen a little bit the scope: I'm refactoring my transaction layer because we're having some lock problems in the DB (SQLServer) after 3 years in production. I used a pessimistic approach, which was very consistent, but not very concurrent. Now that we need more concurrency, I'm trying to make the transactional layer more flexible without going for optimistic locking (which would require as I understand adding a column to all the table in the db).

                  Optimistic locking does not require an adding columns to each table. It only requre a way to determine if record was changed between reading and modification. Special "version" column is only one (while very popular) of such ways. There are other possibilities also.
                  1. Some databases have "system change number" pseudocolumn. I'm not SQL Server expert, so can not say if SQL Server is among them, but it can be easily proved with documentation.
                  2. Comparision of values of all fields in the record with old ones
                  3. Comparision of only changed values (not always acceptable)
                  4. Timestamp (if timestamp column already exissts). Not 100% reliable, but practically acceptable if change rate is not very high
                  External auditors advised to remove all the RO Tx saying they were not useful.
                  So here's my problem. I read everywhere that any communication with the DB should occur within a transaction.
                  Wouldn't any rdbms automatically open a transaction for any request anyway?
                  It depends on RDBMS. Some may treat each single statement as transaction (and note that isolation level may vary from DB to DB), some may execute all statements as single transaction till explicit commit/rollback (e.g. Oracle) and some may execute single statements out of trasaction control (e.g. DB2 for iSeries). And, if you run statement from Java JDBC driver may interfer as well.
                  And for some databases there are Server-wide settings that control this behaviour. So it is much safer to explicitly specify desired behavior (i.e. control it for Java).

                  If not, is seems possible to me that reading *SOME* data would not require a transaction, but this would be decided based on the data nature and not on the method. So fine grained Transaction isolation tuning doesn't seem possible.
                  In reality isolation level shall be determined by semantic of your application, or, more finely grained, by semantic of method, but in most cases READ COMMITED is sufficient.
                  BTW, SQL Server 2005 introduced support for multiversioning (a-la Oracle and Postgress), which reduces the lock contention significantly, you may try to take look in this direction instead of refactoring application.

                  Comment


                  • #10
                    Originally posted by Jean View Post
                    yeah this is crazy, I spent hours doing some readings this afternoon and I'm still - if not more- in doubts.
                    I read those fights dating back from 2004 between Juergen, Christian and gavin... just confused me...
                    Forget about Spring at the moment, it's irrelevant. Anything you can do with Spring you can also do without it. It's basically about locking/concurrency/transactions/hibernate.

                    Anyway my conclusion - at this point in time - is that since, yes, in my case (SQLServer 2000, no MVCC) any communication with the DB occurs in a transaction, I'd better demarcate one even for the readOnly methods.

                    And BTW, I can understand the concepts of readOnlyness and isolation Level are orthogonal, but they might influence each others: if you now the transaction is not gonna write anything, there's good chances that you can lower the isolation level (hum, not sure this is not non sense)
                    Usually you don't go setting a high isolation level and then lower it in certain cases, imo - that's a fundamentally broken strategy. You want to allow high concurrency per default (use read_commited) and then use higher isolation level or manual locking only at a few places where you absolutely know you need it.

                    Anyway, if I still think demarcating Ro Tx makes sense, I was about to lower my isolation level to read_commited (which means that writing Tx won't be blocked anymore by reading ones, which implies what?? hell, I really can't figure... ) using, you bet hibernate.connection.isolation.
                    So what you just said just horrifies me... I'm creating my own c3p0 DS (com.mchange.v2.c3p0.ComboPooledDataSource) that I inject into the sessionFactory bean. Does it apply? What do'you mean exactly by 'Spring datasource' ? Where'd you read that anyway?
                    I didn't read that, I just can't imagine it could work any other way. hibernate.connection.* stuff is used when hibernate creates new connections by itself. If you use Spring LocalSessionFactoryPFB and inject a datasource the way connections are created is not under hibernate control anymore.

                    If true, then what was my isolation level before? And how to set it properly? I just checked the c3p0 doc, and you have to implement a hook on each connection to manually 'force' the isolation level. This is most probably not the regular way.
                    It was the database default most likely. The database default is most probably read_commited. My advice is not to use anything else anyway. Hell - Oracle implements only read_commited and people still manage somehow.

                    Comment


                    • #11
                      Originally posted by dejanp View Post
                      .... Hell - Oracle implements only read_commited and people still manage somehow.
                      It is not exactly so. Firstly,Oracle implements not only read commitesd, but serializable also. Secondly, there are read commited and read commited. Namely, read commited in Oracle is more likely to repeatable read in other (non-multiversioning) databases, look into one of the books by Tom Kyte for details (to put it short Oracle always returns read-consistent result from a query, which is not guaranted be "read commited" definition in standard).

                      Regards,
                      Oleksandr

                      Comment


                      • #12
                        Oracle serializable implemention is ... Hmmm.. Let's try to put it nicely... It's so exotic that I never ever saw anyone who was able to actually use it.

                        Comment


                        • #13
                          Originally posted by dejanp View Post
                          Oracle serializable implemention is ... Hmmm.. Let's try to put it nicely... It's so exotic that I never ever saw anyone who was able to actually use it.
                          And what is so exotic? It adheres to "serializable" definition (i.e. no dirty reads, no non-repeatable reads, no phantom reads). And even if you would search even this forum (and/or "Data access" forum) you will find samples of its usage. BTW, during TPC-C tests in which Oracle performs exceptionally well "seriazable" isolation level is a must.

                          Comment


                          • #14
                            Originally posted by dejanp View Post
                            The problem is that Hibernate people give no reasoning behind their advice
                            First the say that there is no database access without a transaction - which is correct. Even the most trivial SQL is running in a transaction, that's why they mention auto-commit="true". Now the reasoning seems to be as follows: If there is a transaction anyway better take control of it yourself (=> clear boundaries).

                            Joerg

                            Comment


                            • #15
                              Originally posted by Jörg Heinicke View Post
                              First the say that there is no database access without a transaction - which is correct. Even the most trivial SQL is running in a transaction...
                              In the ideal world - yes, in the reald world - no. There are databases that allow SQL outside of transaction control (as I have written already in this thread). For example, JDBC driver for "DB2 Universal Database for iSeries
                              support following isolation levels
                              • none
                              • read uncommited
                              • read commited
                              • repeatable read
                              • "serializable"

                              If level is "none" then SQL is run without transaction at all.
                              Moreover, the same JDBC driver has one more property - "true autocommit",
                              here is quotation from documentation
                              "true autocommit" Specifies whether the connection should use true auto commit support. True autocommit means that autocommit is on and is running under a isolation level other than *NONE. By default, the driver handles autocommit by running under the server isolation level of *NONE.
                              Regards,
                              Oleksandr

                              Comment

                              Working...
                              X