JDBC-Java DateBase Connectivity(Java 数据库连接)
-
概念:Java语言操作数据库
- JDBC本质:是官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包 。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中实现的类
-
快速入门:
-
步骤:
- 导入驱动jar包 mysql-connector-java-8.0.26.jar
- 复制mysql-connector-java-8.0.26.jar到项目的libs目录下
- 右键–>Add as Library
- 注册驱动
- 获取数据库连接对象 Connection
- 定义sql
- 获取执行sql语句的对象 Statement
- 执行sql,接受返回结果
- 处理结果
- 释放资源
//1. 导入驱动jar包 //2. 注册驱动 Class.forName("com.mysql.cj.jdbc.Driver"); //3. 获取数据库连接对象 Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1", "root", "qin"); //4. 定义sql语句 String sql="update emp set salary = 1 where dept_id=1"; //5. 获取执行sql的对象 Statement Statement stmt =con.createStatement(); //6. 执行sql int c=stmt.executeUpdate(sql); //7. 执行结果 System.out.println(c); //8. 释放资源 stmt.close(); con.close();
- 导入驱动jar包 mysql-connector-java-8.0.26.jar
-
-
详解各个对象
-
DriverManager对象:驱动管理对象
-
功能:
-
注册驱动:告诉程序该使用哪一个数据库驱动jar
static void registerDriver(Driver driver):注册与给定的驱动程序DriverManager;
写代码使用:Class.forName(“com.mysql.cj.jdbc.Driver”);ctrl+n:直接跳到相应的类
通过查看源码发现:在com.mysql.cj.jdbc.Driver类中存在静态代码块
static { try { DriverManager.registerDriver(new Driver());//注册驱动 } catch (SQLException var1) { throw new RuntimeException("Can't register driver!"); } }
注意:mysql5之后的驱动jar包可以省略注册驱动的步骤。
-
获取数据库连接:
- 方法:static Connection getConnection(Strng url, String user, String password);
- 参数:
- url:指定连接的路径
- 语法:jdbc:mysql://ip地址(域名):端口号/数据库名称
- 例子:jdbc:mysql://localhost:3306/db1
- 细节:如果连接的是本机的mysql服务器,并且mysql服务默认的端口是3306,则url可以简写为:jdbc:mysql:///数据库名称
- user:用户名
- password:密码
- url:指定连接的路径
-
-
-
Connection对象:数据库连接对象
- 功能:
- 获取执行mysql的对象
- Statement createStatement()
- PreparedStatement prepareStatement(String sql)
- 管理事务:
- 开启事务:void setAutoCommit(boolean autoCommit):调用该方法设置参数为false,即开启事务
- 提交事务:commit()
- 回滚事务:rollback()
- 获取执行mysql的对象
- 功能:
-
Statement对象:执行sql的对象
-
执行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)语句
-
练习:
- 表 添加一条记录
- 表 修改记录
- 表 删除一条记录
Statement stm=null; Connection con =null; try { //1. 注册驱动 Class.forName("com.mysql.cj.jdbc.Driver"); //2. 定义sql String sql="insert into emp values(7,'王五','男',9999,'2001-08-08',2)"; //3. 获取Connection对象 con = DriverManager.getConnection("jdbc:mysql:///db1", "root", "qin"); //4. 获取执行sql的对象Statement stm = con.createStatement(); //5. 执行sql int account=stm.executeUpdate(sql);//影响的行数 //6. 处理结果 System.out.println(account); if (account>0){ System.out.println("添加成功!"); }else{ System.out.println("添加失败!"); } } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); }finally { //7. 释放资源 //避免空指针异常 if (stm != null){ try { stm.close(); } catch (SQLException e) { e.printStackTrace(); } } if (con != null){ try { con.close(); } catch (SQLException e) { e.printStackTrace(); } } }
-
-
ResultSet对象:结果集对象,封装查询结果的对象
-
boolean next():游标向下移动一行,返回boolean,判断当前行是否是最后一行末尾(是否有数据),如果是没有数据则返回false,否则是有数据返回true
-
getXxx(参数):获取数据
- Xxx:代表数据类型 如:int getInt();
- 参数:
- int:代表列的编号,从1开始的,如:getString(1)
- String:代表列的名称。如:getDouble(“balance”);
-
注意:
-
使用步骤:
- 游标向下移动一行
- 判断是否有数据
- 获取数据
// 循环获取 while(res.next()) { //2. 获取数据 int id = res.getInt(1); String name = res.getString("name1"); double salary = res.getDouble("salary"); System.out.println(id + "---" + name + "---" + salary); }
-
-
练习:
- 查询emp表的数据将其封装为对象,然后装载集合,返回。
- 定义Emp的类
- 定义方法 public List<Emp> findAll(){}
- 实现方法 select * from emp;
- 查询emp表的数据将其封装为对象,然后装载集合,返回。
-
-
PreparedStatement对象:执行sql的对象
- SQL注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接,会造成安全问题
- 输入用户随便,输入密码:a’ or ‘a’=‘a’
- sql:select * from user where username = ‘failjdd’ and password = ‘a’ or ‘a’=‘a’;
- 解决sql注入问题:使用PreparedStatement对象来解决
- 预编译的sql:参数使用”?“作为占位符
- 步骤:
- 导入驱动jar包
- 注册驱动
- 获取数据库连接对象 Connction
- 定义sql
- 注意:sql的参数使用?作为占位符。如:select * from user where username = ? and password = ?;
- 获取执行sql语句的对象 PreparedStatement Connection.prepareStatement(String sql)
- 给?赋值:
- 方法:setXxx(参数1(问号位置编号1从开始),参数2(问号值));
- 执行sql,接收返回结果,不需要传递sql语句
- 处理结果
- 释放资源
- 注意:后期都会使用PreparedStatement来完成增删改查的所有操作
- 可以防止SQL注入
- 效率高
- SQL注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接,会造成安全问题
-
例子:
package cn.itcast.jdbc;
import cn.itcast.util.JDBCUtils;
import java.sql.*;
import java.util.Scanner;
/**
* 需求:
* 1. 通过键盘录入用户名和密码
* 2. 判断用户是否登录成功
*/
public class JBDCDemo9 {
public static void main(String[] args) {
//1. 键盘录入,接收用户名和密码
Scanner r = new Scanner(System.in);
System.out.println("请输入用户名:");
String username = r.nextLine();
System.out.println("请输入密码:");
String password=r.nextLine();
//2. 调用方法
boolean f = new JBDCDemo9().login2(username, password);
//3. 判断结果,输出不同语句
System.out.println(username);
if (f){
//成功
System.out.println("登录成功!");
}else{
System.out.println("登录失败!");
}
}
/**
* 登录方法
* @return返回成功或者失败
*/
/*
public boolean login(String username,String password){
if (username==null||password==null){
return false;
}
//连接数据库,判断是否登录成功
Connection con=null;
Statement stmt=null;
ResultSet resultSet=null;
//1. 获取连接
try {
con= JDBCUtils.getConnection();
//2. 定义sql
String sql="select * from user where username = '"+username+"' and password = '"+password+"'";
//3.获取执行sql的对象
stmt=con.createStatement();
//4. 执行查询
resultSet = stmt.executeQuery(sql);
//5. 判断结果集是否有数据
// if (resultSet.next()){//如果有下一行
// return true;
// }else{
// return false;
// }
return resultSet.next();
} catch (SQLException e) {
e.printStackTrace();
}finally {
JDBCUtils.close(resultSet,stmt,con);
}
return true;
}
*/
/**
* 登录方法,使用PreparedStatement实现
* @return返回成功或者失败
*/
public boolean login2(String username,String password){
if (username==null||password==null){
return false;
}
//连接数据库,判断是否登录成功
Connection con=null;
PreparedStatement preparedStatement=null;
ResultSet resultSet=null;
//1. 获取连接
try {
con= JDBCUtils.getConnection();
//2. 定义sql
String sql="select * from user where username = ? and password = ?";
//3.获取执行sql的对象
preparedStatement = con.prepareStatement(sql);
//给?问号赋值
preparedStatement.setString(1,username);
preparedStatement.setString(2,password);
//4. 执行查询,不需要传递sql
resultSet = preparedStatement.executeQuery();
//5. 判断结果集是否有数据
// if (resultSet.next()){//如果有下一行
// return true;
// }else{
// return false;
// }
return resultSet.next();
} catch (SQLException e) {
e.printStackTrace();
}finally {
JDBCUtils.close(resultSet,preparedStatement,con);
}
return true;
}
}
抽取JDBC工具类:JDBCUtils
-
目的:简化书写
-
分析:
-
注册驱动也抽取
-
抽取一个方法获取连接对象
-
需求:不想传递参数(麻烦),还得保证工具类的通用性。
-
解决方案:配置文件(配置文件一定要在src下面,不能套一层文件夹!!!血流量教训)
jdbc.properties
url=
user=
password=
-
-
抽取一个方法释放资源
-
-
代码实现:
package cn.itcast.util;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.sql.*;
import java.util.Properties;
/** * JDBC工具类 */
public class JDBCUtils {
private static String url;
private static String user;
private static String password;
private static String driver1;
static{
//读取资源文件,获取值
try {
//1. 创建Properties集合类
Properties pro = new Properties();
//获取src路径下的文件的方式--->ClassLoader类加载器
ClassLoader classLoader=JDBCUtils.class.getClassLoader();
URL re = classLoader.getResource("jdbc.properties");
String path = re.getPath();
System.out.println(path);
//2. 加载文件
pro.load(new FileInputStream(path));
// pro.load(JDBCUtils.class.getResourceAsStream("/jdbc.properties"));
//3. 获取数据
url=pro.getProperty("url");
user=pro.getProperty("user");
password=pro.getProperty("password");
driver1 = pro.getProperty("driver");
//4. 注册驱动
Class.forName(driver1);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,user,password);
}
/** * 释放资源 */
public static void close(ResultSet res,Statement stmt, Connection con){
if (stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (con!=null){
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (res!=null){
try {
res.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void close(Statement stmt, Connection con){
if (stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (con!=null){
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
-
练习:
-
需求:
- 通过键盘录入用户名和密码
- 判断用户是否登录成功
- select * from user where username = “” and password = “”;
- 如果这个sql有查询结果则成功,否则失败
-
步骤:
-
创建数据库表 user
CREATE TABLE USER( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(32), PASSWORD VARCHAR(32) ); SELECT * FROM USER; INSERT INTO USER VALUES(NULL,'zhnagsan','123'); INSERT INTO USER VALUES(NULL,'lisi','234');
-
-
JDBC控制事务
- 事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。
- 操作
- 开启事务
- 提交事务
- 回滚事务
- 使用Connction对象来管理事务
- 开启事务:setAutoCommit(boolean autoCommit):调用该方法设置参数为false,即开启事务
- 在执行sql之前开启事务
- 提交事务:commit()
- 当所有sql都执行完提交事务
- 回滚事务:rollback()
- 在catch中回滚事务
- 开启事务:setAutoCommit(boolean autoCommit):调用该方法设置参数为false,即开启事务