diff --git a/BerkeleyDB.cabal b/BerkeleyDB.cabal
--- a/BerkeleyDB.cabal
+++ b/BerkeleyDB.cabal
@@ -1,5 +1,5 @@
 name: BerkeleyDB
-version: 0.8
+version: 0.8.1
 license: BSD3
 license-file: LICENSE
 cabal-version: >= 1.4
diff --git a/Database/Berkeley/Db.hsc b/Database/Berkeley/Db.hsc
--- a/Database/Berkeley/Db.hsc
+++ b/Database/Berkeley/Db.hsc
@@ -87,7 +87,6 @@
 import System.IO.Error
 import System.IO (FilePath)
 import Foreign.ForeignPtr
-import System.IO.Unsafe
 import Data.ByteString (ByteString)
 import qualified Data.ByteString.Internal as BSI
 import Data.Word
@@ -778,14 +777,17 @@
 
 
 foreign import ccall "db_helper.h _dbtxn_id" _dbtxn_id
-    :: Ptr DbTxn_struct -> IO CUInt
+    :: Ptr DbTxn_struct -> Ptr CUInt -> IO CInt
 
 -- | Get the locker ID for a transaction, which can be used with 'dbEnv_withLock'.
-dbTxn_id :: DbTxn -> DbLocker
+dbTxn_id :: DbTxn -> IO DbLocker
 dbTxn_id dbtxn =
-    unsafePerformIO $
     withForeignPtr dbtxn $ \c_dbtxn ->
-        liftM DbLocker$ _dbtxn_id c_dbtxn
+    alloca $ \ptr -> do
+        ret <- _dbtxn_id c_dbtxn ptr
+        if ret /= 0
+            then throwDB "dbTxn_id" ret
+            else DbLocker <$> peek ptr
 
 data DbLockMode = DB_LOCK_READ | DB_LOCK_WRITE | DB_LOCK_IWRITE | DB_LOCK_IREAD | DB_LOCK_IWR
 
diff --git a/Database/Berkeley/db_helper.c b/Database/Berkeley/db_helper.c
--- a/Database/Berkeley/db_helper.c
+++ b/Database/Berkeley/db_helper.c
@@ -9,7 +9,7 @@
     if (*dbenvp == NULL) return -20881;  /* Haskell binding-specific error code */ \
     dbenv = *dbenvp;
 
-#define UNWRAP_DBTXN_() \
+#define UNWRAP_DB_TXN_() \
     if (dbtxnp == NULL) \
         dbtxn = NULL; \
     else { \
@@ -17,6 +17,14 @@
         dbtxn = *dbtxnp; \
     }
 
+#define UNWRAP_DB_TXN2_() \
+    if (dbtxnp == NULL) \
+        dbtxn = NULL; \
+    else { \
+        if (dbtxnp[1] == NULL) return -20883;  /* Haskell binding-specific error code */ \
+        dbtxn = dbtxnp[1]; \
+    }
+
 #define UNWRAP_DB() \
     DB* db = *dbp; \
     if (db == NULL) return -20882;  /* Haskell binding-specific error code */
@@ -25,10 +33,14 @@
     DBC* dbc = *dbcp; \
     if (dbc == NULL) return -20884;  /* Haskell binding-specific error code */
 
-#define UNWRAP_DBTXN() \
+#define UNWRAP_DB_TXN() \
     DB_TXN* dbtxn; \
-    UNWRAP_DBTXN_()
+    UNWRAP_DB_TXN_()
 
+#define UNWRAP_DB_TXN2() \
+    DB_TXN* dbtxn; \
+    UNWRAP_DB_TXN2_()
+
 int _dbenv_create(MY_DBENV** dbenvpp, u_int32_t flags)
 {
     int ret;
@@ -146,7 +158,7 @@
     return db->set_pagesize(db, pagesize);
 }
 
-int _db_open(DB** dbp, MY_DBTXN** txnp, const char* file, const char* database,
+int _db_open(DB** dbp, DB_TXN** txnp, const char* file, const char* database,
     int type, u_int32_t flags, int mode)
 {
     DB_TXN* txn;
@@ -160,9 +172,10 @@
     return db->open(db, txn, file, database, (DBTYPE) type, flags, mode);
 }
 
-int _dbenv_txn_begin(MY_DBENV* dbenvp, MY_DBTXN** parentp, MY_DBTXN*** txnpp, u_int32_t flags)
+int _dbenv_txn_begin(MY_DBENV* dbenvp, DB_TXN** parentp, DB_TXN*** txnpp, u_int32_t flags)
 {
-    MY_DBTXN* parent;
+    int ret;
+    DB_TXN* parent;
     UNWRAP_DBENV();
     if (parentp == NULL)
         parent = NULL;
@@ -170,8 +183,14 @@
         parent = *parentp;
         if (parent == NULL) return -20883;  /* Haskell binding-specific error code */
     }
-    *txnpp = (MY_DBTXN**)malloc(sizeof(MY_DBTXN*));
-    return dbenv->txn_begin(dbenv, parent, *txnpp, flags);
+    *txnpp = (DB_TXN**)malloc(sizeof(DB_TXN*)*2);
+    ret = dbenv->txn_begin(dbenv, parent, *txnpp, flags);
+    /* Store the DB_TXN twice - the first is NULLed when we pass it to be wrapped
+       as a DBXML transaction.
+       We keep the second for operations where we still want to access it
+       after DBXML has taken it over, in particular _dbtxn_id(). */
+    (*txnpp)[1] = (*txnpp)[0];
+    return ret;
 }
 
 int _dbenv_txn_checkpoint(MY_DBENV* dbenvp, u_int32_t kbyte, u_int32_t min, u_int32_t flags)
@@ -180,31 +199,34 @@
     return dbenv->txn_checkpoint(dbenv, kbyte, min, flags);
 }
 
-int _dbtxn_abort(MY_DBTXN** dbtxnp)
+int _dbtxn_abort(DB_TXN** dbtxnp)
 {
-    UNWRAP_DBTXN();
-    *dbtxnp = NULL;
+    UNWRAP_DB_TXN();
+    dbtxnp[0] = NULL;
+    dbtxnp[1] = NULL;
     dbtxn->abort(dbtxn);
 }
 
-int _dbtxn_commit(MY_DBTXN** dbtxnp, u_int32_t flags)
+int _dbtxn_commit(DB_TXN** dbtxnp, u_int32_t flags)
 {
-    UNWRAP_DBTXN();
-    *dbtxnp = NULL;
+    UNWRAP_DB_TXN();
+    dbtxnp[0] = NULL;
+    dbtxnp[1] = NULL;
     dbtxn->commit(dbtxn, flags);
 }
 
-void _dbtxn_delete(MY_DBTXN** dbtxnp)
+void _dbtxn_delete(DB_TXN** dbtxnp)
 {
     if (*dbtxnp != NULL)
         (*dbtxnp)->abort(*dbtxnp);
     free(dbtxnp);
 }
 
-u_int32_t _dbtxn_id(MY_DBTXN** dbtxnp)
+int _dbtxn_id(DB_TXN** dbtxnp, u_int32_t* locker)
 {
-    UNWRAP_DBTXN();
-    return dbtxn->id(dbtxn);
+    UNWRAP_DB_TXN2();
+    *locker = dbtxn->id(dbtxn);
+    return 0;
 }
 
 int _dbenv_lock_get(MY_DBENV* dbenvp, u_int32_t lockerID, u_int32_t flags,
@@ -242,14 +264,14 @@
     free(str);
 }
 
-int _db_get(DB** dbp, MY_DBTXN** dbtxnp, const char* key, u_int32_t key_len, char** value, u_int32_t* value_len, u_int32_t flags)
+int _db_get(DB** dbp, DB_TXN** dbtxnp, const char* key, u_int32_t key_len, char** value, u_int32_t* value_len, u_int32_t flags)
 {
     DBT keyDbt;
     DBT valueDbt;
     int ret;
     DB_TXN* dbtxn;
     UNWRAP_DB();
-    UNWRAP_DBTXN_();
+    UNWRAP_DB_TXN2_();
 
     memset(&keyDbt, 0, sizeof(keyDbt));
     keyDbt.flags = DB_DBT_USERMEM;
@@ -268,13 +290,13 @@
     return ret;
 }
 
-int _db_put(DB** dbp, MY_DBTXN** dbtxnp, const char* key, u_int32_t key_len, const char* value, u_int32_t value_len, u_int32_t flags)
+int _db_put(DB** dbp, DB_TXN** dbtxnp, const char* key, u_int32_t key_len, const char* value, u_int32_t value_len, u_int32_t flags)
 {
     DBT keyDbt;
     DBT valueDbt;
     DB_TXN* dbtxn;
     UNWRAP_DB();
-    UNWRAP_DBTXN_();
+    UNWRAP_DB_TXN2_();
 
     memset(&keyDbt, 0, sizeof(keyDbt));
     keyDbt.flags = DB_DBT_USERMEM;
@@ -287,12 +309,12 @@
     return db->put(db, dbtxn, &keyDbt, &valueDbt, flags);
 }
 
-int _db_del(DB** dbp, MY_DBTXN** dbtxnp, const char* key, u_int32_t key_len, u_int32_t flags)
+int _db_del(DB** dbp, DB_TXN** dbtxnp, const char* key, u_int32_t key_len, u_int32_t flags)
 {
     DBT keyDbt;
     DB_TXN* dbtxn;
     UNWRAP_DB();
-    UNWRAP_DBTXN_();
+    UNWRAP_DB_TXN2_();
 
     memset(&keyDbt, 0, sizeof(keyDbt));
     keyDbt.flags = DB_DBT_USERMEM;
@@ -308,11 +330,11 @@
     return db->close(db, flags);
 }
 
-int _db_cursor(DB** dbp, MY_DBTXN** dbtxnp, DBC*** dbcursorpp, u_int32_t flags)
+int _db_cursor(DB** dbp, DB_TXN** dbtxnp, DBC*** dbcursorpp, u_int32_t flags)
 {
     DB_TXN* dbtxn;
     UNWRAP_DB();
-    UNWRAP_DBTXN_();
+    UNWRAP_DB_TXN2_();
     *dbcursorpp = (DBC**)malloc(sizeof(DBC**));
     int ret = db->cursor(db, dbtxn, *dbcursorpp, flags);
     if (ret != 0)
diff --git a/Database/Berkeley/db_helper.h b/Database/Berkeley/db_helper.h
--- a/Database/Berkeley/db_helper.h
+++ b/Database/Berkeley/db_helper.h
@@ -3,7 +3,6 @@
 
 #include <db.h>
 #define MY_DBENV DB_ENV*
-#define MY_DBTXN DB_TXN
 
 typedef struct _DB_LOCK {
     MY_DBENV* dbenv;
@@ -30,25 +29,25 @@
 int _db_create(DB*** dbpp, MY_DBENV* dbenvp, u_int32_t flags);
 void _db_delete(DB** db);
 int _db_set_pagesize(DB** dbp, u_int32_t pagesize);
-int _db_open(DB** dbp, MY_DBTXN** txnp, const char* file, const char* database,
+int _db_open(DB** dbp, DB_TXN** txnp, const char* file, const char* database,
     int type, u_int32_t flags, int mode);
-int _dbenv_txn_begin(MY_DBENV* dbenvp, MY_DBTXN** parent, MY_DBTXN*** txnpp, u_int32_t flags);
+int _dbenv_txn_begin(MY_DBENV* dbenvp, DB_TXN** parent, DB_TXN*** txnpp, u_int32_t flags);
 int _dbenv_txn_checkpoint(MY_DBENV* dbenvp, u_int32_t kbyte, u_int32_t min, u_int32_t flags);
-int _dbtxn_abort(MY_DBTXN** dbtxnp);
-int _dbtxn_commit(MY_DBTXN** dbtxnp, u_int32_t flags);
-void _dbtxn_delete(MY_DBTXN** dbtxnp);
-u_int32_t _dbtxn_id(MY_DBTXN** dbtxnp);
+int _dbtxn_abort(DB_TXN** dbtxnp);
+int _dbtxn_commit(DB_TXN** dbtxnp, u_int32_t flags);
+void _dbtxn_delete(DB_TXN** dbtxnp);
+int _dbtxn_id(DB_TXN** dbtxnp, u_int32_t* locker);
 void _dblock_delete(_DB_LOCK* dblock);
 int _dbenv_lock_get(MY_DBENV* dbenvp, u_int32_t lockerID, u_int32_t flags,
     const char* object, u_int32_t object_len, u_int32_t lockmode, _DB_LOCK** dblock);
 int _dbenv_lock_put(_DB_LOCK* dblock);
 void _deleteString(char* str);
 void _freeString(char* str);
-int _db_get(DB** dbp, MY_DBTXN** dbtxnp, const char* key, u_int32_t key_len, char** value, u_int32_t* value_len, u_int32_t flags);
-int _db_put(DB** dbp, MY_DBTXN** dbtxnp, const char* key, u_int32_t key_len, const char* value, u_int32_t value_len, u_int32_t flags);
-int _db_del(DB** dbp, MY_DBTXN** dbtxnp, const char* key, u_int32_t key_len, u_int32_t flags);
+int _db_get(DB** dbp, DB_TXN** dbtxnp, const char* key, u_int32_t key_len, char** value, u_int32_t* value_len, u_int32_t flags);
+int _db_put(DB** dbp, DB_TXN** dbtxnp, const char* key, u_int32_t key_len, const char* value, u_int32_t value_len, u_int32_t flags);
+int _db_del(DB** dbp, DB_TXN** dbtxnp, const char* key, u_int32_t key_len, u_int32_t flags);
 int _db_close(DB** dbp, u_int32_t flags);
-int _db_cursor(DB** dbp, MY_DBTXN** dbtxnp, DBC*** dbcursorpp, u_int32_t flags);
+int _db_cursor(DB** dbp, DB_TXN** dbtxnp, DBC*** dbcursorpp, u_int32_t flags);
 void _dbcursor_delete(DBC** dbc);
 int _dbCursor_close(DBC** dbc);
 int _dbCursor_count(DBC** dbcp, u_int32_t* countp, u_int32_t flags);
diff --git a/examples/tests.hs b/examples/tests.hs
--- a/examples/tests.hs
+++ b/examples/tests.hs
@@ -139,7 +139,8 @@
         -- This doesn't test very much: Just that locking doesn't cause any
         -- runtime errors, hangs or crashes.
         dbEnv_withTxn [] [] dbenv Nothing $ \txn -> do
-            dbEnv_withLock [] DB_LOCK_WRITE (pack "my_lock") dbenv (dbTxn_id txn) $ do
+            locker <- dbTxn_id txn
+            dbEnv_withLock [] DB_LOCK_WRITE (pack "my_lock") dbenv locker $ do
                 db_put [] db (Just txn) (pack "fruit") (pack "durian")
 
 test_dbCursor_get =
