JDBC入门详细笔记

笔记根据此视频完成

个人博客链接:https://www.qingbo1011.top/ 点击此处前往

Java数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。JDBC是面向关系型数据库的。

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

(理解:Heart接口,Person实现类。Heart h = new Person()多态),执行h.beat,其实执行的是Person实现类中重写的beat方法)

JDBC入门

步骤

1.导入jar包

mysql-connector包已经提前下载好了

在项目中创建一个libs文件夹,将jar包复制到其中。

文件目录结构

注意要将复制的jar包导入驱动:

注意要将复制的jar包导入驱动

2.注册驱动

3.获取数据库连接对象

4.定义sql语句

5.执行sql的对象Statement

6.执行sql

7.处理结果

8.释放资源

例子:

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

public class Demo01 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        // 1.导入驱动jar包
        // 2.注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        // 3.获取数据库连接对象
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc_study", "root", "1234");
        // 4.定义sql语句
        String sql = "update employees set age = 30 where name = 'jay';";
        // 5.获取执行sql的对象Statement
        Statement statement = connection.createStatement();
        // 6.执行sql
        int count = statement.executeUpdate(sql);
        // 7.处理结果
        System.out.println("一共执行了"+count+"条数据");
        // 8.释放资源
        statement.close();
        connection.close();
    }
}

JDBC各个类分析

  • DriverManager:驱动管理对象
  • Connection:数据库连接对象
  • Statement:执行sql的对象
  • ResultSet:结果集对象,封装查询结果
  • PreparedStatement:执行sql的对象

DriverManager:驱动管理对象

功能:

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

static void registerDriver(Dirver driver):注册与给定的驱动DriverManager

使用时:Class.forName("com.mysql.jdbc.Driver");

源码:在com.mysql.jdbc.Driver类中的静态代码块如下:

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

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

原因:在META-INF文件夹下有以下文件:

2.获取数据库连接

方法:static Connection getConnection(String url,String user,String password)

三个参数

  • url:指定连接的路径
    • 语法:jdbc:mysql://ip地址(域名):端口号/数据库名称
    • 例子:jdbc:mysql://localhost:3306/jdbc_study
    • 细节:如果连接的是本地的mysql服务并且服务器默认端口是3306,则url可以简写为:jdbc:mysql:///数据库名称
  • user:用户名
  • password:密码

Connection:数据库连接对象

功能:

1.执行sql的对象

  • Statement createStatement()
  • PreparedStatement prepareStatement(String sql)

2.管理事务

  • 开启事务:setAutoCommit(boolean autoCommit)调用该方法设置参数为false,即开启事务
  • 提交事务:commit()
  • 回滚事务:rollback()

Statement:执行sql的对象

功能:

1.执行sql

  • boolean execute(String sql)可以执行任意的sql(了解)
  • int executeUpdate(String sql):执行DMLDDL语句。
    • 返回值:影响的行数,即操作的记录数。可以通过这个影响行数判断DML语句是否成功。返回值>0则表示执行成功,反之则失败。
  • ResultSet executeQuery(String sql):执行DQL语句

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

两个方法:

  • boolean next():游标向下移动一行,并判断当前行是否是最后一行,如果是返回false,如果不是则返回true
  • getXxx(参数):获取数据
    • Xxx表示数据类型,如:int getInt()String getString()
    • 参数:
      • 参数为int:表示列的编号,从1开始,如:getString(1)
      • 参数为string:表示列的名称。如:getInt("age")

例子:使用jdbc查询employees表中的id=1和id=4的数据:

package day01;

import java.sql.*;

public class Demo03 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        // 1.导入驱动jar包
        // 2.注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        // 3.获取数据库连接对象
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc_study", "root", "1234");
        // 4.定义sql语句
        String sql = "select * from employees where id = 1 or id = 4;";
        // 5.执行sql的对象Statement
        Statement statement = connection.createStatement();
        // 6.执行sql
        ResultSet resultSet = statement.executeQuery(sql);
        // 7.处理结果
        System.out.println("查询结果为:");
        while (resultSet.next()){   // 游标从第0行开始向下移动,到最后一行结束
            int id = resultSet.getInt(1);   // 参数为1表示返回第一列数据(游标所指向的行的)
            String name = resultSet.getString("name");  // 参数为"name"表示返回列名为name的数据(游标所指向的行的)
            int age = resultSet.getInt("age");  // 参数为"age"表示返回列名为age的数据(游标所指向的行的)
            System.out.println(id+"    "+name+"    "+age);
        }
        // 8.释放资源
        statement.close();
        connection.close();
        resultSet.close();
    }
}

执行结果为:

PreparedStatement:执行sql的对象

sql注入基础原理(超详细)

史上最完整的MySQL注入

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

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

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

select * from user where username = ? and password = ?;

使用步骤:

  1. 导入jar包
  2. 注册驱动
  3. 获取数据库连接Connection对象
  4. 定义sql(注意sql参数使用?作为占位符。如select * from user where username = ? and password = ?;)
  5. 获取执行sql的PreparedStatement对象:connection.preparedStatement(String sql)
  6. ?赋值
    • 方法:setXxx(参数1,参数2) (Xxx为数据类型,如getInt)
      • 参数1:?的位置编号,从1开始
      • 参数2:?的值
  7. 执行sql,接受返回结果,不需要传递sql语句
  8. 处理结果
  9. 释放资源

注意:后面我们都会使用PreparedStatement来完成增删改查

  • 可以防止sql注入
  • 效率更高

JDBC增删改练习

针对我们现有的employees表,我们通过JDBC进行以下操作(DML):

添加一条记录

符合规范的jdbc代码:

package day01;

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

public class Demo02 {
    public static void main(String[] args) {
        Connection connection = null;
        Statement statement = null;
        // 2.注册驱动
        try {
            Class.forName("com.mysql.jdbc.Driver");
            // 3.获取数据库连接对象
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc_study", "root", "1234");
            // 4.定义sql语句
            String sql = " insert into employees values (4,'tom',18);";
            // 5.执行sql的对象Statement
            statement = connection.createStatement();
            // 6.执行sql
            int count = statement.executeUpdate(sql);
            // 7.处理结果
            System.out.println("一共执行了"+count+"条记录");
            if (count>0){
                System.out.println("sql执行成功!");
            }else {
                System.out.println("sql执行失败!");
            }
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        } finally {  // 将释放资源放到finally代码块,保证了资源释放操作一定会执行
            // 8.释放资源
            // 这里的try-catch是为了避免空指针异常
            if (statement!=null){
                try {
                    statement.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if (connection!=null){
                try {
                    connection.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
    }
}

修改记录

在上述代码的基础上,将String sql = " insert into employees values (4,'tom',18);";修改为:

String sql = " update employees set age = 20 where name = 'tom';";

删除一条记录

在上述代码的基础上,将String sql = " update employees set age = 20 where name = 'tom';";修改为:

String sql = " delete from employees where id = 2;";

JDBC查询数据(JDBC select语句)

查询emp表中所有数据并将其封装为对象,然后装载集合。将查询结果打印在控制台上。

其中emp表的数据和结构如下:

emp数据

emp表结构

  1. 定义emp类
  2. 定义方法public List<Emp> findAll(){}
  3. 实现功能select * from emp;

我们在domain包下创建Emp.java类,代码如下:

package day01.domain;

import java.math.BigDecimal;
import java.util.Date;

/**
* 封装emp表数据的JavaBean
 */
public class Emp {
    private int id;     // 对应表中id字段
    private String ename;     // 对应表中ename字段
    private int job_id;     // 对应表中job_id字段
    private int mgr;     // 对应表中mgr字段
    private Date joindate; // 对应表中joindate字段
    private BigDecimal salary;  // 对应表中salary字段
    private BigDecimal bonus;  // 对应表中bonus字段
    private int dept_id;    // 对应表中dept_id字段

    // 此处省略Getter和Setter方法
    @Override
    public String toString() {
        return "Emp{" +
                "id=" + id +
                ", ename='" + ename + '\'' +
                ", job_id=" + job_id +
                ", mgr=" + mgr +
                ", joindate=" + joindate +
                ", salary=" + salary +
                ", bonus=" + bonus +
                ", dept_id=" + dept_id +
                '}';
    }
}

(省略Alt+Insert快速生成的Getter和Setter方法)

然后创建主启动类Demo05.java(含findAll方法),代码如下:

package day01;

import day01.domain.Emp;

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

public class Demo05 {
    public static void main(String[] args) {
        List<Emp> list = findAll();
        for (Emp emp : list) {
            System.out.println(emp);
        }
    }
    
    // 查询所有emp对象的方法
    public static List<Emp> findAll(){
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        List<Emp> empList = null;
        try {
            // 1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            // 2.获取数据库连接对象
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc_study", "root", "1234");
            // 3.定义sql语句
            String sql = "select * from emp;";
            // 4.获取执行sql的对象Statement
            statement = connection.createStatement();
            // 5.执行sql
            resultSet = statement.executeQuery(sql);
            // 6.遍历结果集,封装对象,装载集合
            empList = new ArrayList<>();  // 在循环前创建一个集合用来存储获取的emp对象
            Emp emp = null;     // 放在外面,减少内存
            while (resultSet.next()){
                // 获取数据
                int id = resultSet.getInt("id");
                String ename = resultSet.getString("ename");
                int job_id = resultSet.getInt("job_id");
                int mgr = resultSet.getInt("mgr");
                Date joindate = resultSet.getDate("joindate");
                BigDecimal salary = resultSet.getBigDecimal("salary");
                BigDecimal bonus = resultSet.getBigDecimal("bonus");
                int dept_id = resultSet.getInt("dept_id");
                // 创建emp对象,并赋值给其成员变量
                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);
                // 装载集合
                empList.add(emp);
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            // 释放资源
            // 这里的try-catch是为了避免空指针异常
            if (statement!=null){
                try {
                    statement.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if (connection!=null){
                try {
                    connection.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if (resultSet!=null){
                try {
                    resultSet.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
        return empList;
    }
}

执行结果如下:

执行结果

这里给出数据库类型和Java数据类型对应如下:

类型名称显示长度数据库类型JAVA类型JDBC类型索引(int)
VARCHARL+NVARCHARjava.lang.String12
CHARNCHARjava.lang.String1
BLOBL+NBLOBjava.lang.byte[]-4
TEXT65535VARCHARjava.lang.String-1
INTEGER4INTEGER UNSIGNEDjava.lang.Long4
TINYINT3TINYINT UNSIGNEDjava.lang.Integer-6
SMALLINT5SMALLINT UNSIGNEDjava.lang.Integer5
MEDIUMINT8MEDIUMINT UNSIGNEDjava.lang.Integer4
BIT1BITjava.lang.Boolean-7
BIGINT20BIGINT UNSIGNEDjava.math.BigInteger-5
FLOAT4+8FLOATjava.lang.Float7
DOUBLE22DOUBLEjava.lang.Double8
DECIMAL11DECIMALjava.math.BigDecimal3
BOOLEAN1同TINYINT
ID11PK (INTEGER UNSIGNED)java.lang.Long4
DATE10DATEjava.sql.Date91
TIME8TIMEjava.sql.Time92
DATETIME19DATETIMEjava.sql.Timestamp93
TIMESTAMP19TIMESTAMPjava.sql.Timestamp93
YEAR4YEARjava.sql.Date91

JDBC工具类

JDBC工具类(可以体会到配置文件的优点)

从上述的[查询数据](#JDBC查询数据(JDBC select语句))例子中可以发现,有很多重复的代码。

所以我们试着抽取JDBC工具类:

目的:简化代码

分析:

  1. 抽取注册驱动

  2. 抽取一个方法来获取数据库连接对象

    • 需求:在getConnection()方法中不想传递参数,同时还得保证工具类的通用性

    • 解决:使用配置文件

      在src文件夹下创建配置文件jdbc.properties文件,代码如下:

      url=jdbc:mysql://localhost:3306/jdbc_study
      user=root
      password=1234
      driver=com.mysql.jdbc.Driver
      
  3. 抽取一个方法来释放资源

例子:我们在创建util包下创建JDBCUtils.java类,代码如下:

package day01.util;

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

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

    // 文件的读取,只需要读取一次即可拿到这些值。使用静态代码块
    static {
        // 读取资源文件,获取值
        // 以下步骤具体可看反射笔记(https://www.qingbo1011.top/2021/01/22/%E5%8F%8D%E5%B0%84/#%E6%A1%88%E4%BE%8B)
        try {
            // 1.创建Properties集合类
            Properties properties = new Properties();

            // 2.加载文件
            properties.load(new FileReader("src/jdbc.properties"));

            // 3.获取数据,赋值
            url = properties.getProperty("url");
            user = properties.getProperty("user");
            password = properties.getProperty("password");
            driver = properties.getProperty("driver");

            // 4.注册驱动
            Class.forName(driver);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }


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


    // 释放资源(有两种情况,需要重载方法)
    public static void close(Statement statement, Connection connection){
        if (statement != null){
            try {
                statement.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (connection != null){
            try {
                connection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
    public static void close(Statement statement, Connection connection, ResultSet resultSet){
        if (statement != null){
            try {
                statement.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (connection != null){
            try {
                connection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (resultSet != null){
            try {
                resultSet.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

在src文件夹下创建配置文件jdbc.properties文件,代码如下:

url=jdbc:mysql://localhost:3306/jdbc_study
user=root
password=1234
driver=com.mysql.jdbc.Driver

然后我们创建主启动类Demo04.java,代码如下:

package day01;

import day01.domain.Emp;
import day01.util.JDBCUtils;

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

public class Demo04 {
    public static void main(String[] args) {
        List<Emp> list = findAll();
        for (Emp emp : list) {
            System.out.println(emp);
        }
    }

    // 查询所有emp对象的方法
    public static List<Emp> findAll(){
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        List<Emp> empList = null;
        try {
            // 1.注册驱动,获取数据库连接对象
            connection = JDBCUtils.getConnection();
            // 2.定义sql语句
            String sql = "select * from emp;";
            // 3.获取执行sql的对象Statement
            statement = connection.createStatement();
            // 4.执行sql
            resultSet = statement.executeQuery(sql);
            // 5.遍历结果集,封装对象,装载集合
            empList = new ArrayList<>();  // 在循环前创建一个集合用来存储获取的emp对象
            Emp emp = null;     // 放在外面,减少内存
            while (resultSet.next()){
                // 获取数据
                int id = resultSet.getInt("id");
                String ename = resultSet.getString("ename");
                int job_id = resultSet.getInt("job_id");
                int mgr = resultSet.getInt("mgr");
                Date joindate = resultSet.getDate("joindate");
                BigDecimal salary = resultSet.getBigDecimal("salary");
                BigDecimal bonus = resultSet.getBigDecimal("bonus");
                int dept_id = resultSet.getInt("dept_id");
                // 创建emp对象,并赋值给其成员变量
                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);
                // 装载集合
                empList.add(emp);
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            // 释放资源
            JDBCUtils.close(statement,connection,resultSet);
        }
        return empList;
    }
}

执行结果和上述的[查询数据](#JDBC查询数据(JDBC select语句))例子的结果是一样的

JDBC登录案例

需求:

  • 通过键盘录入用户名和密码
  • 判断用户是否登录成功(用户名和密码存储在user表中)

现有user表如下:

user数据

JDBC工具类JDBCUtils.java和jdbc.properties配置文件同上JDBC工具类

使用createStatement()来执行sql

创建主启动类Demo06.java代码如下:

package day01.util;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;

public class Demo06 {
    public static void main(String[] args) {
        // 1.键盘录入接受用户名和密码
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入用户名:");
        String username = scanner.nextLine();
        System.out.print("请输入密码:");
        String password = scanner.nextLine();
        // 2.调用方法
        boolean flag = login(username, password);
        if (flag){
            System.out.println("登陆成功!");
        }else {
            System.out.println("登录失败!用户名或密码错误");
        }
    }

    public static boolean login(String username, String password){
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        if (username==null || password==null){
            System.out.println("用户名或密码不能为空!");
            return false;
        }else {
            try {
                // 1.获取连接
                connection = JDBCUtils.getConnection();
                // 2.定义sql语句
                String sql = "select * from user where username = '"+username+"' and password = '"+password+"';";
                // 3.获取执行sql的对象Statement
                statement = connection.createStatement();
                // 4.执行sql
                resultSet = statement.executeQuery(sql);
                // 5.判断
                return resultSet.next();    // 如果有下一行则返回true
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            } finally {
                JDBCUtils.close(statement,connection,resultSet);
            }
        }
        return false;   // 如果出现异常则返回false
    }
}

这里会出现一个问题,那就是sql注入。关于sql注入在上文已经给出说明了。直接来看一个例子:

sql注入导致错误的用户名和密码却可以登录成功

为了解决sql注入的问题,我们使用prepareStatement(sql)来执行sql

使用prepareStatement(sql)来执行sql

创建主启动类Demo07.java代码如下:

package day01;

import day01.util.JDBCUtils;

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

public class Demo07 {
    public static void main(String[] args) {
        // 1.键盘录入接受用户名和密码
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入用户名:");
        String username = scanner.nextLine();
        System.out.print("请输入密码:");
        String password = scanner.nextLine();
        // 2.调用方法
        boolean flag = login(username, password);
        if (flag){
            System.out.println("登陆成功!");
        }else {
            System.out.println("登录失败!用户名或密码错误");
        }
    }

    public static boolean login(String username, String password){
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        if (username==null || password==null){
            System.out.println("用户名或密码不能为空!");
            return false;
        }else {
            try {
                // 1.获取连接
                connection = JDBCUtils.getConnection();
                // 2.定义sql语句
                String sql = "select * from user where username = ? and password = ?;";
                // 3.获取执行sql的对象Statement
                preparedStatement = connection.prepareStatement(sql); // preparedStatement生成时需要传递sql
                // 4.执行sql
                resultSet = preparedStatement.executeQuery();   // preparedStatement执行时可以不传递sql
                // 5.判断
                return resultSet.next();    // 如果有下一行则返回true
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            } finally {
                JDBCUtils.close(preparedStatement,connection,resultSet);
            }
        }
        return false;   // 如果出现异常则返回false
    }
}

执行效果为:

正确的用户名额密码可以登录成功

成功防止sql注入

在后续开发中我们都会使用PreparedStatement来完成增删改查


JDBC管理事务

关于事务的讲解,之前的笔记有讲到过。这里再简单说一下:

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

相关操作:

  • 开启事务
  • 提交事务
  • 回滚事务

在JDBC中,我们使用Connection对象来管理事务:

  • 开启事务:setAutoCommit(boolean autoCommit):要调用该方法则设置参数为false,即开启事务
    • 在执行sql之前开启事务
  • 提交事务:commit()
    • 当所有sql都执行完提交事务
  • 回滚事务:rollback()
    • try-catch中在catch块里回滚事务

例子:

我们有account表如下:

account表数据

account表结构

JDBC工具类中添加close的重载方法如下:

public static void close(Statement statement1, Statement statement2, Connection connection) {
    if (statement1 != null) {
        try {
            statement1.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
    if (statement2 != null) {
        try {
            statement2.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
    if (connection != null) {
        try {
            connection.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
}

配置文件同上

创建主启动类Demo09.java,代码如下:

package day01;

import day01.util.JDBCUtils;

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

public class Demo08 {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement preparedStatement1 = null;
        PreparedStatement preparedStatement2 = null;
        ResultSet resultSet = null;
        try {
            // 1.获取连接
            connection = JDBCUtils.getConnection();
            // a.开启事务
            connection.setAutoCommit(false);    // 参数设置为false即为开启事务
            // 2.定义sql
            // 2-1 转账方扣钱
            String sql1 = "update account set balance = balance - ? where NAME = ?";
            // 2-2 收账方扣钱
            String sql2 = "update account set balance = balance + ? where NAME = ?";
            // 3.获取执行sql对象
            preparedStatement1 = connection.prepareStatement(sql1);
            preparedStatement2 = connection.prepareStatement(sql2);
            // 4.设置参数
            preparedStatement1.setDouble(1,500);
            preparedStatement1.setString(2,"zhangsan");

            preparedStatement2.setDouble(1,500);
            preparedStatement2.setString(2,"lisi");
            // 5.执行sql
            preparedStatement1.executeUpdate();
            // 人为制造异常
            int i = 1/0;
            preparedStatement2.executeUpdate();
            // b.提交事务
            connection.commit();
        } catch (Exception exception) { // 这里的异常要改为所有异常的父类Exception,因为不管发生什么异常,都需要事务回滚
            // c.事务回滚
            try {
                if (connection!=null){  // 回滚前要先判断connection是否为空
                    connection.rollback();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
            exception.printStackTrace();
        } finally {
            // 释放资源
            JDBCUtils.close(preparedStatement1,preparedStatement2,connection);  // 注意要在在上述JDBC工具类中添加相应的close的重载方法
        }
    }
}
一、概述: JDBC从物理结构上说就是Java语言访问数据库的一套接口集合。从本质上来说就是调用者(程序员)和实现者(数据库厂商)之间的协议。JDBC的实现由数据库厂商以驱动程序的形式提供。JDBC API 使得开发人员可以使用纯Java的方式来连接数据库,并进行操作。 ODBC:基于C语言的数据库访问接口。 JDBC也就是Java版的ODBC。 JDBC的特性:高度的一致性、简单性(常用的接口只有4、5个)。 1.在JDBC中包括了两个包:java.sql和javax.sql。 ① java.sql 基本功能。这个包中的类和接口主要针对基本的数据库编程服务,如生成连接、执行语句以及准备语句和运行批处理查询等。同时也有一些高级的处理,比如批处理更新、事务隔离和可滚动结果集等。 ② javax.sql 扩展功能。它主要为数据库方面的高级操作提供了接口和类。如为连接管理、分布式事务和旧有的连接提供了更好的抽象,它引入了容器管理的连接池、分布式事务和行集等。 注:除了标出的Class,其它均为接口。 API 说明 java.sql.Connection 与特定数据库的连接(会话)。能够通过getMetaData方法获得数据库提供的信息、所支持的SQL语法、存储过程和此连接的功能等信息。代表了数据库java.sql.Driver 每个驱动程序类必需实现的接口,同时,每个数据库驱动程序都应该提供一个实现Driver接口的类。 java.sql.DriverManager (Class) 管理一组JDBC驱动程序的基本服务。作为初始化的一部分,此接口会尝试加载在”jdbc.drivers”系统属性中引用的驱动程序。只是一个辅助类,是工具。 java.sql.Statement 用于执行静态SQL语句并返回其生成结果的对象。 java.sql.PreparedStatement 继承Statement接口,表示预编译的SQL语句的对象,SQL语句被预编译并且存储在PreparedStatement对象中。然后可以使用此对象高效地多次执行该语句。 java.sql.CallableStatement 用来访问数据库中的存储过程。它提供了一些方法来指定语句所使用的输入/输出参数。 java.sql.ResultSet 指的是查询返回的数据库结果集。 java.sql.ResultSetMetaData 可用于获取关于ResultSet对象中列的类型和属性信息的对象。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值