补充
转:在这里面也可以使用自己定义的JDBCUtil,不一定要使用Druid
JDBCTemplate详细介绍
JDBC
概念:JDBC ( Java DataBase Connectivity java数据库连接)是一种用于执行SQL语句的JavaAPI ,可以为多种关系型数据库提供统一访问,它是由一组用Java语言编写的类和接[ ]组成的。
本质:就是java官方提供的一套规范(接口)。用于帮助开发人员快速实现不同关系型数据库的连接!
快速入门
package com.yy;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
/**
* @author Marston
* @date 2021/8/11
*/
public class JDBCDemo1 {
public static void main(String[] args) throws Exception {
//1.导入jar包
//2.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//3.获取连接
Connection con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/db0809pm", "root", "2184021338");
//4.获取执行对象
Statement stat = con.createStatement();
//5.执行sql语句,并且接受结果
String sql = "select * from student";
ResultSet rs = stat.executeQuery(sql);
//6.处理结果
while(rs.next()){
System.out.println(rs.getInt("id")+"\t"+rs.getString("name")+
"\t"+rs.getInt("age")+"\t"
+rs.getString("gender")+"\t"+rs.getInt("score"));
}
//7.释放资源
con.close();
stat.close();
con.close();
}
}
JDBC功能类详解
DriverManager
Connection
Statement
ResultSet
JDBC案例
1.创建数据库,准备数据
db0809pm数据库里面的student表
2.创建Student类
自定义类的功能是为了封装表中每列数据,成员变量和列保持一致所有基本数据类型需要使用对应包装类,以免表中null值无法赋值
public class Student {
private Integer id;
private String name;
private Integer age;
private String gender;
private Integer score;
......
}
3.需求实现
需求一:查询所有学生信息
需求二:根据id查询学生信息
需求三:新增学生信息
需求四:修改学生信息
需求五:删除学生信息
package Case.dao;
import Case.domain.Student;
import java.sql.*;
import java.util.ArrayList;
/**
* @author Marston
* @date 2021/8/11
*/
public class StudentDaoImpl implements StudentDao{
@Override
public ArrayList<Student> findAll() {
ArrayList<Student> list = new ArrayList<>();
//因为作用域的问题,所以需要将这三个在外面声明,这样才能在finally里面释放资源
Connection con = null;
Statement stat = null;
ResultSet rs = null;
try{
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取数据库连接
con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/db0809pm", "root", "2184021338");
//3.获取执行者对象
stat = con.createStatement();
//4.执行sql语句,并且接受返回的结果集
String sql = "SELECT * FROM student";
rs = stat.executeQuery(sql);
//5.处理结果集
while (rs.next()){
Integer id = rs.getInt("id");
String name = rs.getString("name");
Integer age = rs.getInt("age");
String gender = rs.getString("gender");
Integer score = rs.getInt("score");
//封装Student对象
Student stu = new Student(id,name,age,gender,score);
//将Student对象保存到集合中
list.add(stu);
}
//6.释放资源
}catch (Exception e){
e.printStackTrace();
}finally {
//释放资源之前必须先进行资源的判断,
// 因为这三个对象是在外面声明的,如果里面try发生错误,他们就还是null
if (con != null){
try {
con.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (stat != null){
try {
stat.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (rs != null){
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
//将集合对象返回
return list;
}
@Override
public Student findById(Integer id) {
Student stu = new Student();
//因为作用域的问题,所以需要将这三个在外面声明,这样才能在finally里面释放资源
Connection con = null;
Statement stat = null;
ResultSet rs = null;
try{
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取数据库连接
con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/db0809pm", "root", "2184021338");
//3.获取执行者对象
stat = con.createStatement();
//4.执行sql语句,并且接受返回的结果集
String sql = "SELECT * FROM student WHERE id='"+id+"'";
rs = stat.executeQuery(sql);
//5.处理结果集
while (rs.next()){
Integer sid = rs.getInt("id");
String name = rs.getString("name");
Integer age = rs.getInt("age");
String gender = rs.getString("gender");
Integer score = rs.getInt("score");
//封装Student对象
stu.setId(sid);
stu.setAge(age);
stu.setGender(gender);
stu.setScore(score);
stu.setName(name);
}
//6.释放资源
}catch (Exception e){
e.printStackTrace();
}finally {
//释放资源之前必须先进行资源的判断,
// 因为这三个对象是在外面声明的,如果里面try发生错误,他们就还是null
if (con != null){
try {
con.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (stat != null){
try {
stat.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (rs != null){
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
//将集合对象返回
return stu;
}
@Override
public int insert(Student stu) {
//因为作用域的问题,所以需要将这三个在外面声明,这样才能在finally里面释放资源
Connection con = null;
Statement stat = null;
int result = 0;
try{
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取数据库连接
con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/db0809pm", "root", "2184021338");
//3.获取执行者对象
stat = con.createStatement();
//4.执行sql语句,并且接受返回的结果集
String sql = "INSERT INTO student VALUES('"+stu.getId()+"','"+stu.getName()+"','"+stu.getAge()+"','"+stu.getGender()+"','"+stu.getScore()+"')";
result = stat.executeUpdate(sql);
//6.释放资源
}catch (Exception e){
e.printStackTrace();
}finally {
//释放资源之前必须先进行资源的判断,
// 因为这三个对象是在外面声明的,如果里面try发生错误,他们就还是null
if (con != null){
try {
con.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (stat != null){
try {
stat.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
//将集合对象返回
return result;
}
@Override
public int update(Student stu) {
//因为作用域的问题,所以需要将这三个在外面声明,这样才能在finally里面释放资源
Connection con = null;
Statement stat = null;
int result = 0;
try{
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取数据库连接
con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/db0809pm", "root", "2184021338");
//3.获取执行者对象
stat = con.createStatement();
//4.执行sql语句,并且接受返回的结果集
String sql = "UPDATE student SET id='"+stu.getId()+"',name='"+stu.getName()+"',age='"+stu.getAge()+"',gender='"+stu.getGender()+"',score='"+stu.getScore()+"' WHERE id='"+stu.getId()+"'";
result = stat.executeUpdate(sql);
//6.释放资源
}catch (Exception e){
e.printStackTrace();
}finally {
//释放资源之前必须先进行资源的判断,
// 因为这三个对象是在外面声明的,如果里面try发生错误,他们就还是null
if (con != null){
try {
con.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (stat != null){
try {
stat.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
//将集合对象返回
return result;
}
@Override
public int delete(Integer id) {
//因为作用域的问题,所以需要将这三个在外面声明,这样才能在finally里面释放资源
Connection con = null;
Statement stat = null;
int result = 0;
try{
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取数据库连接
con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/db0809pm", "root", "2184021338");
//3.获取执行者对象
stat = con.createStatement();
//4.执行sql语句,并且接受返回的结果集
String sql = "DELETE FROM student WHERE id = '"+id+"'";
result = stat.executeUpdate(sql);
//6.释放资源
}catch (Exception e){
e.printStackTrace();
}finally {
//释放资源之前必须先进行资源的判断,
// 因为这三个对象是在外面声明的,如果里面try发生错误,他们就还是null
if (con != null){
try {
con.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (stat != null){
try {
stat.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
//将集合对象返回
return result;
}
}
package Case.service;
import Case.dao.StudentDao;
import Case.dao.StudentDaoImpl;
import Case.domain.Student;
import java.util.ArrayList;
/**
* @author Marston
* @date 2021/8/11
*/
public class StudentServiceImpl implements StudentService{
private StudentDao dao = new StudentDaoImpl();
@Override
public ArrayList<Student> findAll() throws Exception {
return dao.findAll();
}
@Override
public Student findById(Integer id) {
return dao.findById(id);
}
@Override
public int insert(Student stu) {
return dao.insert(stu);
}
@Override
public int update(Student stu) {
return dao.update(stu);
}
@Override
public int delete(Integer id) {
return dao.delete(id);
}
}
package Case.controller;
import Case.domain.Student;
import Case.service.StudentService;
import Case.service.StudentServiceImpl;
import org.junit.Test;
import java.util.ArrayList;
/**
* @author Marston
* @date 2021/8/11
*/
public class StudentController {
private StudentService service = new StudentServiceImpl();
@Test
public void findAll() throws Exception {
ArrayList<Student> list = service.findAll();
for (Student stu : list){
System.out.println(stu);
}
}
@Test
public void findById(){
Student stu = service.findById(3);
System.out.println(stu);
}
@Test
public void insert(){
Student stu = new Student(5,"王五",29,"女",98);
int result = service.insert(stu);
if (result != 0){
System.out.println("添加成功");
}else{
System.out.println("添加失败");
}
}
@Test
public void update(){
Student stu = service.findById(3);
stu.setName("khk");
int result = service.update(stu);
if (result != 0){
System.out.println("修改成功");
}else {
System.out.println("修改失败");
}
}
@Test
public void delete(){
int result = service.delete(5);
if (result != 0){
System.out.println("删除成功!");
}else {
System.out.println("删除失败!");
}
}
}
JDBC工具类
作用:因为上面dao方法中很多代码重复,为了简化,所以才有工具类
抽取工具类
1.编写配置文件
在src目录下创建config.properties配置文件
2.编写JDBC工具类
这个是需要自己编写的
package Case.utils;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
/**
* @author Marston
* @date 2021/8/11
* JDBC工具类
*/
public class JDBCUtils {
//1.私有构造方法
private JDBCUtils(){}
//2.声明所需要的配置变量
private static String driverClass;
private static String url;
private static String username;
private static String password;
private static Connection con;
//3.提供静态代码块。读取配置文件的信息为变量赋值,注册驱动
static {
try {
//读取配置文件的信息为变量赋值
InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("config.properties");
Properties prop = new Properties();
prop.load(is);
//赋值
driverClass = prop.getProperty("driverClass");
url = prop.getProperty("url");
username = prop.getProperty("username");
password = prop.getProperty("password");
//注册驱动
Class.forName(driverClass);
} catch (Exception e) {
e.printStackTrace();
}
}
//4.提供获取数据流连接方法
public static Connection getConnection(){
try {
con = DriverManager.getConnection(url,username,password);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return con;
}
//5.提供释放资源的方法
//查找调用这个方法,增删改调用下面的操作
public static void close(Connection con, Statement stat, ResultSet rs){
if (con != null){
try {
con.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (stat != null){
try {
stat.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (rs != null){
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
//有的时候执行增删改的操作没有ResultSet结果集对象,所以就要做下面这个重载的方法
public static void close(Connection con, Statement stat){
if (con != null){
try {
con.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (stat != null){
try {
stat.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
3.使用jdbc工具类优化student表的CRUD操作
package Case.dao;
import Case.domain.Student;
import Case.utils.JDBCUtils;
import java.sql.*;
import java.util.ArrayList;
/**
* @author Marston
* @date 2021/8/11
*/
public class StudentDaoImpl implements StudentDao{
@Override
public ArrayList<Student> findAll() {
ArrayList<Student> list = new ArrayList<>();
//因为作用域的问题,所以需要将这三个在外面声明,这样才能在finally里面释放资源
Connection con = null;
Statement stat = null;
ResultSet rs = null;
try{
//1.注册驱动
//2.获取数据库连接
con = JDBCUtils.getConnection();
//3.获取执行者对象
stat = con.createStatement();
//4.执行sql语句,并且接受返回的结果集
String sql = "SELECT * FROM student";
rs = stat.executeQuery(sql);
//5.处理结果集
while (rs.next()){
Integer id = rs.getInt("id");
String name = rs.getString("name");
Integer age = rs.getInt("age");
String gender = rs.getString("gender");
Integer score = rs.getInt("score");
//封装Student对象
Student stu = new Student(id,name,age,gender,score);
//将Student对象保存到集合中
list.add(stu);
}
//6.释放资源
}catch (Exception e){
e.printStackTrace();
}finally {
//释放资源之前必须先进行资源的判断,
// 因为这三个对象是在外面声明的,如果里面try发生错误,他们就还是null
JDBCUtils.close(con,stat,rs);
}
//将集合对象返回
return list;
}
@Override
public Student findById(Integer id) {
Student stu = new Student();
//因为作用域的问题,所以需要将这三个在外面声明,这样才能在finally里面释放资源
Connection con = null;
Statement stat = null;
ResultSet rs = null;
try{
//1.注册驱动
//2.获取数据库连接
con = JDBCUtils.getConnection();
//3.获取执行者对象
stat = con.createStatement();
//4.执行sql语句,并且接受返回的结果集
String sql = "SELECT * FROM student WHERE id='"+id+"'";
rs = stat.executeQuery(sql);
//5.处理结果集
while (rs.next()){
Integer sid = rs.getInt("id");
String name = rs.getString("name");
Integer age = rs.getInt("age");
String gender = rs.getString("gender");
Integer score = rs.getInt("score");
//封装Student对象
stu.setId(sid);
stu.setAge(age);
stu.setGender(gender);
stu.setScore(score);
stu.setName(name);
}
//6.释放资源
}catch (Exception e){
e.printStackTrace();
}finally {
//释放资源之前必须先进行资源的判断,
// 因为这三个对象是在外面声明的,如果里面try发生错误,他们就还是null
JDBCUtils.close(con,stat,rs);
}
//将集合对象返回
return stu;
}
@Override
public int insert(Student stu) {
//因为作用域的问题,所以需要将这三个在外面声明,这样才能在finally里面释放资源
Connection con = null;
Statement stat = null;
int result = 0;
try{
//1.注册驱动
//2.获取数据库连接
con = JDBCUtils.getConnection();
//3.获取执行者对象
stat = con.createStatement();
//4.执行sql语句,并且接受返回的结果集
String sql = "INSERT INTO student VALUES('"+stu.getId()+"','"+stu.getName()+"','"+stu.getAge()+"','"+stu.getGender()+"','"+stu.getScore()+"')";
result = stat.executeUpdate(sql);
//6.释放资源
}catch (Exception e){
e.printStackTrace();
}finally {
//释放资源之前必须先进行资源的判断,
// 因为这三个对象是在外面声明的,如果里面try发生错误,他们就还是null
JDBCUtils.close(con,stat);
}
//将集合对象返回
return result;
}
@Override
public int update(Student stu) {
//因为作用域的问题,所以需要将这三个在外面声明,这样才能在finally里面释放资源
Connection con = null;
Statement stat = null;
int result = 0;
try{
//1.注册驱动
//2.获取数据库连接
con = JDBCUtils.getConnection();
//3.获取执行者对象
stat = con.createStatement();
//4.执行sql语句,并且接受返回的结果集
String sql = "UPDATE student SET id='"+stu.getId()+"',name='"+stu.getName()+"',age='"+stu.getAge()+"',gender='"+stu.getGender()+"',score='"+stu.getScore()+"' WHERE id='"+stu.getId()+"'";
result = stat.executeUpdate(sql);
//6.释放资源
}catch (Exception e){
e.printStackTrace();
}finally {
//释放资源之前必须先进行资源的判断,
// 因为这三个对象是在外面声明的,如果里面try发生错误,他们就还是null
JDBCUtils.close(con,stat);
}
//将集合对象返回
return result;
}
@Override
public int delete(Integer id) {
//因为作用域的问题,所以需要将这三个在外面声明,这样才能在finally里面释放资源
Connection con = null;
Statement stat = null;
int result = 0;
try{
//1.注册驱动
//2.获取数据库连接
con = JDBCUtils.getConnection();
//3.获取执行者对象
stat = con.createStatement();
//4.执行sql语句,并且接受返回的结果集
String sql = "DELETE FROM student WHERE id = '"+id+"'";
result = stat.executeUpdate(sql);
//6.释放资源
}catch (Exception e){
e.printStackTrace();
}finally {
//释放资源之前必须先进行资源的判断,
// 因为这三个对象是在外面声明的,如果里面try发生错误,他们就还是null
JDBCUtils.close(con,stat);
}
//将集合对象返回
return result;
}
}
4.Student表的CRUD操作整合页面
未完成
SQL注入攻击
什么是SQL注入攻击
●就是利用sq|语句的漏洞来对系统进行击
SQL注入攻击的演示
暂时无。。。
SQL注入攻击的原理
●按照正常道理来说,我们在密码处输入的所有内容,都应该认为是密码的组成
●但是现在Statement对象在执行sq|语句时,将密码的一部分内容当做查询条件来执行了
会产生SQL注入的
解决SQL注入问题过后
JDBC事务
数据库连接池
数据库连接池负责**分配、管理和释放数据库连接,**它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个。这项技术能明显提高对数据库操作的性能
自定义数据库连接池
package ConPool;
import Case.utils.JDBCUtils;
import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;
/**
* @author Marston
* @date 2021/8/11
* 自定义数据库连接池
*/
public class MyDataSource implements DataSource {
//1.准备容器,用于保存多个连接对象,将这个ArrayList集合变成线程安全的对象
private static List<Connection> pool = Collections.synchronizedList(new ArrayList<>());
//2.定义静态代码块,通过工具类获取10个连接对象
static {
for (int i = 0; i <= 10 ; i++) {
Connection con = JDBCUtils.getConnection();
pool.add(con);
}
}
//3.重写getConnection(),用于获取有关连接对象
@Override
public Connection getConnection() throws SQLException {
if (pool.size() > 0){
Connection con = pool.remove(0);
return con;
}else {
throw new RuntimeException("连接数量用尽");
}
}
//4.定义getSize方法,获取连接池容器的大小
public int getSize(){
return pool.size();
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return null;
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
}
@Override
public int getLoginTimeout() throws SQLException {
return 0;
}
@Override
public ConnectionBuilder createConnectionBuilder() throws SQLException {
return null;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
@Override
public ShardingKeyBuilder createShardingKeyBuilder() throws SQLException {
return null;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
}
3.数据库连接池的测试
还是存在一个问题,那就是关闭后的那个连接并没有放回连接池中
package ConPool;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* @author Marston
* @date 2021/8/11
*/
public class MyDataSourceTest {
public static void main(String[] args) throws Exception {
//1.创建连接池对象
MyDataSource dataSource = new MyDataSource();
System.out.println("使用之前的数量:"+dataSource.getSize());
//2.通过连接池对象获取连接对象
Connection con = dataSource.getConnection();
//3.查询学生表的全部信息
String sql = "SELECT * FROM student";
PreparedStatement pst = con.prepareStatement(sql);
//4.执行sql语句,接收结果集
ResultSet rs = pst.executeQuery();
//5.处理结果集
while (rs.next()){
System.out.println(rs.getInt("id")+"\t"
+rs.getString("name")+"\t"+rs.getInt("age")
+rs.getString("gender")+"\t"+rs.getInt("score"));
}
//6.释放资源
rs.close();
pst.close();
con.close();//用完以后,还是关闭了连接
System.out.println("使用之后的数量:"+dataSource.getSize());
}
}
归还连接
归还数据库连接的方式
继承方式
package ConPool2;
import com.mysql.jdbc.JDBC4Connection;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Properties;
/**
* @author Marston
* @date 2021/8/11
* 自定义的连接对象
* 1.定义一个类,继承JDBC4Connection
* 2.定义Connection连接对象和容器对象的成员变量
* 3.通过有参构造方法为成变量赋值
* 4.重写c1ose方法,完成归还连接
*/
public class MyConnection1 extends JDBC4Connection {//1.定义一个类,继承JDBC4Connection
//2.定义Connection连接对象和容器对象的成员变量
private Connection con;
private List<Connection> pool;
//3.通过有参构造方法为成变量赋值
public MyConnection1(String hostToConnectTo, int portToConnectTo, Properties info, String databaseToConnectTo, String url,Connection con,List<Connection> pool) throws SQLException {
super(hostToConnectTo, portToConnectTo, info, databaseToConnectTo, url);
this.con = con;
this.pool = pool;
}
//4.重写c1ose方法,完成归还连接
@Override
public void close() throws SQLException {
pool.add(con);
}
}
装饰设计模式
package ConPool2;
import java.sql.*;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;
/**
* @author Marston
* @date 2021/8/11
* 1.定义一个类,实现Connection接口
* 2.定义连接对象和连接池容器对象的成员变量
* 3.通过有参构造方法为成员变量赋值
* 4.重写c1ose方法,完成归还连接
* 5.剩余方法,还是调用原有的连接对象中的功能即可
*/
//1.定义一个类,实现Connection接口
public class MyConnection2 implements Connection {
//2.定义连接对象和连接池容器对象的成员变量
private Connection con;
private List<Connection> pool;
//3.通过有参构造方法为成员变量赋值
public MyConnection2(Connection con,List<Connection> pool){
this.con = con;
this.pool = pool;
}
// 4.重写c1ose方法,完成归还连接
@Override
public void close() throws SQLException {
pool.add(con);
}
// 5.剩余方法,还是调用原有的连接对象中的功能即可
@Override
public Statement createStatement() throws SQLException {
// return null;
return con.createStatement();//下面方法的都是这样调用
}
......
....
适配器设计模式
动态代理方式
动态代理
搞清楚,基本上动态代理就是这样的死格式
实现
package ConPool;
import Case.utils.JDBCUtils;
import javax.sql.DataSource;
import java.io.PrintWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;
/**
* @author Marston
* @date 2021/8/11
* 自定义数据库连接池
*/
public class MyDataSource implements DataSource {
//1.准备容器,用于保存多个连接对象,将这个ArrayList集合变成线程安全的对象
private static List<Connection> pool = Collections.synchronizedList(new ArrayList<>());
//2.定义静态代码块,通过工具类获取10个连接对象
static {
for (int i = 0; i <= 10 ; i++) {
Connection con = JDBCUtils.getConnection();
pool.add(con);
}
}
//3.重写getConnection(),用于获取有关连接对象
//动态代理方式
@Override
public Connection getConnection() throws SQLException {
if (pool.size() > 0){
Connection con = pool.remove(0);
Connection proxyCon = (Connection) Proxy.newProxyInstance(con.getClass().getClassLoader(), new Class[]{Connection.class}, new InvocationHandler() {
/*
* 执行Connection实现类连接对象所有的方法都会经过invoke
如果是c1ose方法,归还连接
如果不是,直接执行连接对象原有的功能即可
* */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("close")){
//归还连接
pool.add(con);
return null;
}else {
return method.invoke(con,args);
}
}
});
return proxyCon;
}else {
throw new RuntimeException("连接数量用尽");
}
}
// //3.重写getConnection(),用于获取有关连接对象
// @Override
// public Connection getConnection() throws SQLException {
// if (pool.size() > 0){
// Connection con = pool.remove(0);
// return con;
// }else {
// throw new RuntimeException("连接数量用尽");
// }
// }
//4.定义getSize方法,获取连接池容器的大小
public int getSize(){
return pool.size();
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return null;
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
}
@Override
public int getLoginTimeout() throws SQLException {
return 0;
}
@Override
public ConnectionBuilder createConnectionBuilder() throws SQLException {
return null;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
@Override
public ShardingKeyBuilder createShardingKeyBuilder() throws SQLException {
return null;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
}
开源数据库连接池
C3P0
C3P0的使用
package ConPool3;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class C3P0Test1 {
public static void main(String[] args) throws Exception {
//1. 创建c3p0的数据库连接池对象
DataSource dataSource = new ComboPooledDataSource();
//2.通过连接池对象获取数据库连接
Connection con = dataSource.getConnection();
//3.执行操作
//3.查询学生表的全部信息
String sql = "SELECT * FROM student";
PreparedStatement pst = con.prepareStatement(sql);
//4.执行sql语句,接收结果集
ResultSet rs = pst.executeQuery();
//5.处理结果集
while (rs.next()){
System.out.println(rs.getInt("id")+"\t"
+rs.getString("name")+"\t"+rs.getInt("age")
+rs.getString("gender")+"\t"+rs.getInt("score"));
}
//6.释放资源
rs.close();
pst.close();
con.close();//用完以后,还是关闭了连接
}
}
C3P0的配置演示
Druid
配置文件内容
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/db0809pm
username=root
password=2184021338
# 初始化连接数量
initialSize=5
# 最大连接数量
maxActive=10
#超时时间
maxWait=3000
package ConPool4;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;
/**
* @author Marston
* @date 2021/8/12
* 1.通过Properties集合,加载配置文件
* 2.通过Druid连接池I厂类获取数据库连接池对象
* 3.通过连接池对象获取数据库连接进行使用
*/
public class DruidTest1 {
public static void main(String[] args) throws Exception{
//获取配置文件的流对象
InputStream is = DruidTest1.class.getClassLoader().getResourceAsStream("druid.properties");
//1.通过Properties集合,加载配置文件
Properties prop = new Properties();
prop.load(is);
//2.通过Druid连接池I厂类获取数据库连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
// 3.通过连接池对象获取数据库连接进行使用
Connection con = dataSource.getConnection();
//3.查询学生表的全部信息
String sql = "SELECT * FROM student";
PreparedStatement pst = con.prepareStatement(sql);
//4.执行sql语句,接收结果集
ResultSet rs = pst.executeQuery();
//5.处理结果集
while (rs.next()){
System.out.println(rs.getInt("id")+"\t"
+rs.getString("name")+"\t"+rs.getInt("age")
+rs.getString("gender")+"\t"+rs.getInt("score"));
}
//6.释放资源,归还容器中
rs.close();
pst.close();
con.close();
}
}
连接池的工具类
工具类Druid
package Case.utils;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/**
* @author Marston
* @date 2021/8/12
* 数据库连接池的工具类
*/
public class DataSourceUtils {
//1.私有构造方法
private DataSourceUtils(){}
//2.声明数据源变量
private static DataSource dataSource;
//3.提供静态代码块,完成配置文件的加载和获取数据库连接池对象
static {
try {
//完成配置文件的加载
InputStream is = DataSourceUtils.class.getClassLoader().getResourceAsStream("druid.properties");
Properties prop = new Properties();
prop.load(is);
//获取数据连接池对象
dataSource = DruidDataSourceFactory.createDataSource(prop);
}catch (Exception e){
e.printStackTrace();
}
}
//4.提供一个获取数据库连接的方法
public static Connection getConnection(){
Connection con = null;
try {
con = dataSource.getConnection();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return con;
}
//5.提供一个获取数据库连接池对象的方法
public static DataSource getDataSource(){
return dataSource;
}
//6.释放资源
public static void close(Connection con, Statement stat, ResultSet rs){
if (con != null){
try {
con.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (stat != null){
try {
stat.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (rs != null){
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
public static void close(Connection con, Statement stat){
if (con != null){
try {
con.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (stat != null){
try {
stat.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
测试
package ConPool4;
import Case.utils.DataSourceUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
/**
* @author Marston
* @date 2021/8/12
*/
public class DruidTest2 {
public static void main(String[] args) throws Exception{
//1.通过连接池工具类获取一个数据库连接
Connection con = DataSourceUtils.getConnection();
//3.查询学生表的全部信息
String sql = "SELECT * FROM student";
PreparedStatement pst = con.prepareStatement(sql);
//4.执行sql语句,接收结果集
ResultSet rs = pst.executeQuery();
//5.处理结果集
while (rs.next()){
System.out.println(rs.getInt("id")+"\t"
+rs.getString("name")+"\t"+rs.getInt("age")
+rs.getString("gender")+"\t"+rs.getInt("score"));
}
//释放资源
DataSourceUtils.close(con,pst,rs);
}
}