aboutsummaryrefslogtreecommitdiff
path: root/optimistic/driver.cxx
blob: 25bc9af84f48da42f179738fd99eb7b1c60c70ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// file      : optimistic/driver.cxx
// copyright : not copyrighted - public domain

#include <memory>   // std::auto_ptr
#include <iostream>

#include <odb/database.hxx>
#include <odb/transaction.hxx>

#include "database.hxx" // create_database

#include "person.hxx"
#include "person-odb.hxx"

using namespace std;
using namespace odb::core;

int
main (int argc, char* argv[])
{
  try
  {
    auto_ptr<database> db (create_database (argc, argv));

    // Persist the object.
    //
    // At this point the initial version (1) is assigned.
    //
    unsigned long id;
    {
      person p ("John", "Doe", 21);

      transaction t (db->begin ());
      id = db->persist (p);
      t.commit ();

      cout << "version after persist: " << p.version () << endl;
    }

    // Process 1: load the object.
    //
    person p1;
    {
      transaction t (db->begin ());
      db->load (id, p1);
      t.commit ();

      cout << "process 1 version after load: " << p1.version () << endl;
    }

    // Process 2: load the object.
    //
    person p2;
    {
      transaction t (db->begin ());
      db->load (id, p2);
      t.commit ();

      cout << "process 2 version after load: " << p2.version () << endl;
    }

    // Process 1: update the object.
    //
    // At this point the version is incremented and becomes 2.
    //
    {
      p1.age (20); // Correct the wrong age.

      transaction t (db->begin ());
      db->update (p1);
      t.commit ();

      cout << "process 1 version after update: " << p1.version () << endl;
    }

    // Process 2: update the object.
    //
    // Since the object version in this process is 1 while in the database
    // it is 2, this operation will fail.
    //
    {
      p2.age (p2.age () + 1); // Increment the age.

      transaction t (db->begin ());

      try
      {
        db->update (p2);
      }
      catch (const object_changed&)
      {
        cout << "process 2 version is out of date: " << p2.version () << endl;

        // Reload the object and retry the operation. Note that the second
        // update call cannot throw object_changed since we reloaded the
        // object and are trying to update it in a single transaction.
        //
        db->reload (p2);

        cout << "process 2 version after reload: " << p2.version () << endl;

        p2.age (p2.age () + 1);
        db->update (p2);
      }

      t.commit ();

      cout << "process 2 version after update: " << p2.version () << endl;
      cout << "final age value: " << p2.age () << endl;
    }

    // Process 1: delete the object if the person is younger than 21.
    //
    // Since the object version in this process is 2 while in the database
    // it is 3, this operation will fail. Note that this will only hold
    // true if we are deleting the object by passing an object instance
    // to the erase() function. If instead we pass object id, then the
    // object will be deleted regardless of the version.
    //
    if (p1.age () < 21)
    {
      transaction t (db->begin ());

      try
      {
        db->erase (p1);
        // db->erase (id); // Never throws object_changed.
      }
      catch (const object_changed&)
      {
        cout << "process 1 version is out of date: " << p1.version () << endl;

        // Reload the object and retry the operation. Similar to update, the
        // second erase call cannot throw object_changed since we reloaded
        // the object and are trying to erase it in a single transaction.
        //
        db->reload (p1);

        cout << "process 1 version after reload: " << p2.version () << endl;

        if (p1.age () < 21)
        {
          db->erase (p1);
          cout << "object deleted" << endl;
        }
        else
          cout << "object not deleted" << endl;
      }

      t.commit ();
    }
  }
  catch (const odb::exception& e)
  {
    cerr << e.what () << endl;
    return 1;
  }
}