1. JDBC简介
Java Database Connectivity 提供了访问数据库的API,它由一些Java类和接口组成。使用JDBC的应用程序一旦和数据库建立连接,就可以使用JDBC提供的API操作数据库
JDBC兼容的数据库,包括Oracle、MySQL、Derby、PostgreSQL、SQL Server、H2等
2. JDBC功能
与一个数据库建立连接
向已连接的数据库发送SQL语句
处理SQL语句返回的结果
连接数据库方式:使用纯Java数据库驱动程序
3. JDBC使用(以MySQL为例)
步骤
加载驱动
连接数据库DriverManager
获得执行sq|的对象Statement
获得返回的结果集
释放连接
例
import java.sql.*;
public class work {
public static void main(String[] args){
try {// 注册驱动:不同数据库使用不同驱动串
Class.forName("com.mysql.cj.jdbc.Driver");
}
catch(ClassNotFoundException e){
System.out.println(""+e);
}
try{// 与数据库建立连接
Connection con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/cj?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8", "root", "root");
Statement sql = con.createStatement();
// 向已连接的数据库发送SQL语句
ResultSet rs = sql.executeQuery("SELECT * FROM cjb");// cjb为数据表名
// 处理SQL语句返回的结果
while(rs.next()){
String xm = rs.getString(1);
String pjf=rs.getString(4);
String yx=rs.getString(6);
System.out.println("姓名:" + xm + "平均分" + pjf + "院系:" + yx);
}
// 释放连接
rs.close();
sql.close();
con.close();
}
catch(SQLException e){
System.out.println(e);
}
}
}
注意
com.mysql.jdbc.Driver
是 mysql-connector-java 5中的
com.mysql.cj.jdbc.Driver
是 mysql-connector-java 6中的
com.mysql.cj.jdbc.Driver
, 需要指定时区serverTimezone
serverTimezone=UTC
在设定时区的时候,如果设定serverTimezone=UTC,会比中国时间早8个小时,如果在中国,可以选择Asia/Shanghai或者Asia/Hongkong
如果不需要使用SSL连接,需要通过设置useSSL=false
来显式禁用SSL连接
useSSL=false
3.1. DriverManager
Connection con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/cj?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8", "root", "root");
connection 代表数据库,可实现:数据库设置自动提交、事务提交、事务滚回
3.2. Statement对象
用于向数据库发送SQL语句,完成对数据库的增删改查
try{
Statement statement=con.createStatement();
}
catch(SQLException e){
System.out.println(e);
}
实现 CRUD
statement.executeQuery('sql'); // 查询操作,返回ResultSet
statement.execute('sql'); // 可执行任何SQL
statement.executeupdate('sql'); // 更新、插入、删除。都是用这个,返回一个受影响的行数
3.3. ResultSet结果集
封装了所有的查询结果
ResultSet rs = sql.executeQuery("select * from 表名");
3.4. 游标
游标是一段内存区域,用于暂时存放受某条SQL语句影响后的数据(如查询后的结果集、DML影响后的记录)。通俗理解就是将这些数据暂时放到了一个内存区域的虚表中,而这个虚表就是游标。
ResultSet对象使用 next()
方法移动游标,定位某条记录。
while(rs.next()){
String xm = rs.getString(1);
String pjf=rs.getString(4);
String yx=rs.getString(6);
System.out.println("姓名:" + xm + "平均分" + pjf + "院系:" + yx);
}
3.5. 释放资源
rs.close();
sql.close();
con.close();
4. CachedRowSetImpl 类
程序在使用ResultSet对象中的数据时,必须连接数据库,而CachedRowSetImpl对象不依赖Connnection对象,即把ResultSet对象中的数据保存到CachedRowSetImpl对象中后,就可以关闭和数据库的连接
CachedRowSetImpl对象可以保存ResultSet对象中的数据
CachedRowSetImpl对象继承了ResultSet对象的所有方法
import java.net.*;
import java.sql.*;
import com.sun.rowset.*;
public class Example12_5{
public static void main(String args[]){
Connection con;
Statement sql;
ResultSet rs;
CachedRowSetImpl rowSet;
try { Class.forName("com.mysql.cj.jdbc.Driver");
}
catch(ClassNotFoundException e){
System.out.println(""+e);
}
try{
con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/cj?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8", "root", "root");
sql = con.createStatement();
rs = sql.executeQuery("SELECT * FROM cjb");
rowSet = new CachedRowSetImpl(); //创建一个CachedRowSetImpl对象
rowSet.populate(rs); //
con.close(); //现在就可以关闭连接了
while(rowSet.next()){
String number=rowSet.getString(1);
String name=rowSet.getString(2);
Date birth=rowSet.getDate(3);
double height=rowSet.getDouble(4);
System.out.println(number+","+name+","+birth+","+height);
}
}
catch(SQLException e){
System.out.println(e);
}
}
}
5. PreparedStatement 类
执行sql语句时,数据库中的sql解释器把sql语句生成底层的内部命令,然后执行该命令。当执行的sql语句较多时,会增加sql解释器的负担,影响速度。同时Statement对象执行sql存在SQL注入问题
使用Connection连接对象con调用方法,返回一个生成数据库底层内部命令的预处理对象pre,通过对sql语句进行预编译处理,提前生成数据库底层的内部命令,加快速度,防止SQL注入
PreparedStatement pre=con.prepareStatement("sql语句")
手动给参数赋值
预处理对象调用方法
ResultSet executeQuery()
int executeUpdate()
boolean execute()
例
package Test;
import java.sql.*;
public class work{
public static void main(String[] args) throws SQLException {
Connection con;
PreparedStatement pre;
ResultSet rs;
try { Class.forName("com.mysql.cj.jdbc.Driver");
}
catch(ClassNotFoundException e){
System.out.println(""+e);
}
try {
con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/cj?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8", "root", "root");
// 使用 ? 占位符代替参数
String sql = "insert into users(id,`name`) values(?,?)";
// 预编译sql
pre = con.prepareStatement(sql);
// 手动给参数赋值
pre.setInt(1,3);
pre.setString(2,"laowang");
// 执行
rs = pre.executeUpdate();
rs.close();
sql.close();
con.close();
}
catch(SQLException e){
System.out.println(e);
}
}
}
使用预处理语句时可在语句中使用通配符?
代替字段的值,但需要在预处理语句执行之前再设置通配符所表示的具体值
prepareStatement pre=con.prepareStatement
("SELECT * FROM message where height<?")
pre.setDouble(1,1.72);
rs=pre.executeQuery();
// 类似方法:setInt 、setLong 、setFloat 、setString 、setDate
6. 事务
事务由一组SQL语句组成,指应用程序保证事务中的SQL语句要么全部都执行,要么一个都不执行。
将connection对象设置非自动提交。con产生的Statement对数据库提交的任何sql语句都是立即生效的,实际应用时,需要多条sql语句同时执行生效或同时不执行。这时用到如下方法,设置connection对象为非自动提交
con.setAutoCommit(false);
在SQL语句组后使用commit()方法
提交的多个sql语句不会被执行,这些sql语句构成了一个事务。直到调用commit()方法,让事务中的sql语句全部生效
con.commit()
提交失败(异常)使用rollback()方法回滚
catch(SQLException e){
try{ con.rollback();
}
catch(SQLException exp){}
System.out.println(e);
}
例
package Test;
import java.sql.*;
public class work{
public static void main(String args[]){
Connection con=null;
Statement sql;
ResultSet rs;
try { Class.forName("com.mysql.cj.jdbc.Driver");
}
catch(ClassNotFoundException e){
System.out.println(""+e);
}
try{ double n=50;
con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/cj?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8", "root", "root");
con.setAutoCommit(false);
sql=con.createStatement();
rs=sql.executeQuery("SELECT * FROM user WHERE number='0001'");
rs.next();
double moneyOne=rs.getDouble("userMoney");
moneyOne=moneyOne-n;
rs=sql.executeQuery("SELECT * FROM user WHERE number='0002'");
rs.next();
double moneyTwo=rs.getDouble("userMoney");
moneyTwo=moneyTwo+n;
sql.executeUpdate("UPDATE user SET userMoney ="+moneyOne+" WHERE number='0001'");
sql.executeUpdate("UPDATE user SET userMoney="+moneyTwo+"WHERE number='0002'");
con.commit();
con.close();
}
catch(SQLException e){
try{ con.rollback();
}
catch(SQLException exp){}
System.out.println(e);
}
}
}
7. 数据库连接池
池化技术:准备一些预先的资源,过来就使用预先准备好的,用完再放回池中
编写连接池,实现一个接口 DataSource
DBCP
C3P0
Druid 阿里巴巴
HikariCP springboot2.x默认