JDBC

1. JDBC基本概念

概念:JDBC即Java DataBase Connectivity,Java数据库连接,Java语言操作数据库

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

2. 快速入门

步骤

  • 导入驱动jar包 mysql-connector-java-8.0.29.jar
    • 复制mysql-connector-java-8.0.29.jar到项目新建的libs目录下
    • 右键libs目录--->Add as library
  • 注册驱动
  • 获取数据库连接对象 Connection
  • 定义sql语句
  • 获取执行sql语句的对象 Statement
  • 执行sql,接收返回结果
  • 处理结果
  • 释放资源
package com.JDBC;

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

/**
 * @ClassName JDBCDemo1
 * @Description TODO JDBC快速入门
 * @Author Mark
 * @Date 2022/7/18 19:20
 * @Version 1.0
 */
public class JDBCDemo1 {
    public static void main(String[] args) throws Exception {
        //1.导入驱动jar包
        //2.注册驱动
        //Class.forName("com.mysql.jdbc.Driver");
        //com.mysql.jdbc.Driver已经被弃用,现在使用com.mysql.cj.jdbc.Driver,而且驱动程序会通过SPI自动注册,不再需要手动注册
        //3.获取数据库连接对象
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode", "root", "123");
        //4.定义sql语句
        String sql="update emp set sal = 1500 where empno=7369";
        //5.获取执行sql的对象 Statement
        Statement stmt = conn.createStatement();
        //6.执行sql
        int count = stmt.executeUpdate(sql);
        //7.处理结果
        System.out.println(count);//1
        //释放资源
        stmt.close();
        conn.close();

    }
}

3. 对JDBC中各个接口和类的详解

3.1 DriverManager

驱动管理对象

  • 功能:

    • 注册驱动

      static void registerDriver(Driver driver) 注册与给定的驱动程序 DriverManager 。

      而在代码中使用Class.forName("com.mysql.jdbc.Driver");注册

      该class源码中使用DriverManager.registerDriver注册驱动

      在MySQL5之后可以不手动注册驱动

    • 获取数据库连接

      • 方法:static Connection getConnection(String url, String user, String password) 尝试建立与给定数据库URL的连接。
      • 参数:
        • url:指定连接路径
          • 语法:jdbc:mysql://ip地址(或域名):端口号/数据库名称
          • eg:jdbc:mysql://localhost:3306/bjpowernode
          • 注意:如果连接的是本机mysql服务器,并且mysql服务默认端口是3306,则url可以简写为jdbc:mysql:///bjpowernode
        • user:用户名
        • password:密码

3.2 Connection

数据库连接对象

  • 功能:
    • 获取执行sql的对象:
      • Statement createStatement() 创建一个 Statement对象,用于将SQL语句发送到数据库。
      • PrepareStatement prepareStatement(String sql) 创建一个 PreparedStatement对象,用于将参数化的SQL语句发送到数据库。
    • 管理事务:
      • 开启事务:setAutoCommit(boolean autoCommit) 调用该方法设置参数为false,即开启事务
      • 回滚事务:rollback()
      • 提交事务:commit()

3.3 Statement

执行静态SQL语句并返回其生成的结果的对象

  • 功能:执行sql

    • boolean execute(String sql) 执行给定的SQL语句,可能会返回多个结果。
    • int executeUpdate(String sql) 执行DML语句(insert update delete)、DDL语句(create、alter、drop)
      • 返回值为int,是影响的行数,判断DML语句是否执行成功,返回值>0则成功
    • ResultSet executeQuery(String sql) 执行DQL语句(select),返回结果集对象
  • 练习:增删改不同的语句

    • emp表 添加一条记录

      package com.JDBC;
      
      import java.sql.Connection;
      import java.sql.DriverManager;
      import java.sql.SQLException;
      import java.sql.Statement;
      
      /**
       * @ClassName JDBCDemo2
       * @Description TODO department表 添加一条记录
       * @Author Mark
       * @Date 2022/7/18 23:58
       * @Version 1.0
       */
      public class JDBCDemo2 {
          public static void main(String[] args) {
              Statement stmt = null;
              Connection conn = null;
      
              try {
      //            Class.forName("com.mysql.cj.jdbc.Driver");
                  conn = DriverManager.getConnection("jdbc:mysql:///studenttest", "root", "123");
                  stmt = conn.createStatement();
                  String sql = "insert into emp values('张三',1,19,2)";
                  int count = stmt.executeUpdate(sql);
                  if (count > 0) {
                      System.out.println("添加成功");
                  } else {
                      System.out.println("添加失败");
                  }
              } catch (SQLException e) {
                  e.printStackTrace();
              } finally {
                  //stmt.close();
                  //避免空指针异常
                  if (stmt != null) {
                      try {
                          stmt.close();
                      } catch (SQLException e) {
                          e.printStackTrace();
                      }
                  }
      
                  if (conn != null) {
                      try {
                          conn.close();
                      } catch (SQLException e) {
                          e.printStackTrace();
                      }
                  }
              }
          }
      }
      
      
    • emp表 修改一条记录

      package com.JDBC;
      
      import java.sql.Connection;
      import java.sql.DriverManager;
      import java.sql.SQLException;
      import java.sql.Statement;
      
      /**
       * @ClassName JDBCDemo3
       * @Description TODO emp表 修改一条记录
       * @Author Mark
       * @Date 2022/7/19 0:54
       * @Version 1.0
       */
      public class JDBCDemo3 {
          public static void main(String[] args) {
              Connection conn = null;
              Statement stmt = null;
      
              try {
                  conn = DriverManager.getConnection("jdbc:mysql:///studenttest", "root", "123");
                  stmt = conn.createStatement();
                  int count = stmt.executeUpdate("update emp set age = 20 where id = 1");
      
                  if (count > 0) {
                      System.out.println("修改成功");
                  } else {
                      System.out.println("失败");
                  }
      
              } 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();
                      }
                  }
              }
          }
      }
      
      
    • emp表 删除一条记录

      package com.JDBC;
      
      import java.sql.Connection;
      import java.sql.DriverManager;
      import java.sql.SQLException;
      import java.sql.Statement;
      
      /**
       * @ClassName JDBCDemo4
       * @Description TODO emp表 删除一条记录
       * @Author Mark
       * @Date 2022/7/19 1:04
       * @Version 1.0
       */
      public class JDBCDemo4 {
          public static void main(String[] args) {
              Statement stmt=null;
              Connection conn=null;
      
              try {
                  conn = DriverManager.getConnection("jdbc:mysql:///studenttest", "root", "123");
                  stmt = conn.createStatement();
                  String sql = "delete from emp where id = 1";
                  int count = stmt.executeUpdate(sql);
                  if (count > 0) {
                      System.out.println("删除成功");
                  } else {
                      System.out.println("失败");
                  }
              } 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();
                      }
                  }
              }
          }
      }
      
      

3.4 ResultSet

结果集对象,封装查询结果

  • ResultSet用到的方法:

    • boolean next():游标向下移动一行,判断当前行是否为最后一行末尾(是否有数据),如果是返回false,如果不是,则返回true

    • getxxx(参数):获取数据

      • xxx代表数据类型 如:int getInt() String getString()
      • 参数有两种情况:
        • int:代表列的编号,从1开始 如:getString(1)
        • String:代表列的名称 如:getDouble("sal")
    package com.JDBC;
    
    import java.sql.*;
    
    /**
     * @ClassName JDBCDemo5
     * @Description TODO
     * @Author Mark
     * @Date 2022/7/19 23:06
     * @Version 1.0
     */
    public class JDBCDemo5 {
        public static void main(String[] args) {
            Statement stmt = null;
            Connection conn = null;
            ResultSet rs = null;
    
            try {
                conn = DriverManager.getConnection("jdbc:mysql:///bjpowernode", "root", "123");
                stmt = conn.createStatement();
                String sql = "select * from emp";
                rs = stmt.executeQuery(sql);
    
                //让游标向下移动一行
                rs.next();
                //获取数据
                int empno = rs.getInt(1);
                String ename = rs.getString("ename");
                String job = rs.getString("job");
                int mgr = rs.getInt("mgr");
                Date hiredate = rs.getDate("hiredate");
                double sal = rs.getDouble("sal");
                double comm = rs.getDouble("comm");
                int deptno = rs.getInt("deptno");
                System.out.println(empno + "---" + ename + "---" + job + "---" + mgr + "---" + hiredate + "---" + sal + "---" + comm + "---" + deptno);
    
            } 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 (rs != null) {
                    try {
                        stmt.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
    
  • ResultSet遍历结果集

    • 使用时步骤:

      • 游标向下移动一行
      • 判断是否有数据
      • 获取数据
      package com.JDBC;
      
      import java.sql.*;
      
      /**
       * @ClassName JDBCDemo6
       * @Description TODO
       * @Author Mark
       * @Date 2022/7/20 10:44
       * @Version 1.0
       */
      public class JDBCDemo6 {
          public static void main(String[] args) {
              Statement stmt = null;
              Connection conn = null;
              ResultSet rs = null;
      
              try {
                  conn = DriverManager.getConnection("jdbc:mysql:///bjpowernode", "root", "123");
                  stmt = conn.createStatement();
                  String sql = "select * from emp";
                  rs = stmt.executeQuery(sql);
      
                  //让游标向下移动一行
                  /*
                  if (rs.next()){
                      int empno = rs.getInt(1);
                      String ename = rs.getString("ename");
                      String job = rs.getString("job");
                      double sal = rs.getDouble("sal");
                      System.out.println(empno + "---" + ename + "---" + job + "---" + sal);
                  }
                  */
      
                  while(rs.next()){
                      //循环判断是否有下一行(判断游标是否是最后一行末尾)
                      //获取数据
                      int empno = rs.getInt(1);
                      String ename = rs.getString("ename");
                      String job = rs.getString("job");
                      double sal = rs.getDouble("sal");
                      System.out.println(empno + "---" + ename + "---" + job + "---" + sal);
                  }
              /*
                  for (; rs.next(); ) {
                      int empno = rs.getInt(1);
                      String ename = rs.getString("ename");
                      String job = rs.getString("job");
                      double sal = rs.getDouble("sal");
                      System.out.println(empno + "---" + ename + "---" + job + "---" + sal);
                  }
             */
              } 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 (rs != null) {
                      try {
                          stmt.close();
                      } catch (SQLException e) {
                          e.printStackTrace();
                      }
                  }
              }
          }
      }
      
      ​```
      
      
  • 练习:

    • 定义一个方法,查询emp表的数据,将其封装为对象,然后装载集合,返回

      • 定义一个Emp类
      • 查询定义方法 public List<EMP> findAll(){}
      • 实现方法 select * from emp;
      package com.JDBCDoMain;
      
      import java.util.Date;
      
      /**
       * @ClassName Emp
       * @Description TODO 封装Emp表数据的JavaBean
       * @Author Mark
       * @Date 2022/7/20 11:09
       * @Version 1.0
       */
      public class Emp {
          private int EmpNO;
          private String EName;
          private String Job;
          private int Mgr;
          private Date HireDate;
          private double Sal;
          private double Comm;
          private int DeptNo;
      
          public int getEmpNO() {
              return EmpNO;
          }
      
          public void setEmpNO(int empNO) {
              EmpNO = empNO;
          }
      
          public String getEName() {
              return EName;
          }
      
          public void setEName(String EName) {
              this.EName = EName;
          }
      
          public String getJob() {
              return Job;
          }
      
          public void setJob(String job) {
              Job = job;
          }
      
          public int getMgr() {
              return Mgr;
          }
      
          public void setMgr(int mgr) {
              Mgr = mgr;
          }
      
          public Date getHireDate() {
              return HireDate;
          }
      
          public void setHireDate(Date hireDate) {
              HireDate = hireDate;
          }
      
          public double getSal() {
              return Sal;
          }
      
          public void setSal(double Sal) {
              this.Sal = Sal;
          }
      
          public double getComm() {
              return Comm;
          }
      
          public void setComm(double comm) {
              Comm = comm;
          }
      
          public int getDeptNo() {
              return DeptNo;
          }
      
          public void setDeptNo(int deptNo) {
              DeptNo = deptNo;
          }
      
          @Override
          public String toString() {
              return "Emp{" +
                      "EmpNO=" + EmpNO +
                      ", EName='" + EName + '\'' +
                      ", Job='" + Job + '\'' +
                      ", Mgr=" + Mgr +
                      ", HireDate=" + HireDate +
                      ", Sal=" + Sal +
                      ", Comm=" + Comm +
                      ", DeptNo=" + DeptNo +
                      '}';
          }
      }
      
      
      package com.JDBC;
      
      import com.JDBCDoMain.Emp;
      
      import java.sql.*;
      import java.util.ArrayList;
      import java.util.List;
      
      /**
       * @ClassName JDBCDemo7
       * @Description TODO 练习 定义一个方法,查询emp表的数据,将其封装为对象,然后装载集合,返回。
       * @Author Mark
       * @Date 2022/7/20 11:18
       * @Version 1.0
       */
      public class JDBCDemo7 {
          public static void main(String[] args) {
              List<Emp> list = new JDBCDemo7().findAll();
              System.out.println(list);
              System.out.println(list.size());
          }
      
      public List<Emp> findAll() {
          Connection conn = null;
          Statement stmt = null;
          ResultSet rs = null;
          List<Emp> list = null;
      
          try {
              conn = DriverManager.getConnection("jdbc:mysql:///bjpowernode", "root", "123");
              stmt = conn.createStatement();
              String sql = "select * from emp";
              rs = stmt.executeQuery(sql);
              Emp emp = null;//不在while中创建,因为会导致额外使用栈内存
              list = new ArrayList<Emp>();
              while (rs.next()) {
                  int EmpNo = rs.getInt(1);
                  String EName = rs.getString("ename");
                  String Job = rs.getString("job");
                  int Mgr = rs.getInt("mgr");
                  Date HireDate = rs.getDate("hiredate");
                  double Sal = rs.getDouble("sal");
                  double Comm = rs.getDouble("comm");
                  int DeptNo = rs.getInt("deptno");
                  //创建emp对象并赋值
                  emp = new Emp();
                  emp.setEmpNO(EmpNo);
                  emp.setEName(EName);
                  emp.setJob(Job);
                  emp.setMgr(Mgr);
                  emp.setHireDate(HireDate);
                  emp.setSal(Sal);
                  emp.setComm(Comm);
                  emp.setDeptNo(DeptNo);
      
                  list.add(emp);
              }
      
          } catch (SQLException e) {
              e.printStackTrace();
          } finally {
              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();
                  }
              }
          }
          return list;
      }
      

      }

      ​```

3.5 PreparedStatement

预编译的SQL语句的对象(执行动态SQL语句)

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

    • 用户名随便输入,输入密码:a' or 'a' ='a

      sql:select * from user where username='dsafasfasgf' and password = 'a' or 'a' ='a'

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

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

  • 步骤:

    • 导入驱动jar包 mysql-connector-java-8.0.29.jar

      • 复制mysql-connector-java-8.0.29.jar到项目新建的libs目录下
      • 右键libs目录--->Add as library
    • 获取数据库连接对象 Connection

    • ※定义sql语句

      • 注意:sql的参数使用?作为占位符。如select * from user where username = ? and password = ?
    • ※获取执行sql语句的对象 prepareStatement Connection.prepareStatement(String sql)

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

    • 给?赋值

      • 方法:setxxx(参数1,参数2)
        • 参数1是?的位置编号,从1开始
        • 参数2是?的值
    • 执行sql,接收返回结果,不需要传递sql语句

    • 处理结果

    • 释放资源

    package com.JDBC;
    
    import com.util.JDBCUtils;
    
    import java.sql.*;
    import java.util.Scanner;
    
    /**
     * @ClassName JDBCDemo9
     * @Description TODO 练习 登陆案例
     * @Author Mark
     * @Date 2022/7/20 15:41
     * @Version 1.0
     */
    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("用户名或密码错误");
            }
        }
    
        //登陆方法
        public boolean login(String username, String password) {
            if (username == null) {
                return false;
            }
            //连接数据库登陆数据库
            Connection conn = null;
            PreparedStatement pstmt = null;
            ResultSet rs = null;
    
            try {
                conn = JDBCUtils.getConnection();
                String sql = "select * from user where username=? and password=?";
                pstmt = conn.prepareStatement(sql);
                pstmt.setString(1,username);
                pstmt.setString(2,password);
                rs = pstmt.executeQuery();
                return rs.next();
    
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                JDBCUtils.close(rs, pstmt, conn);
            }
    
            return false;
        }
    }
    
    

    注意:

    后期都会使用PreparedStatement来完成增删改查的所有操作

    • 可以有效防止SQL注入
    • 效率更高

4. JDBC工具类

抽取JDBC工具类:JDBCUtils

  • 目的:简化书写

  • 分析:

    • 注册驱动

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

      • 需求:不想传递参数(繁琐),还得保证工具类的通用性

      • 解决:配置文件

        • jdbc.properties

          ​ url=

          ​ user=

          ​ password=

    • 抽取一个方法释放资源

package com.util;

import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.sql.*;
import java.util.Properties;

/**
 * @ClassName JDBCUtils
 * @Description TODO JDBC工具类
 * @Author Mark
 * @Date 2022/7/20 11:49
 * @Version 1.0
 */
public class JDBCUtils {
    private static String url;
    private static String username;
    private static String password;

    //配置文件的读取,读取一次,拿到连接数据库需要的值。使用静态代码块
    static {
        //读取资源文件,获取值
        try {
            //1.创建Properties集合类
            Properties pro = new Properties();
            //2.加载文件
//            pro.load(new FileReader("src/jdbc.properties"));
            //获取src路径下文件的方式--ClassLoader
            ClassLoader classLoader = JDBCUtils.class.getClassLoader();
            URL resource = classLoader.getResource("jdbc.properties");
            String path = resource.getPath();
            pro.load(new FileReader(path));
            //3.获取数据,赋值
            url = pro.getProperty("url");
            username = pro.getProperty("username");
            password = pro.getProperty("password");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取连接
     *
     * @return 连接对象
     */
    public static Connection getConnection(/*String url,String user,String password*/) throws SQLException {
//        DriverManager.getConnection(url,user,password);
        return DriverManager.getConnection(url, username, password);
    }

    /**
     * 释放资源
     */
    public static void close(Statement stmt, Connection conn) {
        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 close(ResultSet rs, Statement stmt, Connection conn) {
        if (stmt != null) {
            try {
                stmt.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();
            }
        }
    }
}
package com.JDBC;

import com.JDBCDoMain.Emp;
import com.util.JDBCUtils;

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

/**
 * @ClassName JDBCDemo7
 * @Description TODO 演示jdbc工具类
 * @Author Mark
 * @Date 2022/7/20 11:18
 * @Version 1.0
 */
public class JDBCDemo8 {
    public static void main(String[] args) {
        List<Emp> list = new JDBCDemo8().findAll();
        System.out.println(list);
        System.out.println(list.size());
    }

    public List<Emp> findAll() {
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        List<Emp> list = null;

        try {
//            conn = DriverManager.getConnection("jdbc:mysql:///bjpowernode", "root", "123");
            conn = JDBCUtils.getConnection();
            stmt = conn.createStatement();
            String sql = "select * from emp";
            rs = stmt.executeQuery(sql);
            Emp emp = null;//不在while中创建,因为会导致额外使用栈内存
            list = new ArrayList<Emp>();
            while (rs.next()) {
                int EmpNo = rs.getInt(1);
                String EName = rs.getString("ename");
                String Job = rs.getString("job");
                int Mgr = rs.getInt("mgr");
                Date HireDate = rs.getDate("hiredate");
                double Sal = rs.getDouble("sal");
                double Comm = rs.getDouble("comm");
                int DeptNo = rs.getInt("deptno");
                //创建emp对象并赋值
                emp = new Emp();
                emp.setEmpNO(EmpNo);
                emp.setEName(EName);
                emp.setJob(Job);
                emp.setMgr(Mgr);
                emp.setHireDate(HireDate);
                emp.setSal(Sal);
                emp.setComm(Comm);
                emp.setDeptNo(DeptNo);

                list.add(emp);
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
//            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();
//                }
//            }
            JDBCUtils.close(rs, stmt, conn);
        }
        return list;
    }
}

  • 练习

    • 需求:

      • 通过键盘录入用户名和密码
      • 判断用户是否登陆成功
      • 如果成功提示登陆成功,失败提示登陆失败
    • 步骤

      • 创建一个数据库user表

        CREATE TABLE user(
        	id int PRIMARY KEY AUTO_INCREMENT,
        	username VARCHAR(32),
        	password VARCHAR(32)
        );
        
        DESC user;
        
        INSERT INTO user VALUES(null,'zhangsan','123');
        INSERT INTO user VALUES(null,'lisi','234');
        
        SELECT * FROM user;
        
        package com.JDBC;
        
        import com.util.JDBCUtils;
        
        import java.sql.*;
        import java.util.Scanner;
        
        /**
         * @ClassName JDBCDemo9
         * @Description TODO 练习 登陆案例
         * @Author Mark
         * @Date 2022/7/20 15:41
         * @Version 1.0
         */
        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("用户名或密码错误");
                }
            }
        
            //登陆方法
            public boolean login(String username, String password) {
                if (username == null) {
                    return false;
                }
                //连接数据库登陆数据库
                Connection conn = null;
                Statement stmt = null;
                ResultSet rs = null;
        
                try {
                    conn = JDBCUtils.getConnection();
                    stmt = conn.createStatement();
                    String sql = "select * from user where username='" + username + "' and password='" + password + "'";
                    rs = stmt.executeQuery(sql);
                    return rs.next();
        
                } catch (SQLException e) {
                    e.printStackTrace();
                } finally {
                    JDBCUtils.close(rs, stmt, conn);
                }
        
                return false;
            }
        }
        
        
      • 以上程序存在风险,sql注入:

        请输入用户名
        dsafasfasgf
        请输入密码
        a' or 'a' = 'a
        登陆成功
        

5. JDBC控制事务

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

  • 操作:

    • 开启事务
    • 回滚事务
    • 提交事务
  • 使用Connection对象来管理事务

    • 开启事务:setAutoCommit(boolean autoCommit) 调用该方法设置参数为false,即开启事务
      • 执行sql之前开启事务
    • 回滚事务:rollback()
      • 在catch中回滚事务
    • 提交事务:commit()
      • 所有sql都执行完提交事务
  • 实现银行转账案例

  • package com.JDBC;
    
    import com.util.JDBCUtils;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    /**
     * @ClassName JDBCDemo11
     * @Description TODO 事务
     * @Author Mark
     * @Date 2022/7/20 16:50
     * @Version 1.0
     */
    public class JDBCDemo11 {
        public static void main(String[] args) {
            boolean flag = new JDBCDemo11().transfer("zhangsan", 500, "lisi");
            if (flag) {
                System.out.println("转账成功");
            } else {
                System.out.println("转账失败");
            }
        }
    
        public boolean transfer(String name1, double account, String name2) {
            if (name1 == null || name2 == null) {
                return false;
            }
    
            Connection conn = null;
            PreparedStatement pstmt1 = null;
            PreparedStatement pstmt2 = null;
    
            try {
                conn = JDBCUtils.getConnection();
                conn.setAutoCommit(false);
                String sql1 = "update account set balance = balance-? where name= ?";
                String sql2 = "update account set balance = balance+? where name= ?";
                pstmt1 = conn.prepareStatement(sql1);
                pstmt1.setDouble(1, account);
                pstmt1.setString(2, name1);
                pstmt2 = conn.prepareStatement(sql2);
                pstmt2.setDouble(1, account);
                pstmt2.setString(2, name2);
                int flag1 = pstmt1.executeUpdate();
    //            int i= 3/0;//手动制造异常
                int flag2 = pstmt2.executeUpdate();
                conn.commit();
                if (flag1 == 1 && flag2 == 1) {
                    return true;
                }
            } catch (/*SQLException e*/Exception e) {
                //事务回滚
                try {
                    if (conn != null) {
                        conn.rollback();
                    }
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
                e.printStackTrace();
            } finally {
                JDBCUtils.close(pstmt1, conn);
                JDBCUtils.close(pstmt2, null);
            }
            return false;
        }
    }
    

6. 数据库连接池

  • 概念:其实就是一个容器(集合),存放数据库连接的容器
    • 当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问之后,会将连接对象还给容器
  • 好处:
    • 节约系统资源
    • 用户访问高效
  • 实现:
    • 标准接口:DataSource javax.sql包下的
      • 方法:
        • 获取连接:getConnection()
        • 归还连接:close()如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,则不会再关闭连接了,而是归还连接
    • 一般我们不去实现它,由数据库厂商来实现
      • C3P0:数据库连接池技术(较老)
      • Druid:德鲁伊数据库连接池实现技术,由阿里巴巴提供(全球最好的数据库连接池技术之一)

6.1 C3P0的使用

  • 步骤:

    • 导入jar包 c3p0-0.9.5.2.jar mchange-commons-java-0.2.12.jar(不要忘记数据库驱动jar包

    • 定义配置文件

      • c3p0.properties 或者c3p0-config.xml 名字固定,会自动加载

      • 路径:直接将文件放在src目录下即可

        <c3p0-config>
            <!-- 使用默认的配置读取连接池对象 -->
            <default-config>
                <!--  连接参数 -->
                <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
                <property name="jdbcUrl">jdbc:mysql://localhost:3306/db3</property>
                <property name="user">root</property>
                <property name="password">123</property>
        
                <!-- 连接池参数 -->
                <!--初始化申请的连接数量-->
                <property name="initialPoolSize">5</property>
                <!--最大的连接数量-->
                <property name="maxPoolSize">10</property>
                <!--超时时间为3s-->
                <property name="checkoutTimeout">3000</property>
            </default-config>
        
            <named-config name="otherc3p0">
                <!--  连接参数 -->
                <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
                <property name="jdbcUrl">jdbc:mysql://localhost:3306/db3</property>
                <property name="user">root</property>
                <property name="password">123</property>
        
                <!-- 连接池参数 -->
                <property name="initialPoolSize">5</property>
                <property name="maxPoolSize">8</property>
                <property name="checkoutTimeout">1000</property>
            </named-config>
        </c3p0-config>
        
    • 创建核心对象 数据库连接池对象 ComboPooledDataSource

    • 获取连接:getConnection

      package com.dataSource.c3p0;
      
      import com.mchange.v2.c3p0.ComboPooledDataSource;
      
      import javax.sql.DataSource;
      import java.sql.Connection;
      import java.sql.SQLException;
      
      /**
       * @ClassName C3P0Demo
       * @Description TODO C3P0的演示
       * @Author Mark
       * @Date 2022/7/20 18:01
       * @Version 1.0
       */
      public class C3P0Demo {
          public static void main(String[] args) throws SQLException {
              //1.创建数据库连接池对象
              DataSource ds=new ComboPooledDataSource();
              //2.获取连接对象
              Connection conn = ds.getConnection();
              //3.打印
              System.out.println(conn);
          }
      }
      
      

6.2 Druid的使用

6.2.1 使用步骤

  • 导入jar包 druid-1.2.9.jar
  • 定义配置文件:
    • 是properties形式的
    • 可以叫任意名称,可以放在任意目录下,但是需要手动加载
  • 加载配置文件
  • 获取数据库连接池对象:通过工厂类来获取 DruidDataSourceFactory
  • 获取连接:getConnection
package com.dataSource.druid;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;

/**
 * @ClassName DruidDemo01
 * @Description TODO Druid演示
 * @Author Mark
 * @Date 2022/7/20 19:42
 * @Version 1.0
 */
public class DruidDemo01 {
    public static void main(String[] args) throws Exception {
        //1.导入jar包
        //2.定义配置文件
        //3.加载配置文件
        Properties pro=new Properties();
        InputStream inputStream = DruidDemo01.class.getClassLoader().getResourceAsStream("druid.properties");
        pro.load(inputStream);
        //4.获取连接池对象
        DataSource ds = DruidDataSourceFactory.createDataSource(pro);
        //5.获取连接
        Connection conn = ds.getConnection();
        System.out.println(conn);
    }
}

6.2.2 Druid工具类

  • 定义一个类DruidUtils
  • 提供静态代码块加载配置文件,初始化连接对象
  • 提供方法
    • 获取连接方法:通过数据库连接池获取连接
    • 释放资源
    • 获取连接池的方法
package com.util;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.dataSource.druid.DruidDemo01;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

/**
 * @ClassName DruidUtils
 * @Description TODO DruidUtils工具类
 * @Author Mark
 * @Date 2022/7/20 19:54
 * @Version 1.0
 */
public class DruidUtils {
    //1.定义成员变量 DataSource
    private static DataSource ds;

    static {
        try {
            //1.加载配置文件
            Properties pro = new Properties();
            InputStream inputStream = DruidDemo01.class.getClassLoader().getResourceAsStream("druid.properties");
            //2.获取DataSource
            ds = DruidDataSourceFactory.createDataSource(pro);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取连接
     * @return
     * @throws SQLException
     */
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }

    /**
     * 释放资源
     * @param stmt
     * @param conn
     */
    public static void close(Statement stmt, Connection conn) {
//        if (stmt!= null){
//            try {
//                stmt.close();
//            } catch (SQLException e) {
//                e.printStackTrace();
//            }
//        }
//
//        if (conn!= null){
//            try {
//                conn.close();
//            } catch (SQLException e) {
//                e.printStackTrace();
//            }
//        }
        close(null, stmt, conn);
    }

    /**
     * 释放资源重载
     * @param rs
     * @param stmt
     * @param conn
     */
    public static void close(ResultSet rs, Statement stmt, Connection conn) {
        if (stmt != null) {
            try {
                stmt.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();
            }
        }
    }

    /**
     * 获取连接池
     * @return ds
     */
    public static DataSource getDataSource() {
        return ds;
    }

}

package com.dataSource.druid;

import com.util.DruidUtils;

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

/**
 * @ClassName DruidDemo02
 * @Description TODO Druid工具类测试
 * @Author Mark
 * @Date 2022/7/20 20:06
 * @Version 1.0
 */
public class DruidDemo02 {
    public static void main(String[] args) {
        //完成添加操作,给account添加一条记录
        Connection conn = null;
        PreparedStatement pstmt = null;

        try {
            //1.获取连接
            conn = DruidUtils.getConnection();
            //2.定义sql
            String sql = "insert into account values(null,?,?)";
            //3.获取pstmt对象
            pstmt = conn.prepareStatement(sql);
            //4.给?赋值
            pstmt.setString(1,"wangwu");
            pstmt.setDouble(2,3000);
            //5.执行sql
            int count = pstmt.executeUpdate();
            System.out.println(count);
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //6.释放资源
            DruidUtils.close(pstmt,conn);
        }
    }
}

7.Spring JDBC:JdbcTemplate

7.1 JdbcTemplate简单介绍

  • Spring框架对JDBC的简单封装。提供了一个JdbcTemplate对象简化JDBC的开发

  • 步骤:

    • 导入jar包

    • 创建JdncTemplate对象。依赖于数据源DataSource

      • JdbcTemplate template = new JdbcTemplate(ds);
    • 调用JdbcTemplate的方法来完成CRUD的操作

      • update():执行DML语句(增、删、改语句)

      • queryForMap():查询结果,将结果封装为Map集合。将列名作为key,将值作为value,将这条记录封装为一个Map集合

      • queryForList():查询结果,将结果封装为list集合。将每一条记录封装为Map集合,再将Map集合装载到一个List集合中

      • query():查询结果,将结果封装为JavaBean对象

        • qurey的参数:RowMapper

          • 一般我们使用BeanPropertyRowMapper实现类,可以完成数据到JavaBean的自动封装

          • new BeanPropertyRowMapper<Emp>(Emp.class)
            
      • queryForObject:查询结果,将结果封装为对象

        • 一般用于聚合函数的查询

7.2 JdbcTemplate快速入门

package com.JDBCTemplate;

import com.util.DruidUtils;
import org.springframework.jdbc.core.JdbcTemplate;

/**
 * @ClassName JDBC
 * @Description TODO JDBCTemplate入门
 * @Author Mark
 * @Date 2022/7/20 20:37
 * @Version 1.0
 */
public class JDBCTemplateDemo01 {
    public static void main(String[] args) {
        //1.导入jar包
        //2.创建JDBCTemplate对象
        JdbcTemplate template = new JdbcTemplate(DruidUtils.getDataSource());
        //3.调用方法
        String sql = "update account set balance = 5000 where id = ?";
        int count = template.update(sql, 3);
        System.out.println(count);
    }
}

7.3 练习:JdbcTemplate执行DML语句

  • 需求:
    • 修改SMITH的sal为1800
    • 添加一条记录
    • 三处刚才添加的记录
    • 查询SMITH的记录,将其封装为Map集合
    • 查询所有记录,将其封装为List集合
    • 查询所有记录,将其封装为Emp对象的List集合
    • 查询总记录数
package com.JDBCTemplate;

import com.TemplateDomain.Emp;
import com.util.DruidUtils;
import org.junit.Test;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import java.sql.Date;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

/**
 * @ClassName JDBCTemplateDemo02
 * @Description TODO
 * @Author Mark
 * @Date 2022/7/20 23:40
 * @Version 1.0
 */
public class JDBCTemplateDemo02 {
    private JdbcTemplate template = new JdbcTemplate(DruidUtils.getDataSource());


    @Test
    public void test1(){
//        template = new JdbcTemplate(DruidUtils.getDataSource());

        String sql="update emp set sal = 1800 where ename='SMITH'";
        int count = template.update(sql);
        System.out.println(count);
    }

    @Test
    public void test2(){
        String sql="insert into emp(empno,ename,sal,deptno) values(?,?,?,?)";
        int count = template.update(sql,7799,"MARK",9921,20);
        System.out.println(count);
    }

    @Test
    public void test3(){
        String sql="delete from emp where ename=?";
        int count = template.update(sql, "mark");
        System.out.println(count);
    }

    @Test
    public void test4(){
        String sql="select * from emp where ename = ?";
        Map<String, Object> map = template.queryForMap(sql, "SMITH");
        System.out.println(map);
    }

    //expected 1, actual 2
    //queryForMap()查询的结果只能是1
    @Test
    public void test5(){
        String sql="select * from emp where ename = ? or ename = ?";
        Map<String, Object> map = template.queryForMap(sql, "SMITH","WARD");
        System.out.println(map);
    }

    @Test
    public void test6(){
        String sql="select * from emp";
        List<Map<String, Object>> list = template.queryForList(sql);

        //iter快捷键
        for (Map<String, Object> stringObjectMap : list) {
            System.out.println(stringObjectMap);
        }
    }

    @Test
    public void test7(){
        String sql="select * from emp";
        List<Emp> list = template.query(sql, new RowMapper<Emp>() {
            @Override
            public Emp mapRow(ResultSet rs, int i) throws SQLException {
                Emp emp = new Emp();
                int empno = rs.getInt("empno");
                String ename = rs.getString("ename");
                String job = rs.getString("job");
                int mgr = rs.getInt("mgr");
                Date hiredate = rs.getDate("hiredate");
                double sal = rs.getDouble("sal");
                double comm = rs.getDouble("comm");
                int deptno = rs.getInt("deptno");

                emp.setEmpNO(empno);
                emp.setEName(ename);
                emp.setJob(job);
                emp.setMgr(mgr);
                emp.setHireDate(hiredate);
                emp.setSal(sal);
                emp.setComm(comm);
                emp.setDeptNo(deptno);

                return emp;
            }
        });

        for (Emp emp : list ) {
            System.out.println(emp);
        }
    }

    @Test
    public void test7_2(){
        String sql="select * from emp";
        List<Emp> list = template.query(sql, new BeanPropertyRowMapper<Emp>(Emp.class));
        for (Emp emp : list) {
            System.out.println(emp);
        }
    }

    @Test
    public void test8(){
        String sql="select count(empno) from emp";
        Long total = template.queryForObject(sql,long.class);
        System.out.println(total);
    }
}

posted @   风吹头蛋凉OvO  阅读(53)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示