In a typical RDBMS the row data lives in a separate area of storage called the heap. The B-tree is just an index pointing into the heap. It is straightforward to construct multiple indexes pointing into the same heap, on an arbitrarily determined key (you can even combine fields or apply functions to them to generate a key). There is a special-case where the row data is stored inside the B-tree, called a clustered index, but even there you can have a second B-tree pointing into the primary index.
In order to access the rows quickly multiple strategies are used. Some columns can be kept inside the index, which is very fast to query, and for the others a page cache can be used to keep the most commonly accessed parts of the heap in RAM. If you have enough RAM to keep the working set entirely in memory the database will perform well even without indexes. For larger working sets an SSD with low latency seeks can help a lot with performance.
The challenge that databases have is to keep all these structures in sync even across crashes. The typical approach is to use a write-ahead log (WAL). Writes are first appended to the log, and a memory cache ensures that reads are serviced from the log instead of the out-of-date B-trees. After the log is flushed to disk the B-trees are also updated. If the database crashes before it has finished updating the B-trees, on next startup it will recover from the WAL and finish the update.
If you want to learn more, you can follow along with the notes from this slide deck.