About the original post, here are some thoughts:
That is a nice idea to save yourself from simple crashes.
Case 1:
C++:
player = nullptr;
...
player->addItem(...);
Here your memory is probably consistent and your server crashed by calling a nullptr.
The fix is probably checking if the player is nullptr before calling addItem, and it's probably safe to save players and restart.
Case 2:
C++:
item = container->getFirstItem();
...
delete item;
...
(do several stuff, and then a player interacts with that container's first item, and server crashes)
Here the item has been deleted, so the memory was eventually used for something else.
The crash happened when calling some function of this item, which had random memory and raised a segfault.
The fix is not that simple, cause you need to know why this item got deleted, but the reference was still there.
Your server's memory is corrupt and we're not sure anymore if it's safe to save.
Saving in this state could lead to saving incorrect amount of the item, incorrect id, or simply raising another segfault during save.
So, I believe this piece of code might be useful for server maintainers that suffer from 'Case 1' crashes.
But be aware to keep your server down until you check why it crashed, fixing it and be sure if that save is safe.
About the save function, you probably wanna kick every player first, before saving them.
Some servers might use the 'onLogout' event to remove temporary quest items, so it doesn't seem right to simply teleport them to temple.
In my case, I wouldn't use this approach.
'Case 1' kind of crashes are rare, because once it happens, it's easy to fix and it'll never happen again. If you know what you're coding and have a decent test server infrastructure, probably this won't worry you much.
'Case 2' would be useful, because once it happens, it might take hours or even days to find out what it happening. You sure don't wanna several rollbacks every day until you find it. However 'Case 2' is not safe to save, so this approach is not useful.
Talking about other approaches, here's what I've in mind:
Idea 1 is logging to a second database in another thread every player's achievements.
If the player kills a monster:
C++:
LogThread::executeQuery("insert into player_exp (player_id, exp,recovered,timestamp) values(1234, 150, 0, unix_timestamp())");
LogThread::executeQuery("insert into player_loot (player_id, itemId,count,recovered,timestamp) values(1234, 9290, 10, 0, unix_timestamp())");
Of course there could be some caching and inserting batches of experience/loot.
The idea here is to log the player's boring work. Such as killing monsters, capturing monsters or whatever repetitive task you have in your server.
Players usually won't mind doing a 30 minute quest again, or crafting some items again.
But for sure they'll mind hunting for 8h the same monster again on the same cave. Or if they're trying to catch a super rare shiny, they finally made it and then the server rollbacks.
If your server crashes rarely enough, the extra loot without expanses won't be a problem. It'll actually be a compensation for other losses.
Idea 2 is having a fork and 3 database system.
Database 1 is the main database which your server is running and Database 2 is a mirror of Database 1 (master/slave).
Every 5-10 minutes you fork your server process, create a new Database 3, lock DB2, copy DB2 to DB3, connects the fork to DB3, kick every player and save it.
This way, DB3 is in a state as if your server had shutdown properly. In case your server crashes, you can copy DB3 to DB1 and lose ~10 minutes of gameplay at most.
It needs some polishing, cause it's not clear what happens if your server crashes during the DB copy. But it seems that it could work.
To finish, remember that there're other reasons for rollbacks. Someone getting infinite rewards from a chest should be a reason to rollback. If that's the case, only the Idea 1 approach would be suitable to recover player data.
PS: in case someone has any ideas on how to solve 'Case 2' crashes, I'd be happy to talk about. Usually I just read some code and try to reproduce it. Which is really hard work, cause we know stuff like 'that item had invalid memory, but what caused it?'