To enable transactions for your environment, you must initialize the transactional subsystem. Note that doing this also initializes the logging subsystem. In addition, you must initialize the memory pool (in-memory cache). You must also initialize the locking subsystem. For example:
Notice in the following example that you first create the
environment handle,
and then you provide the handle to the
XmlManager
constructor. You do this because you
cannot use transactions with the XmlManager
instance's default internal environment.
#include "DbXml.hpp" ... using namespace DbXml; int main(void) { u_int32_t env_flags = DB_CREATE | // If the environment does not // exist, create it. DB_INIT_LOCK | // Initialize locking DB_INIT_LOG | // Initialize logging DB_INIT_MPOOL | // Initialize the cache DB_INIT_TXN; // Initialize transactions DB_ENV *myEnv = NULL; XmlManager *myManager = NULL; char *envHome = "/export1/testEnv"; int dberr; dberr = db_env_create(&myEnv, 0); if (dberr) { std::cout << "Unable to create environment: " << db_strerror(dberr) << std::endl; if (myEnv) myEnv->close(myEnv, 0); return (EXIT_FAILURE); } myEnv->open(myEnv, envHome, env_flags, 0); myManager = new XmlManager(myEnv, 0); try { if (myManager != NULL) { delete myManager; } myEnv->close(myEnv, 0); } catch(XmlException &e) { std::cerr << "Error closing manager: " << envHome << std::endl; std::cerr << e.what() << std::endl; return (EXIT_FAILURE); } catch(std::exception &e) { std::cerr << "Error closing environment: " << envHome << std::endl; std::cerr << e.what() << std::endl; return (EXIT_FAILURE); } return (EXIT_SUCCESS); }
You then create and/or open your containers as normal. The only
difference is that you must set
XmlContainerConfig::setTransactional()
to true
and pass that object to the
openContainer()
or createContainer()
method.
For example:
#include "DbXml.hpp"
...
using namespace DbXml;
int main(void)
{
u_int32_t env_flags = DB_CREATE | // If the environment does not
// exist, create it.
DB_INIT_LOCK | // Initialize locking
DB_INIT_LOG | // Initialize logging
DB_INIT_MPOOL | // Initialize the cache
DB_INIT_TXN; // Initialize transactions
DB_ENV *myEnv = NULL;
XmlManager *myManager = NULL;
char *envHome = "/export1/testEnv";
int dberr;
dberr = db_env_create(&myEnv, 0);
if (dberr) {
std::cout << "Unable to create environment: " <<
db_strerror(dberr) << std::endl;
if (myEnv)
myEnv->close(myEnv, 0);
return (EXIT_FAILURE);
}
myEnv->open(myEnv, envHome, env_flags, 0);
myManager = new XmlManager(myEnv, 0);
try {
XmlContainerConfig cconfig;
cconfig.setAllowCreate(true); // If the container does not
// exist, create it.
cconfig.setTransactional(true); // Enable transactions.
std::string containerName = "myContainer.dbxml";
XmlContainer myContainer =
myManager->openContainer(containerName, cconfig);
} catch(XmlException &e) {
std::cerr << "Error opening environment: "
<< envHome << std::endl;
std::cerr << e.what() << std::endl;
return (EXIT_FAILURE);
} catch(std::exception &e) {
std::cerr << "Error opening environment: "
<< envHome
<< " or opening XmlManager or XmlContainer."
<< std::endl;
std::cerr << e.what() << std::endl;
return (EXIT_FAILURE);
}
try {
if (myManager != NULL) {
delete myManager;
}
myEnv.close(0);
} catch(DbException &e) {
std::cerr << "Error closing environment: "
<< envHome << std::endl;
std::cerr << e.what() << std::endl;
return (EXIT_FAILURE);
} catch(std::exception &e) {
std::cerr << "Error closing environment: "
<< envHome << std::endl;
std::cerr << e.what() << std::endl;
return (EXIT_FAILURE);
}
return (EXIT_SUCCESS);
}
It is possible to use Berkeley DB databases along side of BDB XML containers. When you do this, you will typically use both the databases and the containers from within the same environment so that you can combine operations to both using transactions.
There is no difference between opening a Berkeley DB database in an environment that uses containers and opening a database in an environment that does not use containers (see the Berkeley DB Getting Started with Transaction Processing guide for details on how to do this). You simply share the same environment handle between the two when you open the database(s) and container(s). For example:
#include "DbXml.hpp" ... using namespace DbXml; int main(void) { u_int32_t env_flags = DB_CREATE | // If the environment does not // exist, create it. DB_INIT_LOCK | // Initialize locking DB_INIT_LOG | // Initialize logging DB_INIT_MPOOL | // Initialize the cache DB_INIT_TXN; // Initialize transactionsu_int32_t db_flags = DB_CREATE | DB_AUTO_COMMIT; Db *dbp = NULL; const char *file_name = "mydb.db";
DB_ENV *myEnv = NULL; XmlManager *myManager = NULL; char *envHome = "/export1/testEnv"; int dberr; dberr = db_env_create(&myEnv, 0); if (dberr) { std::cout << "Unable to create environment: " << db_strerror(dberr) << std::endl; if (myEnv) myEnv->close(myEnv, 0); return (EXIT_FAILURE); } myEnv->open(myEnv, envHome, env_flags, 0); myManager = new XmlManager(myEnv, 0);dbp = db_create(&dbp, myEnv, 0); dbp->open(NULL, // Txn pointer file_name, // File name NULL, // Logical db name DB_BTREE, // Database type (using btree) db_flags, // Open flags 0); // File mode. Using defaults
try { XmlContainerConfig cconfig; cconfig.setAllowCreate(true); // If the container does not // exist, create it. cconfig.setTransactional(true); // Enable transactions. std::string containerName = "myContainer.dbxml"; XmlContainer myContainer = myManager->openContainer(containerName, cconfig); } catch(XmlException &e) { std::cerr << "Error opening container: " << e.what() << std::endl; return (EXIT_FAILURE); } catch(std::exception &e) { std::cerr << "Error opening database environment: " << envHome << " or opening XmlManager or XmlContainer." << std::endl; std::cerr << e.what() << std::endl; return (EXIT_FAILURE); } try {if (dbp != NULL) { dbp->close(dbp, 0); }
if (myManager != NULL) { delete myManager; } myEnv.close(0); } catch(DbException &e) { std::cerr << "Error closing database and environment: " << envHome << std::endl; std::cerr << e.what() << std::endl; return (EXIT_FAILURE); } catch(std::exception &e) { std::cerr << "Error closing database environment: " << envHome << std::endl; std::cerr << e.what() << std::endl; return (EXIT_FAILURE); } return (EXIT_SUCCESS); }
Never close a database that has active transactions. Make sure all transactions are resolved (either committed or aborted) before closing the database.