JDBC基础知识

JDBC

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

  • JDBC本质:官方定义的一套接口(规则),用于操作所有关系型数据库。各个数据库厂商去实现这个接口,提供数据库驱动jar驱动包。

    ==使用这套接口编程,真正执行的代码是驱动jar包中的实现类==

  • 导包步骤

    • 导入驱动jar包 mysql-connector-java-5.1.37-bin.jar
    • 复制mysql-connector-java-5.1.37-bin.jar到项目的libs目录下
    • 右键-->Add As Library // 添加成库
  • 实现代码

//**初学者代码,有许多不足,需要修改!!!**

public class JdbcDemo1_1 {
    public static void main(String[] args) throws Exception {
//      注册驱动
        Class.forName("com.mysql.jdbc.Driver");
//      获取数据库路径
        String url = "jdbc:mysql:///db3";
//      获取数据库连接对象
        Connection conn = DriverManager.getConnection(url, "root", "root");
//      获取执行sql的对象Statement
        Statement stat = conn.createStatement();
//      写sql语句
        String sql = "update account set balance = 505 where id = 1";
//      通过statement对象调用excuteUpdate执行sql语句
        int count = stat.executeUpdate(sql);
//      输出影响条数
        System.out.println(count);
//      释放资源
        stat.close();
        conn.close();
    }
}

详解对象

  • DriverManager : 驱动管理对象

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

    com.mysql.jdbc.Driver类中存在这样的静态代码块源码:

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

    由此可见,真正注册驱动的是com.mysql.jdbc.Driver类。

    ==注意:mysql5之后的驱动jar包可以省略注册驱动的步骤。==

    • 获取数据库连接
    Connection conn = DriverManager.getConnection(url, user, password);
    

    url:指定连接的路径

    语法: jdbc:mysql://ip地址(域名):端口号/数据库名称

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

    ==注意: 在实际开发中并不推荐采用registerDriver方法注册驱动==

    原因:

    1. 查看Drive的源码可以看到,如果采用此方法,会导致驱动程序注册两次,也就是在内存中会有两个Driver对象。
    2. 程序依赖MySql的API,脱离MySql的jar包,程序将无法编译,将来程序切换底层数据库将会非常麻烦。

  • Connection:数据库连接对象

    • 获取执行SQL的对象Statement
    • createStatement() : 创建向数据库发送sql的statement对象
    • preparedStatement( sql ) : 创建向数据库发送预编译 sql 的PreparedStatement 对象。
    • prepareCall(sql):创建执行存储过程的callableStatement对象。
    • setAutoCommit(boolean autoCommit):设置事务是否自动提交。(false为手动,即开启事务)
    //Statement createStatement()
    Statement stat = connection.createStatement();
    //PreparedStatement prepareStatement(String sql)  
    PreparedStatement p = connection.prepareStatement(sql);
    
    • 管理事务
    //开启事务,调用该方法设置参数为false,即开启事务
    setAutoCommit(boolean autoCommit);
    //提交事务
    commit();
    //回滚事务
    rollback();
    

  • Statement : 执行SQL的对象

    • execute(String sql):执行任意的sql
    boolean execute(String sql);
    
    • executeUpdate(String sql):执行DML(insert、update、delete),DDL(create,alter、drop ) 语句
    int executeUpdate(String sql);
    //返回值:影响的行数,可以通过这个影响的行数判断DML语句是否执行成功 
    //返回值>0的则执行成功,反之,则失败。
    
    • executeQuery(String sql) :执行DQL(select )语句
    ResultSet executeQuery(String sql);
    

  • ResultSet : 结果集对象,封装查询结果

    • next()方法:
     while(rs.next()){
        int id = rs.getInt(1);
        String name = rs.getString("name");
        double balance = rs.getDouble(3);
        System.out.println(id + "---" + name + "---" + balance);
    }
    // 判断游标是否还有下一行,有的话返回值为true
    // 当调用 next 方法返回 false 时,光标位于最后一行的后面
    
    • Previous():移动到前一行
    • absolute(int row):移动到指定行
    • beforeFirst():移动resultSet的最前面。
    • afterLast() :移动到resultSet的最后面。

  • 释放资源
    • JDBC程序运行完之后,切记要释放资源,在运行过程中,创建的那些与数据库交互的对象,比如ResultSet,Statement(包括他的子类PreparedStatement)和Connection对象,特别是Connection对象是非常稀有的资源,用完必须马上释放掉,否则极易导致系统宕(dang<第四声>)机。

练习案例:

  • 定义一个方法,查询emp表的数据将其封装为对象,然后装载集合,返回。
import itcast.domain.Emp;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/*
   需求:* 定义一个方法,查询emp表的数据将其封装为对象,然后装载集合,返回。
                1. 定义Emp类
                2. 定义方法 public List findAll(){}
                3. 实现方法 select * from Emp;
 */
public class JdbcDemo4 {
    public static void main(String[] args) {

        List all = new JdbcDemo4().findAll();
        for (Emp emp : all) {
            System.out.println(emp.getId()+"|\t"+emp.getEname()+"|\t"+emp.getJob_id()+"|\t"+emp.getMgr()+"|\t"+emp.getJoindate()+"|\t"+emp.getSalary()+"|\t"+emp.getBonus()+"|\t"+emp.getDept_id());
        }
    }
    public List findAll(){
        //define and init connection 
        Connection connection = null;
        //define and init statement
        Statement statement = null;
        //define and init resultSet
        ResultSet resultSet = null;
        //definr and init List
        List list = null;
        try {
            //register Drive
            Class.forName("com.mysql.jdbc.Driver");
            //define path
            String url = "jdbc:mysql:///db3";
            //obtain connection from DriverManager--use the method which is getConnection(url,user,password)
            connection = DriverManager.getConnection(url, "root", "admin");
            //obtain execute sql object statement
            statement = connection.createStatement();
            //write sql 
            String sql = "select * from emp";
            //invoking executeQuery to execute sql statement
            resultSet = statement.executeQuery(sql);

            Emp emp = null;
            list = new ArrayList<>();
            //judge whether there is the next line cursor
            while (resultSet.next()){
                //obtain values
                int id = resultSet.getInt(1);
                String ename = resultSet.getString(2);
                int job_id = resultSet.getInt(3);
                int mgr = resultSet.getInt(4);
                Date joindate = resultSet.getDate(5);
                double salary = resultSet.getDouble(6);
                double bonus = resultSet.getDouble(7);
                int dept_id = resultSet.getInt(8);
                //setting emp values
                emp = new Emp();
                emp.setId(id);
                emp.setEname(ename);
                emp.setJob_id(job_id);
                emp.setMgr(mgr);
                emp.setJoindate(joindate);
                emp.setSalary(salary);
                emp.setBonus(bonus);
                emp.setDept_id(dept_id);

                list.add(emp);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            if(resultSet!=null){
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(statement!=null){
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(connection!=null){
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        return list;
    }
}


  • PreparedStatement : 执行sql的对象

    • 它是Statement的子类

    • PreparedStatement的优点:

      • 避免SQL注入问题

      • Statement会使数据库频繁编译SQL,可能造成数据库缓冲区溢出。

        而PreparedStatement可以对SQL进行预编译,从而提高数据库的执行效率。

      • PreparedStatement允许使用占位符替换sql语句中的参数,简化sql语句编写。

    • SQL注入问题

      在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。可以直接绕过账号密码的验证,会造成安全性问题。

    • SQL注入问题解决办法

      使用PreparedStatment对象来解决


抽取JDBC工具类:JDBCUtils

  • 分析:
    • 抽取方法释放资源
    • 注册驱动也抽取
    • 抽取一个方法获取连接对象
  • 不想传递参数(麻烦),还得保证工具类的通用性。

JDBCUtils类

package itcast.jdbc;

import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

/*
  工具类
 */
public class JDBCUtils {
    private static String url;
    private static String user;
    private static String password;
    private static String driver;

    //注册驱动一次就好,所以使用静态代码块
    static {
        //1.创建Properties集合类
        Properties properties = new Properties();
        ClassLoader classLoader = JDBCUtils.class.getClassLoader();
        InputStream resourceAsStream = classLoader.getResourceAsStream("pro.properties");
        try {
            properties.load(resourceAsStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        url = properties.getProperty("url");
        user = properties.getProperty("user");
        password = properties.getProperty("password");
        driver = properties.getProperty("driver");

        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    //连接
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url, user, password);

    }

    //executeUpdate释放资源
    public static void close(Statement statement, Connection connection) {

        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    //    executeQuary释放资源
    public static void close(ResultSet resultSet, Statement statement, Connection connection) {

        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }

}

配置文件

url = jdbc:mysql:///db3
user = root
password = admin
driver=com.mysql.jdbc.Driver

案例:使用JDBCUtils工具类完成以下需求

  1. 通过键盘录入用户名和密码
  2. 判断用户是否登录成功

JdbcDemo6类

package itcast.jdbc;

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

public class JdbcDemo6 {
    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        System.out.println("请输入账号:");
        String username = sc.nextLine();
        System.out.println("请输入密码:");
        String password = sc.nextLine();

        boolean flag = new JdbcDemo6().login(username, password);

        if (flag) {
            System.out.println("登陆成功");
        } else {
            System.out.println("用户名或密码错误!");
        }

    }

    //    方法体:判断登陆
    public boolean login(String username, String password) {
        if (username == null || password == null) {
            return false;
        }
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;

        try {
            connection = JDBCUtils.getConnection();
            String sql = "select * from user where username = ? and password = ? ";
            preparedStatement = connection.prepareStatement(sql);

            preparedStatement.setString(1, username);
            preparedStatement.setString(2, password);

            resultSet = preparedStatement.executeQuery();

            return resultSet.next();


        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(resultSet, preparedStatement, connection);
        }
        return false;
    }
}

配置文件

url = jdbc:mysql:///db4
user = root
password = admin
driver=com.mysql.jdbc.Driver

JDBC控制事务:

代码:

public class JDBCDemo10 {

    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 - ? where id = ?";
            //2.2 李四 + 500
            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 {
                if(conn != null) {
                    conn.rollback();
                }
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        }finally {
            JDBCUtils.close(pstmt1,conn);
            JDBCUtils.close(pstmt2,null);
        }
    }
}

你可能感兴趣的:(JDBC基础知识)