【JavaSE】JDBC详解优化(21)

引言

🐍因为之前学过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返回的对象

executeexecuteUpdate

  • 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的话,会凉得~;
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200727230721643.png
(现在可能已经修复了),所以使用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();
        }

    }

}

在这里插入图片描述在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

高冷小伙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值