Presentation is loading. Please wait.

Presentation is loading. Please wait.

Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. Introduction to Spring JDBC Simplifying.

Similar presentations


Presentation on theme: "Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. Introduction to Spring JDBC Simplifying."— Presentation transcript:

1 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. Introduction to Spring JDBC Simplifying JDBC-based data access with Spring JDBC

2 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 2 Topics in this Session Problems with traditional JDBC –Results in redundant, error prone code –Leads to poor exception handling Spring’s JdbcTemplate –Configuration –Query execution –Working with result sets –Exception handling

3 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 3 Topics in this Session Problems with traditional JDBC –Results in redundant, error prone code –Leads to poor exception handling Spring’s JdbcTemplate –Configuration –Query execution –Working with result sets –Exception handling

4 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 4 Redundant, Error Prone Code public List findByLastName(String lastName) { List personList = new ArrayList(); Connection conn = null; String sql = “ select first_name, age from PERSON where last_name=? “ ; try { DataSource dataSource = DataSourceUtils.getDataSource(); conn = dataSource.getConnection(); PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, lastName); ResultSet rs = ps.executeQuery(); while (rs.next()) { String firstName = rs.getString( ” first_name “ ); int age = rs.getInt( “ age ” ); personList.add(new Person(firstName, lastName, age)); } } catch (Exception e) { /* ??? */ } finally { try { conn.close(); } catch (SQLException e) { /* ??? */ } } return personList; } public List findByLastName(String lastName) { List personList = new ArrayList(); Connection conn = null; String sql = “ select first_name, age from PERSON where last_name=? “ ; try { DataSource dataSource = DataSourceUtils.getDataSource(); conn = dataSource.getConnection(); PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, lastName); ResultSet rs = ps.executeQuery(); while (rs.next()) { String firstName = rs.getString( ” first_name “ ); int age = rs.getInt( “ age ” ); personList.add(new Person(firstName, lastName, age)); } } catch (Exception e) { /* ??? */ } finally { try { conn.close(); } catch (SQLException e) { /* ??? */ } } return personList; }

5 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 5 Redundant, Error Prone Code public List findByLastName(String lastName) { List personList = new ArrayList(); Connection conn = null; String sql = "select first_name, age from PERSON where last_name=?"; try { DataSource dataSource = DataSourceUtils.getDataSource(); conn = dataSource.getConnection(); PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, lastName); ResultSet rs = ps.executeQuery(); while (rs.next()) { String firstName = rs.getString( “ first_name ” ); int age = rs.getInt( “ age ” ); personList.add(new Person(firstName, lastName, age)); } } catch (Exception e) { /* ??? */ } finally { try { conn.close(); } catch (SQLException e) { /* ??? */ } } return personList; } public List findByLastName(String lastName) { List personList = new ArrayList(); Connection conn = null; String sql = "select first_name, age from PERSON where last_name=?"; try { DataSource dataSource = DataSourceUtils.getDataSource(); conn = dataSource.getConnection(); PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, lastName); ResultSet rs = ps.executeQuery(); while (rs.next()) { String firstName = rs.getString( “ first_name ” ); int age = rs.getInt( “ age ” ); personList.add(new Person(firstName, lastName, age)); } } catch (Exception e) { /* ??? */ } finally { try { conn.close(); } catch (SQLException e) { /* ??? */ } } return personList; } The bold matters - the rest is boilerplate

6 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 6 public List findByLastName(String lastName) { List personList = new ArrayList(); Connection conn = null; String sql = "select first_name, age from PERSON where last_name=? “ ; try { DataSource dataSource = DataSourceUtils.getDataSource(); conn = dataSource.getConnection(); PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, lastName); ResultSet rs = ps.executeQuery(); while (rs.next()) { String firstName = rs.getString( ” first_name “ ); int age = rs.getInt( “ age ” ); personList.add(new Person(firstName, lastName, age)); } } catch (Exception e) { /* ??? */ } finally { try { conn.close(); } catch (SQLException e) { /* ??? */ } } return personList; } public List findByLastName(String lastName) { List personList = new ArrayList(); Connection conn = null; String sql = "select first_name, age from PERSON where last_name=? “ ; try { DataSource dataSource = DataSourceUtils.getDataSource(); conn = dataSource.getConnection(); PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, lastName); ResultSet rs = ps.executeQuery(); while (rs.next()) { String firstName = rs.getString( ” first_name “ ); int age = rs.getInt( “ age ” ); personList.add(new Person(firstName, lastName, age)); } } catch (Exception e) { /* ??? */ } finally { try { conn.close(); } catch (SQLException e) { /* ??? */ } } return personList; } Poor Exception Handling What can you do?

7 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 7 Topics in this session Problems with traditional JDBC –Results in redundant, error prone code –Leads to poor exception handling Spring’s JdbcTemplate –Configuration –Query execution –Working with result sets –Exception handling

8 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 8 Spring’s JdbcTemplate Greatly simplifies use of the JDBC API –Eliminates repetitive boilerplate code –Alleviates common causes of bugs –Handles SQLExceptions properly Without sacrificing power –Provides full access to the standard JDBC constructs

9 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 9 JdbcTemplate in a Nutshell Acquisition of the connection Participation in the transaction Execution of the statement Processing of the result set Handling any exceptions Release of the connection int count = jdbcTemplate.queryForInt( “SELECT COUNT(*) FROM CUSTOMER”); int count = jdbcTemplate.queryForInt( “SELECT COUNT(*) FROM CUSTOMER”); All handled by Spring

10 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 10 JdbcTemplate Approach Overview List results = jdbcTemplate.query(someSql, new RowMapper() { public Object mapRow(ResultSet rs, int row) { // map the current row to an object } }); class JdbcTemplate { public List query(sql, rowCallback) { try { // acquire connection // prepare statement // execute statement // for each row in the result set results.add(rowCallback.mapRow(rs, rowNumber)); return results; } catch (SQLException e) { // convert to root cause exception } finally { // release connection } }

11 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 11 Creating a JdbcTemplate Requires a DataSource Create a template once and re-use it –Do not create one for each use –Thread safe after construction JdbcTemplate template = new JdbcTemplate(dataSource);

12 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 12 When to use JdbcTemplate Useful standalone –Anytime JDBC is needed –In utility or test code –To clean up messy legacy code Useful for implementing a repository in a layered application –Also known as a data access object (DAO)

13 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 13 Steps to implementing a JDBC-based repository 1.Create a new class –Typically implementing a data access interface you define 2.Implement data access methods using the JdbcTemplate or SimpleJdbcTemplate 3.Unit test the data access behavior 4.Integrate the repository into your application Where it will typically participate in application- driven transactions

14 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 14 Creating a JDBC-based Repository class Spring provides two support classes you may extend from –Extend JdbcDaoSupport on Java 1.4 –Extend SimpleJdbcDaoSupport on Java 5.0 or greater After extending you inherit a JdbcTemplate you configure by injecting a DataSource

15 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 15 Implementing a JDBC-based Repository - Java 1.4 public class JdbcCustomerRepository implements CustomerRepository { private JdbcTemplate jdbcTemplate; private JdbcCustomerRepository(DataSource ds) { this.jdbcTemplate = new JdbcTemplate(dataSource); } public int getCustomerCount() { String sql = “select count(*) from customer”; return jdbcTemplate.queryForInt(sql); } public class JdbcCustomerRepository implements CustomerRepository { private JdbcTemplate jdbcTemplate; private JdbcCustomerRepository(DataSource ds) { this.jdbcTemplate = new JdbcTemplate(dataSource); } public int getCustomerCount() { String sql = “select count(*) from customer”; return jdbcTemplate.queryForInt(sql); }

16 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 16 Implementing a JDBC-based Repository - Java 5.0 or > public class JdbcCustomerRepository implements CustomerRepository { private SimpleJdbcTemplate jdbcTemplate; private JdbcCustomerRepository(DataSource ds) { this.jdbcTemplate = new SimpleJdbcTemplate(dataSource); } public int getCustomerCountOlderThan(int age) { String sql = “select count(*) from customer where age > ?”; return jdbcTemplate.queryForInt(sql, age); } public class JdbcCustomerRepository implements CustomerRepository { private SimpleJdbcTemplate jdbcTemplate; private JdbcCustomerRepository(DataSource ds) { this.jdbcTemplate = new SimpleJdbcTemplate(dataSource); } public int getCustomerCountOlderThan(int age) { String sql = “select count(*) from customer where age > ?”; return jdbcTemplate.queryForInt(sql, age); }

17 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 17 Integrating a Repository into an Application <bean id=“customerRepository” class=“example.customer.JdbcCustomerRepository”> <bean id=“customerRepository” class=“example.customer.JdbcCustomerRepository”> Configure the repository’s DataSourceInject the repository into application services

18 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 18 A Word on JdbcDaoSupport Spring has a convenient super class you can extend –Provides a setDataSource() method –Instantiates a (Simple)JdbcTemplate for you –Get access to the template using getJdbcTemplate() Preferably use constructor-injection and code up your own class instead of using the JdbcDaoSupport class –Support class uses setter injection: less concise –Support class does not work well with @Autowired

19 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 19 A Word on JdbcTemplate versus SimpleJdbcTemplate SimpleJdbcTemplate is not only for Java 5 and above –Some infrequently used functionality has been removed If you need more control, use the getJdbcOperations() method to get to the underlying JdbcTemplate, which has all the power you want. Stick to using SimpleJdbcTemplate where possible

20 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 20 Querying with JdbcTemplate JdbcTemplate can query for –Simple types (int, long, String) –Generic Maps –Domain Objects

21 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 21 Querying for Simple Java Types (1) Query with no bind variables public int getPersonCount() { String sql = “select count(*) from PERSON”; return getJdbcTemplate().queryForInt(sql); } public int getPersonCount() { String sql = “select count(*) from PERSON”; return getJdbcTemplate().queryForInt(sql); }

22 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 22 Querying for Simple Java Types (2) Query with a bind variable public int getCountOfPersonsOlderThan(int age) { return getJdbcTemplate().queryForInt( “select count(*) from PERSON where age > ?”, new Object[] { new Integer(age) }); } public int getCountOfPersonsOlderThan(int age) { return getJdbcTemplate().queryForInt( “select count(*) from PERSON where age > ?”, new Object[] { new Integer(age) }); }

23 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 23 Querying With SimpleJdbcTemplate Use SimpleJdbcTemplate if running on Java 5 or > public int getCountOfPersonsOlderThan(int age) { return getSimpleJdbcTemplate().queryForInt( “select count(*) from PERSON where age > ?”, age); } public int getCountOfPersonsOlderThan(int age) { return getSimpleJdbcTemplate().queryForInt( “select count(*) from PERSON where age > ?”, age); } No need for new Object[] { new Integer(age) }

24 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 24 Generic Queries JdbcTemplate can return each row of a ResultSet as a Map When expecting a single row –Use queryForMap(..) When expecting multiple rows –Use queryForList(..) Useful for reporting, testing, and ‘window-on- data’ use cases

25 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 25 Querying for Generic Maps (1) Query for a single row returns: Map { ID=1, FIRST_NAME= “ John ”, LAST_NAME= “ Doe ” } public Map getPersonInfo(int id) { String sql = “select * from PERSON where id=?”; return getJdbcTemplate().queryForMap(sql, id); } public Map getPersonInfo(int id) { String sql = “select * from PERSON where id=?”; return getJdbcTemplate().queryForMap(sql, id); }

26 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 26 Querying for Generic Maps (2) Query for multiple rows returns: List { 0 - Map { ID=1, FIRST_NAME= “ John ”, LAST_NAME= “ Doe ” } 1 - Map { ID=2, FIRST_NAME= “ Jane ”, LAST_NAME= “ Doe ” } 2 - Map { ID=3, FIRST_NAME= “ Junior ”, LAST_NAME= “ Doe ” } } public List getAllPersonInfo() { String sql = “select * from PERSON”; return getJdbcTemplate().queryForList(sql); } public List getAllPersonInfo() { String sql = “select * from PERSON”; return getJdbcTemplate().queryForList(sql); }

27 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 27 Domain Object Queries Often it is useful to map relational data into domain objects –e.g. a ResultSet to an Account Spring’s JdbcTemplate supports this using a callback approach

28 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 28 Querying for Domain Objects (1) Query for a single row public Person getPerson(int id) { return (Person)getJdbcTemplate().queryForObject( “select first_name, last_name from PERSON where id=?”, new Object[] { new Long(id) }, new PersonMapper()); } public Person getPerson(int id) { return (Person)getJdbcTemplate().queryForObject( “select first_name, last_name from PERSON where id=?”, new Object[] { new Long(id) }, new PersonMapper()); } class PersonMapper implements RowMapper { public Object mapRow(ResultSet rs, int i) { return new Person(rs.getString(1), rs.getString(2)); } class PersonMapper implements RowMapper { public Object mapRow(ResultSet rs, int i) { return new Person(rs.getString(1), rs.getString(2)); } Maps rows to Person objects

29 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 29 Querying for Domain Objects (2) Query for multiple rows public List getAllPersons() { return getJdbcTemplate().query( “select first_name, last_name from PERSON”, new PersonMapper()); } public List getAllPersons() { return getJdbcTemplate().query( “select first_name, last_name from PERSON”, new PersonMapper()); } class PersonMapper implements RowMapper { public Object mapRow(ResultSet rs, int i) { return new Person(rs.getString(1), rs.getString(2)); } class PersonMapper implements RowMapper { public Object mapRow(ResultSet rs, int i) { return new Person(rs.getString(1), rs.getString(2)); } Same row mapper can be used

30 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 30 Querying for a Single Domain Object with SimpleJdbcTemplate SimpleJdbcTemplate benefits from generics public Person getPerson(int id) { return getSimpleJdbcTemplate().queryForObject( “select first_name, last_name from PERSON where id=?”, new PersonMapper(), id); } public Person getPerson(int id) { return getSimpleJdbcTemplate().queryForObject( “select first_name, last_name from PERSON where id=?”, new PersonMapper(), id); } class PersonMapper implements ParameterizedRowMapper { public Person mapRow(ResultSet rs, int i) { return new Person(rs.getString(1), rs.getString(2)); } class PersonMapper implements ParameterizedRowMapper { public Person mapRow(ResultSet rs, int i) { return new Person(rs.getString(1), rs.getString(2)); } Parameterizes return type No need to cast

31 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 31 Querying for Multiple Domain Objects with SimpleJdbcTemplate public List getAllPersons() { return getSimpleJdbcTemplate().query( “select first_name, last_name from PERSON”, new PersonMapper()); public List getAllPersons() { return getSimpleJdbcTemplate().query( “select first_name, last_name from PERSON”, new PersonMapper()); class PersonMapper implements ParameterizedRowMapper { public Person mapRow(ResultSet rs, int i) { return new Person(rs.getString(1), rs.getString(2)); } class PersonMapper implements ParameterizedRowMapper { public Person mapRow(ResultSet rs, int i) { return new Person(rs.getString(1), rs.getString(2)); } No need to cast

32 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 32 RowCallbackHandler Spring provides a simpler RowCallbackHandler interface when there is no return object –Streaming rows to a file –Filtering rows before adding to a Collection public interface RowCallbackHandler { void processRow(ResultSet rs) throws SQLException; } public interface RowCallbackHandler { void processRow(ResultSet rs) throws SQLException; }

33 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 33 Using a RowCallbackHandler public class JdbcOrderRepository { public void generateReport() { // select all orders for a full report getJdbcTemplate().query(“select...from order o, item i”, new OrderReportWriter()); } public class JdbcOrderRepository { public void generateReport() { // select all orders for a full report getJdbcTemplate().query(“select...from order o, item i”, new OrderReportWriter()); } class OrderReportWriter implements RowCallbackHandler { public void processRow(ResultSet rs) throws SQLException { // stream row to a file } class OrderReportWriter implements RowCallbackHandler { public void processRow(ResultSet rs) throws SQLException { // stream row to a file }

34 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 34 ResultSetExtractor Spring provides a ResultSetExtractor interface for mapping an entire ResultSet to an object public interface ResultSetExtractor { Object extractData(ResultSet rs) throws SQLException, DataAccessException; } public interface ResultSetExtractor { Object extractData(ResultSet rs) throws SQLException, DataAccessException; }

35 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 35 Using a ResultSetExtractor public class JdbcOrderRepository { public Order findByConfirmationNumber(String number) { // execute an outer join between order and item tables return (Order) getJdbcTemplate().query( “select...from order o, item i...conf_id = ?”, new Object[] { number }, new OrderExtractor()); } public class JdbcOrderRepository { public Order findByConfirmationNumber(String number) { // execute an outer join between order and item tables return (Order) getJdbcTemplate().query( “select...from order o, item i...conf_id = ?”, new Object[] { number }, new OrderExtractor()); } class OrderExtractor implements ResultSetExtractor { public Object extractData(ResultSet rs) throws SQLException { // create an Order object from multiple rows } class OrderExtractor implements ResultSetExtractor { public Object extractData(ResultSet rs) throws SQLException { // create an Order object from multiple rows }

36 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 36 Summary of Callback Interfaces RowMapper –Best choice when each row of a ResultSet maps to a domain object RowCallbackHandler –Best choice when no value should be returned from the callback method ResultSetExtractor –Best choice when multiple rows of a ResultSet map to a domain object

37 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 37 Inserts and Updates (1) Inserting a new row public int insertPerson(Person person) { return getSimpleJdbcTemplate().update( “insert into PERSON (first_name, last_name, age)” + “values (?, ?, ?)”, person.getFirstName(), person.getLastName(), person.getAge()); } public int insertPerson(Person person) { return getSimpleJdbcTemplate().update( “insert into PERSON (first_name, last_name, age)” + “values (?, ?, ?)”, person.getFirstName(), person.getLastName(), person.getAge()); }

38 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 38 Inserts and Updates (2) Updating an existing row public int updateAge(Person person) { return getSimpleJdbcTemplate().update( “update PERSON set age=? where id=?”, person.getAge(), person.getId()); } public int updateAge(Person person) { return getSimpleJdbcTemplate().update( “update PERSON set age=? where id=?”, person.getAge(), person.getId()); }

39 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 39 SQLException Handling SQLExceptions are often handled inconsistently in many applications Using the JdbcTemplate ensures SQLExceptions are handled properly

40 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 40 SQLException Handling Issues Hard to determine cause of failure –Must read a vendor-specific error code SQLException is a leaky abstraction –As a checked exception a SQLException must propagate if it is not caught –Leads to one of two things: “Catch and wrap” Being swallowed

41 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 41 Spring SQLException Handling SQLExceptions are handled consistently –Resources are always released properly Generic SQLExceptions are translated to root cause DataAccessExceptions –Provides consistency across all database vendors –Frees you from your own catch-and-wrap approach –Enables selective handling by type of failure –Exceptions always propagate if not caught

42 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. 42 Spring DataAccessException Hierarchy (subset) DataRetrievalFailureException DataAccessResourceFailureException CleanupFailureDataAccessException InvalidDataAccessApiUsageException InvalidDataAccessResourceUsageException IncorrectUpdateSemanticsDataAccessException TypeMismatchDataAccessException OptimisticLockingFailureException ObjectRetrievalFailureException DataAccessException UncategorizedDataAccessException DataIntegrityViolationException DeadlockLoserDataAccessException ObjectOptimisticLockingFailureException

43 Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. Lab Introduction to Spring JDBC


Download ppt "Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. Introduction to Spring JDBC Simplifying."

Similar presentations


Ads by Google