JDBC:Connection链接,Statement方法。链接的封装。PreparedStatement预编译。事务回滚。

本文介绍了JDBC中的Connection连接数据库的基本操作,包括加载驱动、获取连接和执行SQL。接着讲解了Statement对象的使用,并对比了PreparedStatement的预编译特性,强调其在防止SQL注入和提高效率上的优势。最后,文章探讨了JDBC事务管理,包括如何设置手动提交、回滚事务以及使用保存点。

一。JDBC: Java DataBase Connective 是 Java连接数据库的规范 - 接口

  • java.sql -> JDBC 规范相关的接口,类 实现类: 各个数据库厂商来提供

  • 1.Connection - 连接
    a.引入jar包
    mysql-connector-java-5.1.8-bin.jar
    推荐数据库版本: 5.5 5.7 5.x
    mysql-connector-java-8.0.16.jar
    推荐数据库版本: 8.x
    b.加载驱动 - 类
    Class.forName(“驱动类名”);
    oracle: oracle.jdbc.driver.OracleDriver
    mysql: com.mysql.jdbc.Driver
    c.获得连接
    DriverManager.getConnection(url, username, password);
    url: jdbc:mysql://ip:port/database?serverTimezone=GMT
    username: 账号
    password: 密码
    d.获得执行SQL语句的Statement对象
    e.执行SQL, 获得结果 boolean int ResultSet
    f.释放资源

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class Demo1 {
    public static void main(String[] args) {
        //加载驱动
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");// cj 控制台升级
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
//建立连接
        try {
             /*
            账号或密码错误:SQLException: Access denied for user 'liuliudr'@'localhost' (using password: YES)
            时区错误:java.sql.SQLException: The server time zone value
            port错误:java.net.ConnectException:
            ip错误:UnknownHostException
            
            可能产生异常: SQLException
                 1.dataBase 指定错误
                 2.账号/密码错误
                 3.端口错误 -> Connection refused
                 4.ip错误 -> Network is unreachable
                 5.jdbc:mysql 错误 -> No suitable driver
                   结论: 连接数据库url需要匹配合适的驱动类
             */
            // url:(jdbc:mysql://ip:port/database?serverTimezone=GMT),user,password;
            Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/work01?serverTimezone=GMT","liuliudr","123456");
            // url也可写成jdbc:mysql:///database前提是localhost

            //System.out.println(conn);

            /*
            Statement 中:
            boolean execute(String sal)
            执行DDL DQL 返回 false,执行DCL返回true。返回值看他有没有结果
             */
            Statement statement = conn.createStatement();
            //DDL
            String sql="create table sks(id int(10) primary key auto_increment,name varchar(20));";
            statement.execute(sql);
            //DQL
            String sql1="insert into sks value(1,'黑土');";
            statement.execute(sql1);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
}
    1. Statement 中执行sql语句的方法有三个

          boolean execute(String sql)
              DDL DML: 返回false    DQL: 返回true
              因为DML 和 DQL有专门的执行方法, 所以该方法通常用来执行DDL
              返回值: 有没有结果
          int executeUpdate(String sql)
              只能执行 DML
              返回值: 影响了几行
          ResultSet executeQuery(String sql)
              只能执行 DQL
              返回值: 查询出来的结果集
      
 @Test
    public void testDML() {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db_day01", "root", "root");
            Statement stmt = conn.createStatement();
            // 5.执行sql语句  DDL DML DQL
            // 执行DML
            String sql = "insert into u values(1, 'lucy')";
            boolean b = stmt.execute(sql); // false
            System.out.println(b);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }

    @Test
    public void testDQL() {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db_day01", "root", "root");
            Statement stmt = conn.createStatement();
            // 5.执行sql语句  DDL DML DQL
            // 执行DQL
            String sql = "select * from u ";
            boolean b = stmt.execute(sql); // true
            System.out.println(b);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
    @Test
    public void testDML2() {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db_day01", "root", "root");
            Statement stmt = conn.createStatement();
            // 5.执行sql语句  DDL DML DQL
            // 执行DML
            String sql = "insert into u values(2, 'tom')";
            int i = stmt.executeUpdate(sql); // 1
            System.out.println(i);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
    
    1. ResultSet rs = stmt.executeQuery(sql); // 返回结果集
      rs.next(); // 询问有没有下一个,并且指针向后移动
      // ResultSet获得的数据 就是当前指针位置这一行的数据
      // 获得这一行第一列的数据
 @Test
    public void testDQL() {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/work01?serverTimezone=GMT", "liuliudr", "123456");
            Statement stmt = conn.createStatement();
            // 5.执行sql语句  DDL DML DQL
            // 执行DQL
            String sql1 = "select * from sks";
            /*
               将一整行数据作为一个整体, 并且存入ResultSet中
             */
            ResultSet rs = stmt.executeQuery(sql1); // 返回结果集
            rs.next(); // 询问有没有下一个,并且指针向后移动
            // ResultSet获得的数据 就是当前指针位置这一行的数据
            // 获得这一行第一列的数据
            int id1 = rs.getInt(1);
            String name1 = rs.getString(2);
            System.out.println(id1 + " -- " + name1);

            // 获得第二行数据
            boolean is = rs.next();
            int id2 = rs.getInt(1);
            String name2 = rs.getString(2);
            System.out.println(id2 + " -- " + name2);

            // 如果rs.next()超出会报错 After end of result set
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
      @Test
    public void testDQL3Finally() {
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/work01?serverTimezone=GMT", "liuliudr", "123456");
            stmt = conn.createStatement();
            // 5.执行sql语句  DDL DML DQL
            // 执行DQL
            String sql = "select id i, name from sks ";
            rs = stmt.executeQuery(sql); // 返回结果集
            while (rs.next()) {
                // ResultSet获得的数据 就是当前指针位置这一行的数据
                // 获得列名为 i 的值
                int id1 = rs.getInt("i");
                String name1 = rs.getString("name");
                System.out.println(id1 + " -- " + name1);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            // 6.释放资源 - finally
            JDBCUtil.close(conn, stmt, rs);
            /*try {
                // 避免空指针
                if (rs != null) {
                    rs.close();
                }
                stmt.close();
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }*/
        }
    }

二。链接的封装
封装文件和配置文件

1.分装
package Conne;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class JDBCUtil {//数据库连接封装
    //静态成员变量
    private static String driver;
    private static String url;
    private static String password;
    private static String user;

    //静态代码块读取内容
    static {
    /*
        Properties类表示了一个持久的属性集,它是在一个文件中存储键值对儿的,其中键值对儿以等号分隔。
        Properties可保存在流中或从流中加载。属性列表中的每个键及其所对应的值都是字符串。
        Properties类是线程安全的:多个线程可以共享单个Properties对象而无需进行外部同步。
         */
        Properties pro = new Properties();
        try {
            pro.load(JDBCUtil.class.getResourceAsStream("getResource.properties"));
            driver = pro.getProperty("driver");
            url = pro.getProperty("url");
            user = pro.getProperty("user");
            password = pro.getProperty("password");
            Class.forName(driver);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    //连接封装
    public static Connection getConnection() {
        Connection conn = null;
        try {
            conn = DriverManager.getConnection(url, user, password);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return conn;
    }

    //关闭方法封装1
    public static void close(Connection cn, Statement st, ResultSet rs) {

        try {

            if (rs != null) {
                rs.close();
            }
            if (cn != null) {
                cn.close();
            }
            if (st != null) {
                st.close();
            }

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }

    //关闭方法封装2
    public static void close(Connection cn, Statement st) {
        try {
            if (cn != null) {
                cn.close();
            }
            if (st != null) {
                st.close();
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
}
2.配置文件.properties
url=jdbc:mysql://localhost:3306/work01?serverTimezone=GMT
user=liuliudr
password=123456
driver=com.mysql.cj.jdbc.Driver

-------------------------------------------------------------

@Test
    //调用封装来驱动连接和关闭
    public void de5() {
        Connection conn = null;
        Statement statement = null;
        try {
            conn = JDBCUtil.getConnection();
            statement = conn.createStatement();
            //DCL
            String sql1 = "select * from sks";
            ResultSet rs = statement.executeQuery(sql1);
            while (rs.next()) {
                int id = rs.getInt("id");
                String name = rs.getString("name");
                System.out.println(id + "--" + name);
            }

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            JDBCUtil.close(conn, statement);
        }
    }

三。PreparedStatement预编译
1.PreparedStatement extends Statement

  • 给占位符传参
    1.有效防止SQL注入
    2.当多次执行相同的/相似的SQL, 只需要预编译一次, 而Statement需要编译多次, PreparedStatement效率更高
@Test
    public void de6() throws SQLException {
        //PreparedStatement在进行多次的类似的插入时,效率更快
        Connection connection = JDBCUtil.getConnection();  
        String sql = "insert into login(password,NAME) values(?,?);";
        //PreparedStatement预编译sql一次
        PreparedStatement stmt = connection.prepareStatement(sql);// SQLException抛出异常
        stmt.setString(1, "武松");
        stmt.setString(2, "黄菊");
        stmt.executeUpdate();//插入。此时执行sql一次
        }

2.设置节点和回滚

  • JDBC中的事务, 绑定在连接对象上的, 都是默认自动提交
    1.设置事务手动提交
    conn.setAutoCommit(false)
    2.代码正常结束, 提交事务
    conn.commit();
    3.代码出现异常, 回滚事务
    conn.rollback()
    4.了解:
    保存事务结点 SavePoint a = conn.setSavePoint();
    回滚到指定的结点 conn.rollback(a);
public class JDBCDemo06 {
    @Test
    public void testPreparedStatement() {
        Connection conn = JDBCUtils.getConnection();
        PreparedStatement stmt = null;
        try {
            conn.setAutoCommit(false); // 1.设置事务为手动提交
            String sql = "insert into user values(null,?,?,?,?)";
            // 预编译SQL, 一次
            stmt = conn.prepareStatement(sql);
            // 执行第一次sql - 传递一次参数
            stmt.setString(1, "赵六11");
            stmt.setInt(2, 28);
            stmt.setString(3, "2020-08-01");
            stmt.setString(4, "123");
            // 执行一次sql
            stmt.executeUpdate();

            // 保存当前事务结点 => savepoint a - 了解
//          Savepoint a = conn.setSavepoint();
            stmt.setString(1, "赵老六1");
            stmt.setInt(2, 28);
            stmt.setString(3, "2020-08-01");
            stmt.setString(4, "123");
            // 第二次执行SQL
            stmt.executeUpdate();
            // 事务提交
            conn.commit();
        } catch (Exception throwables) {
            // 事务回滚 -> 通常是在异常中回滚
            try {
                conn.rollback();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        } finally {
            JDBCUtils.close(stmt, conn);
        }

        // 了解
        // 回滚到保存的a结点中 => rollback to a
//        conn.rollback(a);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值