There's no indication of what the keys are in each table.
There is inconsistent use of IDs for keys. (Can two different John Smiths register for classes?)
Students have no existence apart from their presence in a schedule.
DaysTimes is not atomic. It can be broken into smaller parts .
A good rule in table design is this: Each row depends on the key, the whole key, and nothing but the key.
Identify keys: Course: Name; Offering: ID; Schedule: Name + OfferingID.
Give ID fields to Course and Student.
Extract a Student table.
Turn each session time into its own row (perhaps in another table).
Exercise 51. Duplication
Each class loads the database driver (just in case).
Each class defines a create() method (similar but not identical).
Many find() and update() methods are similar.
Test classes have duplicate setups.
Test cases could communicate better. (How about an explanation string on the less obvious asserts?)
Divergent change: classes depend on both the database and the domain.
Course and Offering pretty much consist of public access methods, with little behavior of their own.
We may be missing some collection classes.
B. Create() creates the object in memory, and all() or find() can locate an existing copy. Code manipulates the object in memory and then calls update() to write it. There's no general approach to deleting objects.
Exercise 52. Application
B. It makes sense to create a class to represent tables. It may be easiest to start by making this the superclass, but in the long run we'd probably evolve to having it in a separate part of the hierarchy from our domain objects.
Exercise 53. Database Layer
A. It would probably be easier to do some cleanup first and define a separable persistence layer.
B. A layer would make it easier to test the domain model and database code separately. A memory-based database would improve the running speed of many tests, because not all tests need the slow-but-safe disk-based database.
C. There's no reason to expose any of JDBC.
Exercise 54. Find
B. This probably crosses the line into being development.
C. We could put the objects in the map instead of the keys.
Exercise 55. Multiple Open Queries
A. It could potentially affect a lot of code.
B. One approach would be to load only the keys of related objects. When a client does a get on the corresponding field, then do a lookup based on the stored key. You could optionally cache the reference.
Exercise 56. Counter
This can be problematic if there's more than one process or thread simultaneously accessing the database. The usual solution is to introduce transactions. (Some databases may have a simple solution for the special case of a counter, but in general we may need transactions.)
Exercise 58. Database Refactorings
Look for work by Martin Fowler and Scott Ambler in this area.
Exercise 59. Domain Class Independence
Ideally, the database classes will depend on the data model rather than vice versa.