④JdbcTemplate与声明式事务
JdbcTemplate
1.概述
前面我们已经学习了 Spring 中的Core Container
核心部分和AOP
、Aspects
等面向切面编程部分,接下来就是Data Access/Integration
即数据访问和集成部分
Spring 既可以单独使用,也可以集成其他框架,如Hibernate
、MyBatis
等。除此之外,其中对于JDBC
也做了封装,即本章节的JdbcTemplate
,用它可以比较方便地对数据库进行增删改查等操作
总结一下:
-
JdbcTemplate
就是 Spring 框架对JDBC
技术进行的二次封装模板,能够简化对数据库的操作
2.准备工作
2.1 相关SQL
DROP TABLE IF EXISTS `t_book`;
CREATE TABLE `t_book` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(25) NOT NULL,`price` decimal(10, 2) ,PRIMARY KEY (`id`)
);
2.2 步骤预览
-
1)引入相关
jar
包 -
2)Spring 配置文件配置
Druid
连接池信息 -
3)配置
JdbcTemplate
对象,注入dataSource
-
4)创建 Service 和 Dao 类,在 Dao 类中注入
JdbcTemplate
对象
2.3 详细操作
-
1)引入相关
jar
包(或依赖)-
druid
-
mysql-connector-java
-
spring-jdbc
-
spring-orm
-
spring-tx
-
-
2)Spring 配置文件配置
Druid
连接池信息<!--加载外部属性文件--> <context:property-placeholder location="classpath:jdbc.properties"/> <!--数据源--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${mysql.driverClassName}"/><property name="url" value="${mysql.url}"/><property name="username" value="${mysql.username}"/><property name="password" value="${mysql.password}"/> </bean>
沿用之前章节的
Jdbc.properties
配置信息,但稍作修改mysql.driverClassName=com.mysql.jdbc.Driver mysql.url=jdbc:mysql://127.0.0.1:3306/book_db mysql.username=root mysql.password=sasa
-
3)配置
JdbcTemplate
对象,注入dataSource
<!--配置JdbcTemplate--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><!--属性注入dataSource--><property name="dataSource" ref="dataSource"></property> </bean>
2.4 为何使用属性注入?
JdbcTemplate
虽然含有DataSource
的有参构造,但其调用了setDataSource()
方法
这个方法是在其父类中定义了的:
-
4)创建 Service 和 Dao 类,在 Dao 类中注入
JdbcTemplate
对象<!--Dao 类--> public interface BookDao { } @Repository public class BookDaoImpl implements BookDao {@Autowiredprivate JdbcTemplate jdbcTemplate; } <!--Service 类-->@Service public class BookServiceImpl implements BookService {@Autowiredprivate BookDao bookDao; }
别忘了开启注解扫描
<!--开启注解扫描--> <context:component-scan base-package="com.zking.spring"/>
2.5 配置文件整体结构
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--开启注解扫描--><context:component-scan base-package="com.zking.spring"/>
<!--加载外部属性文件--><context:property-placeholder location="classpath:jdbc.properties"/><!--数据源--><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${mysql.driverClassName}"/><property name="url" value="${mysql.url}"/><property name="username" value="${mysql.username}"/><property name="password" value="${mysql.password}"/></bean><!--配置JdbcTemplate--><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><!--属性注入dataSource--><property name="dataSource" ref="dataSource"></property></bean>
</beans>
3.添加操作
3.1 步骤预览
-
1)创建数据库中
t_book
表对应的实体对象 -
2)编写 Service 和 Dao 代码,增加添加图书的功能逻辑
-
3)代码测试
3.2 详细操作
-
1)创建数据库中
t_book
表对应的实体对象public class Book {private Integer id;private String name;private Double price;//省略get/set方法 }
2)编写 Service 和 Dao 代码,增加添加图书的功能逻辑
Service 类:添加
addBook()
方法@Repository public class BookDaoImpl implements BookDao {@Autowiredprivate JdbcTemplate jdbcTemplate; @Overridepublic int save(Book book) {String sql = "insert into t_book(id,name,price) values(null,?,?)";Object[] params = {book.getName(),book.getPrice()};return jdbcTemplate.update(sql,params);} }
Dao 类:通过操作
JdbcTemplate
对象的update()
方法可实现插入,其中两个参数分别是
第一个参数
sql
:编写插入数据对应的sql
语句,可使用通配符?
做占位符第二个参数
args
:可变参数列表,设置占位符对应的参数值@Service public class BookServiceImpl implements BookService {@Autowiredprivate BookDao bookDao; @Overridepublic int save(Book book) {return bookDao.save(book);} }
-
3)代码测试
@Testpublic void testSave(){//操作JdbcTemplate对象,使用update方法进行增删改操作ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");BookService bookService = ctx.getBean("bookServiceImpl",BookService.class);Book book = new Book();book.setName("西游记");book.setPrice(200.0);bookService.save(book);}
刷新数据库中
t_book
表数据,核验是否插入成功可以看到,表中成功新增了一条数据
4.修改和删除
修改、删除操作和添加操作代码逻辑基本一致
BookService 类:添加
updateBook()
和deleteBook()
方法/*** 修改*/int update(Book book);/*** 删除*/int delete(Integer id);
BookDao 类:添加
update()
和delete()
方法/*** 修改*/int update(Book book);/*** 删除*/int delete(Integer id);
BookDaoImpl 类:实现
update()
和delete()
方法@Override public int update(Book book) {String sql = "update t_book set name=?,price=? where id=?";Object[] params={book.getName(),book.getPrice(),book.getId()};return jdbcTemplate.update(sql,params); } @Override public int delete(Integer id) {String sql = "delete from t_book where id=?";Object[] params={id};return jdbcTemplate.update(sql,params); }
4.1 测试修改
@Test
public void testUpdate(){ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");BookService bookService = ctx.getBean("bookServiceImpl",BookService.class);Book book = new Book();book.setId(19);book.setName("西游记");book.setPrice(250.0);bookService.update(book);
}
4.2 测试删除
@Test
public void testDelete(){ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");BookService bookService = ctx.getBean("bookServiceImpl",BookService.class);bookService.delete(19);
}
5.查询操作
这里演示三种查询操作:
-
1)查询返回某个值
-
2)查询返回对象
-
3)查询返回集合
为了演示效果,需要先在数据库的t_book
表中添加两条数据
接着我们先将代码完成,最后再作进一步的分析说明
5.1 代码实现
BookService 类:添加
count()
、findById()
和list()
方法@Override public int count() {return bookDao.count(); } @Override public Book findById(Integer id) {return bookDao.findById(id); } @Override public List<Book> list() {return bookDao.list(); }
BookDao 类:添加
selectCount()
、selectById()
和selectAll()
方法/*** 查找返回一个值*/int count(); /*** 查找返回对象*/Book findById(Integer id);/*** 查找返回集合*/List<Book> list();
BookDaoImpl 类:实现
count()
、findById()
和list()
方法@Overridepublic int count() {String sql = "select count(0) from t_book";return jdbcTemplate.queryForObject(sql,Integer.class);} @Overridepublic Book findById(Integer id) {String sql = "select * from t_book where id=?";return jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<>(Book.class),id);} @Overridepublic List<Book> list() {String sql = "select * from t_book";return jdbcTemplate.query(sql,new BeanPropertyRowMapper<>(Book.class));}
测试代码
@Test public void testQuery(){ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");BookService bookService = ctx.getBean("bookServiceImpl",BookService.class);int count = bookService.count();System.out.println(count);Book book = bookService.findById(1);System.out.println(book);List<Book> list=bookService.list();System.out.println(list); }
测试结果:
1 Book{id=1, name='西游记', price=200.0} [Book{id=1, name='西游记', price=200.0}]
5.2 代码分析
上述代码逻辑中使用到了
queryForObject()
和query()
方法jdbcTemplate.queryForObject(sql, Integer.class); jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(Book.class), id); jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Book.class));
分别对应
JdbcTemplate
中的三个方法:public <T> T queryForObject(String sql, Class<T> requiredType); public <T> T queryForObject(String sql, RowMapper<T> rowMapper, Object... args); public <T> List<T> query(String sql, RowMapper<T> rowMapper);
其中,有两个参数值得关注,一个是
Class<T> requiredType
,另一个是RowMapper<T> rowMapper:
Class<T> requiredType
:返回值的Class
类型
RowMapper<T> rowMapper
:是一个接口,返回不同类型数据,可以使用其实现类进行数据的封装。其实现类有很多,因为我们需要返回一个数据库实体对象,所以可以选择使用BeanPropertyRowMapper
另外,
queryForObject(String sql, RowMapper<T> rowMapper, Object... args)
和query(String sql, RowMapper<T> rowMapper)
的区别在于:
queryForObject
返回一个对象
query
返回一个集合
6.小结
简单总结下JdbcTemplate
操作数据库的各个方法:
-
添加、修改、删除操作:
update()
方法 -
查询操作:
queryForObject()
和query()
方法,关注两个参数:-
Class<T> requiredType
:返回值的Class
类型 -
RowMapper<T> rowMapper
:接口,具体实现类BeanPropertyRowMapper
,封装对象实体
-
-
批量操作:
batchUpdate()
方法