Javaweb day5 JDBC

今日内容

  1. JDBC基本概念
  2. 快速入门
  3. 对JDBC中各个接口和类详解

在这里插入图片描述

JDBC:

  1. 概念:Java DataBase Connectivity Java 数据库连接, Java语言操作数据库
    * JDBC本质:其实是官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。
  2. 快速入门:
    • 步骤:
      1. 导入驱动jar包 mysql-connector-java-5.1.37-bin.jar
      2. 注册驱动 Class.forname载入注册
      3. 获取数据库连接对象 Connection
      4. 定义sql
      5. 获取执行sql语句的对象 Statement
      6. 执行sql,接受返回结果
      7. 处理结果
      8. 释放资源

代码实现:

public static void main(String[] args)   {
        //1. 导入驱动jar包
        //2. 注册驱动
        Statement sta=null;
        Connection conn=null;
        try {
            //1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            String sql="insert into account values(null,'王五',3000)";
            //2.获取连接对象
            conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/db3",
                    "root","CR123123");
            //3.定义sql
            //4.获取执行sql对象
            sta=conn.createStatement();
            //5. 执行sql
            int count=sta.executeUpdate(sql);
            System.out.println(count);
            if(count>0)
            {
                System.out.println("成功");
            }
            else
                System.out.println("失败");
        }
        catch (ClassNotFoundException | SQLException e){
            e.printStackTrace();
        }
        finally{
            if(sta!=null){
                try {
                    sta.close();
                }
                catch (SQLException E){
                    E.printStackTrace();
                }
            }
            if(conn!=null){
                try {
                    sta.close();
                }
                catch (SQLException E){
                    E.printStackTrace();
                }
            }
        }
    }
  1. 详解各个对象:
    1. DriverManger:驱动管理对象
      功能:
      1. 注册驱动:告诉程序应该使用哪一个数据库驱动jar(如例子中使用的是Mysql数据库驱动

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

      但是在实际写代码时却用的是

      `Class.forName("com.mysql.jdbc.Driver");
      

      通过查看com.mysql.Driver类存在静态代码块,在执行Class.forname函数时会自动执行类的静态代码块。存在的静态代码块是

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

      这样一目了然。
      而mysql5之后的驱动jar包可以省略注册驱动的步骤。
      原因:在mysql5以后导入jar包后
      在这里插入图片描述
      会自动生成java.sq.Driver文件
      文件内容:
      在这里插入图片描述
      当你没有写注册驱动的代码时,系统会自动帮你读取到该文件,自动完成注册。

      1. 获取数据库连接:
      2. 方法:static Connection getConnection(String url, String user, String password)
        参数:
        • url:指定连接的路径

          • 语法:jdbc:mysql://ip地址(域名):端口号/数据库名称
          • 例子:jdbc:mysql://localhost:3306/db3

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

        1. user:用户名
        2. password:密码
    2. Connection:数据库连接对象

      1. 功能:
        1. 获取执行sql的对象:
          Statement CreateStatement();
          PreparedStatement prepareStatement(String sql)
        2. 管理事务:
          1. 开启事务:
            SetAutoCommit(boolean autoCommit):调用该方法设置参数为false,即开启事务
          2. 提交事务
            commit()
          3. 回滚事务:rollback();
            一般在try catch finally中
            在finally中进行回滚操作
    3. Statement:
      执行sql的对象

      1. boolean execute(String sql):执行任意的sql

      2. int executeupdate(String sql):执行DML(iinsert update delete)语句 和DDL(create ,alter ,drop)语句
        返回值 :数据库中表的影响的行数,可以通过这个影响的行数判断DML语句是否执行成功 返回值>0的则执行成功,反之,则失败。

      3. ResultSet executeQuery(String sql):
        执行DQL(select)语句:
        练习:

            public static void main(String[] args)   {
                //1. 导入驱动jar包
                //2. 注册驱动
                Statement sta=null;
                Connection conn=null;
                try {
                    //1.注册驱动
                    Class.forName("com.mysql.jdbc.Driver");
                    String sql="insert into account values(null,'王五',3000)";
                    //2.获取连接对象
                    conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/db3",
                            "root","CR123123");
                    //3.定义sql
                    //4.获取执行sql对象
                    sta=conn.createStatement();
                    //5. 执行sql
                    int count=sta.executeUpdate(sql);
                    System.out.println(count);
                    if(count>0)
                    {
                        System.out.println("成功");
                    }
                    else
                        System.out.println("失败");
                }
                catch (ClassNotFoundException | SQLException e){
                    e.printStackTrace();
                }
                finally{
                    if(sta!=null){
                        try {
                            sta.close();
                        }
                        catch (SQLException E){
                            E.printStackTrace();
                        }
                    }
                    if(conn!=null){
                        try {
                            sta.close();
                        }
                        catch (SQLException E){
                            E.printStackTrace();
                        }
                    }
                }
            }
        
    4. ResultSet:结果集对象,封装查询结果

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

      2. getxxx(参数):

        1. Xxx:代表数据类型 如: int getInt() , String getString()
          1. int:代表列的编号,从1开始 如: getString(1)
          2. String:代表列名称。 如: getDouble(“balance”)
      3. 使用步骤:
        1. 游标向下移动一行
        2. 判断是否有数据
        3. 获取数据

         while(re.next()){
        	int id=re.getInt(1);
        	String name=re.getString("name");
        	double balance=re.getDouble("balance");
        	System.out.println(id+name+balance);
        	}		```
        
    练习:定义一个方法,查询emp表的数据将其封装为对象,然后装载集合,返回。
    1. 定义Emp类
    2. 定义方法 public List findAll(){}
    3. 实现方法 select * from emp;
String sql = "select * from emp";
            rs = st.executeQuery(sql);
            list=new ArrayList<>();
            while (rs.next()) {
                emp=new Emp();
                int id = rs.getInt(1);
                String name = rs.getString(2);
                int job_id = rs.getInt(3);
                int mgr = rs.getInt(4);
                Date date = rs.getDate(5);
                double salary = rs.getDouble(6);
                double bonus = rs.getDouble(7);
                int dept_id = rs.getInt(8);
                emp.setId(id);
                emp.setEname(name);
                emp.setJob_id(job_id);
                emp.setMgr(mgr);
                emp.setJoindate(date);
                emp.setSalary(salary);
                emp.setBonus(bonus);
                emp.setDept_id(dept_id);
                list.add(emp);
            }
  1. PreparedStatement:执行sql的对象
    1. SQL注入问题:就是在拼接sql的时候,有一些sql的特殊关键字参与字符串的拼接。会造成安全性问题

      1. 如sql:select * from user where username = ‘fhdsjkf’ and password = ‘a’ or ‘a’ = ‘a’
        ‘a’ = ‘a’ 结果是true,因此会使得用户成功登录
    2. 解决sql注入问题:使用PreparedStatement对象来解决

    3. 预编译的SQL:参数使用?作为占位符

    4. 步骤

      1. 导入驱动jar包 mysql-connector-java-5.1.37-bin.jar
      2. 注册驱动
      3. 获取数据库连接对象 Connection
      4. 定义sql
        * 注意:sql的参数使用?作为占位符。 如:select * from user where username = ? and password = ?;
      5. 获取执行sql语句的对象 PreparedStatement Connection.prepareStatement(String sql)
      6. 给?赋值:
        * 方法: setXxx(参数1,参数2)
        * 参数1:?的位置编号 从1 开始
        * 参数2:?的值
      7. 执行sql,接受返回结果,不需要传递sql语句
        8. 处理结果
        9. 释放资源
    5. 注意:后期都会使用PreparedStatement来完成增删改查的所有操作
      1. 可以防止SQL注入
      2. 效率更高,在Mysql中
      (缓存机制中有预编译语句,如果查询语句的结构相同,就不会去再进行编译,而是进行一些参数的替换,这样就会提高效率,但是在进行con.prepareStatement(sql)和prst.executeUpdate()中会进行两次访问数据库操作,第一次是解析和优化这个查询,第二次是进行查询操作,如果该数据库是以分布式为架构的话,实际上网络请求成本也许会大于查询的效率优化。实际上Statement的执行,不一定是没有缓存的,而恰恰相反, 现在大多数的数据库软件的查询分析模块, 会透明的在第一次执行 像insert into tb_name (col1,col2) values (‘11’,‘22’) 这样的sql简单语句时将其转化为 insert into tb_name (col1,col2) values (?,?), 为后面重复执行缓存优化。 当然不同的数据库实现的策略是不同的

      相关的资料见解请参考
      [PreparedStatement效率为什么高/为什么要使用PreparedStatement代替Statement]

抽取JDBC工具类 : JDBCUtils

  • 目的:简化书写
    • 分析:
      1. 注册驱动也抽取
      2. 抽取一个方法获取连接对象
        * 需求:不想传递参数(麻烦),还得保证工具类的通用性。
        * 解决:配置文件
        jdbc.properties
        url=
        user=
        password=
      3. 抽取一个方法释放资源
package JDBC;

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

public class JDBCutills {
    /**
     * 获取连接
     * @ return 连接对象
     */
     private static String url;
     private static String user;
     private static String password;
     private static String Driver;
    static {
        try{
          Properties p=new Properties();
            ClassLoader classLoader = JDBCutills.class.getClassLoader();
            URL resource = classLoader.getResource("jdbc.properties");
            String path = resource.getPath();
            System.out.println(path);
            p.load(new FileReader(path));
            url = p.getProperty("url");
           user = p.getProperty("user");
           password = p.getProperty("password");
           Driver = p.getProperty("driver");
           Class.forName(Driver);
        }
        catch(IOException| ClassNotFoundException E){
            E.printStackTrace();
        }
    }
    public static Connection getConnection() throws SQLException{

            return DriverManager.getConnection(url,user,password);
    }
    public static void close(Statement st, Connection c, ResultSet rs){
            if (c != null) {
                try {
                    c.close();
                }
                catch (SQLException E) {
                    E.printStackTrace();
                }
            }

            if (st != null){
                try {
                    st.close();
                }
                catch (SQLException E) {
                    E.printStackTrace();
                }
            }
            if (rs!=null) {
                try {
                    rs.close();
                }
                catch (SQLException E) {
                    E.printStackTrace();
                }
            }
    }

}
  • 练习:
    * 需求:
    1. 通过键盘录入用户名和密码
    2. 判断用户是否登录成功
    * select * from user where username = “” and password = “”;
    * 如果这个sql有查询结果,则成功,反之,则失败
public class exercise {
    /**
     * 登录方法
     */


    public Boolean login(String username, String password) {
        if (username == null || password == null) {
            return false;
        }
        Connection c = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            Connection connection = JDBCutills.getConnection();
            String sql = "SELECT * from user where username =? and password=?";
            ps= connection.prepareStatement(sql);
            ps.setString(1,username);
            ps.setString(2,password);
            rs = ps.executeQuery();
            return rs.next();
        } catch (SQLException E) {
            E.printStackTrace();
        } finally {
            JDBCutills.close(ps, c, rs);
        }
        return false;
    }

    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 exercise().login(username, password);
        //3.判断结果,输出不同语句
        if(flag){
            //登录成功
            System.out.println("登录成功!");
        }else{
            System.out.println("用户名或密码错误!");
        }
    }

}

使用Connection对象来管理事务

  • 开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务
    * 在执行sql之前开启事务
  • 提交事务:commit()
    * 当所有sql都执行完提交事务
  • 回滚事务:rollback()
    * 在catch中回滚事务
 try{
            c=JDBCutills.getConnection();
            c.setAutoCommit(false);
            String sql1="update account set balance=balance-? where id=?";
            String sql2="update account set balance=balance+? where id=?";
            p1 = c.prepareStatement(sql1);
            p2 = c.prepareStatement(sql2);
            p1.setInt(1,500);
            p1.setInt(2,1);
            p2.setInt(1,500);
            p2.setInt(2,2);
            p1.executeUpdate();
            //手动制造异常
            p2.executeUpdate();
            c.commit();
        }
        catch (Exception E){
            if(c!=null) {
                try {
                    c.rollback();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            E.printStackTrace();
        }
        finally {
            JDBCutills.close(p1, c, null);
            JDBCutills.close(p2, c, null);
        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值