javascript
004Spring事务001JdbcTemplate
1 概述
1.1 簡介
為了使JDBC更加易于使用,Spring在JDBC的API上定義了一個抽象層,以此建立一個JDBC存取框架。
JdbcTemplate類對可變部分采用CallBack回調(diào)接口方式實(shí)現(xiàn),在CallBack接口實(shí)現(xiàn)類的Connection處于自動提交狀態(tài),在CallBack接口實(shí)現(xiàn)類的方法中不能進(jìn)行事物管理。
1.2 目的
JDBC模板的設(shè)計目的是為不同類型的JDBC操作提供模板方法,通過這種方式,可以在盡可能保留靈活性的情況下,將數(shù)據(jù)庫存取的工作量降到最低。
可以將Spring的JdbcTemplate看作是一個小型的輕量級持久化層框架,和DBUtils的風(fēng)格非常接近。
2 導(dǎo)包
2.1 IOC容器需要的包
commons-logging-1.1.1.jar spring-beans-4.0.0.RELEASE.jar spring-context-4.0.0.RELEASE.jar spring-core-4.0.0.RELEASE.jar spring-expression-4.0.0.RELEASE.jar2.2 AOP需要的包
spring-aop-4.0.0.RELEASE.jar spring-aspects-4.0.0.RELEASE.jar2.3 JdbcTemplate需要的包
spring-jdbc-4.0.0.RELEASE.jar spring-orm-4.0.0.RELEASE.jar spring-tx-4.0.0.RELEASE.jar2.4 數(shù)據(jù)庫驅(qū)動和數(shù)據(jù)源需要的包
c3p0-0.9.1.2.jar mysql-connector-java-5.1.7-bin.jar3 使用
3.1 數(shù)據(jù)庫連接信息屬性文件
在類路徑下創(chuàng)建jdbc.properties文件。
user=root password=root jdbcUrl=jdbc:mysql:///query_data driverClass=com.mysql.jdbc.Driver initialPoolSize=30 minPoolSize=10 maxPoolSize=100 acquireIncrement=5 maxStatements=1000 maxStatementsPerConnection=103.2 配置XML文件
將數(shù)據(jù)庫連接屬性文件引入到XML文件中,并注冊數(shù)據(jù)源Bean,使用SpEL表達(dá)式將外部文件中的配置信息賦值給數(shù)據(jù)源Bean。
還需要注冊一個Spring框架中JDBC的核心組件JdbcTemplate的Bean,并設(shè)置dataSource屬性引用數(shù)據(jù)源Bean。
<context:property-placeholder location="classpath:jdbc.properties"/> <bean id="comboPooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><property name="user" value="${user}"/><property name="password" value="${password}"/><property name="jdbcUrl" value="${jdbcUrl}"/><property name="driverClass" value="${driverClass}"/><property name="initialPoolSize" value="${initialPoolSize}"/><property name="minPoolSize" value="${minPoolSize}"/><property name="maxPoolSize" value="${maxPoolSize}"/><property name="acquireIncrement" value="${acquireIncrement}"/><property name="maxStatements" value="${maxStatements}"/><property name="maxStatementsPerConnection" value="${maxStatementsPerConnection}"/> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><constructor-arg ref="comboPooledDataSource" /> </bean>3.3 獲取JdbcTemplate組件
獲取到組件之后就可以進(jìn)行增刪改查操作了。
public class JdbcTemplateTest {ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");@Testpublic void test() throws Exception {// 獲取容器的JdbcTemplate組件。JdbcTemplate jdbcTemplate = (JdbcTemplate) ioc.getBean(JdbcTemplate.class);} }4 詳細(xì)說明
4.1 回調(diào)類
4.1.1 預(yù)編譯語句創(chuàng)建回調(diào)及存儲過程創(chuàng)建回調(diào)
用于根據(jù)JdbcTemplate提供的Connection創(chuàng)建語句。
PreparedStatementCreator:通過回調(diào)獲取JdbcTemplate提供的Connection,由用戶使用該Conncetion創(chuàng)建PreparedStatement。 CallableStatementCreator:通過回調(diào)獲取JdbcTemplate提供的Connection,由用戶使用該Conncetion創(chuàng)建CallableStatement。4.1.2 預(yù)編譯語句設(shè)值回調(diào)
用于給預(yù)編譯語句的參數(shù)設(shè)值。
PreparedStatementSetter:通過回調(diào)獲取JdbcTemplate提供的PreparedStatement,由用戶來給預(yù)編譯語句的參數(shù)設(shè)值。 BatchPreparedStatementSetter:類似于PreparedStatementSetter,但用于批處理,需要指定批處理大小。4.1.3 自定義功能回調(diào)
提供給用戶一個擴(kuò)展點(diǎn),用戶可以在指定類型的擴(kuò)展點(diǎn)執(zhí)行需要的操作,包括將預(yù)設(shè)值參數(shù)設(shè)置到預(yù)編譯語句中。
ConnectionCallback:通過回調(diào)獲取JdbcTemplate提供的Connection,用戶可在該Connection執(zhí)行操作。 StatementCallback:通過回調(diào)獲取JdbcTemplate提供的Statement,用戶可以在該Statement執(zhí)行操作。 PreparedStatementCallback:通過回調(diào)獲取JdbcTemplate提供的PreparedStatement,用戶可以在該P(yáng)reparedStatement執(zhí)行操作。 CallableStatementCallback:通過回調(diào)獲取JdbcTemplate提供的CallableStatement,用戶可以在該CallableStatement執(zhí)行操作。4.1.4 結(jié)果集處理回調(diào)
通過回調(diào)處理ResultSet或?qū)esultSet轉(zhuǎn)換為需要的形式。
RowMapper:用于封裝結(jié)果集數(shù)據(jù)到指定類型,需要重寫mapRow方法,每次封裝一行數(shù)據(jù),無需執(zhí)行rs.next()。 RowCallbackHandler:用于處理結(jié)果集數(shù)據(jù)而無需保存到內(nèi)存,需重寫processRow方法,每次處理一行數(shù)據(jù),無需執(zhí)行rs.next()。 ResultSetExtractor:用于結(jié)果集數(shù)據(jù)提取,需要重寫extractData方法,一次處理整個結(jié)果集,需要執(zhí)行rs.next()。4.2 主要方法
4.2.1 增加、刪除、修改
執(zhí)行一條語句:
// int update(String sql, Object... args); String sql = "update bs_book set title=? where id=?"; jdbcTemplate.update(sql, "新書", 10);執(zhí)行一條語句并返回自增主鍵:
// int update(PreparedStatementCreator psc, KeyHolder generatedKeyHolder); String sql = "insert into bs_book(title, author) values(?, ?)"; KeyHolder keyHolder = new GeneratedKeyHolder(); jdbcTemplate.update(new PreparedStatementCreator() {@Overridepublic PreparedStatement createPreparedStatement(Connection con)throws SQLException {PreparedStatement prepareStatement = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);prepareStatement.setString(1, "平凡的世界");prepareStatement.setString(2, "路遙");return prepareStatement;} }, keyHolder); System.out.println("id=" + keyHolder.getKey().intValue());批量執(zhí)行多條語句:
// int[] batchUpdate(String sql, List<Object[]> batchArgs); String sql = "insert into bs_book(title, author) values(?, ?)"; List<Object[]> books = new ArrayList<Object[]>(); books.add(new Object[]{"夢里花落知多少", "三毛"}); books.add(new Object[]{"雨季不再來", "三毛"}); int[] counts = jdbcTemplate.batchUpdate(sql, books); for (int i : counts) {System.out.println("count=" + i); }4.2.2 查詢
查詢一條數(shù)據(jù)并封裝到基本類型中返回:
// <T> T queryForObject(String sql, Class<T> requiredType, Object... args); String sql = "select count(id) from bs_book where author=?"; int count = jdbcTemplate.queryForObject(sql, Integer.class, "三毛"); System.out.println("count=" + count);查詢一條數(shù)據(jù)并封裝到指定類型中返回:
// <T> T queryForObject(String sql, RowMapper<T> rowMapper, Object... args); String sql = "select * from bs_book where id=?"; Book book = jdbcTemplate.queryForObject(sql, new RowMapper<Book>() {@Overridepublic Book mapRow(ResultSet rs, int rowNum) throws SQLException {System.out.println("rowNum=" + rowNum);Book book = new Book();book.setId(rs.getInt("id"));book.setTitle(rs.getString("title"));book.setAuthor(rs.getString("author"));return book;} }, "10"); // 也可以使用RowMapper的實(shí)現(xiàn)類BeanPropertyRowMapper來自動封裝結(jié)果。 // Book book = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(Book.class), "10"); System.out.println("book=" + book);查詢一條數(shù)據(jù)并封裝到Map中返回:
// Map<String,Object> queryForMap(String sql, Object... args); String sql = "select * from bs_book where id=?"; Map<String, Object> map = jdbcTemplate.queryForMap(sql, 10); map.forEach((key, value) -> System.out.println(key + "=" + value));查詢多條數(shù)據(jù)并封裝到基本類型中最后以List類型返回:
// <T> List<T> queryForList(String sql, Class<T> elementType, Object... args); String sql = "select title from bs_book where id<?"; List<String> list = jdbcTemplate.queryForList(sql, String.class, 10); list.forEach(title -> System.out.println(title));查詢多條數(shù)據(jù)并封裝到Map中最后以List類型返回:
// List<Map<String,Object>> queryForList(String sql, Object... args); String sql = "select title, author from bs_book where id<?"; List<Map<String, Object>> list = jdbcTemplate.queryForList(sql, 10); list.forEach(map -> System.out.println(map));查詢多條數(shù)據(jù)并封裝到指定類型中最后以List類型返回:
// <T> List<T>query(String sql, RowMapper<T> rowMapper, Object... args); String sql = "select * from bs_book where id<?"; List<Book> books = jdbcTemplate.query(sql, new RowMapper<Book>(){@Overridepublic Book mapRow(ResultSet rs, int rowNum) throws SQLException {Book book = new Book();book.setId(rs.getInt("id"));book.setTitle(rs.getString("title"));book.setAuthor(rs.getString("author"));return book;} }, 10); //也可以使用RowMapper的實(shí)現(xiàn)類BeanPropertyRowMapper來自動封裝結(jié)果。 // List<Book> books = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Book.class), 10); books.forEach(book -> System.out.println(book));查詢多條數(shù)據(jù)并封裝到指定類型中最后以自定義類型返回:
// <T> T query(String sql, ResultSetExtractor<T> rse, Object... args); String sql = "select * from bs_book where id<?"; Book book = jdbcTemplate.query(sql, new ResultSetExtractor<Book>() {@Overridepublic Book extractData(ResultSet rs) throws SQLException,DataAccessException {Book book = new Book();while (rs.next()) {book.setId(rs.getInt("id"));book.setTitle(rs.getString("title"));book.setAuthor(rs.getString("author"));if ("百年孤獨(dú)".equals(book.getTitle())) {break;}}return book;} }, 10);查詢多條數(shù)據(jù)并封裝到指定類型中處理最后不返回:
// void query(String sql, RowCallbackHandler rch, Object... args); String sql = "select * from bs_book where id<?"; jdbcTemplate.query(sql, new RowCallbackHandler() {@Overridepublic void processRow(ResultSet rs) throws SQLException {Book book = new Book();book.setId(rs.getInt("id"));book.setTitle(rs.getString("title"));book.setAuthor(rs.getString("author"));System.out.println(book);} }, 10);5 使用具名參數(shù)
5.1 關(guān)于具名參數(shù)
相對于基于位置的參數(shù),具名參數(shù)具有更好的可維護(hù)性,在SQL語句中參數(shù)較多時可以考慮使用具名參數(shù)。
在Spring中可以通過NamedParameterJdbcTemplate類的對象使用帶有具名參數(shù)的SQL語句。
5.2 通過IOC容器創(chuàng)建NamedParameterJdbcTemplate對象
NamedParameterJdbcTemplate類沒有提供無參的構(gòu)造器,不能使用屬性方式只能通過構(gòu)造器方式創(chuàng)建Bean。
<bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate"><constructor-arg ref="comboPooledDataSource" /> </bean>5.3 獲取IOC容器的NamedParameterJdbcTemplate對象
NamedParameterJdbcTemplate namedParameterJdbcTemplate = ioc.getBean(NamedParameterJdbcTemplate.class);5.4 具名參數(shù)在SQL語句中的格式
可以在SQL語句中使用“:屬性名”的方式進(jìn)行參數(shù)傳遞。
INSERT INTO depts (id, name) VALUES (:id, :name)5.5 具名參數(shù)傳入并執(zhí)行
5.5.1 使用Map
通過Map對象傳入,Map的鍵是參數(shù)名,值是參數(shù)值。
// NamedParameterJdbcTemplate.update(String sql, Map<String, ?> paramMap); public void test() {String sql = "insert into employee(id, name) values(:id, :name)";HashMap<String, Object> map = new HashMap<>();map.put("id", 100);map.put("name", "Tom");namedParameterJdbcTemplate.update(sql, map); }5.5.2 使用SqlParameterSource
通過SqlParameterSource對象傳入,使用該接口下的BeanPropertySqlParameterSource的實(shí)例。
// NamedParameterJdbcTemplate.update(String sql, SqlParameterSource paramSource); public void test() {String sql = "insert into employee(id, name) values(:id, :name)";Employee employee = new Employee(100, "Sam");int update = namedParameterJdbcTemplate.update(sql, new BeanPropertySqlParameterSource(employee));System.out.println(update); }總結(jié)
以上是生活随笔為你收集整理的004Spring事务001JdbcTemplate的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 开发在线投票系统过程遇到的问题
- 下一篇: 尚学堂JAVA基础学习笔记_1/2