JavaEE Day05 JDBC(用Java语言操作数据库)
阅读原文时间:2023年07月08日阅读:1

今日内容

  • 基本概念
  • 快速入门
  • 对JDBC中各个接口和类的详解

一、基本概念

1.概念:Java Database Connectivity:Java数据库连接,Java语言操作数据库

2.本质:官方(Sun)定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商实现这套接口,提供数据库驱动jar包,我们可以使用这套接口(JDBC)编程,真正执行的代码是jar包中的实现类

即:JDBC是接口,真正执行的是jar包中的实现类

SUN公司写的代码,定义了一套操作所有关系型数据库的规则(接口),没有定义实现类,实现类由不同数据库厂商写出对应数据库的实现类(数据库驱动),不同实现类可以操作自己的数据库。

                                                                                            以接口类型调用方法,真正执行的是实现方法

例如 interface Person              class Worker                     Person p=new Work();             p.eat();多态调用

3.快速入门

  • 步骤【创建空项目project,新建模块module,模块module就放到了项目下】

  • 导入驱动jar包mysql-con__nector-java-5.1.37-bin.jar

  • 复制mysql-connector-java-5.1.37-bin.jar到项目的libs目录下

  • 右键-->add as library

jar包内是一些已经编译好的class字节码文件

src是开源的源码文件

  • 注册驱动

  • 获取数据库的连接对象Connection(java和数据库的桥梁对象)

  • 定义SQL语句

  • 获取执行SQL语句的对象Statement

  • 执行SQL,接收返回的结果

  • 处理结果

  • 释放资源,不释放容易造成内存的泄露问题

  • 使用

  • 创建一个_项目_Project---itcast

  • 在项目的project structure创建一个新module---day04_jdbc

    package cn.itcast.jdbc;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.Statement;
    /**

    • JDBC快速入门
      */
      public class JdbcDemo1 {
      public static void main(String[] args) throws Exception{
      //1.导入驱动jar包mysql-connector-java-5.1.37-bin.jar
      //创建libs文件夹便于管理
      //复制后右键,add as library
      //2.注册驱动
      Class.forName("com.mysql.jdbc.Driver");
      //3.获取数据库的连接对象
      Connection conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/db3","root","root");
      //4.定义一个SQL语句
      String sql="update account set balance = 500 where id=1";//sql语句后不用加分号
      //5.获取SQL的执行对象
      Statement stmt = conn.createStatement();
      //6.执行SQL
      int count = stmt.executeUpdate(sql);
      //7.处理结果,打印
      System.out.println(count);
      //8.释放资源
      stmt.close();
      conn.close();
      }
      }

二、各个对象的详解

常见对象

  • DriverManager--驱动管理对象

  • Connection--数据库连接对象

  • Statement--_执行_SQL的对象

  • ResultSet--结果集对象
  • PreparedStatement--预编译SQL对象

1.JDBC各个类详解_DriverManager_注册驱动

可以实现注_册驱动和获取数据库连接_

数据库驱动管理类的功能:

  • 注册驱动Class.forName("com.mysql.jdbc.Driver");

  • 代码是这么写的Class.forName("com.mysql.jdbc.Driver");把字节码文件加载进内存【这样简单,实际上还是用了DriverManager

  • 实际上DriverManager有注册驱动的方法   static void registerDriver(Driver driver) 使用 DriverManager注册给定的驱动程序。

  • 二者的区别:上者中有一些代码会随着类执行(静态代码块

  • 通过查看源码发现,在mom.mysql.jdbc.Driver中存在静态代码块:

    static {
    try {
    java.sql.DriverManager.registerDriver(new Driver());
    } catch (SQLException E) {
    throw new RuntimeException("Can't register driver!");
    }
    }

注意:

        在mysql5之后的驱动jar包,注册驱动的代码可以省略,注释Class.forName("com.mysql.jdbc.Driver");

MySQL5之后的驱动jar包可以省略注册驱动的步骤

  • 获取数据库连接 Connection conn= DriverManager.ge__tConnection("jdbc:mysql://localhost:3306/db3","root","root");

  • static Connection getConnection(String url, String user, String password) 尝试建立与给定数据库URL的连接。

  • url:指定连接的l路径

  • 语法:(MySQL)-jdbc:mysql:-//ip地址:端口/数据库名

  • 例子:jdbc:mysql://localhost:3306/db3

  • 细节:如果连接的是本机的MySQL服务器,并且默认端口是3306,则可以简写为jdbc:mysql///数据库名

    package cn.itcast.jdbc;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.Statement;
    public class Jdbc_demo1 {
    public static void main(String[] args) throws Exception{
    //1.导入驱动jar包mysql-connector-java-5.1.37-bin.jar
    //创建libs文件夹便于管理
    //复制后右键,add as library
    //2.注册驱动
    //Class.forName("com.mysql.jdbc.Driver");
    //3.获取数据库的连接对象
    Connection conn= DriverManager.getConnection("jdbc:mysql:///db3","root","root");
    //4.定义一个SQL语句
    String sql="update account set balance = 2000 where id=1";//sql语句后不用加分号
    //5.获取SQL的执行对象
    Statement stmt = conn.createStatement();
    //6.执行SQL
    int count = stmt.executeUpdate(sql);
    //7.处理结果,打印
    System.out.println(count);
    //8.释放资源
    stmt.close();
    conn.close();
    }
    }

2.JDBC各个类详解_Connection

可以获取_执行SQL的对象并可以实现事务的管理_

数据库和Java之间的桥梁

2.1功能

  • 获取执行SQL的对象_Statement stmt = conn._createStatement();

Statement createStatement() 创建一个 Statement对象,用于将SQL语句发送到数据库。  

PreparedStatement prepareStatement(String sql) 创建一个 PreparedStatement对象,用于将参数化的SQL语句发送到数据库。  

  • 管理事务

  • 事务:多个步骤的业务操作,要么同时成功,要么同时失败

  • 三个方法--开启事务:void setAutoCommit(boolean autoCommit) 调用此方法设置false,即开启事务并不自动提交

  • 三个方法--提交事务:void commit() 提交事务

  • 三个方法--回滚事务:void rollback() 回滚事务

3.JDBC各个类详解_Statement

执行SQL的对象

参数的值是给定的

3.1 常用的方法

  • boolean execute() 可以执行任意的SQL,了解
  • true如果第一个结果是一个ResultSet对象; false如果第一个结果是更新计数或没有结果
  • int executeUpdate() 可以执行DML(insert update delete对表中数据进行修改)语句、DDL(对表和库进行修改,create、alter、drop,不常用,dba用SQL设置好)语句
  • (1)SQL数据操作语言(DML)语句的行计数或(2)0不返回的SQL语句 
    如update account set balance =1000;//返回影响的行数
    可以通过影响的行数判断DML是否执行成功,如果大于0,则执行成功,反之则失败
  • ResultSet executeQuery(String sql) :执行DQL(select)语句,返回ResultSet
  • 先学习update增删改,再学习select

3.2 Statement--JDBC练习_insert语句执行增删改

之前代码不规范,释放资源应该放入finally内部,不管是否执行成功都要释放资源

练习

  • 为account表添加一条记录

    package cn.itcast.jdbc;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    import java.sql.Statement;
    /**

    • account表,添加一条记录 insert语句
      */
      public class Jdbc_demo2 {
      public static void main(String[] args){
      Statement stmt=null;
      Connection conn= null;
      try {
      //1.注册驱动
      Class.forName("com.mysql.jdbc.Driver");
      //定义sql语句
      String sql="insert into account values(null,'wangwu',3000)";
      //3.获取Connection对象
      conn = DriverManager.getConnection("jdbc:mysql:///db3", "root", "root");
      // 有异常 ,alt+enter
      //4.获取执行sql的对象 Statement
      stmt = conn.createStatement();
      //5.执行sql
      int count = stmt.executeUpdate(sql);//影响的行数
      //6.处理结果
      System.out.println(count);
      if (count>0){
      System.out.println("添加成功");
      }else
      System.out.println("添加失败");
      } catch (ClassNotFoundException e) {
      e.printStackTrace();
      } catch (SQLException e) {
      e.printStackTrace();
      }finally {
      //7.释放资源
      //先释放Statement对象,是由connection获取的
      //stmt.close();//作用域不同
      //为了避免空指针异常,判断是否为null
      if (stmt!= null){
      try {
      stmt.close();
      } catch (SQLException e) {
      e.printStackTrace();
      }
      }
      //释放conn
      if (conn!= null){
      try {
      conn.close();
      } catch (SQLException e) {
      e.printStackTrace();
      }
      }
      }

      }
      }

  • account表修改记录

    package cn.itcast.jdbc;

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    import java.sql.Statement;

    /**

    • account 表 修改记录
      */
      public class JDBC_Demo3 {
      public static void main(String[] args) {
      //修改王五的工资为1500
      Statement stmt=null;
      Connection conn=null;
      try {
      //1.注册驱动
      Class.forName("com.mysql.jdbc.Driver");
      //2.获取连接对象
      conn = DriverManager.getConnection("jdbc:mysql:///db3", "root", "root");
      //3.定义sql
      String sql="update account set balance=1500 where name='wangwu'";
      //4.获取执行sql的对象
      stmt = conn.createStatement();
      //5.执行sql
      int count = stmt.executeUpdate(sql);
      //6.处理结果
      System.out.println(count);
      if (count>0){
      System.out.println("修改成功");
      }else
      System.out.println("修改失败");
      } catch (ClassNotFoundException e) {
      e.printStackTrace();
      } catch (SQLException e) {
      e.printStackTrace();
      }finally {
      if (stmt!=null){
      try {
      stmt.close();
      } catch (SQLException e) {
      e.printStackTrace();
      }
      }
      if (conn!=null){
      try {
      conn.close();
      } catch (SQLException e) {
      e.printStackTrace();
      }
      }
      }
      }
      }
  • account表删除一条记录

    package cn.itcast.jdbc;

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    import java.sql.Statement;

    /**

    • 删除表中的记录
      */
      public class JDBCDemo4 {
      public static void main(String[] args) {
      //删除王五
      Statement stmt=null;
      Connection conn=null;
      try {
      //1.注册驱动
      Class.forName("com.mysql.jdbc.Driver");
      //2.获取连接对象
      conn = DriverManager.getConnection("jdbc:mysql:///db3", "root", "root");
      //3.定义sql
      String sql="delete from account where id=3";
      //4.获取执行sql的对象
      stmt = conn.createStatement();
      //5.执行sql
      int count = stmt.executeUpdate(sql);
      //6.处理结果
      System.out.println(count);
      if (count>0){
      System.out.println("删除成功");
      }else
      System.out.println("删除失败");
      } catch (ClassNotFoundException e) {
      e.printStackTrace();
      } catch (SQLException e) {
      e.printStackTrace();
      }finally {
      if (stmt!=null){
      try {
      stmt.close();
      } catch (SQLException e) {
      e.printStackTrace();
      }
      }
      if (conn!=null){
      try {
      conn.close();
      } catch (SQLException e) {
      e.printStackTrace();
      }
      }
      }
      }
      }

executeUpdate也可以执行DDL语句

package cn.itcast.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * 执行DDL语句
 */
public class JDBCDemo5 {
    public static void main(String[] args) {
        //删除王五
        Statement stmt=null;
        Connection conn=null;
        try {
            //1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2.获取连接对象
            conn = DriverManager.getConnection("jdbc:mysql:///db3", "root", "root");
            //3.定义sql
            String sql="create TABLE student(id INT, name VARCHAR(20))";
            //4.获取执行sql的对象
            stmt = conn.createStatement();
            //5.执行sql
            int count = stmt.executeUpdate(sql);
            //6.处理结果,DML返回结果,DDL不返回结果
            System.out.println(count);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            if (stmt!=null){
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn!=null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

DML会返回

DDL不会返回int值,只返回0

4.JDBC各个类详解_ResultSet

4.1 基本使用

State__ment可以执行两类方法

  • int executeUpdate() 可以执行DML(insert update delete对表中数据进行修改)语句、DDL(对表和库进行修改,create、alter、drop,不常用,dba用SQL设置好)语句

  • (1)SQL数据操作语言(DML)语句的行计数或(2)0不返回的SQL语句 
    如update account set balance =1000;//返回影响的行数
    可以通过影响的行数判断DML是否执行成功,如果大于0,则执行成功,反之则失败

  • ResultSet executeQuery(String sql) :执行DQL(select)语句,返回ResultSet

  • ResultSet是一个结果集对象,用于封装查询结果

  • 目的:从resultset中将结_果取出来_

  • 方法:通过游标,取每一行,需要两类方法

  • n__ex__t()_:游标向下移动一行_

  • 获取每一列getXXX()获取数据

  • XXX代表数据类型

  • 如:int getInt(XX) getString(XX)

  • 参数中的值为获取的第几列,两种参数构成了重载

  • int:代表列的编号  如getString(1)   id,从1开始

  • Sting:代表列名,如getString("balance")

    package cn.itcast.jdbc;

    import java.sql.*;

    /**

    • 执行DDL语句
      */
      public class JDBCDemo6 {
      public static void main(String[] args) {
      //删除王五
      Statement stmt=null;
      Connection conn=null;
      ResultSet rs=null;
      try {
      //1.注册驱动
      Class.forName("com.mysql.jdbc.Driver");
      //2.获取连接对象
      conn = DriverManager.getConnection("jdbc:mysql:///db3", "root", "root");
      //3.定义sql
      String sql="select * from account";
      //4.获取执行sql的对象
      stmt = conn.createStatement();
      //5.执行sql
      rs = stmt.executeQuery(sql);//资源需要关闭
      //6.处理结果
      // 6.1游标向下移动一行
      rs.next();
      //6.2 获取数据
      int id = rs.getInt(1);
      String name = rs.getString("name");
      double balance = rs.getDouble(3);
      System.out.println(id+"---"+name+"---"+balance);
      } catch (ClassNotFoundException e) {
      e.printStackTrace();
      } catch (SQLException e) {
      e.printStackTrace();
      }finally {
      if (stmt!=null){
      try {
      stmt.close();
      } catch (SQLException e) {
      e.printStackTrace();
      }
      }
      if (conn!=null){
      try {
      conn.close();
      } catch (SQLException e) {
      e.printStackTrace();
      }
      }
      if (conn!=null){
      try {
      conn.close();
      } catch (SQLException e) {
      e.printStackTrace();
      }
      }
      if (rs!=null){
      try {
      rs.close();
      } catch (SQLException e) {
      e.printStackTrace();
      }
      }
      }
      }
      }

4.2 遍历结果集

注意:

  • 游标向下移动一行,判断当前行是否是最后一行末尾,如果是末尾,返回false,如果有数据返回true

  • boolean next() 将光标从当前位置向前移动一行。

  • 判断是否有数据

  • 获取数据

    package cn.itcast.jdbc;

    import java.sql.*;

    /**

    • 执行DDL语句
      */
      public class JDBCDemo7 {
      public static void main(String[] args) {
      //删除王五
      Statement stmt=null;
      Connection conn=null;
      ResultSet rs=null;
      try {
      //1.注册驱动
      Class.forName("com.mysql.jdbc.Driver");
      //2.获取连接对象
      conn = DriverManager.getConnection("jdbc:mysql:///db3", "root", "root");
      //3.定义sql
      String sql="select * from account";
      //4.获取执行sql的对象
      stmt = conn.createStatement();
      //5.执行sql
      rs = stmt.executeQuery(sql);//资源需要关闭
      //6.处理结果
      // 6.1游标向下移动一行
      while (rs.next()){
      //循环判断结果集是否有下一行
      //循环判断有标是否是最后一行末尾
      //6.2 获取数据
      int id = rs.getInt(1);
      String name = rs.getString("name");
      double balance = rs.getDouble(3);
      System.out.println(id+"---"+name+"---"+balance);
      }
      } catch (ClassNotFoundException e) {
      e.printStackTrace();
      } catch (SQLException e) {
      e.printStackTrace();
      }finally {
      if (stmt!=null){
      try {
      stmt.close();
      } catch (SQLException e) {
      e.printStackTrace();
      }
      }
      if (conn!=null){
      try {
      conn.close();
      } catch (SQLException e) {
      e.printStackTrace();
      }
      }
      if (conn!=null){
      try {
      conn.close();
      } catch (SQLException e) {
      e.printStackTrace();
      }
      }
      if (rs!=null){
      try {
      rs.close();
      } catch (SQLException e) {
      e.printStackTrace();
      }
      }
      }
      }
      }

4.3 JDBC练习_select语句

要求:查询emp表的数据,将其封装为对象,并打印

解决:通过集合,将对象装载到集合,并打印

package cn.itcast.domain;

import java.util.Date;

/**
 * 对应封装emp表数据的javabean
 */
public class Emp {
    private int id;
    private String ename;
    private int job_id;
    private int mgr;
    private Date joindate;
    private double salary;
    private double bonus;
    private int dept_id;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getEname() {
        return ename;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }

    public int getJob_id() {
        return job_id;
    }

    public void setJob_id(int job_id) {
        this.job_id = job_id;
    }

    public int getMgr() {
        return mgr;
    }

    public void setMgr(int mgr) {
        this.mgr = mgr;
    }

    public Date getJoindate() {
        return joindate;
    }

    public void setJoindate(Date joindate) {
        this.joindate = joindate;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public double getBonus() {
        return bonus;
    }

    public void setBonus(double bonus) {
        this.bonus = bonus;
    }

    public int getDept_id() {
        return dept_id;
    }

    public void setDept_id(int dept_id) {
        this.dept_id = dept_id;
    }
    @Override
    public String toString() {
        return "Emp{" +
                "id=" + id +
                ", ename='" + ename + '\'' +
                ", job_id=" + job_id +
                ", mgr=" + mgr +
                ", joindate=" + joindate +
                ", salary=" + salary +
                ", bonuds=" + bonus +
                ", dept_id=" + dept_id +
                '}';
    }
}

package cn.itcast.jdbc;
import cn.itcast.domain.Emp;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/**
 * 定义一个方法,查询emp表的数据将其封装为对象,然后装载集合,并返回
 */
public class JDBCDemo8 {
    public static void main(String[] args) {
        //想调用非静态方法,则需要创建对象
        List<Emp> list = new JDBCDemo8().findAll();
        System.out.println(list);
    }
    /**
     * 查询所有emp对象
     * @return
     */
    public List<Emp> findAll(){
        Connection conn=null;
        Statement stmt=null;
        ResultSet rs=null;
        List<Emp> list=null;
        try {
            //1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");//最好写,写上可以向下兼容
            //2.获取连接
            conn = DriverManager.getConnection("jdbc:mysql:///db3", "root", "root");
            //3.定义sql
            String sql="select * from emp";
            //4.获取执行sql的对象
            stmt = conn.createStatement();
            //5.执行sql
            rs = stmt.executeQuery(sql);
            //6.遍历结果集,封装对象,装载集合
            Emp emp=null;
            list = new ArrayList<>();
            while(rs.next()){
                //获取数据
                int id = rs.getInt("id");
                String ename = rs.getString("ename");
                int job_id = rs.getInt("job_id");
                int mgr = rs.getInt("mgr");
                //怎么把光标放上就能显示概述?
                //Date是sql包下的类,继承了util的date,子类继承父类
                Date joindate = rs.getDate("joindate");
                double salary = rs.getDouble("salary");
                double bonus = rs.getDouble("bonus");
                int dept_id = rs.getInt("dept_id");
                //封装对象,对象引用复用
                emp=new Emp();
                emp.setId(id);
                emp.setBonus(bonus);
                emp.setDept_id(dept_id);
                emp.setEname(ename);
                emp.setJoindate(joindate);
                emp.setMgr(mgr);
                emp.setSalary(salary);
                list.add(emp);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            if (conn!=null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (stmt!=null){
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (rs!=null){
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        return list;
    }
}

5.抽取JDBC工具类:JDBCUtils

分析:

上述代码重复度太高,每次都要注册驱动,每次都要获取连接对象

目标:

写工具类,简化代码,简化以后书写的操作

内容:

  • 注册驱动也抽取

  • 抽取一个方法,获取连接对象

  • 需求:不想传递参数(麻烦),还要保证工具类的通用性

  • 解决方案:通过配置文件解决此问题

  • jdbc.properties

  • url=

  • user=

  • password=

  • 抽取一个方法,释放资源

    package cn.itcast.utils;
    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 driver; /*
      • 文件的读取,只需要读取一次就可以拿到这些值
      • 方案:通过静态代码块
        / static{ //读取配置资源文件,获取值 //BufeeredReader。。。麻烦 try { //1.创建Properties集合类 Properties prop=new Properties(); //2.加载文件,代码提示 //prop.load(new FileReader("src/jdbc.properties")); //找不到资源文件,最笨的方法---可以写绝对路径D:\IdeaProjects\liujinhui\day04_jdbc_20201220\src\jdbc.properties //另外:获取src路径下的文件--->ClassLoader 类加载器:可以 加载字节码文件进内存,同时可以获取src下的资源文件 ClassLoader classLoader = JDBCUtils.class.getClassLoader(); //传的是以src相对的文件路径 //返回统一资源定位符,即文件的绝对路径 URL res= classLoader.getResource("jdbc.properties"); String path = res.getPath(); System.out.println(path); prop.load(new FileReader(path)); //3.获取数据,赋值 url=prop.getProperty("url"); user=prop.getProperty("user"); password=prop.getProperty("password"); driver=prop.getProperty("driver"); //4.注册驱动 Class.forName(driver); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } //Arrays等都是静态,方便类直接调用 /*
      • 获取连接的工具方法
      • @return 连接对象
        / //String url,String root,String password有参数仍然很麻烦 //通过私有变量、配置文件及静态代码块解决 public static Connection getConnection() throws SQLException{ return DriverManager.getConnection(url,user,password); } /*
      • 释放资源
      • @param stmt
      • @param conn
        / public static void close(Statement stmt,Connection conn){ if (stmt!=null){ try { stmt.close(); //conn.close();多个语句要放到多个try..catch中 } catch (SQLException e) { e.printStackTrace(); } } if (conn!=null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } /*
      • 释放资源
      • @param rs
      • @param stmt
      • @param conn
        */
        public static void close(ResultSet rs, Statement stmt, Connection conn){
        if (stmt!=null){
        try {
        stmt.close();
        //conn.close();多个语句要放到多个try..catch中
        } catch (SQLException e) {
        e.printStackTrace();
        }
        }
        if (conn!=null){
        try {
        conn.close();
        } catch (SQLException e) {
        e.printStackTrace();
        }
        }
        if (rs!=null){
        try {
        rs.close();
        } catch (SQLException e) {
        e.printStackTrace();
        }
        }
        }
        }

    package cn.itcast.jdbc;
    import cn.itcast.domain.Emp;
    import cn.itcast.utils.JDBCUtils;

    import java.sql.; import java.util.ArrayList; import java.util.List; /*

    • 定义一个方法,查询emp表的数据将其封装为对象,然后装载集合,并返回 / public class JDBCDemo8 { public static void main(String[] args) { //想调用非静态方法,则需要创建对象 List list = new JDBCDemo8().findAll2(); System.out.println(list); } /*
      • 演示JDBC工具类
      • @return
        */
        public List findAll2(){
        Connection conn=null;
        Statement stmt=null;
        ResultSet rs=null;
        List list=null;
        try {
        //1.注册驱动
        //Class.forName("com.mysql.jdbc.Driver");//最好写,写上可以向下兼容
        //2.获取连接
        //conn = DriverManager.getConnection("jdbc:mysql:///db3", "root", "root");
        conn=JDBCUtils.getConnection();
        //3.定义sql
        String sql="select * from emp";
        //4.获取执行sql的对象
        stmt = conn.createStatement();
        //5.执行sql
        rs = stmt.executeQuery(sql);
        //6.遍历结果集,封装对象,装载集合
        Emp emp=null;
        list = new ArrayList<>();
        while(rs.next()){
        //获取数据
        int id = rs.getInt("id");
        String ename = rs.getString("ename");
        int job_id = rs.getInt("job_id");
        int mgr = rs.getInt("mgr");
        //怎么把光标放上就能显示概述?
        //Date是sql包下的类,继承了util的date,子类继承父类
        Date joindate = rs.getDate("joindate");
        double salary = rs.getDouble("salary");
        double bonus = rs.getDouble("bonus");
        int dept_id = rs.getInt("dept_id");
        //封装对象,对象引用复用
        emp=new Emp();
        emp.setId(id);
        emp.setBonus(bonus);
        emp.setDept_id(dept_id);
        emp.setEname(ename);
        emp.setJoindate(joindate);
        emp.setMgr(mgr);
        emp.setSalary(salary);
        list.add(emp);
        }
        }catch (SQLException e) {
        e.printStackTrace();
        }finally {
        JDBCUtils.close(rs,stmt,conn);
        }
        return list;
        }
        /**
      • 查询所有emp对象
      • @return
        */
        public List findAll(){
        Connection conn=null;
        Statement stmt=null;
        ResultSet rs=null;
        List list=null;
        try {
        //1.注册驱动
        Class.forName("com.mysql.jdbc.Driver");//最好写,写上可以向下兼容
        //2.获取连接
        conn = DriverManager.getConnection("jdbc:mysql:///db3", "root", "root");
        //3.定义sql
        String sql="select * from emp";
        //4.获取执行sql的对象
        stmt = conn.createStatement();
        //5.执行sql
        rs = stmt.executeQuery(sql);
        //6.遍历结果集,封装对象,装载集合
        Emp emp=null;
        list = new ArrayList<>();
        while(rs.next()){
        //获取数据
        int id = rs.getInt("id");
        String ename = rs.getString("ename");
        int job_id = rs.getInt("job_id");
        int mgr = rs.getInt("mgr");
        //怎么把光标放上就能显示概述?
        //Date是sql包下的类,继承了util的date,子类继承父类
        Date joindate = rs.getDate("joindate");
        double salary = rs.getDouble("salary");
        double bonus = rs.getDouble("bonus");
        int dept_id = rs.getInt("dept_id");
        //封装对象,对象引用复用
        emp=new Emp();
        emp.setId(id);
        emp.setBonus(bonus);
        emp.setDept_id(dept_id);
        emp.setEname(ename);
        emp.setJoindate(joindate);
        emp.setMgr(mgr);
        emp.setSalary(salary);
        list.add(emp);
        }
        } catch (ClassNotFoundException e) {
        e.printStackTrace();
        } catch (SQLException e) {
        e.printStackTrace();
        }finally {
        if (conn!=null){
        try {
        conn.close();
        } catch (SQLException e) {
        e.printStackTrace();
        }
        }
        if (stmt!=null){
        try {
        stmt.close();
        } catch (SQLException e) {
        e.printStackTrace();
        }
        }
        if (rs!=null){
        try {
        rs.close();
        } catch (SQLException e) {
        e.printStackTrace();
        }
        }
        }
        return list;
        }
        }

知识点:自定义工具类、配置文件、静态代码块

6.JDBC练习_登录案例

练习:

  • 通过键盘录入用户名和密码

  • 判断用户名是否登录成功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,"zhangsan","123");
    INSERT INTO USER VALUES(NULL,"lisi","123");

  • 代码实现--创建登录方法

    package cn.itcast.jdbc;
    import cn.itcast.utils.JDBCUtils;
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.util.Scanner;
    /**

    • 练习: 通过键盘录入用户名和密码 判断用户名是否登录成功 / public class JDBCDemo9 { public static void main(String[] args) { //1.键盘录入,接收用户名和密码 Scanner sc=new Scanner(System.in); System.out.println("请输入用户名:"); String username = sc.nextLine(); System.out.println("请输入密码:"); String password = sc.nextLine(); //2.调用方法 //静态调用非静态需要声明对象 boolean flag = new JDBCDemo9().login(username, password); //3.判断结果,输出不同语句 if (flag){ //登录成功 System.out.println("登录成功"); }else{ System.out.println("用户名或密码错误"); } //2.调用方法 //3.判断结果,输出不同语句 } /*
      • 登录方法
        */
        public boolean login(String username ,String password){
        if (username==null||password==null){
        return false;
        }
        Connection conn=null;
        Statement stmt=null;
        ResultSet rs=null;
        try {
        //连接数据库判断是否登录成功
        //1.获取连接,更改数据库只需要修改配置文件,可扩展性强
        conn = JDBCUtils.getConnection();
        //2.定义 sql
        String sql="select * from user where username='"+username+"' and password='"+password+"'";
        //3.获取执行SQL的对象
        stmt = conn.createStatement();
        //4.执行查询
        rs = stmt.executeQuery(sql);
        //5.判断
        /if (rs.next()){ return true; }else{ return false; }/
        //直接返回
        return rs.next();
        } catch (SQLException e) {
        e.printStackTrace();
        }finally {
        JDBCUtils.close(rs,stmt,conn);
        }
        return false;
        }
        }

7.JDBC各个类详解_PreparedStatement

上述方法存在的问题 :

  • SQL注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接,会造成安全性问题

  • 输入密码时输入:a' or 'a' = 'a ,可以登录成功

  • 输出的SQL语句:select * from user where username='dsgdf' and password='a' or 'a' = 'a'

  • 在 sqlyog中可以 查到所有记录

  • 解决sql注入问题:使用PreparedStatement对象来解决

  • 是statement的子接口,是 一个预编译的接口

  • 预编译的sql:参数使用?作为占位符

  • 使用步骤

  • 导入驱动jar包

  • 注册驱动

  • 获取数据库的连接对象Connection(java和数据库的桥梁对象)

  • 定义SQL语句

  • 注意:SQL的参数使用?作为占位符

  • 如:select * from user where username=?  and password=?

  • 获取执行SQL语句的对象PreparedStatement   PreparedStatement prepareStatement(String sql)

  • 给?赋值

  • 方法:setXX__X(_参数1,参数 2)_

  • 参数 1:?的位置,从1开始

  • 参数2:?的值

  • 执行SQL,接收返回的结果,不需要传递 SQL语句ResultSet executeQuery()

  • 处理结果

  • 释放资源,不释放容易造成内存的泄露问题

  • 注意:后期都会使用PreparedStatement对象来完成增删改查 操作

  • 可以防止SQL注入

  • 效率更高

    package cn.itcast.jdbc;

    import cn.itcast.utils.JDBCUtils;

    import java.sql.*;
    import java.util.Scanner;

    /**

    • 使用PrepareStatement实现登录操作

    • 练习:
      通过键盘录入用户名和密码
      判断用户名是否登录成功
      */
      public class JDBCDemo10 {
      public static void main(String[] args) {
      //1.键盘录入,接收用户名和密码
      Scanner sc=new Scanner(System.in);
      System.out.println("请输入用户名:");
      String username = sc.nextLine();
      System.out.println("请输入密码:");
      String password = sc.nextLine();
      //2.调用方法
      //静态调用非静态需要声明对象
      boolean flag = new JDBCDemo10().login(username, password);
      //3.判断结果,输出不同语句
      if (flag){
      //登录成功
      System.out.println("登录成功");
      }else{
      System.out.println("用户名或密码错误");
      }

      //2.调用方法
      
      //3.判断结果,输出不同语句

      }
      /**

      • 登录方法
        */
        public boolean login(String username ,String password){
        if (username==null||password==null){
        return false;
        }
        Connection conn=null;
        PreparedStatement pstmt=null;
        ResultSet rs=null;
        try {
        //连接数据库判断是否登录成功
        //1.获取连接,更改数据库只需要修改配置文件,可扩展性强
        conn = JDBCUtils.getConnection();
        //2.定义 sql
        String sql="select * from user where username= ? and password= ?";
        //System.out.println(sql);
        //3.获取执行SQL的对象
        pstmt = conn.prepareStatement(sql);
        //给 ?赋值
        pstmt.setString(1,username);
        pstmt.setString(2,password);
        //4.执行查询
        rs =pstmt.executeQuery();
        //5.判断
        /if (rs.next()){ return true; }else{ return false; }/
        //直接返回
        return rs.next();
        } catch (SQLException e) {
        e.printStackTrace();
        }finally {
        JDBCUtils.close(rs,pstmt,conn);
        }
        return false;
        }
        }

三、使用JDBC控制事务

1.事务:包含多个步骤的业务操作,如果这个业务操作被事务管理,则这多个事务要么同时成功,要么同时失败

2.操作

  • 开启事务
  • 提交事务
  • 回滚事务

3.回顾:Connection对象可以进行获取连接和管理事务

使用Connection对象管理事务

  • 三个方法--开启事务voi__d setAutoCommit(boolean autoCommit) 调用此方法设置false,即开启事务并不自动提交
  • 三个方法--提交事务:void commit() 提交事务
  • 三个方法--回滚事务:void rollback() 回滚事务

4.银行转账案例--JDBC控制事务

package cn.itcast.jdbc;

import cn.itcast.utils.JDBCUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * 事务操作
 */
public class JDBCDemo11 {

    public static void main(String[] args) {
        Connection conn=null;
        PreparedStatement pstmt1=null;
        PreparedStatement pstmt2=null;
        try {
            //1.获取连接
            conn = JDBCUtils.getConnection();
            //开启事务
            conn.setAutoCommit(false);
            //2,定义SQL
            //2.1 张三-500
            //String sql1="update account set balance=balance-500 where id=1";
            //2.2 李四+500
            //String sql2="update account set balance=balance+500 where id=2";
            //通用写法
            String sql1="update account set balance=balance-? where id=?";
            String sql2="update account set balance=balance+? where id=?";
            //3.获取执行sql对象
            pstmt1 = conn.prepareStatement(sql1);
            pstmt2= conn.prepareStatement(sql2);
            //代码格式化快捷键
            //4.设置参数
            pstmt1.setDouble(1,500);
            pstmt1.setInt(2,1);
            pstmt2.setDouble(1,500);
            pstmt2.setInt(2,2);
            //5.执行SQL
            pstmt1.executeUpdate();
            //手动制造异常
            int i=3/0;
            pstmt2.executeUpdate();
            //提交事务
            conn.commit();
            //使用大异常
        } catch (Exception e) {
            try {

                //事务回滚,前提不为null
                if (conn!=null){
                    conn.rollback();
                }
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        }finally {
            JDBCUtils.close(pstmt1,conn);
            JDBCUtils.close(pstmt2,null);
        }

    }
}

在执行sql之前开启事务

在当所有sql执行完提交事务

在 catch中回滚事务

来自为知笔记(Wiz)