JDBC:Java DataBase Connectivity(Java数据库连接)
概念:Java DataBase Connectivity(Java数据库连接),Java语言操作数据库。
JDBC本质:其实是官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。
0. 前言
本文所用到的数据库有da3、db4。所用到的表有da3中的account表、emp表,db4中的user表
account表:
emp表:
user表:
1.快速入门
-
步骤
-
导入驱动jar包
- 复制相应的.jar包到项目的libs(也可以建立其他名字的文件夹,建立文件夹的目的是方便管理)
- 然后右键libs文件夹–>Add As Library
-
注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
-
获取数据库连接对象Connection
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/数据库名称?useSSL=false&serverTimezone=UTC", "root", "root");
-
定义sql语句
-
获取执行sql语句的对象 Statement
-
执行sql,接收返回结果
-
处理结果
-
释放资源
-
-
代码示例:
//这里我们用名为da3的数据库 import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; public class Main { public static void main(String[] args) throws Exception { //1.导入驱动jar包 //2.注册驱动 Class.forName("com.mysql.cj.jdbc.Driver");//这一行可以省略 //3.获取数据库连接对象 Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/da3?useSSL=false&serverTimezone=UTC", "root", "root"); //4、定义sql语句 String sql = "update account set balance = 1000 where id = 1"; //5、获取执行sql的对象Statement Statement stmt = connection.createStatement(); //6、执行sql int count = stmt.executeUpdate(sql); //7.处理结果 System.out.println(count); //8.释放资源 stmt.close(); connection.close(); } }
2.详解各个对象
- DriverManager:驱动管理对象
- Connection:数据库连接对象
- Statement:执行sql的对象
- ResultSet:结果集对象
- PreparedStatement:执行sql的对象,是Statement的子接口
2.1 DriverManager:驱动管理对象
功能1.注册驱动
告诉程序该使用哪一个数据库驱动jar
在DriverManager中有一个静态方法static void registerDriver(Driver driver)
可以注册与给定的驱动程序DriverManager。但是我们在写代码的时候却直接使用Class.forName("com.mysql.cj.jdbc.Driver")
注册驱动。通过查看源码我们可以发现原因:在com.mysql.cj.jdbc.Driver
类中存在静态代码块(如下),可以驱动程序。
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
注意:mysql5之后的驱动jar包可以省略注册驱动步骤。
功能2.获取数据库连接
-
方法:
static Connection getConnection(String url, String user, String password)
-
参数:
url:指定连接的对象 语法:jdbc:mysql://ip地址(域名):端口号/数据库名称?useSSL=false&serverTimezone=UTC user:用户名 password:密码
-
2.2 Connection:数据库连接对象
功能1.获取执行sql的对象
方法1:Statement createStatement()
方法2:PreparedStatement PreparedStatement (String sql)
功能2.管理事务
开启事务
Connection.setAutoCommit(boolean autoCommit)
:调用该方法设置参乎上位false,即开启事务
提交事务
commit()
回滚事务
rollback()
案例
转账。这里我们用数据库da3中的account表。
代码实现:
import jdbc_utils.JDBCUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Tran_Main {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement1 = null;
PreparedStatement preparedStatement2 = null;
try {
//获取连接
connection = JDBCUtils.getConnection();
//开启事务
connection.setAutoCommit(false);
//定义sql语句
String sql1 = "update account set balance = balance - ? where id = ?";
String sql2 = "update account set balance = balance + ? where id = ?";
//获取执行对象
preparedStatement1 = connection.prepareStatement(sql1);
preparedStatement2 = connection.prepareStatement(sql2);
//设置参数
preparedStatement1.setInt(1, 500);
preparedStatement1.setInt(2, 1);
preparedStatement2.setInt(1, 500);
preparedStatement2.setInt(2, 2);
//执行SQL
preparedStatement1.executeUpdate();
//测试:在下面手动制造异常
//int i = 3 / 0;
preparedStatement2.executeUpdate();
//提交事务
connection.commit();
} catch (Exception e) {
e.printStackTrace();
}finally {
//如果在事务中遇到了异常,就回滚事务
try {
connection.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
//释放资源
JDBCUtils.close(preparedStatement1, connection);
JDBCUtils.close(preparedStatement2, null);
}
}
}
2.3 Statement:执行sql的对象
相关方法
boolean execute(String sql)
: 可以执行任意的sql,了解即可int executeUpdate(String sql)
: 执行DML(insert、update、delete)语句、DDL(create、alter、drop)语句- 返回值:影响的行数,可以通过这个影响的行数判断DML是否执行成功,返回值>0则执行成功,反之,则失败
ResultSet executeQuery(String sql)
: 执行DQL(select)语句
练习
- account表,添加一条记录
- account表,修改记录
- account表,删除一条记录
//1.account表,添加一条记录
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBCDemo01 {
public static void main(String[] args) {
Statement statement = null;
Connection connection = null;
try {
//1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取数据库连接对象
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/da3?useSSL=false&serverTimezone=UTC", "root", "root");
//3.定义sql语句
String sql = "insert into account values(null, '王五', 3000 )";
//4.获取执行sql语句的对象 Statement
statement = connection.createStatement();
//5.执行sql,接收返回结果
int i = statement.executeUpdate(sql);
//6.处理结果
System.out.println(i);
if(i > 0){
System.out.println("添加成功");
}else{
System.out.println("添加失败");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
//释放资源
if(statement != null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection != null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
//2.account表,修改记录
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBCDemo02 {
public static void main(String[] args) {
Statement statement = null;
Connection connection = null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/da3?useSSL=false&serverTimezone=UTC", "root", "root");
statement = connection.createStatement();
String sql = "update account set balance = 10000 where id = 3";
int i = statement.executeUpdate(sql);
System.out.println(i);
if(i > 0){
System.out.println("修改成功");
}else{
System.out.println("修改失败");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
if(statement != null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection != null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
//3.account表,删除一条记录
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBCDemo03 {
public static void main(String[] args) {
Statement statement = null;
Connection connection = null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/da3?useSSL=false&serverTimezone=UTC", "root", "root");
statement = connection.createStatement();
String sql = "delete from account where id = 3";
int i = statement.executeUpdate(sql);
System.out.println(i);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
if(statement != null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection != null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
2.4 ResultSet:结果集对象
封装查询的结果。
相关方法
-
boolean next()
: 游标向下移动一行,判断当前行是否是最后一行末尾(是否有数据),如果是,则返回false
,如果不是则返回true
-
getXxx(参数)
: 获取数据Xxx
: 如int getInt(参数)
String getString(参数)
- 参数:
- int : 代表列的编号,从1开始,如:
getString(1)
- String : 代表列名称。如
getDouble("列名")
- int : 代表列的编号,从1开始,如:
-
使用步骤
- 游标向下移动一行
- 判断是否有数据
- 获取数据
-
代码示例:
import java.sql.*; public class JDBCDemo04 { public static void main(String[] args) { Statement statement = null; Connection connection = null; ResultSet resultSet = null; try { Class.forName("com.mysql.cj.jdbc.Driver"); connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/da3?useSSL=false&serverTimezone=UTC", "root", "root"); statement = connection.createStatement(); String sql = "select * from account"; resultSet = statement.executeQuery(sql); //获取数据 while (resultSet.next()){ int anInt = resultSet.getInt(1); String name = resultSet.getString("name"); double aDouble = resultSet.getDouble(3); System.out.println(anInt + "---" + name + "---" + aDouble); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); }finally { if(resultSet != null){ try { resultSet.close(); } catch (SQLException e) { e.printStackTrace(); } } if(statement != null){ try { statement.close(); } catch (SQLException e) { e.printStackTrace(); } } if(connection != null){ try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }
练习
查询da3中的emp表
- 创建emp类:
import java.util.Date;
public class Emp {
private int id;
private String ename;
private int job_id;
private int mgr;
private Date joindate;
private double salary;
private double bonus;
private int dept_id;
public Emp() {
}
public Emp(int id, String ename, int job_id, int mgr, Date joindate, double salary, double bonus, int dept_id) {
this.id = id;
this.ename = ename;
this.job_id = job_id;
this.mgr = mgr;
this.joindate = joindate;
this.salary = salary;
this.bonus = bonus;
this.dept_id = dept_id;
}
@Override
public String toString() {
return "emp{" +
"id=" + id +
", ename='" + ename + '\'' +
", job_id=" + job_id +
", mgr=" + mgr +
", joindate=" + joindate +
", salary=" + salary +
", bonus=" + bonus +
", dept_id=" + dept_id +
'}';
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public int getJob_id() {
return job_id;
}
public void setJob_id(int job_id) {
this.job_id = job_id;
}
public int getMgr() {
return mgr;
}
public void setMgr(int mgr) {
this.mgr = mgr;
}
public Date getJoindate() {
return joindate;
}
public void setJoindate(Date joindate) {
this.joindate = joindate;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public double getBonus() {
return bonus;
}
public void setBonus(double bonus) {
this.bonus = bonus;
}
public int getDept_id() {
return dept_id;
}
public void setDept_id(int dept_id) {
this.dept_id = dept_id;
}
}
- 实现查询
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class empMain {
public static void main(String[] args) {
List<Emp> all = getAll();
for(Emp e : all){
System.out.println(e);
}
}
public static List<Emp> getAll(){
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
//注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/da3?useSSL=false&serverTimezone=UTC", "root", "root");
//定义sql语句
String sql = "select * from emp";
//获取执行对象
statement = connection.createStatement();
//获取结果集
resultSet = statement.executeQuery(sql);
//把结果集中的数据依次存入emp对象中,并把每个对象封装成集合
Emp emp = null;
List<Emp> list = new ArrayList<>();
while(resultSet.next()){
int id = resultSet.getInt("id");
String ename = resultSet.getString("ename");
int job_id = resultSet.getInt("job_id");
int mgr = resultSet.getInt("mgr");
Date joindate = resultSet.getDate("joindate");
double salary = resultSet.getDouble("salary");
double bonus = resultSet.getDouble("bonus");
int dept_id = resultSet.getInt("dept_id");
//存入emp对象中并返回
emp = new Emp(id, ename, job_id, mgr, joindate, salary, bonus, dept_id);
list.add(emp);
}
return list;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
}finally {
if(resultSet != null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(statement != null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection != null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return null;//这里的返回值表名如果try中的代码出现异常,就不会返回list集合,但是这个方法是需要有返回值的,程序就会直接执行finally中的代码,返回null
}
}
- 查询结果:
emp{id=1001, ename='孙悟空', job_id=4, mgr=1004, joindate=2000-12-17, salary=8000.0, bonus=0.0, dept_id=20}
emp{id=1002, ename='卢俊义', job_id=3, mgr=1006, joindate=2001-02-20, salary=16000.0, bonus=3000.0, dept_id=30}
emp{id=1003, ename='林冲', job_id=3, mgr=1006, joindate=2001-02-22, salary=12500.0, bonus=5000.0, dept_id=30}
emp{id=1004, ename='唐僧', job_id=2, mgr=1009, joindate=2001-04-02, salary=29750.0, bonus=0.0, dept_id=20}
emp{id=1005, ename='李逵', job_id=4, mgr=1006, joindate=2001-09-28, salary=12500.0, bonus=14000.0, dept_id=30}
emp{id=1006, ename='宋江', job_id=2, mgr=1009, joindate=2001-05-01, salary=28500.0, bonus=0.0, dept_id=30}
emp{id=1007, ename='刘备', job_id=2, mgr=1009, joindate=2001-09-01, salary=24500.0, bonus=0.0, dept_id=10}
emp{id=1008, ename='猪八戒', job_id=4, mgr=1004, joindate=2007-04-19, salary=30000.0, bonus=0.0, dept_id=20}
emp{id=1009, ename='罗贯中', job_id=1, mgr=0, joindate=2001-11-17, salary=50000.0, bonus=0.0, dept_id=10}
emp{id=1010, ename='吴用', job_id=3, mgr=1006, joindate=2001-09-08, salary=15000.0, bonus=0.0, dept_id=30}
emp{id=1011, ename='沙僧', job_id=4, mgr=1004, joindate=2007-05-23, salary=11000.0, bonus=0.0, dept_id=20}
emp{id=1012, ename='李逵', job_id=4, mgr=1006, joindate=2001-12-03, salary=9500.0, bonus=0.0, dept_id=30}
emp{id=1013, ename='小白龙', job_id=4, mgr=1004, joindate=2001-12-03, salary=30000.0, bonus=0.0, dept_id=20}
emp{id=1014, ename='关羽', job_id=4, mgr=1007, joindate=2002-01-23, salary=13000.0, bonus=0.0, dept_id=10}
2.5 抽取JDBC工具类:JDBCUtils
目的:简化书写。
分析:
1. 抽取注册驱动的相关代码
2. 抽取一个方法用来获取连接对象
* 需求:不想传递参数,而且必须保证工具类的通用性
* 解决方案:用配置文件来结局
3. 抽取一个方法用来释放资源
1.定义配置文件
定义配置文件jdbc.proprities
(名字可随意,此处只是例子)
Url=jdbc:mysql://localhost:3306/da3?useSSL=false&serverTimezone=UTC
user=root
password=root
driver=com.mysql.cj.jdbc.Driver
2.创建工具类JDBCUtils
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.sql.*;
import java.util.Properties;
public class JDBCUtils {
private static String url;
private static String user;
private static String password;
private static String driver;
//用类加载器获取配置文件的路径
//注册代码
static {
try {
Properties properties = new Properties();
//获取src路径下的文件的方式---->ClassLoader: 类加载器
ClassLoader classLoader = JDBCUtils.class.getClassLoader();
URL resource = classLoader.getResource("jdbc.proprities");
String path = resource.getPath();
properties.load(new FileReader(path));
url = properties.getProperty("Url");
user = properties.getProperty("user");
password = properties.getProperty("password");
driver = properties.getProperty("driver");
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, user, password);
}
//释放资源
public static void close(Statement statement, Connection connection){
if (statement != null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void close(ResultSet resultSet, Statement statement, Connection connection){
if(resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement != null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
3.测试
以上一节查询emp表为例进行测试
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class empMain {
public static void main(String[] args) {
List<Emp> all = getAll();
for(Emp e : all){
System.out.println(e);
}
}
public static List<Emp> getAll(){
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = JDBCUtils.getConnection();
//定义sql语句
String sql = "select * from emp";
//获取执行对象
statement = connection.createStatement();
//获取结果集
resultSet = statement.executeQuery(sql);
//把结果集中的数据依次存入emp对象中,并把每个对象封装成集合
Emp emp = null;
List<Emp> list = new ArrayList<>();
while(resultSet.next()){
int id = resultSet.getInt("id");
String ename = resultSet.getString("ename");
int job_id = resultSet.getInt("job_id");
int mgr = resultSet.getInt("mgr");
Date joindate = resultSet.getDate("joindate");
double salary = resultSet.getDouble("salary");
double bonus = resultSet.getDouble("bonus");
int dept_id = resultSet.getInt("dept_id");
//存入emp对象中并返回
emp = new Emp(id, ename, job_id, mgr, joindate, salary, bonus, dept_id);
list.add(emp);
}
return list;
} catch (SQLException e) {
e.printStackTrace();
}finally {
JDBCUtils.close(resultSet, statement, connection);
}
return null;//这里的返回值表名如果try中的代码出现异常,就不会返回list集合,程序就会直接执行finally中的代码,
}
}
练习
-
需求:
- 通过键盘录入用户名和密码
- 判断用户是否登录成功
-
代码实现:
数据库部分:create database db4; use db4; CREATE table user( id int primary key auto_increment, username varchar(32), password varchar(32) ); insert into user values(null, 'zhangsan', '123'); insert into user values(null, 'lisi', '234'); select * from user;
Java部分:
import jdbc_utils.JDBCUtils; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Scanner; public class Login_Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("请输入用户名:"); String username = sc.nextLine(); System.out.println("请输入密码:"); String password = sc.nextLine(); boolean flag = flag(username, password); if(flag){ System.out.println("登录成功!"); }else{ System.out.println("登录失败!"); } } //判断用户名和密码是否匹配,如果匹配则返回true,否则返回false public static boolean flag(String username, String password){ if(username == null || password == null){ return false; } Connection connection = null; Statement statement = null; ResultSet resultSet = null; try { connection = JDBCUtils.getConnection(); String sql = "select * from user where username = '" + username + "'and password = '" + password + "'"; statement = connection.createStatement(); resultSet = statement.executeQuery(sql); return resultSet.next(); } catch (SQLException e) { e.printStackTrace(); }finally { JDBCUtils.close(resultSet, statement, connection); } return false; } }
2.6 PreparedStatement:执行sql的对象
是Statement的子接口。
-
对于上一节练习中的代码会出现如下情况:
请输入用户名: dsvbjhbadvsjd 请输入密码: a' or 'a' = 'a 登录成功! Process finished with exit code 0
我们随便输入了一个用户名和密码
a' or 'a' = 'a
,竟然登录成功了。这就是sql注入问题。
-
SQL注入问题:
在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。会造成安全性问题
随便输入一个用户名,输入密码:a' or 'a' = 'a 这时执行的SQL语句是:select * from user where username = '随便输入的用户名' and password = 'a' or 'a' = 'a' 这条语句是可以正确执行的。
-
解决SQL注入问题:使用PreparedStatement对象来解决
-
预编译SQL:参数使用?作为占位符
-
步骤:
- 导入jar包
- 注册驱动
- 获取数据库连接对象Connection
- 定义sql
- 注意:sql的参数使用?作为占位符。如:
select * from user where username = ? and password = ?
- 注意:sql的参数使用?作为占位符。如:
- 获取执行sql的对象 PreparedStatement
COnnection.prepareStatement(String sql)
- 给?(占位符)复制
- 方法:setXxx(参数1,参数2)
- 参数1:?的位置编号 从1开始
- 参数2:?的值
- 方法:setXxx(参数1,参数2)
- 执行sql,接收返回结果,不需要传递sql语句
- 处理结果
- 释放资源
-
注意:后期都会使用PreparedStatement来完成增删改查的所有操作
- 可以防止SQL注入
- 效率更高
-
应用上述步骤解决上一节的问题
import jdbc_utils.JDBCUtils; import java.sql.*; import java.util.Scanner; public class Login_Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("请输入用户名:"); String username = sc.nextLine(); System.out.println("请输入密码:"); String password = sc.nextLine(); boolean flag = flag(username, password); if(flag){ System.out.println("登录成功!"); }else{ System.out.println("登录失败!"); } } //判断用户名和密码是否匹配,如果匹配则返回true,否则返回false public static boolean flag(String username, String password){ if(username == null || password == null){ return false; } Connection connection = null; PreparedStatement preparedStatement = null; ResultSet resultSet = null; try { connection = JDBCUtils.getConnection(); String sql = "select * from user where username = ? and password = ?"; preparedStatement = connection.prepareStatement(sql); preparedStatement.setString(1, username); preparedStatement.setString(2, password); resultSet = preparedStatement.executeQuery(); return resultSet.next(); } catch (SQLException e) { e.printStackTrace(); }finally { JDBCUtils.close(resultSet, preparedStatement, connection); } return false; } }
此时,就不会出现sql注入问题了。
请输入用户名: adishjvchsakjds 请输入密码: a' or 'a' = 'a 登录失败! Process finished with exit code 0
数据库连接池
-
概念:其实就是一个容器(集合),存放数据库连接的容器。
当系统初始化好后,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。
-
好处:
- 节约资源
- 用户访问高效
-
实现:
- 标准接口:
DateSource
javax.sql
包下的- 该接口中常用的方法:
- 获取连接:
getConnection()
- 归还连接:
COnnection.close()
;如果连接对象Connection是从连接池中获取的,那么调用COnnection.close()
方法就不会再关闭连接了,而是归还连接。
- 获取连接:
- 该接口中常用的方法:
- 常用的数据库连接池技术如下(一般我们不去实现它,由数据库厂商来实现)
- C3P0:数据库连接池技术
- Druid:数据库连接池实现技术,由阿里巴巴提供
- 标准接口:
1. C3P0
1.1 使用步骤:
-
导入jar包(两个):
c3p0-0.9.5.2. jar
mchange - commons-java-0.2.12. jar
不要忘记导入数据库驱动jar包
-
定义配置文件
- 名称:
c3p0. properties或者c3p0- config . xml
- 路径:直接将文件放在src目录下即可
- 名称:
-
创建核心对象:数据库连接池对象
ComboPooledDataSource
-
获取连接:
getConnection
1.2 配置文件详解
c3p0- config . xml
文件详解(这里我们使用了db4数据库):
<c3p0-config>
<!-- 使用默认的配置读取连接池对象 -->
<default-config>
<!-- 连接参数 -->
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/db4?useSSL=false&serverTimezone=UTC</property>
<property name="user">root</property>
<property name="password">root</property>
<!-- 连接池参数 -->
<!-- 初始化申请的连接数量-->
<property name="initialPoolSize">5</property>
<!-- 最大的连接数量 -->
<property name="maxPoolSize">10</property>
<!-- 超时时间 -->
<property name="checkoutTimeout">3000</property>
</default-config>
<!-- 下面是指定名字的配置 -->
<named-config name="otherc3p0">
<!-- 连接参数 -->
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/db4?useSSL=false&serverTimezone=UTC</property>
<property name="user">root</property>
<property name="password">root</property>
<!-- 连接池参数 -->
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">8</property>
<property name="checkoutTimeout">1000</property>
</named-config>
</c3p0-config>
1.3 代码测试
import com.mchange.v2.c3p0.ComboPooledDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
public class C3P0Demo {
public static void main(String[] args) throws SQLException {
//1.创建数据库连接池对象,使用默认配置,还可以指定名称配置
DataSource dataSource = new ComboPooledDataSource();
/*
如果使用指定名称的配置,则可以进行如下操作
DataSource dataSource = new ComboPooledDataSource("oteherc3p0");
*/
//2.获取连接对象
Connection connection = dataSource.getConnection();
//3.打印,如果能打印出地址值则代表获取成功
System.out.println(connection);
}
}
--------------------------------------------------
//输出结果
com.mchange.v2.c3p0.impl.NewProxyConnection@1e802ef9 [wrapping: com.mysql.cj.jdbc.ConnectionImpl@2b6faea6]
2. Druid
2.1 使用步骤:
- 导入jar包 druid-1.0.9.jar
- 定义配置文件:
- 这个配置文件是
properties
形式的 - 可以叫任意名称,可以放在任意目录下,需要我们手动导入
- 这个配置文件是
- 加载配置文件
- 获取数据库连接池对象:通过工厂来获取:
DruidDatasourceFactory
- 获取连接:
getConnection
2.2 配置文件详解
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/da3?useSSL=false&serverTimezone=UTC
username=root
password=root
initialSize=5
maxActive=10
maxWait=3000
2.3 代码测试
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;
public class DruidDemo {
public static void main(String[] args) throws Exception {
//1.导入jar包
//2.定义配置文件
//3.加载配置文件
ClassLoader classLoader = DruidDemo.class.getClassLoader();
Properties properties = new Properties();
InputStream resourceAsStream = classLoader.getResourceAsStream("druid.properties");
properties.load(resourceAsStream);
//4.获取数据库连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
//5.获取连接
Connection connection = dataSource.getConnection();
//6.打印,如果能获取到地址,则代表获取连接成功
System.out.println(connection);
}
}
2.4 定义工具类
JDBCUtils.java
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class JDBCUtils {
private static DataSource dataSource;
static {
try {
//1.加载配置文件
Properties properties = new Properties();
properties.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
//获取DataSource
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接的方法
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
//三个参数的释放资源(归还连接)方法
public static void close(ResultSet resultSet, Statement statement, Connection connection){
if(resultSet != null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(statement != null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection != null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//两个参数的释放资源(归还连接)方法
public static void close(Statement statement, Connection connection){
close(null, statement, connection);
}
//获取连接池的方法
public static DataSource getDataSource(){
return dataSource;
}
}
- 测试工具类
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class utils_test {
public static void main(String[] args) {
//完成一个添加数据的操作
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
//1.获取连接
connection = JDBCUtils.getConnection();
//2.定义sql
String sql = "insert into account values(null, ?, ?)";
//3.获取PreparedStatement对象
preparedStatement = connection.prepareStatement(sql);
//4.给?赋值
preparedStatement.setString(1, "wangwu");
preparedStatement.setInt(2, 3000);
//5.执行sql
int count = preparedStatement.executeUpdate();
System.out.println(count);
} catch (SQLException e) {
e.printStackTrace();
}finally {
//6.释放资源(归还连接)
JDBCUtils.close(preparedStatement, connection);
}
}
}
Spring JDBC
Spring框架对JDBC的简单封装。提供了一个JDBCTemplate对象简化JDBC的开发。
1.使用步骤
- 导入jar包
- 创建JDBCTemplate对象(依赖于数据源DataSource)
JDBCTemplate t = new JDBCTemplate(ds);
- 调用JDBCTemplate的相关方法来完成CURD的操作
update()
:执行DML语句(增删改语句)queryForMap()
:查询结果,将结果集风封装为map集合,将列名作为key,将值作为value,将这条记录封装为一个map集合- 注意:这个方法的查询长度只能是1
queryForList()
:查询结果,将结果集风封装为list集合- 注意:将每一条记录封装为一个Map集合,再将Map集合装载到List集合中
query()
:查询结果,将结果封装为JavaBean对象- query的参数
- 一般我们使用BeanPropertyRowMapper实现类。可以完成数据到JavaBean的自动封装
new BeanPropertyRowMapper<类型名>(类型名.class)
- query的参数
queryForObject()
:查询结果,将结果集风封装为对象- 一般用于聚合函数的查询
2.入门
这里我们更新da3数据库中的account表中的一条数据
import org.springframework.jdbc.core.JdbcTemplate;
import utils.JDBCUtils;
import javax.sql.DataSource;
public class Temp_test {
public static void main(String[] args) {
//获取连接池
DataSource dataSource = JDBCUtils.getDataSource();
//创建JdbcTemplate对象
JdbcTemplate template = new JdbcTemplate(dataSource);
//定义sql语句
String sql = "update account set balance = 60000 where id = ?";
//执行sql,第二个参数为占位符
int updateLineNum = template.update(sql, 2);//影响的行数
System.out.println(updateLineNum);
}
}
3.练习
使用da3数据库中的emp表。
需求:
- 修改1号数据的salary为10000
- 添加一条记录
- 删除刚才添加的记录
- 查询id为1的记录,将其封装为Map集合
- 查询所有记录,将其封装为List
- 查询所有记录,将其封装为Emp对象的List集合
- 查询总记录数
代码实现:
import org.junit.Test;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import utils.JDBCUtils;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
public class Emp_Test {
//获取JdbcTemplate对象
JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
//1.修改1号数据的salary为10000
@Test
public void test1(){
//定义sql语句
String sql = "update emp set salary = ? where id = ?";
//执行sql
int update = template.update(sql, 10000, 1001);
//打印执行结果
System.out.println(update);
}
//2.添加一条记录
@Test
public void test2(){
//定义sql语句
String sql = "insert into emp(id, ename) values(?, ?) ";
//执行sql
int update = template.update(sql, 1015, "哈哈哈");
//打印执行结果
System.out.println(update);
}
//3.删除刚才添加的记录
@Test
public void test3(){
//定义sql语句
String sql = "delete from emp where id = ?";
//执行sql
int update = template.update(sql, 1015);
//打印执行结果
System.out.println(update);
}
//4.查询id为1001的记录,将其封装为Map集合
@Test
public void test4(){
//定义sql语句
String sql = "select * from emp where id = ?";
//执行sql
Map<String, Object> stringObjectMap = template.queryForMap(sql, 1001);
//打印执行结果
System.out.println(stringObjectMap);
}
//5.查询所有记录,将其封装为Map集合
@Test
public void test5(){
//定义sql语句
String sql = "select * from emp";
//执行sql
List<Map<String, Object>> maps = template.queryForList(sql);
//打印执行结果
for(Map<String, Object> m : maps){
System.out.println(m);
}
}
//6_1.查询所有记录,将其封装为Emp对象的List集合
@Test
public void test6_1(){
//定义sql语句
String sql = "select * from emp";
//执行sql
List<Emp> query = template.query(sql, new RowMapper<Emp>() {
@Override
public Emp mapRow(ResultSet resultSet, int i) throws SQLException {
int id = resultSet.getInt("id");
String ename = resultSet.getString("ename");
int job_id = resultSet.getInt("job_id");
int mgr = resultSet.getInt("mgr");
Date joindate = resultSet.getDate("joindate");
double salary = resultSet.getDouble("salary");
double bonus = resultSet.getDouble("bonus");
int dept_id = resultSet.getInt("dept_id");
Emp emp = new Emp();
emp.setId(id);
emp.setEname(ename);
emp.setJob_id(job_id);
emp.setMgr(mgr);
emp.setJoindate(joindate);
emp.setSalary(salary);
emp.setBonus(bonus);
emp.setDept_id(dept_id);
return emp;
}
});
//打印执行结果
for(Emp m : query){
System.out.println(m);
}
}
//6_1.查询所有记录,将其封装为Emp对象的List集合
@Test
public void test6_2(){
//定义sql语句
String sql = "select * from emp";
//执行sql
List<Emp> query = template.query(sql, new BeanPropertyRowMapper<Emp>(Emp.class));
//打印执行结果
for(Emp m : query){
System.out.println(m);
}
}
//7.查询所有记录,将其封装为Emp对象的List集合
@Test
public void test7(){
//定义sql语句
String sql = "select count(id) from emp";
//执行sql
Integer integer = template.queryForObject(sql, Integer.class);
//打印执行结果
System.out.println(integer);
}
}