JDBCTemplate概述
在讲JDBCTemplate之前,我先来介绍一下什么是JDBC,JDBC即java database connectivity,指Java数据库连接,是Java语言中用来规范客户端程序如何来访问数据库的应用程序的接口,提供了诸如查询,更新数据库中的数据的方法;
JDBCTemplate则是Spring 对 JDBC的封装,JDBCTemplate能够帮助程序员更加高效便利的进行开发,下面我们来对比一下用JDBC开发和JDBCTemplate开发有哪些区别吧。
本文使用的是JDK 11,数据库使用的是MySql 8.0,使用的是eclipse 进行开发
JDBC操作数据库步骤:
1.加载驱动(一定要和数据库的版本一致,导入对应的驱动包)
Class.forName(“Driver实现类的全路径类名”)[第三方的包]
加载这个类,调用静态代码块,实例化一个驱动,然后注册到DriverManager
2.获得连接
Connection = DriverManager.getConnection(url,user,password);
3.编写sql 语句
4.准备Statement,发送sql,并执行
Statement statement = connection.createStatement();
statement.execute(sql);//select
statement.executeUpdate(sql);//insert update delete
5.如果有结果集,解析结果集
ResultSet resultSet = statement.executeQuery( sql );
//执行给定的SQL语句,该语句返回单个ResultSet对象。
ResultSet resultSet = statement.executeUpdate( sql );
//执行给定的SQL语句,这可能是INSERT , UPDATE ,或DELETE语句
6.关闭资源
在以上步骤中有大量重复的代码,于是我们就有了JDBCTemplate,
JDBCTempalte中执行sql语句的方法大致分为3类:
execute:可以执行所有sql语句,一般用于执行DDL语句
update:用于执行insert,update,delete等DML语句
queryXxx:用于DQL数据查询语句
JDBCTemplate 对象的创建需要连接池,这里我们使用的是 DBCP 连接池
public JdbcTemplate(DataSource dataSource)
接下来我们用一个小的案例来演示一下JDBCTemplate的使用方法:
(1)首先我们先创建一个数据库
CREATE DATABASE jdbctest DEFAULT CHARACTER SET utf8
(2)接着我们创建一个数据表tb_user
CREATE TABLE tb_user (
id INT PRIMARY KEY auto_increment,
username VARCHAR ( 20 ) NOT NULL,
age INT );
(3)我们向表中添加几组数据
INSERT INTO tb_user VALUES( 100, 'Lily', 20 );
INSERT INTO tb_user VALUES( 101, 'Nancy', 21 );
INSERT INTO tb_user VALUES( 102, 'Mike', 20 );
(4)接着我们到 eclipse 中创建项目,点击next
添加jar包,这里添加了jdbc依赖包,lombok依赖包,dbcp依赖包
(5)创建好项目之后,我们先来完善一下项目结构
(6)接着把db.properties配置文件放在src目录下
db.properties的内容如下:
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbctest?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
username=root
password=123456
#<!-- 初始化连接 -->
dataSource.initialSize=10
#<!-- 最大空闲连接 -->
dataSource.maxIdle=20
#<!-- 最小空闲连接 -->
dataSource.minIdle=5
#最大连接数量
dataSource.maxActive=50
#是否在自动回收超时连接的时候打印连接的超时错误
dataSource.logAbandoned=true
#是否自动回收超时连接
dataSource.removeAbandoned=true
#超时时间(以秒数为单位)
#设置超时时间有一个要注意的地方,超时时间=现在的时间-程序中创建Connection的时间,如果maxActive比较大,比如超过100,那么removeAbandonedTimeout可以设置长一点比如180,
#也就是三分钟无响应的连接进行回收,当然应用的不同设置长度也不同。
dataSource.removeAbandonedTimeout=180
#<!-- 超时等待时间以毫秒为单位 -->
#maxWait代表当Connection用尽了,多久之后进行回收丢失连接
dataSource.maxWait=1000
(7)添加工具类:JDBCUtil和静态工厂类BeanFactory
JDBCUtil:
package com.gem.util;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
public class JDBCUtil {
private static DataSource dataSource;
static {
Properties properties = new Properties();
try {
properties.load(JDBCUtil.class.getClassLoader().getResourceAsStream("db.properties"));
try {
dataSource = new BasicDataSourceFactory().createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static DataSource getDataSource() {
return dataSource;
}
public static Connection getConnection() {
try {
return dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public static void close(ResultSet set, Statement preparedStatement, Connection connection) {
if (set != null) {
try {
set.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
BeanFactory:
package com.gem.util;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class BeanFactory {
public static Object getBean(String allClassName) {
try {
Class objectClass = Class.forName(allClassName);
Constructor<Object> constructor = objectClass.getConstructor();//无参构造
return constructor.newInstance();//实例化对象
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
(8)添加完工具类之后,我们准备工作就做好了,接下来我们先来写实体类User
package com.gem.entity;
import lombok.*;
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class User {
private Integer id;
private String username;
private Integer age;
public User(String username, Integer age) {
super();
this.username = username;
this.age = age;
}
}
(9)接着写持久层UserDao 和UserDaoImpl
UserDao:
package com.gem.dao;
import java.util.List;
import com.gem.entity.User;
public interface UserDao {
//查看所有用户
List<User> selectAllUser();
//根据id查找用户
User selectUserById(int id);
//根据年龄查找用户
List<User> selectUserByAge(int age);
//添加用户
boolean insertUser(User user);
//删除用户
boolean deleteUserById(int id);
//修改用户信息
boolean updateUserById(User user);
}
UserDaoImpl:
★主要看一下UserDaoImpl中,JDBCTemplate中的实现细节。
package com.gem.dao.impl;
import java.util.List;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import com.gem.dao.UserDao;
import com.gem.entity.User;
import com.gem.util.JDBCUtil;
public class UserDaoImpl implements UserDao {
//创建JDBCTemplate的对象,并获得连接池对象
JdbcTemplate template = new JdbcTemplate(JDBCUtil.getDataSource());
@Override
public List<User> selectAllUser() {//查看所有用户
//编写sql语句
String sql = "select * from tb_user";
//创建一个users集合来存放从数据库中取出的User对象,BeanPropertyRowMapper的作用是将实体类User中的各个属性对应数据库中的各个字段,
//将数据库中的数据取出(所以实体类中的属性名要和数据库中的字段名相同)
List<User> users = template.query(sql, new BeanPropertyRowMapper<User>(User.class));
if (users.size() > 0)
return users;
return null;
}
@Override
public User selectUserById(int id) {//根据id查找用户
//这里的?设置参数
String sql = "select * from tb_user where id=?";
//这里后面添加的id参数,用来填入上面的 "?" 中
List<User> users = template.query(sql, new BeanPropertyRowMapper<User>(User.class), id);
if (users.size() > 0 && users.get(0) != null)
return users.get(0);
return null;
}
@Override
public List<User> selectUserByAge(int age) {//根据年龄查找用户
//这里的?设置参数
String sql = "select * from tb_user where age=?";
//这里后面添加的age参数,用来填入上面的 "?" 中
List<User> users = template.query(sql, new BeanPropertyRowMapper<User>(User.class), age);
if (users.size() > 0)
return users;
return null;
}
@Override
public boolean insertUser(User user) { //添加用户
String sql = "insert into tb_user values(null,?,?)";
//count用来接收上面这句sql语句更新表中数据所影响的行数
int count = template.update(sql, user.getUsername(), user.getAge());
return count > 0;
}
@Override
public boolean deleteUserById(int id) { //删除用户
String sql = "delete from tb_user where id=?";
int count = template.update(sql, id);
return count > 0;
}
@Override
public boolean updateUserById(User user) { //修改用户信息
String sql = "update tb_user set username=?,age=? where id=?";
int count = template.update(sql, user.getUsername(), user.getAge(), user.getId());
return count > 0;
}
}
(10)写完持久层之后,我们写业务层:UserService和UserServiceImpl
UserService:
package com.gem.service;
import java.util.List;
import com.gem.entity.User;
public interface UserService {
//查看所有用户
List<User> getAllUser();
//根据id查找用户
User getUserById(int id);
//根据年龄查找用户
List<User> getUserByAge(int age);
//添加用户
boolean addUser(User user);
//删除用户
boolean deleteUserById(int id);
//修改用户信息
boolean updateUserById(User user);
}
UserServiceImpl:
package com.gem.service.impl;
import java.util.List;
import com.gem.dao.UserDao;
import com.gem.entity.User;
import com.gem.service.UserService;
import com.gem.util.BeanFactory;
public class UserServiceImpl implements UserService {
UserDao userDao = (UserDao) BeanFactory.getBean("com.gem.dao.impl.UserDaoImpl");
@Override
public List<User> getAllUser() {
return userDao.selectAllUser();
}
@Override
public User getUserById(int id) {
return userDao.selectUserById(id);
}
@Override
public List<User> getUserByAge(int age) {
return userDao.selectUserByAge(age);
}
@Override
public boolean addUser(User user) {
return userDao.insertUser(user);
}
@Override
public boolean deleteUserById(int id) {
return userDao.deleteUserById(id);
}
@Override
public boolean updateUserById(User user) {
return userDao.updateUserById(user);
}
}
(11)最后我们来写一下Client。用来测试JDBCTemplate
package com.gem.client;
import java.util.Scanner;
import com.gem.entity.User;
import com.gem.service.UserService;
import com.gem.util.BeanFactory;
public class Client {
public static void main(String[] args) {
UserService userService = (UserService) BeanFactory.getBean("com.gem.service.impl.UserServiceImpl");
Scanner sc = new Scanner(System.in);
while (true)
menu(sc, userService);
}
private static void menu(Scanner sc, UserService userService) {
System.out.println("1.查看所有用户");
System.out.println("2.根据id查找用户");
System.out.println("3.根据年龄查找用户");
System.out.println("4.添加用户");
System.out.println("5.删除用户");
System.out.println("6.修改用户信息");
String choice = sc.nextLine().trim();
switch (choice) {
case "1":
searchAllUser(sc, userService);
break;
case "2":
searchUserById(sc, userService);
break;
case "3":
searchUserByAge(sc, userService);
break;
case "4":
addUser(sc, userService);
break;
case "5":
deleteUserById(sc, userService);
break;
case "6":
updateUserById(sc, userService);
break;
default:
break;
}
}
private static void updateUserById(Scanner sc, UserService userService) {
System.out.println("请输入要修改的用户的id");
int id = Integer.parseInt(sc.nextLine().trim());
System.out.println("请输入新姓名");
String newUsername = sc.nextLine().trim();
System.out.println("请输入新年龄");
int newAge = Integer.parseInt(sc.nextLine().trim());
if (userService.updateUserById(new User(id, newUsername, newAge)))
System.out.println("修改成功");
else
System.out.println("修改失败");
}
private static void deleteUserById(Scanner sc, UserService userService) {
System.out.println("请输入要删除的id");
int id = Integer.parseInt(sc.nextLine().trim());
if (userService.deleteUserById(id))
System.out.println("删除成功");
else
System.out.println("删除失败");
}
private static void addUser(Scanner sc, UserService userService) {
System.out.println("请输入姓名");
String username = sc.nextLine().trim();
System.out.println("请输入年龄");
int age = Integer.parseInt(sc.nextLine().trim());
if (userService.addUser(new User(username, age)))
System.out.println("添加成功");
else
System.out.println("添加失败");
}
private static void searchUserByAge(Scanner sc, UserService userService) {
System.out.println("请输入要查询的年龄");
int age = Integer.parseInt(sc.nextLine().trim());
userService.getUserByAge(age).forEach(System.out::println);
}
private static void searchUserById(Scanner sc, UserService userService) {
System.out.println("请输入要查询的id");
int id = Integer.parseInt(sc.nextLine().trim());
System.out.println(userService.getUserById(id));
}
private static void searchAllUser(Scanner sc, UserService userService) {
userService.getAllUser().forEach(System.out::println);
}
}