ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Agile Object to Relational Database Replication with db4o
Pages: 1, 2, 3, 4, 5, 6, 7, 8

Going the Other Way

Replication is bidirectional, so it is possible to update values in the MySQL database and replicate these back to the original db4o databases. In the following example, we'll update a couple of rows of the CUSTOMERS table. We'll increase the creditline value for customers whose contactcode is Joe. If you look at the original data stored in the db4o databases, you can see that this means the two Customers originally from the mobileone.yap database. We have to be careful, though. If we just run a simple update query like this:

update customers
set creditLine = creditLine + 20000,
where customers.contactCode = 'Joe';

then dRS will not know about the changes, and the new values will not be replicated. We can make sure they are replicated by also updating the drs_version value for each affected row. If this is set to be greater than the highest version value in the REPLICATIONRECORD table, then dRS will recognize that these rows have changed since the last replication round. The following version of the update query does this:

update customers
set
creditLine = creditLine + 20000,
drs_version = (select max(version) from replicationrecord) + 1
where customers.contactCode = 'Joe';

After executing the update query, we can look at the new data and see that the specified rows have been updated:

mysql> select id, firstname,lastname, creditline, contactcode from customers;
+----+-----------+----------------+------------+-------------+
| id | firstname | lastname       | creditline | contactcode |
+----+-----------+----------------+------------+-------------+
|  1 | Matt      | Hasselbeck     |      36000 | Joe         |
|  2 | Ben       | Roethlisberger |      92000 | Joe         |
|  3 | Jake      | Delhomme       |      45000 | Sue         |
|  4 | Jake      | Plummer        |      12000 | Sue         |
+----+-----------+----------------+------------+-------------+
4 rows in set (0.00 sec)

The code to replicate from Hibernate to a db4o database is very similar to the forward-replication code. We just specify that we want to replicate objects changed in provider B rather than provider A.

ExtDb4o.configure().generateUUIDs(Integer.MAX_VALUE);
ExtDb4o.configure().generateVersionNumbers(Integer.MAX_VALUE);
ObjectContainer objectContainer = Db4o.openFile("c:/mobileone.yap");
Configuration config = new Configuration().configure("hibernate.cfg.xml");
ReplicationSession replication = Replication.begin(container, config);
ObjectSet changed = replication.providerB().objectsChangedSinceLastReplication();
while (changed.hasNext())
    replication.replicate(changed.next());
replication.commit();
replication.close();
objectContainer.close();

After doing this, the relevant objects in mobileone.yap should have updated creditLine values. We could use the ObjectManager to browse the db4o database, but instead let's see how it's done using a db4o native query. The code to run a query that finds all objects with a contactCode that equals Joe is shown below. The query is expressed as an anonymous Predicate class that implements a method match. The match method contains the code that defines the query. All Customer objects in the database are candidates for matching, and the query returns a List of those Customer objects for which the match method returns true. Some clever optimization in the background means that this query actually executes without having to instantiate every candidate object in order to match it, which means that native queries can be fast. The code is written in Java, using the Predicate interface from the db4o API; there are no embedded query strings in SQL or any other query language. The only string value is the actual search value.

ObjectContainer objectContainer = Db4o.openFile("c:/mobileone.yap");
List<Customer> customers = objectContainer.query(new Predicate<Customer>() {
    public boolean match(Customer customer) {
        return customer.getContactCode().equals("Joe");
    }
});
for (Customer customer : customers){
    System.out.println("Name: " + customer.getLastName() + 
       ", Credit Line: " + customer.getCreditLine());
}
objectContainer.close();

The output shows that the values updated in MySQL have been successfully replicated to the db4o database:

Querying Mobile1...
Name: Roethlisberger, Credit Line: 92000
Name: Hasselbeck, Credit Line: 36000

This example demonstrated the replication of MySQL updates made directly using SQL. If the MySQL database is instead updated by a Java application using Hibernate, then the dRS ReplicationConfigurator class can be used within that application to install an event listener. This listener detects updates or inserts done through Hibernate, and automatically updates the drs_version field in the same way as we did manually above. It can also generate version numbers and UUIDs for data inserted with Hibernate. The dRS listener transparently ensures that Hibernate updates can be correctly replicated back to db4o. The listing below shows installation of a listener followed by updating with Hibernate. The objects to be updated are retrieved using HQL. The result after replication is the same as that of the SQL update described above.

Configuration cfg = new Configuration().configure("hibernate.cfg.xml");
ReplicationConfigurator.configure(cfg);
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession();
ReplicationConfigurator.install(session, cfg);
Transaction tx = session.beginTransaction();

List result = session.createQuery(
    "from Customer customer where customer.contactCode = 'Joe'").list();
Iterator it = result.iterator();
while(it.hasNext()){
    Customer cust = (Customer)it.next();
    cust.setCreditLine(cust.getCreditLine()+20000);
    session.save(cust);
}  
tx.commit();
session.close();

Pages: 1, 2, 3, 4, 5, 6, 7, 8

Next Pagearrow