People use all types of persistance layers with Struts: JDBC, JDO, EJB, OJB, CORBA, Torque, you name it.
But regardless of how you connect to a persistance layer, the best advice is to develop a facade (or internal API) for your application. The facade declares the inputs and outputs for each discrete function your application performs. Behind the facade, these input and outputs can connect to whatever you want. In front of the facade, a Struts Action can pass through the input (from an ActionForm) and then return the output (either in ActionForm or some type of collection or result object).
A facade also makes it easy to use more than one persistance layer. One method may use JDBC. Another method may use a search engine, like Lucene. A third may reach out to a web service. But they all look the same to whatever controller you want to use (including Struts).
The Artimus application bundled with Struts in Action uses this technique to connect to both JDBC and Lucene. Interally, we can switch from one to the other without the rest of the application knowing the difference.
A facade also makes it easy to switch between a working persitance layer and a mock persistance layer for
unit testing.
HTH, Ted.