JdbcTemplate 是Spring提供的一套JDBC模板框架,利用AOP 技术来解决直接使用JDBC时大量重复代码的问题。JdbcTemplate虽然没有MyBatis 那么灵活,但是直接使用JDBC要方便很多。Spring Boot中对Jdbc Template的使用提供了自动化配置类JdbcTemplateAutoConfiguration,部分源码如下:

1 package org.springframework.boot.autoconfigure.jdbc; 2 3 // 省略 import 行 4 5 @Configuration 6 // 仅在类 DataSource,JdbcTemplate 存在于 classpath 时生效, 7 // 这两个类属于 spring-jdbc 8 @ConditionalOnClass({ DataSource.class, JdbcTemplate.class }) 9 // 仅在单数据源bean存在时才生效 10 @ConditionalOnSingleCandidate(DataSource.class) 11 // 在数据源自动配置应用之后应用 12 @AutoConfigureAfter(DataSourceAutoConfiguration.class) 13 // 确保前缀为 spring.jdbc 的配置参数被加载到 bean JdbcProperties 14 @EnableConfigurationProperties(JdbcProperties.class) 15 public class JdbcTemplateAutoConfiguration { 16 17 // 内嵌配置类 18 @Configuration 19 static class JdbcTemplateConfiguration { 20 21 private final DataSource dataSource; 22 23 private final JdbcProperties properties; 24 25 JdbcTemplateConfiguration(DataSource dataSource, JdbcProperties properties) { 26 this.dataSource = dataSource; 27 this.properties = properties; 28 } 29 30 // 定义 bean JdbcTemplate jdbcTemplate 31 @Bean 32 @Primary 33 // 仅在此bean没有被定义时才定义 34 @ConditionalOnMissingBean(JdbcOperations.class) 35 public JdbcTemplate jdbcTemplate() { 36 JdbcTemplate jdbcTemplate = new JdbcTemplate(this.dataSource); 37 JdbcProperties.Template template = this.properties.getTemplate(); 38 jdbcTemplate.setFetchSize(template.getFetchSize()); 39 jdbcTemplate.setMaxRows(template.getMaxRows()); 40 if (template.getQueryTimeout() != null) { 41 jdbcTemplate 42 .setQueryTimeout((int) template.getQueryTimeout().getSeconds()); 43 } 44 return jdbcTemplate; 45 } 46 47 } 48 49 // 内嵌配置类 50 @Configuration 51 // 导入 JdbcTemplateConfiguration 配置类 52 @Import(JdbcTemplateConfiguration.class) 53 static class NamedParameterJdbcTemplateConfiguration { 54 55 // 定义 bean NamedParameterJdbcTemplate namedParameterJdbcTemplate 56 @Bean 57 @Primary 58 @ConditionalOnSingleCandidate(JdbcTemplate.class) 59 @ConditionalOnMissingBean(NamedParameterJdbcOperations.class) 60 public NamedParameterJdbcTemplate namedParameterJdbcTemplate( 61 JdbcTemplate jdbcTemplate) { 62 return new NamedParameterJdbcTemplate(jdbcTemplate); 63 } 64 65 } 66 ...... 67 }
从上面这段源码中可以看出,当classpath下存在DataSource和JdbcTemplate 并且DataSource只有一个实例时,自动配置才会生效,若开发者没有提供JdbcOperations,则Spring Boot会自动向容器中注入一个JdbcTemplate(Jdbc Template是JdbcOperations的子类)。由此可以看到,开发者想要使用Jdbc Template,只需要提供JdbcTemplate的依赖和DataSource依赖即可。具体操作步骤
1,创建数据库表并插入数据

1 CREATE DATABASE 'chapter05'DEFAULT CHARACTER SET utf8; 2 USE‘chapter05; 3 CREATE TABLE book( 4 id int(11)NOT NULL AUTO INCREMENT, 5 name varchar(128)DEFAULT NULL, 6 author varchar(64)DEFAULT NULL, 7 PRIMARY KEY('id') 8 ENGINE=InnoDB DEFAULT CHARSET=utf8; 9 insert into book'(id,name,author)values(1,'三国演义,罗贯中'),(2,'水浒传','施耐庵');
2,添加依赖

1 <dependency> 2 <groupId>org.springframework.boot</groupId> 3 <artifactId>spring-boot-starter-jdbc</artifactId> 4 </dependency> 5 <dependency> 6 <groupId>org.springframework.boot</groupId> 7 <artifactId>spring-boot-starter-web</artifactId> 8 </dependency> 9 <dependency> 10 <groupId>mysql</groupId> 11 <artifactId>mysql-connector-java</artifactId> 12 <scope>runtime</scope> 13 </dependency> 14 <dependency> 15 <groupId>com.alibaba</groupId> 16 <artifactId>druid</artifactId> 17 <version>1.1.9</version> 18 </dependency>
3.数据库配置(注意数据库的配置)
在application.properties中配置数据库基本连接信息:

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource spring.datasource.url=jdbc:mysql:///chapter05 spring.datasource.username=root(你自己的) spring.datasource.password=123(你自己的密码,没有不用填)
4.创建实体类,
创建Book实体类,代码如下:

public class Book{ private Integer id; private String name; private String author; //省略 getter/setter }
5.创建数据库访问层

1 @Repository 2 public class BookDao { 3 @Autowired 4 JdbcTemplate jdbcTemplate; 5 public int addBook(Book book) { 6 return jdbcTemplate.update("INSERT INTO book(name,author) VALUES (?,?)", 7 book.getName(), book.getAuthor()); 8 } 9 public int updateBook(Book book) { 10 return jdbcTemplate.update("UPDATE book SET name=?,author=? WHERE id=?", 11 book.getName(), book.getAuthor(), book.getId()); 12 } 13 public int deleteBookById(Integer id) { 14 return jdbcTemplate.update("DELETE FROM book WHERE id=?", id); 15 } 16 public Book getBookById(Integer id) { 17 return jdbcTemplate.queryForObject("select * from book where id=?", 18 new BeanPropertyRowMapper<>(Book.class), id); 19 } 20 public List<Book> getAllBooks() { 21 return jdbcTemplate.query("select * from book", 22 new BeanPropertyRowMapper<>(Book.class)); 23 } 24 }
代码解释:
创建BookDao,注入Jdbc Template。由于已经添加了spring-jdbc相关的依赖,JdbcTemplate会被自动注册到Spring容器中,因此这里可以直接注入Jdbc Template使用。在JdbcTemplate中,增删改三种类型的操作主要使用update和batchUpdate方法来完成。query和queryForObject方法主要用来完成查询功能。另外,还有execute方法可以用来执行任意的SQL、cal方法用来调用存储过程等。·在执行查询操作时,需要有一个/RowMapper f查询出来的列和实体类中的属性一一对应起)来。如果列名和属性名都是相同的,那么可以直接使用BeanPropertyRowMapper;如果列名和属性名不同就需要开发者自己实见RowMapper 接口,将列和实体类属性一一对应起来。
6.创建Service和Controller
创建BookService和BookController,代码如下:
BookService

1 @Service 2 public class BookService { 3 @Autowired 4 BookDao bookDao; 5 public int addBook(Book book) { 6 return bookDao.addBook(book); 7 } 8 public int updateBook(Book book) { 9 return bookDao.updateBook(book); 10 } 11 public int deleteBookById(Integer id) { 12 return bookDao.deleteBookById(id); 13 } 14 public Book getBookById(Integer id) { 15 return bookDao.getBookById(id); 16 } 17 public List<Book> getAllBooks() { 18 return bookDao.getAllBooks(); 19 } 20 }
BookController

1 package org.sang; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.web.bind.annotation.GetMapping; 5 import org.springframework.web.bind.annotation.RestController; 6 7 import java.util.List; 8 9 /** 10 * Created by 半仙 11 */ 12 @RestController 13 public class BookController { 14 @Autowired 15 BookService bookService; 16 @GetMapping("/bookOps") 17 public void bookOps() { 18 Book b1 = new Book(); 19 b1.setId(99); 20 b1.setName("西厢记"); 21 b1.setAuthor("王实甫"); 22 int i = bookService.addBook(b1); 23 System.out.println("addBook>>>" + i); 24 Book b2 = new Book(); 25 b2.setId(1); 26 b2.setName("朝花夕拾"); 27 b2.setAuthor("鲁迅"); 28 int updateBook = bookService.updateBook(b2); 29 System.out.println("updateBook>>>"+updateBook); 30 Book b3 = bookService.getBookById(1); 31 System.out.println("getBookById>>>"+b3); 32 int delete = bookService.deleteBookById(2); 33 System.out.println("deleteBookById>>>"+delete); 34 List<Book> allBooks = bookService.getAllBooks(); 35 System.out.println("getAllBooks>>>"+allBooks); 36 } 37 }
最后,在浏览器中访问http://localhost:8080/bookOps地址,控制台打印日志如图5-1所示
addBook>〉>1
updateBoolk>〉>1
getBookById>>>Book{id=1,name='朝花夕拾’,author='鲁迅’}
deleteBoolkById>>>1
getA11Books>>>[Book{id=1,name='朝花夕拾’,author='鲁迅’},Book{id=4,name='西厢记’,author='王实甫’}]
这里只是介绍SpringBoot集成JDBCTemplate的Demo,重点在于上面说的这句话“·在执行查询操作时,需要有一个/RowMapper f查询出来的列和实体类中的属性一一对应起)来。如果列名和属性名都是相同的,那么可以直接使用BeanPropertyRowMapper;如果列名和属性名不同就需要开发者自己实见RowMapper 接口,将列和实体类属性一一对应起来。”
那么在上面我们看到,JdbcTemplate已经封装了对应增删改的方法,我们只需直接调用即可,关键在于query查询时候RowMapper的这点上,正如上面所说,如果列名和属性名都是相同的,我们可以直接使用BeanPropertyRowMapper,如果列名和属性名不同就需要开发者自己实见RowMapper 接口,将列和实体类属性一一对应起来。”
那么到底这个RowMapper是什么 ,官方的源码如下
package org.springframework.jdbc.core; import java.sql.ResultSet; import java.sql.SQLException; import org.springframework.lang.Nullable; @FunctionalInterface public interface RowMapper<T> { @Nullable T mapRow(ResultSet var1, int var2) throws SQLException; }
不难看出这是一个方法接口 ,里面的抽象法中的ResultSet又是什么呢 ,表示数据库结果集的数据表,通常由执行查询数据库的语句生成,这里我只贴出官方的版本,想看的直接点击ctrl+鼠标左键点进去看,我用的是IDEA

1 ** 2 * A table of data representing a database result set, which 3 * is usually generated by executing a statement that queries the database. 4 * 5 * <P>A <code>ResultSet</code> object maintains a cursor pointing 6 * to its current row of data. Initially the cursor is positioned 7 * before the first row. The <code>next</code> method moves the 8 * cursor to the next row, and because it returns <code>false</code> 9 * when there are no more rows in the <code>ResultSet</code> object, 10 * it can be used in a <code>while</code> loop to iterate through 11 * the result set. 12 * <P> 13 * A default <code>ResultSet</code> object is not updatable and 14 * has a cursor that moves forward only. Thus, you can 15 * iterate through it only once and only from the first row to the 16 * last row. It is possible to 17 * produce <code>ResultSet</code> objects that are scrollable and/or 18 * updatable. The following code fragment, in which <code>con</code> 19 * is a valid <code>Connection</code> object, illustrates how to make 20 * a result set that is scrollable and insensitive to updates by others, and 21 * that is updatable. See <code>ResultSet</code> fields for other 22 * options. 23 * <PRE> 24 * 25 * Statement stmt = con.createStatement( 26 * ResultSet.TYPE_SCROLL_INSENSITIVE, 27 * ResultSet.CONCUR_UPDATABLE); 28 * ResultSet rs = stmt.executeQuery("SELECT a, b FROM TABLE2"); 29 * // rs will be scrollable, will not show changes made by others, 30 * // and will be updatable 31 * 32 * </PRE> 33 * The <code>ResultSet</code> interface provides 34 * <i>getter</i> methods (<code>getBoolean</code>, <code>getLong</code>, and so on) 35 * for retrieving column values from the current row. 36 * Values can be retrieved using either the index number of the 37 * column or the name of the column. In general, using the 38 * column index will be more efficient. Columns are numbered from 1. 39 * For maximum portability, result set columns within each row should be 40 * read in left-to-right order, and each column should be read only once. 41 * 42 * <P>For the getter methods, a JDBC driver attempts 43 * to convert the underlying data to the Java type specified in the 44 * getter method and returns a suitable Java value. The JDBC specification 45 * has a table showing the allowable mappings from SQL types to Java types 46 * that can be used by the <code>ResultSet</code> getter methods. 47 * 48 * <P>Column names used as input to getter methods are case 49 * insensitive. When a getter method is called with 50 * a column name and several columns have the same name, 51 * the value of the first matching column will be returned. 52 * The column name option is 53 * designed to be used when column names are used in the SQL 54 * query that generated the result set. 55 * For columns that are NOT explicitly named in the query, it 56 * is best to use column numbers. If column names are used, the 57 * programmer should take care to guarantee that they uniquely refer to 58 * the intended columns, which can be assured with the SQL <i>AS</i> clause. 59 * <P> 60 * A set of updater methods were added to this interface 61 * in the JDBC 2.0 API (Java™ 2 SDK, 62 * Standard Edition, version 1.2). The comments regarding parameters 63 * to the getter methods also apply to parameters to the 64 * updater methods. 65 *<P> 66 * The updater methods may be used in two ways: 67 * <ol> 68 * <LI>to update a column value in the current row. In a scrollable 69 * <code>ResultSet</code> object, the cursor can be moved backwards 70 * and forwards, to an absolute position, or to a position 71 * relative to the current row. 72 * The following code fragment updates the <code>NAME</code> column 73 * in the fifth row of the <code>ResultSet</code> object 74 * <code>rs</code> and then uses the method <code>updateRow</code> 75 * to update the data source table from which <code>rs</code> was derived. 76 * <PRE> 77 * 78 * rs.absolute(5); // moves the cursor to the fifth row of rs 79 * rs.updateString("NAME", "AINSWORTH"); // updates the 80 * // <code>NAME</code> column of row 5 to be <code>AINSWORTH</code> 81 * rs.updateRow(); // updates the row in the data source 82 * 83 * </PRE> 84 * <LI>to insert column values into the insert row. An updatable 85 * <code>ResultSet</code> object has a special row associated with 86 * it that serves as a staging area for building a row to be inserted. 87 * The following code fragment moves the cursor to the insert row, builds 88 * a three-column row, and inserts it into <code>rs</code> and into 89 * the data source table using the method <code>insertRow</code>. 90 * <PRE> 91 * 92 * rs.moveToInsertRow(); // moves cursor to the insert row 93 * rs.updateString(1, "AINSWORTH"); // updates the 94 * // first column of the insert row to be <code>AINSWORTH</code> 95 * rs.updateInt(2,35); // updates the second column to be <code>35</code> 96 * rs.updateBoolean(3, true); // updates the third column to <code>true</code> 97 * rs.insertRow(); 98 * rs.moveToCurrentRow(); 99 * 100 * </PRE> 101 * </ol> 102 * <P>A <code>ResultSet</code> object is automatically closed when the 103 * <code>Statement</code> object that 104 * generated it is closed, re-executed, or used 105 * to retrieve the next result from a sequence of multiple results. 106 * 107 * <P>The number, types and properties of a <code>ResultSet</code> 108 * object's columns are provided by the <code>ResultSetMetaData</code> 109 * object returned by the <code>ResultSet.getMetaData</code> method. 110 * 111 * @see Statement#executeQuery 112 * @see Statement#getResultSet 113 * @see ResultSetMetaData 114 */
如何实现自己的RowMapper?参照如下代码
public class BeanRowMapper implements RowMapper<Article> { //这里的类名只是为了掩饰 根据自己的情况修改 @Override public Article mapRow(ResultSet resultSet, int i) throws SQLException { Bean bean= new Bean();
//设置不一致的列名与实体字段对应 bean.setId(resultSet.getInt("id")); bean.setTitle(resultSet.getString("title")); bean.setDescription(resultSet.getString("description")); return Bean; } }
然后修改对应的Dao代码
/** * 查询所有数据 */ public List<Bean> findAll() { String sql = "SELECT id, title, description FROM Bean"; return jdbcTemplate.query(sql, new BeanRowMapper()); } /** * 查询单条数据 */ public BeanfindById(Integer id) { String sql = "SELECT id, title, description FROM BeanWHERE id = ?"; return jdbcTemplate.queryForObject(sql, new BeanRowMapper()); }
然后在测试对应的接口
才疏学浅,有错误请指出