初识Java中的JDBC

JAVA中的JDBC

JDBC
  • 概念: Java DataBase Connectivity (java数据库链接),java语言操作数据库

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

  • 快速入门

    • 步骤
      1. 导入驱动jar包:mysql-connector-java
        1. 复制jar包到项目的libs目录下
        2. 右键 add as llibrary
      2. 注册驱动
      3. 获取数据库链接对象 Connection
      4. 定义sql
      5. 获取执行sql语句对象 Statement
      6. 执行sql,接受返回结果
      7. 处理结果
      8. 释放资源

    代码:

        public static void main(String[] args) {
            Connection conn = null;
            Statement stmt = null;
            try {
                /*注册驱动*/
                Class.forName("com.mysql.jdbc.Driver");
                /*获取链接*/
                conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc", "root", "root");
                /*定义sql*/
                String sql = "delete from jdbc where id = 1";
                /*获取执行sql对象*/
                stmt = conn.createStatement();
                /*执行sql,返回值为影响的行数*/
                int i = stmt.executeUpdate(sql);
                if (i > 0) {
                    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 (stmt!=null){
                    try {
                        conn.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
  • 详解各个常用对象

    • DriverManager:驱动管理对象

      1. 功能:

        1. 注册驱动:告诉程序该使用哪一个数据库的驱动jar包

          大家可能有疑问:注册驱动不是Class.forName(“com.mysql.jdbc.Driver”)?为什么DriverManager可以注册驱动?那么他们有什么关系呢?

          在DriverManager类下有一个方法registerDriver(),他可以注册驱动

          static void registerDriver(Driver driver):
          /*注册与给定的驱动程序
          写代码使用Class.forName("com.mysql.jdbc.Driver");
          */
          

          我们再来想一下Class.forName()被调用就可以完成注册驱动的动作,那么有什么方式可以随着类的加载而自动执行,回答是肯定的,静态代码块

          带着疑问我们再来查看Driver源码 发现:在Driver类中果然存在静态代码块

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

          由此可以看出真正执行注册驱动的动作是 DriverManager.registerDriver(new Driver()),我们写Class.forName(“com.mysql.jdbc.Driver”)比较简单

          注意:在mysql5版本之后注册驱动可以省略

        2. 获取数据链接:

          1. 方法:getConnection()

          2. 参数:

            1. url:指定连接路径

              语法(每个数据库语法不同,以mysql为例):jdbc:mysql://ip(域名):端口号/数据库名称

              如果链接本机mysql服务器,并且mysql默认端口3306,则url可以省略为:jdbc:mysql:///数据库名称

            2. user:用户名

            3. password:密码

    • Connection:数据库链接对象

      1. 功能:获取执行sql对象
        1. Statement createStatement()
        2. PreparedStatement prepareStatement(String sql)
      2. 管理事务:
        1. 开启事务:setAutoCommit(boolean autoCommit) --调用该方法设置参数为false,即开启事务
        2. 提交事务:commit()
        3. 回滚事务rollback()
    • Statement:执行sql对象

      1. 执行sql常用方法
        1. boolean execute(String sql):可以执行任意sql
        2. int executeUpdate(String sql) :执行DML语句,DDL语句,返回值为int表示影响的行数,可以通过这个返回值判断sql是否执行成功
        3. ResultSet executeQuery(String sql) :执行DQL语句
    • ResultSet:结果集对象,封装查询结果

      1. boolean next():将游标向下移动一行,判断当前行是否为最后一行末尾(是否有数据),如果是最后一行返回flase,反之返回turn

        ResultSet对象牵扯到游标的概念(类似指针),游标看做默认指向表头(列名行),要想取出ResultSet对象中查询到的数据,需要将游标向下移动,每移动一行取出一行的数据需要用到next方法:

      2. getXxx(参数):获取数据

        • Xxx表示数据类型 如:getInt,getString…
        • 参数:
          1. int:代表列的编号(数字代表第几列)
          2. String:代表列名称
      3. 注意:

        1. 使用步骤:
          1. 游标向下移动一行
          2. 判断是否有数据
          3. 获取数据
           public static void main(String[] args) {
           Connection conn = null;
           Statement stmt = null;
           ResultSet rs = null;
           try {
               /*注册驱动*/
               Class.forName("com.mysql.jdbc.Driver");
               /*获取链接*/
               conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc", "root", "root");
               /*定义sql*/
               String sql = "select * from user";
               /*获取执行sql对象*/
               stmt = conn.createStatement();
        
               /*执行sql*/
               rs = stmt.executeQuery(sql);
               while (rs.next()) {
                   int uid = rs.getInt("uid");
                   String username = rs.getString("username");
                   int money = rs.getInt("money");
                   System.out.println("uid: " + uid + "username: " + username + "money: " + money);
        
               }
           } catch (ClassNotFoundException e) {
               e.printStackTrace();
           } 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

           public class JdbcUtils {
      
         private static String url;
         private static String user;
         private static String password;
         private static String driver;
      
         static {
             try {
                 Properties pro = new Properties();
      
                 ClassLoader classLoader = JdbcUtils.class.getClassLoader();
      
                 InputStream is = classLoader.getResourceAsStream("jdbc.properties");
                 pro.load(is);
      
                 url = pro.getProperty("url");
                 user = pro.getProperty("user");
                 password = pro.getProperty("password");
                 driver = pro.getProperty("driver");
      
                 Class.forName(driver);
             } catch (Exception e) {
                 e.printStackTrace();
             }
         }
      
         public static Connection getConnection() throws SQLException {
             return DriverManager.getConnection(url, user, password);
         }
      
         public static void close(Connection conn, Statement stat, ResultSet rs) {
             if (rs != null) {
                 try {
                     rs.close();
                 } catch (SQLException e) {
                     e.printStackTrace();
                 }
             }
      
             if (stat != null) {
                 try {
                     stat.close();
                 } catch (SQLException e) {
                     e.printStackTrace();
                 }
             }
      
             if (conn != null) {
                 try {
                     conn.close();
                 } catch (SQLException e) {
                     e.printStackTrace();
                 }
             }
         }
      }
      
    PreparedStatement:执行sql对象
    1. sql注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接,会造成安全问题

    2. 解决sql注入问题:使用PreparedStatement对象

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

    4. 步骤

      1. 导入驱动jar包:mysql-connector-java

        1. 复制jar包到项目的libs目录下
        2. 右键 add as llibrary
      2. 注册驱动

      3. 获取数据库链接对象 Connection

      4. 定义sql

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

        如:select * from user where id = ?

      5. 获取执行sql语句对象 PreparedStatement

        Connection.preparedStatement(String sql)

      6. 给?赋值:

        方法: setXxx(参数1,参数2)

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

        参数2:?的值

      7. 执行sql,接受返回结果,不需要传递参数

      8. 处理结果

      9. 释放资源

    5. 注意:后期都会使用preparedStatement来完成赠三改查的所有操作

      1. 可以防止sql注入
      2. 效率更高
    public static void main(String[] args) {
            User user = new User();
            Connection conn = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
    
            try {
                /*获取链接*/
                conn = JdbcUtils.getConnection();
                
                /*获取预编译执行sql对象*/
                ps = conn.prepareStatement("select * from user where uid = ?");
                
                /*为?赋值*/
                ps.setInt(1,1);
                
                /*执行sql*/
                rs = ps.executeQuery();
    
                if (rs.next()) {
                    /*获取查询信息*/
                    int uid = rs.getInt("uid");
                    String username = rs.getString("username");
                    int money = rs.getInt("money");
    
                    /*将信息存入user对象*/
                    user.setUid(uid);
                    user.setUsername(username);
                    user.setMoney(money);
                    
                    /*打印控制台*/
                    System.out.println(user);
    
                }
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                
                /*释放资源*/
                JdbcUtils.close(conn, ps, rs);
            }
    

    如果查询结果为多条,可以使用while循环来获取/存入数据

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

    /**
         * 转账的案例
         *
         * @param args
         */
            public static void main(String[] args) {
            Connection conn = null;
            PreparedStatement ps1 = null;
            PreparedStatement ps2 = null;
    
            try {
                conn = JdbcUtils.getConnection();
    
                /*修改zhangsan用户金额减500*/
                ps1 = conn.prepareStatement("update user set money = money + ? where username = ?");
                ps1.setInt(1, -500);
                ps1.setString(2, "zhangsan");
    
    
                /*修改lisi用户金额加500*/
                ps2 = conn.prepareStatement("update user set money = money + ? where username = ?");
                ps2.setInt(1, 500);
                ps2.setString(2, "lisi");
    
                /*执行sql*/
                ps1.executeUpdate();
                
                /*设置一个异常*/
                int i = 1 / 0;
                ps2.executeUpdate();
    
            } catch (SQLException e) {
                e.printStackTrace();
            }finally {
                /*释放资源*/
                JdbcUtils.close(conn,ps1,null);
                JdbcUtils.close(null,ps2,null);
            }
        }
    
    

    通过代码发现:zhangsan用户金额已减,但是lisi却没有增加,我们期望的结果:如果转账过程中出现任何异常,所有用户的数据不发生改变,如果其中一个发生改变就都会改变.那么我们需要事务的控制

  • 操作:

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

    • 开启事务:setAutoCommit(boolean autoCommit) --调用该方法设置参数为false,即开启事务
      • 在执行sql之前开启事务
    • 提交事务:commit()
      • 当所有sql都执行完之后
    • 回滚事务:rollback()
      • 在catch中回滚事务
    /**
         * 转账的案例
         *
         * @param args
         */
            public static void main(String[] args) {
            Connection conn = null;
            PreparedStatement ps1 = null;
            PreparedStatement ps2 = null;
    
            try {
                conn = JdbcUtils.getConnection();
                /*开启事务*/
                conn.setAutoCommit(false);
                /*修改zhangsan用户金额减500*/
                ps1 = conn.prepareStatement("update user set money = money + ? where username = ?");
                ps1.setInt(1, -500);
                ps1.setString(2, "zhangsan");
    
    
                /*修改lisi用户金额加500*/
                ps2 = conn.prepareStatement("update user set money = money + ? where username = ?");
                ps2.setInt(1, 500);
                ps2.setString(2, "lisi");
    
                /*执行sql*/
                ps1.executeUpdate();
                
                /*设置一个异常*/
                int i = 1 / 0;
                ps2.executeUpdate();
    
                /*提交事务*/
                conn.commit();
            } catch (SQLException e) {
                try {
                    /*回滚事务*/
                    conn.rollback();
                } catch (SQLException e1) {
                    e1.printStackTrace();
                }
                e.printStackTrace();
            }finally {
                /*释放资源*/
                JdbcUtils.close(conn,ps1,null);
                JdbcUtils.close(null,ps2,null);
            }
        }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值