Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

See the New Neo4j Bolt Drivers in Action

DZone's Guide to

See the New Neo4j Bolt Drivers in Action

With the 1.2 release of Neo4j's Bolt drivers, expect an easier experience with Python and Java, better cluster failure recovery, and automatic role change handling.

· Database Zone ·
Free Resource

MariaDB TX, proven in production and driven by the community, is a complete database solution for any and every enterprise — a modern database for modern applications.

We are happy to announce that all our officially supported Bolt drivers are now available as versions 1.2. With this release, we massively improved the way you write code to work with a cluster, introducing reusable “transaction functions” and built-in retry functionality.

For some new capabilities, we added new APIs. Here you can find detailed documentation and the driver repositories.

New Capabilities in All Neo4j Drivers

Drivers now handle cluster server failures and role changes automatically, allowing the application to treat the cluster as a single black box providing read and write services. This simplifies the programming model massively. You don’t have to care about cluster state or retrying operations after its change.

  • A Bolt+routing URI represents a network address
  • Automatic DNS “Round Robin” resolution can yield multiple hosts → addresses
  • A load balancer (e.g., AWS ELB) can route to multiple hosts → addresses
  • These are the routing bootstrap addresses: they should be configured to be probable core servers
  • Read Replicas cannot provide routing tables
  • When the driver is initialized, it goes to one of the bootstrap addresses to get a routing table

Neo4j drivers requests routing table

Neo4j drivers cluster returns routing table

Neo4j drivers routes client request

Neo4j drivers refreshes routing table

The Neo4j driver will switch traffic to an appropriate read or write connection depending on the transaction access mode. The read/write transaction access mode is a familiar SQL/ODBC/JDBC pattern of use.

We added new methods Session.read_transaction and Session.write_transaction to allow the execution of reusable units of work. You simply pass in a transaction function to the method. To allow re-execution of failed operations, the duration for retries is configurable via max_retry_time in the Neo4j driver configuration (the default is 30s).

Let's check out an example of how you would use this capability.

Python Example

from neo4j.v1 import GraphDatabase


driver = GraphDatabase.driver("bolt+routing://server:7687",
                              auth=("neo4j", "password"))


def add_friends(tx, name, friend_name):
    tx.run("MERGE (p:Person {name: $name}) "
           "MERGE (f:Person {name: $friend_name}) "
           "MERGE (p)-[:KNOWS]-(f)",
           name=name, friend_name=friend_name)


def print_friends(tx, name):
    for record in tx.run(
          "MATCH (a:Person)-[:KNOWS]->(friend) WHERE a.name = $name "
          "RETURN friend.name ORDER BY friend.name", name=name):
        print(record["friend.name"])


with driver.session() as session:
    session.write_transaction(
      lambda tx:
        tx.run("create constraint on (p:Person) assert p.name is unique"))
    session.write_transaction(add_friends, "Arthur", "Guinevere")
    session.write_transaction(add_friends, "Arthur", "Lancelot")
    session.write_transaction(add_friends, "Arthur", "Merlin")
    session.read_transaction(print_friends, "Arthur")


Java Example

You can find the full code in this example project.

public class Person{
    private final static String COUNT_PEOPLE =
         ("MATCH (a:Person) RETURN count(a)");

    // callback method
    public static long count(Transaction tx){
        StatementResult result = tx.run(COUNT_PEOPLE);
        return result.single().get(0).asLong();
    }
    ...
}


public class SocialNetwork{
    public long countUsers() {
        try (Session session = driver.session()){
            return session.readTransaction(Person::count);
        }
    }

    public long addUser(Person user) {
        System.out.println(format("Adding user %s", user));
        try (Session session = driver.session(){
            return session.writeTransaction(user::save);
        }
    }
}


We decoupled the Session from a single underlying connection; a Session can now be defined as a causally linked sequence of transactional units of work.

You don’t need to manage bookmarks for causal consistency manually any longer. Bookmarks are now automatically passed between transactions within a routing session. This makes causal consistency the default interaction mode with the database cluster.

Auto-commit transactions (Session.run) will now run partially synchronous to the network (RUNand PULL_ALL will be sent to the server, the RUN response will be immediately received); this allows exceptions to be raised at a more logical point in the application.

Updates in Some of the Neo4j Drivers

The Python language driver now includes a compiled C module included for improved performance on supported platforms. Please let us know if this works for you.

If the provided hostname resolves to multiple IP addresses most of the drivers (except .NET) can handle this now.

As always, we’d love your feedback, so please try out the new Neo4j driver releases and raise feature or bug requests on the driver repositories. Please let us also know what you think about the new APIs and if there are ways to improve them.

If you need quick help, please join neo4j.com/slack and ask in the #drivers or the appropriate #neo4j-<language> channel. Otherwise you can also ask on Stack Overflow. Please tag your Stack Overflow questions with [neo4j-<language>-driver]

Enjoy the new Neo4j drivers!

MariaDB AX is an open source database for modern analytics: distributed, columnar and easy to use.

Topics:
neo4j ,database ,drivers ,causal consistency

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}