上期回顾
改进后的JDBC 帮助类
package com.chen.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class JdbcHelper {
private static String url = "jdbc:mysql://localhost:3306/boot_crm?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC";
private static String driver = "com.mysql.jdbc.Driver";
private static String user = "root";
private static String pwd = "root";
static {
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 获取数据库连接
* @return connection
*/
public static Connection getConnection() {
Connection conn = null;
try {
conn = DriverManager.getConnection(url, user, pwd);
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
}
我们可以看到,每次请求连接的时候,都需要重新获取连接DriverManager.getConnection(url, user, pwd);
这样一个过程非常耗费资源,所以我们使用了数据库连接池来优化
今日知识学习 数据库连接池,JdbcTemplate
数据库连接池
- 初始化后创建数据库连接池,
- 每次请求,不想数据库申请连接,改向数据库连接池来申请(租借)连接来节约资源、更加高效的获取
- 连接结束后,将连接归还给数据库连接池
数据库连接池实现接口 javax.sql.DataSource
package javax.sql;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Wrapper;
public interface DataSource extends CommonDataSource, Wrapper {
//不带参数的获取连接
Connection getConnection() throws SQLException;
//带参数的获取连接
Connection getConnection(String username, String password) throws SQLException;
}
下面是我模拟实现的数据库连接池
package cheng.jdbc;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Logger;
import javax.sql.DataSource;
/**
* 自定义的数据库连接池
* @author newChenyingtao
*/
public class DataSourceUtil implements DataSource {
// 数据库连接池集合
private List<Connection> pool;
private String url = "jdbc:mysql://localhost:3306/boot_crm?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC";
private String driver = "com.mysql.jdbc.Driver";
private String user = "root";
private String pwd = "root";
public Connection getOneConnection(){
Connection conn = null;
try {
// 1. 过程1 加载数据库驱动
Class.forName(driver);
// 2 过程2 向数据库申请连接
conn = DriverManager.getConnection(url, user, pwd);
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return conn;
}
@Override
public Connection getConnection(){
Connection conn = null;
if(pool == null) {
// 如果第一次访问,新建数据库
pool = new LinkedList<>();
for(int i = 0; i < 5; i++) {
pool.add(getOneConnection());
}
}
if(pool.size() <= 0) {
//当前数据库线程池连接用尽,需要等待
}
if(pool.size() > 0) {
//数据库连接足够,分配到一个返回
conn = pool.get(0);
pool.remove(0);
}
return conn;
}
//自己写的,模拟方法
public void close(Connection conn) {
//归还连接的方法
pool.add(conn);
}
/*其他方法 因为没有重写,所以在此删除 自己写的时候,会要求继承很多方法
但只要具体关注 getConnection()方法即可*/
- 使用C3P0:数据库连接池技术
jar包两个:
配置文件 - Druid:数据库连接池技术
- 导入jar包 com.alibaba.druid.pool.DruidDataSource
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
定义工具类
package com.chen.jdbc;
import com.alibaba.druid.pool.DruidDataSource;
import javax.sql.DataSource;
/**
* @ClassName DataSourceUtil
* @Description TODO
* @Author newChenyingtao
* @Date 2020/6/20 10:51
* @Version 1.0
*/
public class DataSourceUtil {
// 定义配置文件 properties 任意名称和位置
private static String url = "jdbc:mysql://localhost:3306/boot_crm?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC";
private static String driver = "com.mysql.jdbc.Driver";
private static String user = "root";
private static String pwd = "root";
public static DataSource getDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setPassword(pwd);
dataSource.setUsername(user);
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
return dataSource;
}
}
实现类
package com.chen.jdbc.dal;
import com.chen.jdbc.CloseHelper;
import com.chen.jdbc.DataSourceUtil;
import com.chen.jdbc.JdbcHelper;
import com.chen.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @ClassName UserDal
* @Description 使用jdbc 实现的数据库操作层
* @Author newChenyingtao
* @Date 2020/6/19 16:08
* @Version 1.0
*/
public class UserDal {
// 无线程池,使用Jdbc帮助类,申请连接
public List<User> findAll() throws SQLException {
Connection conn = JdbcHelper.getConnection();
String sql = "select * from sys_user";
PreparedStatement ps = conn.prepareStatement(sql);
List<User> list = new ArrayList<>();
ResultSet rs = ps.executeQuery();
while (rs.next()){
User user = new User();
user.setUser_id(rs.getInt(1));
user.setUser_code( rs.getString(2));
user.setUser_name(rs.getString(3));
user.setUser_password( rs.getString(4));
user.setUser_state( rs.getInt(5));
list.add(user);
}
CloseHelper.close(conn, ps, rs);
return list;
}
/**
* 使用了 dataSource 只修改了两句话
*/
public List<User> findAllByDataSource() throws SQLException {
// 以下两句话改变
DataSource dataSource = DataSourceUtil.getDataSource();
Connection conn = dataSource.getConnection();
// 以下未改变
String sql = "select * from sys_user";
PreparedStatement ps = conn.prepareStatement(sql);
List<User> list = new ArrayList<>();
ResultSet rs = ps.executeQuery();
while (rs.next()){
User user = new User();
user.setUser_id(rs.getInt(1));
user.setUser_code( rs.getString(2));
user.setUser_name(rs.getString(3));
user.setUser_password( rs.getString(4));
user.setUser_state( rs.getInt(5));
list.add(user);
}
return list;
}
}
可以看到,使用数据库连接池,改变了我们获取Connection 的方法,提高了程序性能,但是,代码量好像并没有减少多少,所以我们使用
JdbcTemplate 简介
jdbcTemplate类似人DBUtils,用于操作Jdbc的工具类,它需要依赖于连接池DataSource(数据源)
JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API
ODBC(Open Database Connectivity,ODBC)开放数据库连接,是微软公司开提供了一组对数据库访问的标准API(应用程序编程接口)
DBCP(DataBase Connection Pool)数据库连接池,是java数据库连接池的一种,由Apache开发
C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。
c3p0与dbcp区别
dbcp没有自动回收空闲连接的功能
c3p0有自动回收空闲连接功能
JdbcTemplate简介
Spring对数据库的操作在jdbc上面做了深层次的封装,使用spring的注入功能,可以把DataSource注册到JdbcTemplate之中。
JdbcTemplate位于中。简化 JDBC的配置
步骤;
- 导入jar包:
- 创建jdbcTemplate对象,依赖于数据源datasource
jdbcTemplate template = new jdbcTemplate(ds); - 调用jdbctemplate来进行增删改查
- update(); 执行dml语句 增删改
- query() 查询 可以添加转换模式
- queryForObject() 用于聚合函数的查询 比如统计记录
- queryForMap() 封装为map 只能一条
- queryForList() 记录封装为map,再封装为List
package com.chen.jdbc.dal;
import com.chen.jdbc.CloseHelper;
import com.chen.jdbc.DataSourceUtil;
import com.chen.jdbc.JdbcHelper;
import com.chen.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @ClassName UserDal
* @Description 使用jdbc 实现的数据库操作层
* @Author newChenyingtao
* @Date 2020/6/19 16:08
* @Version 1.0
*/
@Repository
public class UserDal {
// queryForObject 函数 统计总记录的条数
public int count(){
JdbcTemplate jdbcTemplate = new JdbcTemplate(DataSourceUtil.getDataSource());
String sql = "select count(sys_user.user_id) from sys_user";
return jdbcTemplate.queryForObject(sql, Integer.class);
}
// 只能查询单个记录 queryForMap将结果封装到 Map
public Map selectOne(){
JdbcTemplate jdbcTemplate = new JdbcTemplate(DataSourceUtil.getDataSource());
String sql = "select * from sys_user where user_id = ?";
Map map = jdbcTemplate.queryForMap(sql, 12);
System.out.println(map);
return map;
}
// queryForList 将结果封装到 Map 中再封装到List
public List selectAll(){
JdbcTemplate jdbcTemplate = new JdbcTemplate(DataSourceUtil.getDataSource());
String sql = "select * from sys_user";
List list = jdbcTemplate.queryForList(sql);
return list;
}
// query函数 将记录封装到 Java 对象,需要实现RowMapper<User>接口,看上去代码和原生的一样多
public List<User> selectAll2(){
JdbcTemplate jdbcTemplate = new JdbcTemplate(DataSourceUtil.getDataSource());
String sql = "select * from sys_user";
List<User> list = jdbcTemplate.query(sql, new RowMapper<User>() {
@Override
public User mapRow(ResultSet resultSet, int i) throws SQLException {
User user = new User();
user.setUser_id(resultSet.getInt("user_id"));
user.setUser_code(resultSet.getString(2));
user.setUser_name(resultSet.getString(3));
user.setUser_password(resultSet.getString(4));
user.setUser_state(resultSet.getInt(5));
return user;
}
});
return list;
}
//升级版本 new BeanPropertyRowMapper<User>(User.class)) 该对象是RowMapper的实现类,可以实现对象的转换 这才是我们使用 Jdbc Template 后的简化操作
public List<User> selectAll3(){
// 1. 获取数据库连接池
// 2. 注入到 Jdbc Template 中
JdbcTemplate jdbcTemplate = new JdbcTemplate(DataSourceUtil.getDataSource());
// 3. 注入sql语句
String sql = "select * from sys_user";
// 4. 执行 sql 语句,转换对象
List<User> list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<User>(User.class));
// 5. 返回对象
return list;
}
// update 语句 增、删、改
public int updateUser(){
DataSource dataSource = DataSourceUtil.getDataSource();
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
String sql = "update base_dict set ";
int x = jdbcTemplate.update(sql);
return x;
}
/
public int insertUser(){
JdbcTemplate jdbcTemplate = new JdbcTemplate(DataSourceUtil.getDataSource());
String sql = "insert into sys_user values (?,?,?,?,?)";
int x = jdbcTemplate.update(sql, "12","2015","Jacket","1234","1");
return x;
}
}
既然提到了依赖注入,我们就可以使用 spring来实现
配置思路
1. 配置数据库连接池
2. 配置JdbcTemplate,并且注入数据库连接池
3. 配置 Dao 操作语句
4. 执行
具体的实现,就放到下一期吧