文章目录
一、数据库基础
单靠客户端或者服务器管理这些数据是不可能的,所以就出现了数据库的概念
将所有数据都放在数据库中保存,程序需要什么样的数据,直接让数据库提供相关的数据就可以了
程序把管理数据的功能分离了出去,既可以减轻程序的负荷,又能减少程序所占的硬盘大小,这是一个非常好的开发模式
二、JDBC简介
JDBC技术是数据库与java应用程序间的纽带***
程序用java代码写,而程序产生的数据往往存在了数据库这一端,两个分离的程序需要一个连接的桥梁,这个桥梁就是JDBC技术
JDBC可以将程序需要执行的SQL语句传递给数据库,也可以将数据库查到的结果传递给程序*(但JDBC并不能直接访问数据库,必须依赖于数据库厂商提供的驱动程序)
每一种数据库都有独立的驱动jar包,这就使得JDBC连接数据库的底层机制都不一样,但JDBC提供给程序的接口是保持不变的
DriverManager类:每种数据库的驱动都不一样,我们需要在这里指定数据库的驱动类型,并配置好要连接的数据库地址和账号密码
因为连接数据库涉及到了数据流的操作,所以在使用完这些连接之后要及时关闭,顺序是从下往上依次关闭
三、链接数据库
**注意:**在运行这行代码时,必须要保证驱动包已经导入进来了。(若没有导入驱动包而直接加载驱动的话,它会报出一个类找不到的异常)
通过DriverManager.getConnection()方法获得数据库的连接对象(第一个参数是数据库的URL,后面是数据库的账号密码),这样就创建了一个Connection对象
package c11;
import java.sql.*;
public class L11_01_DBUtils {
// 数据库驱动程序
private static String DRIVERCLASS = "com.mysql.cj.jdbc.Driver";
// 连接数据的URL
private static String URL = "jdbc:mysql://localhost:3306/test";
// 连接数据库的用户名和密码
private static String USERNAME = "root";
private static String PASSWORD = "123456";
/**
* 获取数据库连接对象
*
* @throws SQLException
*/
public Connection getConnection() throws ClassNotFoundException, SQLException {
// 加载驱动程序
Class.forName(DRIVERCLASS);
// 建立与MySQL数据库的连接
Connection conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
return conn;
}
/**
* 关闭连接对象,释放资源
*/
public void close(ResultSet rs, Statement stmt, Connection conn) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
L11_01_DBUtils dbUtils = new L11_01_DBUtils();
Connection conn = null;
try {
conn = dbUtils.getConnection();
System.out.println("数据库连接成功-" + conn);
} catch (ClassNotFoundException e) {
System.out.println("数据库连接失败-" + e.getMessage());
} catch (SQLException e) {
System.out.println("数据库连接失败-" + e.getMessage());
} finally {
dbUtils.close(null, null, conn);
}
}
}
四、数据库查询
Connection对象提供了一个程序到数据库的连接
查询数据库内容:创建Statement接口对象
ResultSet接口:将数据库返回的结果放入结果集中
创建接口对象
ResultSet接口常用方法
ResultSet结果集有个特点:指针(最开始没有指向任何一个位置)
我们获取到一行数据之后,需要将一行里的数据拆分开(ResultSet有多种返回类型,每一种方法都有两种重载方式,也就是两种参数)
其中,列数必须是大于等于1的正整数
finally代码块中:从后往前关闭数据流
package query;
import java.sql.*;
public class Query {
// 数据库驱动程序
private static String DRIVERCLASS = "com.mysql.cj.jdbc.Driver";
// 连接数据的URL
private static String URL = "jdbc:mysql://localhost:3306/test";
// 连接数据库的用户名和密码
private static String USERNAME = "root";
private static String PASSWORD = "123456";
/**
* 获取数据库连接对象
*
* @throws SQLException
*/
public Connection getConnection() throws ClassNotFoundException, SQLException {
// 加载驱动程序
Class.forName(DRIVERCLASS);
// 建立与MySQL数据库的连接
Connection conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
return conn;
}
/**
* 关闭连接对象,释放资源
*/
public void close(ResultSet rs, Statement stmt, Connection conn) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Query qry = new Query();
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = qry.getConnection();
stmt = conn.createStatement(); //创建Statement对象
rs = stmt.executeQuery("select * from user"); //注意:可以不写分号
while(rs.next()) { //下一行数据
int id = rs.getInt("id"); //获取id这一列的值
String name = rs.getString(2); //获取第二列的值
String phone = rs.getString("phone");
String email = rs.getString(4);
System.out.println("编号=" + id + " 姓名=" + name + " 电话=" + phone + " 邮箱=" + email);
}
// System.out.println("数据库连接成功-" + conn);
} catch (ClassNotFoundException e) {
System.out.println("数据库连接失败-" + e.getMessage());
} catch (SQLException e) {
System.out.println("数据库连接失败-" + e.getMessage());
} finally {
qry.close(rs, stmt, conn);
}
}
}
五、添加、修改和删除数据
添加、修改和删除数据用到的都是一个方法:executeUpdate()
用statement接口执行插入、修改、删除这三个sql:
package update;
import java.sql.*;
public class Update {
// 数据库驱动程序
private static String DRIVERCLASS = "com.mysql.cj.jdbc.Driver";
// 连接数据的URL
private static String URL = "jdbc:mysql://localhost:3306/test";
// 连接数据库的用户名和密码
private static String USERNAME = "root";
private static String PASSWORD = "123456";
/**
* 获取数据库连接对象
*
* @throws SQLException
*/
public Connection getConnection() throws ClassNotFoundException, SQLException {
// 加载驱动程序
Class.forName(DRIVERCLASS);
// 建立与MySQL数据库的连接
Connection conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
return conn;
}
/**
* 关闭连接对象,释放资源
*/
public void close(ResultSet rs, Statement stmt, Connection conn) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Update upd = new Update();
Connection conn = null;
Statement stmt = null;
try {
conn = upd.getConnection();
stmt = conn.createStatement(); //创建Statement对象
//插入数据
String sql1 = "insert into user(name, phone, email) values('tom', '123456', 'vrf@42few.com')";
int result1 = stmt.executeUpdate(sql1);
System.out.println("有" + result1 + "行记录被修改");
//修改数据
String sql2 = "update user set phone = '999999' where name = 'tom'";
int result2 = stmt.executeUpdate(sql2);
System.out.println("有" + result2 + "行记录被修改");
//删除数据
String sql3 = "delete from user where name = 'tom'";
int result3 = stmt.executeUpdate(sql3);
System.out.println("有" + result3 + "行记录被修改");
// System.out.println("数据库连接成功-" + conn);
} catch (ClassNotFoundException e) {
System.out.println("数据库连接失败-" + e.getMessage());
} catch (SQLException e) {
System.out.println("数据库连接失败-" + e.getMessage());
} finally {
upd.close(null, stmt, conn);
}
}
}
六、批处理
一次运行很多条sql语句,用之前讲过的方法:
先创建Statement接口,然后调用它的executeUpdate()方法,执行第一句sql后关闭;然后再创建一个Statement对象,执行第二个sql,执行完关闭…直到将所有sql都运行完
代码量太大
所以Statement提供了批量操作的功能:
package batch;
import java.sql.*;
public class Batch {
// 数据库驱动程序
private static String DRIVERCLASS = "com.mysql.cj.jdbc.Driver";
// 连接数据的URL
private static String URL = "jdbc:mysql://localhost:3306/test";
// 连接数据库的用户名和密码
private static String USERNAME = "root";
private static String PASSWORD = "123456";
/**
* 获取数据库连接对象
*
* @throws SQLException
*/
public Connection getConnection() throws ClassNotFoundException, SQLException {
// 加载驱动程序
Class.forName(DRIVERCLASS);
// 建立与MySQL数据库的连接
Connection conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
return conn;
}
/**
* 关闭连接对象,释放资源
*/
public void close(ResultSet rs, Statement stmt, Connection conn) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Batch bat = new Batch();
Connection conn = null;
Statement stmt = null;
try {
conn = bat.getConnection();
stmt = conn.createStatement();
stmt.addBatch("insert into user(name, phone, email) values('阿呆', '4532435', 'we@34f.com')");
stmt.addBatch("insert into user(name, phone, email) values('翠花', '9348235', 'nuy@43df.com')");
stmt.addBatch("insert into user(name, phone, email) values('二蛋', '4598871', 'jij@879hu.com')");
int results[] = stmt.executeBatch();
for(int result: results) {
System.out.println("影响的行数为:" + result);
}
// System.out.println("数据库连接成功-" + conn);
} catch (ClassNotFoundException e) {
System.out.println("数据库连接失败-" + e.getMessage());
} catch (SQLException e) {
System.out.println("数据库连接失败-" + e.getMessage());
} finally {
bat.close(null, stmt, conn);
}
}
}
我们调用了executeBatch()方法,执行列表中的sql,一次性执行这样能大大提高执行效率
七、动态查询
系统安全漏洞:sql注入
为了防止这种sql注入,JDBC提供了一种简单并实用的功能:动态查询
sql中有一个问号,这个问号叫做通配符:起占位作用(因为是动态查询,也就是说在查询之前,这句sql到底要查什么,谁都不知道)
PreparedStatement提供了很多方法,它可以给通配符赋值。
这种动态查询的效果有效避免了sql注入的问题
package dynamic_query;
import java.sql.*;
public class Dy_query {
// 数据库驱动程序
private static String DRIVERCLASS = "com.mysql.cj.jdbc.Driver";
// 连接数据的URL
private static String URL = "jdbc:mysql://localhost:3306/test";
// 连接数据库的用户名和密码
private static String USERNAME = "root";
private static String PASSWORD = "123456";
/**
* 获取数据库连接对象
*
* @throws SQLException
*/
public Connection getConnection() throws ClassNotFoundException, SQLException {
// 加载驱动程序
Class.forName(DRIVERCLASS);
// 建立与MySQL数据库的连接
Connection conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
return conn;
}
/**
* 关闭连接对象,释放资源
*/
public void close(ResultSet rs, Statement stmt, Connection conn) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Dy_query dquery = new Dy_query();
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = dquery.getConnection();
String sql = "select * from user where name = ? or phone = ?";
ps = conn.prepareStatement(sql);
ps.setString(1, "阿呆");
ps.setString(2, "3478345");
rs = ps.executeQuery();
System.out.println("id\tname\tphone\temail");
while(rs.next()) {
System.out.println(rs.getInt(1) + "\t" + rs.getString(2) + "\t" + rs.getString(3) + "\t" + rs.getString(4));
}
// System.out.println("数据库连接成功-" + conn);
} catch (ClassNotFoundException e) {
System.out.println("数据库连接失败-" + e.getMessage());
} catch (SQLException e) {
System.out.println("数据库连接失败-" + e.getMessage());
} finally {
dquery.close(rs, ps, conn);
}
}
}
String sql = "select * from user where name like ? and phone = ?";
ps = conn.prepareStatement(sql);
ps.setString(1, "二%");
ps.setString(2, "4598871");
rs = ps.executeQuery();
System.out.println("id\tname\tphone\temail");
while(rs.next()) {
System.out.println(rs.getInt(1) + "\t" + rs.getString(2) + "\t" + rs.getString(3) + "\t" + rs.getString(4));
}
给动态sql赋完值后,去创建结果集对象
注意:它和Statement不一样,因为它创建对象时调用的这个方法是con.prepareStatement()【并且它返回结果集的时候没有参数,因为它创建对象时就要指定sql】;而Statement创建对象时调用con.createStatement()
八、调用存储过程
用java程序去调用数据库中的存储过程
package call_stored_procedure;
import java.sql.*;
public class Calling_Stored_Procedure {
// 数据库驱动程序
private static String DRIVERCLASS = "com.mysql.cj.jdbc.Driver";
// 连接数据的URL
private static String URL = "jdbc:mysql://localhost:3306/test";
// 连接数据库的用户名和密码
private static String USERNAME = "root";
private static String PASSWORD = "123456";
/**
* 获取数据库连接对象
*
* @throws SQLException
*/
public Connection getConnection() throws ClassNotFoundException, SQLException {
// 加载驱动程序
Class.forName(DRIVERCLASS);
// 建立与MySQL数据库的连接
Connection conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
return conn;
}
/**
* 关闭连接对象,释放资源
*/
public void close(ResultSet rs, Statement stmt, Connection conn) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Calling_Stored_Procedure call_sp = new Calling_Stored_Procedure();
Connection conn = null;
CallableStatement call = null;
ResultSet rs = null;
try {
conn = call_sp.getConnection();
call = conn.prepareCall("{call dd(?)}");
call.setInt(1,4);
rs = call.executeQuery();
System.out.println("name");
while(rs.next()) {
System.out.println(rs.getString(1));
}
// System.out.println("数据库连接成功-" + conn);
} catch (ClassNotFoundException e) {
System.out.println("数据库连接失败-" + e.getMessage());
} catch (SQLException e) {
System.out.println("数据库连接失败-" + e.getMessage());
} finally {
call_sp.close(rs, call, conn);
}
}
}