Spring5学习总结(三)JdbcTemplate实现数据库增删改查操作/JdbcTemplate实现批量增删改操作
一、JdbcTemplate概述
什么是 JdbcTemplate?
JdbcTemplate是Spring 框架对 JDBC 进行的封装,使用它可以更方便实现对数据库的操作。
二、使用JdbcTemplate实现对数据库的操作
(一)准备工作
1.引入相关 jar 包
2.在 spring 配置文件配置数据库连接池
首先创建外部属性文件,properties 格式文件,写数据库信息
jdbc.properties(src下创建的):
prop.driverClass=com.mysql.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/test_book?useUnicode=true&characterEncoding=utf8
prop.username=root
prop.password=123456
把外部 properties 属性文件引入到 spring 配置文件中(记得引入 context 名称空间):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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:property-placeholder location="classpath:jdbc.properties"/>
<!-- 数据库连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="url" value="${prop.url}" />
<property name="username" value="${prop.username}" />
<property name="password" value="${prop.password}" />
<property name="driverClassName" value="${prop.driverClass}" />
</bean>
</beans>
3.配置 JdbcTemplate 对象,注入 DataSource
通过查看JdbcTemplate的父类JdbcAccessor的源码,我们可以发现有一个设置数据源的set方法:
因此我们可以通过set注入,将我们的数据源注入:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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:property-placeholder location="classpath:jdbc.properties"/>
<!-- 数据库连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="url" value="${prop.url}" />
<property name="username" value="${prop.username}" />
<property name="password" value="${prop.password}" />
<property name="driverClassName" value="${prop.driverClass}" />
</bean>
<!-- JdbcTemplate 对象 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--注入上面写好的dataSource-->
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
4.创建 service 类,创建 dao 类,在 dao 类中注入 jdbcTemplate 对象
BookDao:
public interface BookDao {
}
BookDaoImpl:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class BookDaoImpl implements BookDao {
//注入 JdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
}
BookService:
import com.fox.dao.BookDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class BookService {
//注入dao
@Autowired
private BookDao bookDao;
}
5.在spring配置文件中开启注解扫描:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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.fox"></context:component-scan>
<!--引入外部属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 数据库连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="url" value="${prop.url}" />
<property name="username" value="${prop.username}" />
<property name="password" value="${prop.password}" />
<property name="driverClassName" value="${prop.driverClass}" />
</bean>
<!-- JdbcTemplate 对象 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--注入上面写好的dataSource-->
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
(二)实现数据库添加操作
场景:假设我现在有以下这么一张book表,我想往表里添加数据
1.对应数据库创建实体类
Book类:
public class Book {
private String bookId;
private String bookName;
private String author;
private double price;
public String getBookId() {
return bookId;
}
public void setBookId(String bookId) {
this.bookId = bookId;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Book{" +
"bookId='" + bookId + '\'' +
", bookName='" + bookName + '\'' +
", author='" + author + '\'' +
", price=" + price +
'}';
}
}
2.编写 service 层和 dao 层
- JdbcTemplate类中有一个
update()
方法:
- 这个方法可以实现数据库的添加、修改和删除。
- 它共有两个参数:
- 第一个参数:sql 语句
- 第二个参数:是可变参数(其实是一个数组),表示填充占位符的值
BookDao:
import com.fox.pojo.Book;
public interface BookDao {
public void add(Book book);
}
BookDaoImpl:
import com.fox.pojo.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class BookDaoImpl implements BookDao {
//注入 JdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
//添加一本书
@Override
public void add(Book book) {
//创建 sql 语句
String sql="insert into book values(?,?,?,?)";
//将填充占位符的值写进一个数组里
Object[] args={book.getBookId(), book.getBookName(), book.getAuthor(), book.getPrice()};
//调用JdbcTemplate中的update方法实现
int update = jdbcTemplate.update(sql,args);
//update返回的结果就是数据表受影响的行数
System.out.println("共"+update+"行受到影响");
}
}
BookService:
import com.fox.dao.BookDao;
import com.fox.pojo.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class BookService {
//注入dao
@Autowired
private BookDao bookDao;
public void addBook(Book book){
bookDao.add(book);
}
}
3.测试类
import com.fox.pojo.Book;
import com.fox.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
BookService bookService = context.getBean("bookService", BookService.class);
Book book = new Book();
book.setBookId("10004");
book.setBookName("精通HTML");
book.setAuthor("小红");
book.setPrice(10.0);
bookService.addBook(book);
}
}
运行:
我们的数据库也成功添加了一条记录:
(三)实现数据库修改操作
其实修改和删除操作和添加操作同理
BookDao:
public void update(Book book);
BookDaoImpl:
@Override
public void update(Book book) {
//创建 sql 语句
String sql="update book set book_name=?,author=?,price=? where book_id=?";
//将填充占位符的值写进一个数组里
Object[] args={book.getBookName(),book.getAuthor(),book.getPrice(),book.getBookId()};
//调用JdbcTemplate中的update方法实现
int update = jdbcTemplate.update(sql,args);
//update返回的结果就是数据表受影响的行数
System.out.println("共"+update+"行受到影响");
}
BookService:
public void updateBook(Book book){
bookDao.update(book);
}
测试类:
import com.fox.pojo.Book;
import com.fox.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
BookService bookService = context.getBean("bookService", BookService.class);
Book book = new Book();
book.setBookId("10004");
book.setBookName("HTML入门");
book.setAuthor("小红");
book.setPrice(10.0);
bookService.updateBook(book);
}
}
(四)实现数据库删除操作
BookDao:
public void delete(String id);
BookDaoImpl:
@Override
public void delete(String id) {
//创建 sql 语句
String sql="delete from book where book_id=?";
//调用JdbcTemplate中的update方法实现
int update = jdbcTemplate.update(sql,id);
//update返回的结果就是数据表受影响的行数
System.out.println("共"+update+"行受到影响");
}
BookService:
public void deleteBook(String id){
bookDao.delete(id);
}
测试类:
import com.fox.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
BookService bookService = context.getBean("bookService", BookService.class);
bookService.deleteBook("10004");
}
}
(五)实现数据库查询操作
1.查询返回一个值
场景:还是以Book表为例,假如我们想查询Book表里有几条记录或者查询Book表里最贵的书的价格是多少等等,这种使用到分组函数的查询都是只返回一个值。
我们可以通过使用 JdbcTemplate 里的queryForObject()
方法实现查询返回某个值:
- 第一个参数:sql 语句
- 第二个参数:查询结果类型的Class
案例:
BookDao:
public interface BookDao {
public void maxPrice();
}
BookDaoImpl:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class BookDaoImpl implements BookDao {
//注入 JdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void maxPrice() {
String sql="select max(price) from book";
Double query = jdbcTemplate.queryForObject(sql, Double.class);
System.out.println("最贵的书的价格:"+query+"元");
}
}
BookDaoService:
import com.fox.dao.BookDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class BookService {
//注入dao
@Autowired
private BookDao bookDao;
public void selectMaxPrice(){
bookDao.maxPrice();
}
}
测试类:
import com.fox.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
BookService bookService = context.getBean("bookService", BookService.class);
bookService.selectMaxPrice();
}
}
2.查询返回一个对象
场景:假如我们想在book表中查询某一本图书的详情,那么数据库就会返回一行数据,也就是Java里的一个对象。
使用过原生JDBC的朋友应该知道,从数据库查询出来的记录全都被保存在ResultSet结果集中,我们需要将结果集中的数据一条条地获取并设置到具体的实体类上,如此,该实体类才能在接下来的程序中使用。然而问题是,每次都要这么操作实在是太麻烦了,JdbcTemplate就不应该提供什么功能来替我们做这些事情吗?答案当然是有的,那就是——RowMapper。
JdbcTemplate中查询返回对象的方法:
- 第一个参数:sql 语句
- 第二个参数:RowMapper 是一个接口,使用这个接口的实现类BeanPropertyRowMapper完成数据封装,将数据库查询结果转换为我们想要的Java类对象
- 第三个参数:是可变参数(其实是一个数组),表示填充占位符的值
我们在使用BeanPropertyRowMapper时,是给queryForObject()
方法传递一个BeanPropertyRowMapper对象,让JdbcTemplate帮我们把查询结果集ResultSet的每一行结果都使用BeanPropertyRowMapper.mapRow()
方法,转化成我们想要的Java类对象。从BeanPropertyRowMapper名称上也能够看出来,它是用来映射Java对象的属性和MySQL表的字段名称的,它可自动将一行数据映射到指定类的实例中,它首先将这个类实例化,然后通过名称匹配的方式,映射到属性中去。但是,在映射的过程中,需要确保数据库表列名称与Java实体类属性名称相同(字段名字一样或者驼峰式与下划线式对应)。
所以,如果在使用时,Java类名称要想和数据库字段名称匹配上,必须要把数据库字段名称设计成以下两种中的一种:
- 数据库字段名设计成全小写的形式,如bookname;
- 数据库字段名设计成下划线分割的形式,如book_name;
同时,Java属性名称应该尽量遵循Java编码风格,使用camelCase风格(驼峰命名形式),如bookName。
案例:
首先确保数据库字段名和Java属性名都遵循以上格式:
BookDao:
import com.fox.pojo.Book;
public interface BookDao {
public Book selectById(String id);
}
BookDaoImpl:
import com.fox.pojo.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class BookDaoImpl implements BookDao {
//注入 JdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public Book selectById(String id) {
String sql="select * from book where book_id=?";
Book book = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Book>(Book.class), id);
return book;
}
}
BookService:
import com.fox.dao.BookDao;
import com.fox.pojo.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class BookService {
//注入dao
@Autowired
private BookDao bookDao;
public Book selectById(String id){
return bookDao.selectById(id);
}
}
测试类:
import com.fox.pojo.Book;
import com.fox.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
BookService bookService = context.getBean("bookService", BookService.class);
Book book = bookService.selectById("10002");
System.out.println(book);
}
}
3.查询返回集合
场景:假如我们想查询价格低于50元的图书,那么可能不止一本,查询的结果就是几行数据,也就是几个对象组成的集合。
JdbcTemplate中查询返回集合的方法:
- 第一个参数:sql 语句
- 第二个参数:RowMapper 是一个接口,使用这个接口的实现类BeanPropertyRowMapper完成数据封装,将数据库查询结果转换为我们想要的Java类对象
- 第三个参数:是可变参数(其实是一个数组),表示填充占位符的值
案例:
BookDao:
import com.fox.pojo.Book;
import java.util.List;
public interface BookDao {
public List<Book> selectAllBook();
}
BookDaoImpl:
import com.fox.pojo.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public class BookDaoImpl implements BookDao {
//注入 JdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public List<Book> selectAllBook() {
String sql="select * from book";
List<Book> bookList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Book>(Book.class));
return bookList;
}
}
BookService:
import com.fox.dao.BookDao;
import com.fox.pojo.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class BookService {
//注入dao
@Autowired
private BookDao bookDao;
public List<Book> selectAllBook(){
return bookDao.selectAllBook();
}
}
测试类:
import com.fox.pojo.Book;
import com.fox.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
BookService bookService = context.getBean("bookService", BookService.class);
List<Book> bookList = bookService.selectAllBook();
for (Book book : bookList) {
System.out.println(book);
}
}
}
(六)实现数据库批量添加操作
场景:假如我想向book表中一次性添加多条数据,这就是批量添加操作
JdbcTemplate中批量添加、修改、删除的方法:
- 第一个参数:sql 语句
- 第二个参数:List 集合,需要添加的多个对象的集合
这个List集合里的数据都是数组,每个数组装的是每一行记录的各个字段的值(即每一个对象的各个属性值) - 此方法会遍历集合中每个数组,对每个数组执行sql语句
案例:
BookDao:
import java.util.List;
public interface BookDao {
public void batchAdd(List<Object[]> batchArgs);
}
12345
BookDaoImpl:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.Arrays;
import java.util.List;
@Repository
public class BookDaoImpl implements BookDao {
//注入 JdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void batchAdd(List<Object[]> batchArgs) {
String sql="insert into book values(?,?,?,?)";
//batchUpdate方法会遍历集合中每个数组,对每个数组执行sql语句
int[] update = jdbcTemplate.batchUpdate(sql, batchArgs);
System.out.println(Arrays.toString(update));
}
}
BookService:
import com.fox.dao.BookDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class BookService {
//注入dao
@Autowired
private BookDao bookDao;
public void batchAdd(List<Object[]> batchArgs){
bookDao.batchAdd(batchArgs);
}
}
测试类:
import com.fox.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.ArrayList;
import java.util.List;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
BookService bookService = context.getBean("bookService", BookService.class);
List<Object[]> list = new ArrayList<>();
Object[] o1={"10004","CSS详解","小白",6.8};
Object[] o2={"10005","JavaScript详解","小王",9.8};
Object[] o3={"10006","MyBatis详解","小李",8.9};
list.add(o1);
list.add(o2);
list.add(o3);
bookService.batchAdd(list);
}
}
[1,1,1] 表示每条记录添加后受影响的行数,共三条记录。
(七)实现数据库批量修改操作
和批量添加同理。
案例:
BookDao:
import java.util.List;
public interface BookDao {
public void batchUpdate(List<Object[]> batchArgs);
}
BookDaoImpl:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.Arrays;
import java.util.List;
@Repository
public class BookDaoImpl implements BookDao {
//注入 JdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void batchUpdate(List<Object[]> batchArgs) {
String sql="update book set book_name=?,author=?,price=? where book_id=?";
//batchUpdate方法会遍历集合中每个数组,对每个数组执行sql语句
int[] update = jdbcTemplate.batchUpdate(sql, batchArgs);
System.out.println(Arrays.toString(update));
}
}
BookService:
import com.fox.dao.BookDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class BookService {
//注入dao
@Autowired
private BookDao bookDao;
public void batchUpdate(List<Object[]> batchArgs){
bookDao.batchUpdate(batchArgs);
}
}
测试类:
import com.fox.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.ArrayList;
import java.util.List;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
BookService bookService = context.getBean("bookService", BookService.class);
List<Object[]> list = new ArrayList<>();
Object[] o1={"CSS从入门到秃顶","小白",6.8,"10004"};
Object[] o2={"JavaScript详解","小王",8.8,"10005"};
Object[] o3={"MyBatis详解","李白",8.9,"10006"};
list.add(o1);
list.add(o2);
list.add(o3);
bookService.batchUpdate(list);
}
}
(八)实现数据库批量删除操作
案例:
BookDao:
import java.util.List;
public interface BookDao {
public void batchDelete(List<Object[]> batchArgs);
}
BookDaoImpl:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.Arrays;
import java.util.List;
@Repository
public class BookDaoImpl implements BookDao {
//注入 JdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void batchDelete(List<Object[]> batchArgs) {
String sql="delete from book where book_id=?";
//batchUpdate方法会遍历集合中每个数组,对每个数组执行sql语句
int[] update = jdbcTemplate.batchUpdate(sql, batchArgs);
System.out.println(Arrays.toString(update));
}
}
BookService:
import com.fox.dao.BookDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class BookService {
//注入dao
@Autowired
private BookDao bookDao;
public void batchDelete(List<Object[]> batchArgs){
bookDao.batchDelete(batchArgs);
}
}
测试类:
import com.fox.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.ArrayList;
import java.util.List;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
BookService bookService = context.getBean("bookService", BookService.class);
List<Object[]> list = new ArrayList<>();
Object[] o1={"10004"};
Object[] o2={"10005"};
Object[] o3={"10006"};
list.add(o1);
list.add(o2);
list.add(o3);
bookService.batchDelete(list);
}
}