Thanks to both of you for those responses.  They totally make sense.

Like many people, I'm riding the learning curve with graph databases.  I've 
been doing RDBMS work forever, and only working with neo4j for about a year 
and a half, and there's still so many things I don't know yet.

RE: the use of transactions, in the RDBMS world it's kind of a secret that 
all reads are wrapped in transactions, but usually the programmer is 
ignorant of that; they can just issue SELECT queries and get data back.   
The DBMS might do that inside of a transaction for all the reasons you 
provide, but the user doesn't know it's happening.  Users do transactions 
more for when they want to do things incrementally, be able to roll-back if 
something in the middle fails, and so on.

So I won't take issue with the rationale, but perhaps some of this can be 
hidden from the users over time.  With all of the benefits for read-only 
operations that you cite, and with transactions being required everywhere, 
perhaps there are opportunities where the API could do this for me.    If I 
do have to do it everywhere (reads and writes) then while the Java 7 
pattern reduces the amount of code I'm writing, I'm still writing a lot of 
boilerplate try/with blocks, and trying to remember to put tx.success() 
before every exit point of the block (e.g. when my try block has 3 
different spots where it returns something from the method).

David

On Thursday, January 2, 2014 7:36:25 PM UTC-5, Michael Hunger wrote:
>
> Thanks a lot Johannes for chiming in. 
>
> Adding transactions for reads is mostly about creating the foundations for 
> - repeatable reads, 
> - better resource management 
> - allowing support for more isolation levels 
> - better automatic locking 
>
> The move from try - finally to try - with and AutoClosable was something 
> that came after Java7 was required, just a easier to use pattern. 
>
> Currently in Neo4j the approach is fail by default, other tx-systems use 
> succeed by default and offer something like tx.setRollbackOnly() to mark 
> for failure. 
>
> According to the core team this is by intent but unfortunately makes it 
> easy to miss the necessary tx.success() call. :( 
>
>
> so the current pattern required is: 
>
> try (Transaction tx = db.beginTx()) { 
>  do stuff 
>  tx.success(); 
> } 
>
>
> HTH 
>
> Mcihael 
>
> Am 02.01.2014 um 23:41 schrieb Johannes Mockenhaupt 
> <[email protected]<javascript:>>: 
>
>
> > On 12/31/2013 04:12 PM, M. David Allen wrote: 
> >> Just curious, what's the thinking behind requiring transactions for 
> reads? 
> > 
> > Since nobody else answered yet I'll take a stab at it :-) 
> > 
> > As far as I know the reason for requiring transaction for read 
> > operations is optimization: fetched resources can be released after the 
> > transactional context has been closed. A nice side-effect is 
> > consistency: your read operations will be unaffected by write 
> > transactions that are going on in parallel. 
> > 
> >> Also, some documentation updates might be appropriate.  For example: 
> >> 
> >> 
> http://api.neo4j.org/current/org/neo4j/graphdb/NotInTransactionException.html 
> >> 
> >> public class NotInTransactionException 
> >> extends RuntimeException 
> > <
> http://docs.oracle.com/javase/7/docs/api/java/lang/RuntimeException.html?is-external=true>
>  
>
> >> 
> >> Thrown when attempting to modify the graph outside of a transaction. 
> >> 
> > 
> > Thanks for catching that, the docs have been updated but that spot has 
> > been missed. I have opened a pull request for an update of that JavaDoc 
> > which has already been merged. 
> > 
> >> Finally, I noticed that with 2.0, apparently the code wants you to use 
> >> try/with, instead of try/finally, e.g. 
> >> 
> >> |try ( Transaction tx = graphDb.beginTx() ) { blah(); } 
> >> 
> >> I'm also curious about that decision, since it requires I choose 
> between looking 
> >> at deprecation warnings on my use of tx.finish() or trying to upgrade 
> all my 
> >> developer's IDEs to java7 code style compliance. 
> > 
> > I like the reduction of redundant code this change brings, but then 
> > again, I don't have a migrate a (big) code base too it ;-) 
> > 
> > Johannes 
> > 
> >> On Tuesday, December 31, 2013 10:07:08 AM UTC-5, Michael Hunger wrote: 
> >> 
> >>    Hi 
> >> 
> >>    Read operation on the database and nodes and relationships now 
> >>    require transactions 
> >> 
> >>    Probably most sensible to wrap the tx around the entry point to your 
> >>    service layer. 
> >> 
> >>    HTH 
> >> 
> >>    Michael 
> >> 
> >>    Sent from mobile device 
> >> 
> >>    Am 31.12.2013 um 15:53 schrieb "M. David Allen" <[email protected] 
> >>    <javascript:>>: 
> >> 
> >>>    I'm in the middle of retrofitting neo4j code that was running on 
> >>>    1.9.3 to 2.0.0.  This is all happening under windows, jdk1.7.0_45, 
> >>>    and eclipse. 
> >>> 
> >>>     I expected some teething problems and cut-overs; here's one I've 
> >>>    run into: 
> >>> 
> >>>    org.neo4j.graphdb.NotInTransactionException 
> >>>        at 
> >>>   
>  
> org.neo4j.kernel.impl.persistence.PersistenceManager.getResource(PersistenceManager.java:214)
>  
>
> >>>        at 
> >>>   
>  
> org.neo4j.kernel.impl.persistence.PersistenceManager.currentKernelTransaction(PersistenceManager.java:84)
>  
>
> >>>        at 
> >>>   
>  
> org.neo4j.kernel.impl.core.ThreadToStatementContextBridge.transaction(ThreadToStatementContextBridge.java:53)
>  
>
> >>>        at 
> >>>   
>  
> org.neo4j.kernel.impl.core.ThreadToStatementContextBridge.instance(ThreadToStatementContextBridge.java:47)
>  
>
> >>>        at 
> >>>   
>  org.neo4j.kernel.impl.core.NodeProxy.hasProperty(NodeProxy.java:346) 
> >>>        at 
> >>>    blah.blah.mypackage.MyStorage.isMyObjectNode(Neo4JStorage.java:219) 
> >>>        at 
> >>>   
>  blah.blah.mypackage.MyFactory.newObject(Neo4JPLUSObjectFactory.java:190) 
> >>>        at 
> >>>    blah.blah.mypackage.MyFactory.listWorkflows(Neo4JStorage.java:933) 
> >>> 
> >>>    I can make it happy by wrapping the methods below in a 
> >>>    transaction, but I'm pretty sure that's not the right thing to do. 
> >>> 
> >>>    Here's the relevant method: 
> >>> 
> >>>        public static boolean isMyObjectNode(Node n) { 
> >>>            return n != null && n.hasProperty(PROP_PLUSOBJECT_ID) && 
> >>>    n.hasProperty(PROP_TYPE) && n.hasProperty(PROP_SUBTYPE); 
> >>>        } 
> >>> 
> >>>    (Context: all of those PROP_TYPE, etc are all public static final 
> >>>    String) 
> >>> 
> >>>    The "newObject" method in my package is just creating one of my 
> >>>    domain objects out of a node.  In order to do that, it needs to 
> >>>    check which kind of node it's dealing with.   I'd rather not paste 
> >>>    that code because it's involved and includes many other subclasses 
> >>>    that makes the rabbit hole deeper.  Suffice to say I'm sure that 
> >>>    it's just creating my domain objects, and not modifying anything 
> >>>    in the graph. 
> >>> 
> >>>    The "listWorkflows" method looks like this: 
> >>> 
> >>>        public static List<MyWorkflow> listWorkflows(User user, int 
> >>>    maxReturn) throws MyException { 
> >>>            if(maxReturn <= 0 || maxReturn > 1000) maxReturn = 100; 
> >>> 
> >>>            String query = "start n=node:node_auto_index(type=\"" + 
> >>>    MyWorkflow.TYPE_WORKFLOW + "\") " + 
> >>>                           "where has(n.oid) " + 
> >>>                           "return n " + 
> >>>                           "limit " + maxReturn; 
> >>> 
> >>>            Iterator<Node> ns = 
> Neo4JStorage.execute(query).columnAs("n"); 
> >>>            ArrayList<MyWorkflow> wfs = new ArrayList<MyWorkflow>(); 
> >>> 
> >>>            while(ns.hasNext()) { 
> >>>                MyObject o = MyFactory.newObject(ns.next()); 
> >>>                if(o.isWorkflow()) wfs.add((MyWorkflow)o); 
> >>>                else { 
> >>>                    log.warning("Returned non-workflow " + o + " from 
> >>>    workflow query!"); 
> >>>                } 
> >>>            } 
> >>> 
> >>>            return wfs; 
> >>>        } // End listWorkflows 
> >>> 
> >>>    Indeed this code (and its caller) doesn't happen within a 
> >>>    transaction, but it shouldn't need to -- no modification is going 
> >>>    on here. 
> >>> 
> >>>    Lastly -- yes, I know about labels, and how labels would probably 
> >>>    be a better way to do this.  I'm planning on exploiting that, but 
> >>>    the first thing to do is to get the current code base working on 
> >>>    the new release, and I've got other fish to fry (like cypher query 
> >>>    syntax updates to get rid of "?") before I get to using labels. 
> >>> 
> >>>    Thanks! 
> >>> 
> >>>    -- 
> >>>    You received this message because you are subscribed to the Google 
> >>>    Groups "Neo4j" group. 
> >>>    To unsubscribe from this group and stop receiving emails from it, 
> >>>    send an email to [email protected] <javascript:>. 
> >>>    For more options, visit https://groups.google.com/groups/opt_out 
> >>>    <https://groups.google.com/groups/opt_out>. 
> >> 
> >> -- 
> >> You received this message because you are subscribed to the Google 
> >> Groups "Neo4j" group. 
> >> To unsubscribe from this group and stop receiving emails from it, send 
> >> an email to [email protected] <javascript:>. 
> >> For more options, visit https://groups.google.com/groups/opt_out. 
> > 
> > -- 
> > You received this message because you are subscribed to the Google 
> Groups "Neo4j" group. 
> > To unsubscribe from this group and stop receiving emails from it, send 
> an email to [email protected] <javascript:>. 
> > For more options, visit https://groups.google.com/groups/opt_out. 
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Neo4j" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to