Legacy DaoSupport And Template API
In the Spring core framework(provided in the spring-jdbc and spring-orm maven dependency), it has provided a series of standard DaoSupport APIs and Template pattern to help user to retrieve data from database and save data back into database.Jdbc support
There is a JdbcDaoSupport class and JdbcTempalte class provided for Jdbc operations.Using these APIs in your project is very simple and stupid.
-
Firstly register a DataSource bean, and also declare a Jdbc transaction manager(we will discuss Spring transaction in future posts).
<jdbc:embedded-database id="dataSource" type="H2"> <jdbc:script location="classpath:/com/hantsylabs/example/spring/config/schema.sql" /> </jdbc:embedded-database> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean>
In this codes fragment, we are using a H2 embedded database, and execute a predefined sql scripts to create the tables and insert the initial test data when the application starts up.
-
Declare your Dao interface and provide your implementation to subclass JdbcDaoSupprt.
public interface ConferenceDao { public abstract Conference findById(Long id); public abstract Long save(Conference conference); public abstract void delete(Long id); public abstract void delete(Conference obj); public abstract void update(Conference conference); public abstract void deleteAll(); public abstract Conference findBySlug(String string); }
In your implementation class, inject the DataSouce bean on the class constructor. If you explore the JdbcDaoSupport class in your IDE, you will find it had already provided a JdbcTemplate bean for you, you can use getJdbcTemplate() method to access it.
JdbcTemplate provides a lots of methods to simplify Jdbc operations.
public class JdbcConferenceDaoImpl extends JdbcDaoSupport implements ConferenceDao { @Autowired public JdbcConferenceDaoImpl(DataSource dataSource) { super(); setDataSource(dataSource); } @Override public Conference findById(Long id) { return jdbcTemplate.queryForObject( "select conference where id =?", new Object[] { id }, new ConferenceMapper()); } }
Alternatively, you can declare a JdbcTemplate bean(and inject the DataSource bean) yourself, and use JdbcTemplate in your implementation class directly. The benefit is you are free from subclassing the JdbcDaoSupport class.
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource" /> </bean>
Now you can use the injected JdbcTemplate directly.
public class JdbcConferenceDaoImpl implements ConferenceDao { @Autowired JdbcTemplate jdbcTemplate; @Override public Conference findById(Long id) { return jdbcTemplate.queryForObject( "select conference where id =?", new Object[] { id }, new ConferenceMapper()); } }
-
A glance at the JdbcTemplate API.
JdbcTemaplate provides a series of methods for sql execution, the generic method is execute, there are several variants provided for accepting different parameters. Some specific-purpose methods are also provided, such as:
query is designated for executing a general select * from table statement.
public Conference findBySlug(String slug) { List<Conference> confs = getJdbcTemplate().query( "select * from conference where slug=?", new Object[] { slug }, new ConferenceMapper()); if (!confs.isEmpty()) { return confs.get(0); } return null; }
Generally, you can implement a RowMapper, RowCallbackHandler or ResultSetExtacter to extract the data from Jdbc ResultSet and wrap them into your own object.
private class ConferenceMapper implements ParameterizedRowMapper<Conference> { @Override public Conference mapRow(ResultSet rs, int rowNum) throws SQLException { Conference conference = new Conference(); conference.setName(rs.getString("name")); conference.setDescription(rs.getString("description")); conference.setSlug(rs.getString("slug")); conference.setStartedDate(rs.getDate("started_date")); conference.setEndedDate(rs.getDate("ended_date")); conference.setId(rs.getLong("id")); return conference; } }
There are some simplified queryForXXX methods, which are useful for some specific queries. For example, in order to get the count of the table rows, you can use queryForInt to get the result directly.
getJdbcTemplate().queryForInt("select count(*) from conference);
And update is more easy when executing a insert, update, delete SQL statement.
public void delete(final Long id) { getJdbcTemplate().update("delete from conference where id=?", id); }
The update method can accept a KeyHolder parameter which is use for storing the generated identity key when a insert sql is executed.
public Long save(final Conference conference) { final String INSERT_SQL = "insert into conference (id, name, slug, description, started_date, ended_date, version) values (default, ?, ?, ?, ?, ?, 1) "; KeyHolder generatedKeyHolder = new GeneratedKeyHolder(); getJdbcTemplate().update(new PreparedStatementCreator() { @Override public PreparedStatement createPreparedStatement( Connection connection) throws SQLException { PreparedStatement ps = connection.prepareStatement(INSERT_SQL, new String[] { "id" }); ps.setString(1, conference.getName()); ps.setString(2, conference.getSlug()); ps.setString(3, conference.getDescription()); ps.setTimestamp(4, new java.sql.Timestamp( conference.getStartedDate().getTime())); ps.setTimestamp(5, new java.sql.Timestamp( conference.getEndedDate().getTime())); return ps; } }, generatedKeyHolder); return (Long) generatedKeyHolder.getKey(); }
batchUpdate is use for batch operations.
Let us have a look at the parameter classes of these methods.
PreparedStatementCreator is use for creating a PreparedStatement object from the Jdbc Connection object.
PreparedStatementSetter is use for filling values into the PreparedStatement placeholder.
PreparedStatementCallback is use for gathering the result of the execution.
There are also some method and classes are ready for Stored Procedure operations which are not covered here.
-
The improved NamedParameterJdbcTemplate.
As the name indicates, it is an improved version of JdbcTemplate and allow you use named parameters in sql statement instead of the position based placeholder.
<bean id="namedParamJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTempl ate"> <constructor-arg index="0" ref="dataSource"> </constructor-arg> </bean>
The NamedParameterJdbcTemplate can accept a DataSource bean or a classic JdbcTemplate bean as constructor arguments.
@Autowired NamedParameterJdbcTemplate namedParamJdbcTemplate; @Override public Conference findBySlug(String slug) { List<Conference> confs = namedParamJdbcTemplate.query( "select * from conference where slug=:slug", new MapSqlParameterSource().addValue("slug", slug), new ConferenceMapper()); if (!confs.isEmpty()) { return confs.get(0); } return null; }
Now the query method can accept a SqlParameterSource or a Map as arguments.
Another improved JdbcDaoSupport version named NamedParameterJdbcDaoSupport is also provided.
As you see, the improved variant APIs are more friendly for developers.
Hibernate support
Here we will use Hibernate 3 as the example to demonstrate the HibernateDaoSupport API and HibernateTemplate.NOTE: In Spring 3.1, Spring provides another ~.hibernate4 package to support the new Hibernate 4 API, it does not include DaoSupport and Template at all, Spring recommend developers use the native Hibernate API in new projects, I will demo it in the next posts.
The HibernateDaoSupport and HibernateTemplate are very similar with the Jdbc ones.
-
Register a DataSource bean, a Hibernate specific SessionFactoryBean bean and declare a HibernateTransactionManager.
<jdbc:embedded-database id="dataSource"> </jdbc:embedded-database> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="packagesToScan"> <list> <value>com.hantsylabs.example.spring.model</value> </list> </property> <property name="hibernateProperties"> <value> hibernate.format_sql=true hibernate.show_sql=true hibernate.hbm2ddl.auto=create hibernate.cache.provider_class=org.hibernate.cache.HashtableCacheProvider </value> </property> </bean> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean>
-
Write your implementation class which is extended HibernateDaoSupport class, and inject the SessionFactory bean.
public class Hibernate3ConferenceDaoImpl extends HibernateDaoSupport implements ConferenceDao { @Autowired public Hibernate3ConferenceDaoImpl( SessionFactory sessionFactory) { super(); setSessionFactory(sessionFactory); } }
Now you can use HibernateTemplate freely in your implementation class via getHibernateTemplate() method from HibernateDaoSupport.
Alternatively, you can declare a HiberanteTemplate bean and inject it into your implementation class, it is very similar with the scenario in the Jdbc section.
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate"> <property name="sessionFactory" ref="sessionFactory" /> </bean>
Now you are free from subclassing HibernateDaoSupport, only need to implement your own interface.
public class HibernateTemplateConferenceDaoImpl implements ConferenceDao { @Autowired private HibernateTemplate hibernateTemplate; }
-
HibernateTemplate API
In fact, the methods in HibernateTemplate class are very similar with the ones in Hibernate Session API, but it provides more features, such as it supports Spring exception translator.
You can use Hibernate Session API in a custom HibernateCallback inner class.
public Conference findBySlug(final String slug) { List<Conference> result = getHibernateTemplate().executeFind( new HibernateCallback<List<Conference>>() { @Override public List<Conference> doInHibernate(Session session) throws HibernateException, SQLException { return session .createQuery("from Conference where slug=:slug") .setParameter("slug", slug) .list(); } }); if (!result.isEmpty()) { return result.get(0); } return null; }
HibernateCallback includes a single callback method doInHibernate which accept a Hibernate Session as arguments, you can write your own Hibernate query in the method freely.
Jpa Support
Hibernate was proved it is a big success in the latest years in Java communities, and finally most of the Hibernate APIs were standardized as JPA specification 1.0, which is part of Java EE 5. Hibernate 3.2 is one of the JPA 1.0 implementations. NOTE, the reference implementation of JPA specification is EclipseLink.Some Hibernate concept can be mapped to JPA directly, for example, Session is equivalent to the EntityManager and SessionFactory acts as the same role of EntityManagerFactory.
Spring embraces JPA at the first time when it was released.
It also provides JpaDaoSupport and JpaTemplate classes.
-
Configure EntityManagerFactory and JpaTransactionManager beans.
<jdbc:embedded-database id="dataSource"> </jdbc:embedded-database> <bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory"> <property name="persistenceUnitName" value="persistenceUnit" /> <property name="dataSource" ref="dataSource" /> <property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence"></property> <property name="packagesToScan"> <array> <value>com.hantsylabs.example.spring.model</value> </array> </property> <property name="jpaProperties"> <value> hibernate.format_sql=true hibernate.show_sql=true hibernate.hbm2ddl.auto=create </value> </property> </bean> <bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean>
-
Use JpaTemplate freely in your implementation class.
public class JpaConferenceDaoImpl extends JpaDaoSupport implements ConferenceDao { @Autowired public JpaConferenceDaoImpl(EntityManagerFactory emf) { super(); setEntityManagerFactory(emf); } @Override public Conference findById(Long id) { return (Conference) getJpaTemplate().find(Conference.class, id); } }
JpaTemplate almost copies the methods from EntityManager.
NOTE: In Spring 3.1, the JpaDaoSupport is marked as @Deprecated and not recommended in new projects. In the future posts, I will demonstrate how to use the native JPA API.
Please check out the source codes from my Github.com, https://github.com/hantsy/spring-sandbox
评论