引言
🐍因为之前学过Mysql的内容(虽然只记得基本操作了),所以就直接开始学JDBC吧;
🐍距离开学还有34天,我还是没有准备好;
知识点总结
JDBC
概念
JDBC(Java Databae Connectivity)是Java与数据库之间的一个桥梁;是一个规范而不是一个实现,按照JDBC的规范使用定义的接口和类来执行Sql语句,从而实现对操作数据库的操作;
实现步骤
1.导入jar包
(Github下载即可)注意分清楚名字mysql-connector-java-5.1.36-bin.jar;
2.注册驱动
3.获取数据库连接对象
4.定义sql语句
5.获取执行SQL语句的对象(Statement)
6.执行sql语句,接受返回结果(execute)
7.处理结果
8.释放资源
下面是一个完整的JDBC操作步骤;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Collections;
public class demo01 {
/**
* 1.导入驱动jar包
* 2.注册驱动
* 2.获取数据库连接对象
* @param args
*/
public static void main(String[] args) {
Connection ctr=null;
Statement str=null;
try{
Class.forName("com.mysql.jdbc.Driver");
//1.注册驱动
ctr= DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo","root","admin");
//2.获取数据库连接对象
String sql="INSERT INTO `Student` (`name`, `Grade`) VALUES ('高弟弟', '235')";
//3.定义sql语句
str=ctr.createStatement();
//4.获取sql操作对象
boolean bok=str.execute(sql);
System.out.println(bok);
//5.执行sql,返回结果
}catch (Exception e){
e.printStackTrace();
}
finally {
//释放资源
if(ctr!=null){
try {
str.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(str!=null){
try {
str.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
}
步骤分析
注册驱动
Class.forName("com.mysql.jdbc.Driver");
这是mysql的固定格式,在mysql-connector-java的5版本之后可以不写,因为包中会在没有驱动的时候自动生成;
获取数据库连接
Connection ctr= DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo","root","admin");
参数由三部分组成:
url: jdbc:mysql://ip地址:端口号/数据库名
;
name: mysql用户名;
**password:**用户密码;
数据库连接对象
Connection的功能主要有两个。一是获取执行sql的对象(Statement);二是管理事务(后面再详说);
String sql1="INSERT INTO `Student` (`name`, `Grade`) VALUES ('高弟弟', '235')";
Statement st=ctr.createStatement();
str=ctr.createStatement();
====================================
String sql2="INSERT INTO `Student` (`name`, `Grade`) VALUES (?, ?)";
PreparedStatement pst=ctr.prepareStatement(sql2);
pst.setString(1,"高哥哥");
pst.setDouble(2,23.4);
PrepardStatement的特性
1.prepareStatement(sql);在构造对象时就需要传递SQL语句;
2.使用PreparedStatement在需要拼接字符串时可以非常简便的完成,因为它可以用“ ?”来充当占位符,用set*()方法来赋值;
3.使用“ ?”占位符可以有效防止sql注入的攻击;(在下面的登录案例中会解释sql注入);
4.具有预编译机制,性能由于Statement;
获取处理sql返回的对象
execute与executeUpdate
- execute可以执行查询操作,返回ResultSet结果;executeUpdate只能执行增。删,改等,不能执行查询操作;
- execute返回值为boolean类型,true表示查询操作,false表示其他;executeUpdate返回int型,表示操作了多少条数据;
ResultSet结果封装为对象
在执行查询语句之后,会返回ResultSet对象,其中封装的是我们所需要的数据,那么我们可以创建一个与数据表相匹配的对象来封装这些数据;
public class Demo02 {
public static void main(String[] args) {
List<Student> als= new Demo02().FindAll();
}
/**
*
* @return
*/
public List<Student> FindAll(){
List<Student> list=new ArrayList<>();
Statement st=null;
Connection ct=null;
ResultSet rt=null;
try{
Class.forName("com.mysql.jdbc.Driver");
ct= DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo","root","admin");
st=ct.createStatement();
String sql="select * from Student";
rt=st.executeQuery(sql);
Student stu=new Student();
int i=0;
while(rt.next()){
// .next()方法判断是否存在下一条语句,防止空指针异常
double Grade=rt.getDouble(3);
int id=rt.getInt(2);
String name=rt.getString("name");
stu.setId(id);
stu.setName(name);
stu.getGrade(Grade);
list.add(stu);
System.out.println(list.get(i++).toString());
}
}catch (Exception e){
e.printStackTrace();
}
finally {
if(st!=null){
try {
st.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(rt!=null){
try {
rt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(ct!=null){
try {
ct.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
return list;
}
}
其中Student类如下
package libs;
public class Student {
private String name;
private int id;
private double Grade;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", id=" + id +
", Grade=" + Grade +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getGrade(double grade) {
return Grade;
}
public void setGrade(double grade) {
Grade = grade;
}
}
释放资源
一般我们放在try/catch的finally中,保证资源能释放;同时也要判断是否为空,防止空指针异常;
if(st!=null){
try {
st.close();
//关闭Statement对象
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(rt!=null){
try {
rt.close();
//关闭ResultSet
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(ct!=null){
try {
ct.close();
//关闭Connection
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
工具类
我们在上面的代码中不难发现,连接,关闭资源等代码冗长且重复;为解决这一问题,我们自己来写个工具类;
功能分析
1.加载驱动
2.获取连接对象(url,name,password)
3.释放资源
我理解的工具类应尽可能简洁易操作,所以没必要用配置文件,以及关闭操作只需要一个就好
代码实现
package util;
import java.sql.*;
public class DBUtil {
/**
* 连接数据库的操作,用户名,密码,使用jdbc连接
*/
public static String username = "root";
public static String password = "123456";
public static String url = "jdbc:mysql://localhost:3306/booksystem";
static{
try {
Class.forName("com.mysql.jdbc.Driver");
} catch(ClassNotFoundException e){
e.printStackTrace();
}
}
public static Connection getConnectDb(){
Connection conn = null;
try{
conn = DriverManager.getConnection(url,username,password);
} catch (SQLException e){
e.printStackTrace();
}
return conn;
}
public static void CloseDB(ResultSet rs, PreparedStatement stm, Connection conn){
if(rs!=null)
{
try {
rs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(stm!=null)
{
try {
stm.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(conn!=null)
{
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
登录案例
功能分析
用户在控制台输入信息,与数据库中信息进行匹配,符合则登录成功,否则默认自动注册;
import utils.JDBCUtils;
import java.sql.*;
import java.util.Scanner;
public class demo05 {
/**
* 一个登录案例,判断用户是否存在&密码正确
* @param args
*/
public static void main(String[] args) throws SQLException {
Scanner sc=new Scanner(System.in);
System.out.println("请输入账号(如果不存在将默认注册)");
String username=sc.next();
System.out.println("请输入密码");
String password=sc.next();
boolean judge=new demo05().login(username,password);
if(judge) System.out.println("登录成功");
else {
System.out.println("登录失败");
boolean jd=new demo05().Register(username,password);
if (jd) System.out.println("已帮您成功注册");
else System.out.println("注册失败");
}
}
public boolean login(String username,String password) throws SQLException {
Connection ct= JDBCUtils.getConnection();
String sql="select * from Customer where username= ? and password= ? ;";
PreparedStatement pst=ct.prepareStatement(sql);
pst.setString(1,username);
pst.setString(2,password);
ResultSet rs=pst.executeQuery();
if (rs.next()==false)
return false;
return true;
}
public boolean Register(String username,String password) throws SQLException {
Connection ct= JDBCUtils.getConnection();
String sql="INSERT INTO `Customer` (`username`, `password`) VALUES (?, ?)";
PreparedStatement pst=ct.prepareStatement(sql);
pst.setString(1,username);
pst.setString(2,password);
int answer=pst.executeUpdate();
if(answer!=0)
return true;
return false;
}
}
测试输出
sql注入
如果在实际开发中用Statement的话,会凉得~;
(现在可能已经修复了),所以使用PreparedStatement更保险;
事务
数据库事务(Transaction)是由若干个SQL语句构成的一个操作序列,有点类似于Java的synchronized同步。数据库系统保证在一个事务中的所有SQL要么全部执行成功,要么全部不执行;JDBC的事务也一样,要么所有sql语句都执行,要么都不执行;
1.开启事务
void setAutoCommit(fasle)默认是自动提交
将此连接的自动提交模式设置为给定状态。
2.提交事务
void commit()
使自上次提交/回滚以来所做的所有更改都将永久性,并释放此 Connection对象当前持有的任何数据库锁。
3.回滚事务
void rollback()
撤消在当前事务中所做的所有更改,并释放此 Connection对象当前持有的任何数据库锁。
银行转账案例(使用JDBCUtils工具类)
import utils.JDBCUtils;
import java.sql.*;
import java.util.Collection;
import java.util.Collections;
public class Demo07 {
/**
* 高弟弟向高妹妹打500块钱
* @param args
*/
public static void main(String[] args) {
Connection ct=null;
try {
ct= JDBCUtils.getConnection();
ct.setAutoCommit(false);
//1.开启事务
String sql1="UPDATE `Bank` SET `Balance`=Balance- ? WHERE (`name`=?)";
String sql2="UPDATE `Bank` SET `Balance`=Balance+ ? WHERE (`name`=?)";
PreparedStatement pst1=ct.prepareStatement(sql1);
pst1.setDouble(1,500);
pst1.setString(2,"高弟弟");
PreparedStatement pst2=ct.prepareStatement(sql2);
pst2.setDouble(1,500);
//int i=3/0;
//如果没有事务的话,中间出了异常,钱就没了~~~
pst2.setString(2,"高妹妹");
pst1.execute();
pst2.execute();
//2.提交事务
ct.commit();
JDBCUtils.CloseConnection2(pst1,ct);
pst2.close();
} catch (Exception throwables) {
try {
ct.rollback();
//回滚事务
} catch (SQLException e) {
e.printStackTrace();
}
throwables.printStackTrace();
}
}
}