JDBC简介及原理和使用介绍

news2024/11/19 2:49:08

JDBC简介及原理和使用介绍

JDBC简介

jdbc概述

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

​ 使用Java程序访问数据库时,Java代码并不是直接通过TCP连接去访问数据库,而是通过JDBC接口来访问,而JDBC接口则通过JDBC驱动来实现真正对数据库的访问

例如,我们在Java代码中如果要访问MySQL,那么必须编写代码操作JDBC接口。JDBC接口是Java标准库自带的,所以可以直接编译。而具体的JDBC驱动是由数据库厂商提供的。因此,访问某个具体的数据库,我们只需要引入该厂商提供的JDBC驱动,就可以通过JDBC接口来访问,这样保证了Java程序编写的是一套数据库访问代码,却可以访问各种不同的数据库
Java 应用程序 -> JDBC Interface -> JDBC Driver -> Database

JDBC 的常用接口和类

  • Driver 接口:加载驱动程序。
  • DriverManager 类:装人所需的 JDBC 驱动程序,编程时调用它的方法来创建连接。
  • Connection 接口:编程时使用该类对象创建 Statement 对象。
  • Statement 接口:编程时使用该类对象得到 ResultSet 对象。
  • ResultSet 类:负责保存 Statement 执行后所产生的查询结果。

JDBC接口(API)

JDBC接口(API)包括两个层次

  • 面向应用的API
    • Java API,抽象接口,供应用程序开发人员使用(连接数据库,执行SQL语句,获得结果)
  • 面向数据库的API
    • Java Driver API,供开发商开发数据库驱动程序用

Driver接口

  • java.sql.Driver 接口是所有 JDBC 驱动程序需要实现的接口。这个接口是提供给数据库厂商使用的,不同数据库厂商提供不同的实现
  • 在程序中不需要直接去访问实现了 Driver 接口的类,而是由驱动程序管理器类(java.sql.DriverManager)去调用
    • Oracle的驱动:oracle.jdbc.driver.OracleDriver
    • mySql的驱动: com.mysql.jdbc.Driver

建立连接的五大步骤

  1. 加载(注册驱动)数据库
  2. 建立链接(Connection)
  3. 创建执行SQL的语句(Statement)
  4. 执行语句
  5. 处理结果集(ResultSet)
  6. 关闭数据库释放资源

加载与注册JDBC驱动

  • 方式1:加载 JDBC 驱动需调用 Class 类的静态方法 forName(),向其传递要加载的 JDBC 驱动的类名

    • Class.forName(com.mysql.jdbc.Driver);
      
  • 方式2:DriverManager 类是驱动程序管理器类,负责管理驱动程序

    • DriverManager.registerDriver(com.mysql.jdbc.Driver);
      

建立连接(Connection)

  • 可以调用 DriverManager 类的 getConnection() 方法建立到数据库的连接
  • user,password可以用“属性名=属性值”方式告诉数据库
  • JDBC URL 用于标识一个被注册的驱动程序,驱动程序管理器通过这个 URL 选择正确的驱动程序,从而建立到数据库的连接。
  • JDBC URL的标准由三部分组成,各部分间用冒号分隔。
    • jdbc:子协议:子名称
    • 协议:JDBC URL中的协议总是jdbc
    • 子协议:子协议用于标识一个数据库驱动程序
    • 子名称:一种标识数据库的方法。子名称可以依不同的子协议而变化,用子名称的目的是为了定位数据库提供足够的信息。包含主机名(对应服务端的ip地址),端口号,数据库名

示例:

jdbc:mysql://localhost:3306/databasename

jdbc : 协议
mysql : 子协议
localhost:3306/databasename : 子名称

常见的数据库URL

jdbc:oracle:thin:@localhost:1521:testdb
jdbc:microsoft:sqlserver//localhost:1433; DatabaseName=testdb
jdbc:mysql://localhost:3306/testdb

PreparedStatement接口

PreparedStatement,是java.sql包中的接口,继承了Statement,并与之在两方面有所不同,包含已编译的 SQL 语句,用以执行包含动态参数的SQL查询和更新。

  • 可以通过调用 Connection 对象的 preparedStatement() 方法获取 PreparedStatement 对象
  • PreparedStatement 接口是 Statement 的子接口,它表示一条预编译过的 SQL 语句
  • PreparedStatement 对象所代表的 SQL 语句中的参数用问号(?)来表示,调用 PreparedStatement 对象的 setXxx() 方法来设置这些参数. setXxx() 方法有两个参数
    • 设置的 SQL 语句中的参数的索引(从 1 开始)
    • 设置的 SQL 语句中的参数的值

数据类型转换

java类型SQL类型
booleanBIT
byteTINYINT
shortSMALLINT
intINTEGER
longBIGINT
StringCHAR,VARCHAR,LONGVARCHAR
byte arrayBINARY , VAR BINARY
java.sql.DateDATE
java.sql.TimeTIME
java.sql.TimestampTIMESTAMP

数据库释放资源

  • 释放ResultSet, Statement,Connection

数据库连接(Connection)是非常稀有的资源,用完后必须马上释放,如果Connection不能及时正确的关闭将导致系统宕机。Connection的使用原则是尽量晚创建,尽量早的释放

ResultSet接口

ResultSet,数据库结果集的数据表,通常通过执行查询数据库的语句生成

  • 通过调用 PreparedStatement 对象的 excuteQuery() 方法创建该对象
  • ResultSet 对象以逻辑表格的形式封装了执行数据库操作的结果集,ResultSet 接口由数据库厂商实现
  • ResultSet 对象维护了一个指向当前数据行的游标,初始的时候,游标在第一行之前,可以通过 ResultSet 对象的 next() 方法移动到下一行

关于ResultSet的说明

  1. 查询需要调用Prepared Statement 的 executeQuery() 方法,查询结果是一个 ResultSet 对象
  2. 关于 ResultSet:代表结果集
    1. ResultSet: 结果集. 封装了使用 JDBC 进行查询的结果
    2. 调用 PreparedStatement 对象的 executeQuery() 可以得到结果集
    3. ResultSet 返回的实际上就是一张数据表. 有一个指针指向数据表的第一条记录的前面
  3. 可以调用 next() 方法检测下一行是否有效. 若有效该方法返回 true, 且指针下移. 相当于Iterator 对象的 hasNext() 和 next() 方法的结合体
  4. 当指针指向一行时, 可以通过调用 getXxx(int index) 或 getXxx(int columnName) 获取每一列的值
  5. ResultSet 也需要进行close关闭

JDBC代码使用

环境准备

准备MySQL测试库

一般常用的为MySQL5.7或者MariaDB均可

创建一个database:wow

CREATE DATABASE wow;

创建一张表:wow_info

CREATE TABLE `wow_info` (
	`id` int(11) NOT NULL AUTO_INCREMENT,
	`role` varchar(255) DEFAULT NULL,
	`role_cn` varchar(255) DEFAULT NULL,
	`role_pinyin` varchar(255) DEFAULT NULL,
	`zhuangbei` varchar(255) DEFAULT NULL,
	PRIMARY KEY (`id`)
) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARSET = utf8

插入一些实验样例数据:

INSERT INTO `wow_info`
VALUES (1, 'fs', '法师', 'fashi', '布甲'),
	(2, 'ms', '牧师', 'mushi', '布甲'),
	(3, 'ss', '术士', 'shushi', '布甲'),
	(4, 'dz', '盗贼', 'daozei', '皮甲'),
	(5, 'ws', '武僧', 'wuseng', '皮甲'),
	(6, 'xd', '德鲁伊', 'xiaode', '皮甲'),
	(7, 'sq', '圣骑士', 'shengqi', '板甲'),
	(8, 'zs', '战士', 'zhanshi', '板甲'),
	(9, 'dk', '死亡骑士', 'siwangqishi', '板甲'),
	(10, 'dh', '恶魔猎手', 'emolieshou', '皮甲');

查看环境信息:

[root@wangting ~]# mysql -uroot -p
Enter password: 
MariaDB [(none)]> use wow;
Database changed
MariaDB [wow]> show tables;
+---------------+
| Tables_in_wow |
+---------------+
| wow_info      |
+---------------+
1 row in set (0.000 sec)
MariaDB [wow]> select * from wow_info;
+----+------+--------------+-------------+-----------+
| id | role | role_cn      | role_pinyin | zhuangbei |
+----+------+--------------+-------------+-----------+
|  1 | fs   | 法师         | fashi       | 布甲      |
|  2 | ms   | 牧师         | mushi       | 布甲      |
|  3 | ss   | 术士         | shushi      | 布甲      |
|  4 | dz   | 盗贼         | daozei      | 皮甲      |
|  5 | ws   | 武僧         | wuseng      | 皮甲      |
|  6 | xd   | 德鲁伊       | xiaode      | 皮甲      |
|  7 | sq   | 圣骑士       | shengqi     | 板甲      |
|  8 | zs   | 战士         | zhanshi     | 板甲      |
|  9 | dk   | 死亡骑士     | siwangqishi | 板甲      |
| 10 | dh   | 恶魔猎手     | emolieshou  | 皮甲      |
+----+------+--------------+-------------+-----------+
10 rows in set (0.000 sec)

idea新建maven项目

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tuwuFU60-1673490621386)(https://osswangting.oss-cn-shanghai.aliyuncs.com/jdbc/20230110140615.png)]

项目信息可自定义设置,不影响代码调试测试

pom文件中增加Test、MySQLjdbc依赖

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.31</version>
        </dependency>
    </dependencies>

因为核心逻辑使用到jdbc的jar包,所以需要在pom中加依赖

注意:

version版本取决于使用的数据库是什么版本,例如MySQL5.7则需要去找到对应的MySQL版本依赖

所有的依赖信息清单见:

https://mvnrepository.com/artifact/mysql/mysql-connector-java

例如5.7添加了5.1.38,小版本影响不大

mysql
mysql-connector-java
5.1.38

新建package

com.wangting.bigdata

在包下会陆续创建各个实现类,例如 JDBCDemo

pom文件中每加一个新依赖,对应一个新xxx

接口开发使用介绍

项目整体结构:

简单连接数据库demo实现

包下创建一个TestJdbc类

代码示例:

package com.wangting.bigdata;

import java.sql.*;

public class TestJdbc {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection conn = DriverManager.getConnection("jdbc:mysql://47.88.88.88:3306/wow", "root", "123456");
        Statement statement = conn.createStatement();
        String sql = "select * from wow_info";
        ResultSet resultSet = statement.executeQuery(sql);
        while (resultSet.next()) {
            System.out.println(
                    resultSet.getInt("id") + "|"
                            + resultSet.getString("role") + "|"
                            + resultSet.getString("role_cn") + "|"
                            + resultSet.getString("role_pinyin") + "|"
                            + resultSet.getString("zhuangbei"));

        }
        statement.close();
        conn.close();
    }
}

执行效果如下:

1|fs|法师|fashi|布甲
2|ms|牧师|mushi|布甲
3|ss|术士|shushi|布甲
4|dz|盗贼|daozei|皮甲
5|ws|武僧|wuseng|皮甲
6|xd|德鲁伊|xiaode|皮甲
7|sq|圣骑士|shengqi|板甲
8|zs|战士|zhanshi|板甲
9|dk|死亡骑士|siwangqishi|板甲
10|dh|恶魔猎手|emolieshou|皮甲

但是这种简单实现,一般业务上很少使用,仅用于调试或者功能测试时使用,弊端非常明显,MySQL连接信息写死在代码中,查询功能高度耦合,非常的不灵活,基于这些原因,需要使用面向对象的思路去拆分功能来实现。

JDBCUtils工具类

创建JDBCUtils类,用于实现连接逻辑,交互配置文件等等

因为实际使用场景中,几乎数据库连接信息都不会写死在代码中,采用了配置文件的形式,使得灵活配置

对于配置文件的实现:

  1. 创建Properties对象
  2. 创建流
  3. 加载流
  4. 通过Properties对象读取文件中的内容
  5. 关闭资源

JDBCUtils工具类详解:

  1. 在JdbcUtils的静态代码static代码块中读取db.properties中的相关配置,并加载驱动

  2. 每次使用JDBC之前都要获取getConnection连接,而获取连接的代码都是固定的,因此可以提取成一个公共方法getConnection;用户代码可以通过调用JdbcUtils.getConnection()来获取连接。

  3. 使用JDBCUtils工具类的优点,在我们有大量使用mysql的数据库的情况下,可以通过更改jdbc.properties配置文件就可以灵活修改数据库的配置,而不是寻找代码然后在一次次更改代码中的数据

  4. 查询操作中可以通过调用JdbcUtils.close(rs, stmt, conn)来关闭释放资源,而更新操作中可以通过调用JdbcUtils.close(stmt, conn)来释放资源

JDBCUtils.java代码示例:

package com.wangting.bigdata;

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

public class JDBCUtils {
    private static String className;
    private static String url;
    private static String user;
    private static String password;

    static {
        FileInputStream fis = null;
        try {
            // 1.创建Properties对象
            Properties p = new Properties();
            // 2.创建流
            fis = new FileInputStream("jdbc.properties");
            // 3.加载流到Properties中
            p.load(fis);
            // 4.通过Properties读取文件中的内容
            user = p.getProperty("user");
            password = p.getProperty("password");
            url = p.getProperty("url");
            className = p.getProperty("className");
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        } finally {
            // 5.关闭资源
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /*
        获取Connection对象
     */
    public static Connection getConnection() {
        try {
            //1.让Driver类中的静态代码块执行
            Class.forName(className);
            //3.获取Connection对象
            Connection connection = DriverManager.getConnection(url, user, password);
            return connection;
        } catch (Exception e) {
            e.printStackTrace();
            //终止程序运行
            throw new RuntimeException(e.getMessage());
        }
    }

    /*
        关闭资源
     */
    public static void close(Connection connection, PreparedStatement ps) {
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

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

    public static void close(Connection connection, PreparedStatement ps, ResultSet rs) {
        close(connection, ps);
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

代码行:fis = new FileInputStream(“jdbc.properties”);

这里使用的是以项目的根目录为相对路径,直接文件名意味着在项目顶级路径下查找jdbc.properties配置文件

在项目根目录下创建jdbc.properties配置文件:

user=root
password=123456
url=jdbc:mysql://47.88.88.88:3306/wow
className=com.mysql.cj.jdbc.Driver

使用key=value的键值对形式来进行配置

表对象

表对象Wow.java

这里Wow表仅仅做参考,不同的表对应不同的对象,把MySQL中被操作的表理解成一个对象

后面会用到,也可以在new Wow对象,调用JDBCUtils工具类去操作Wow对象时,再创建。这里提前创建好备着

流程基本固定为:

private定义属性对应表中的字段

无参构造器

全参构造器

属性的get和set方法

重写toString方法

Wow.java代码示例:

package com.wangting.bigdata;

public class Wow {
    private int id;
    private String role;
    private String role_cn;
    private String role_pinyin;
    private String zhuangbei;

    public Wow() {
    }

    public Wow(int id, String role, String role_cn, String role_pinyin, String zhuangbei) {
        this.id = id;
        this.role = role;
        this.role_cn = role_cn;
        this.role_pinyin = role_pinyin;
        this.zhuangbei = zhuangbei;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getRole() {
        return role;
    }

    public void setRole(String role) {
        this.role = role;
    }

    public String getRole_cn() {
        return role_cn;
    }

    public void setRole_cn(String role_cn) {
        this.role_cn = role_cn;
    }

    public String getRole_pinyin() {
        return role_pinyin;
    }

    public void setRole_pinyin(String role_pinyin) {
        this.role_pinyin = role_pinyin;
    }

    public String getZhuangbei() {
        return zhuangbei;
    }

    public void setZhuangbei(String zhuangbei) {
        this.zhuangbei = zhuangbei;
    }

    @Override
    public String toString() {
        return id + "|" + role + "|" + role_cn + "|" + role_pinyin + "|" + zhuangbei;
    }
}

增删改查操作示例

insert新增数据

原表:

MariaDB [wow]> select * from wow_info;
+----+------+--------------+-------------+-----------+
| id | role | role_cn      | role_pinyin | zhuangbei |
+----+------+--------------+-------------+-----------+
|  1 | fs   | 法师         | fashi       | 布甲      |
|  2 | ms   | 牧师         | mushi       | 布甲      |
|  3 | ss   | 术士         | shushi      | 布甲      |
|  4 | dz   | 盗贼         | daozei      | 皮甲      |
|  5 | ws   | 武僧         | wuseng      | 皮甲      |
|  6 | xd   | 德鲁伊       | xiaode      | 皮甲      |
|  7 | sq   | 圣骑士       | shengqi     | 板甲      |
|  8 | zs   | 战士         | zhanshi     | 板甲      |
|  9 | dk   | 死亡骑士     | siwangqishi | 板甲      |
| 10 | dh   | 恶魔猎手     | emolieshou  | 皮甲      |
+----+------+--------------+-------------+-----------+
10 rows in set (0.000 sec)

创建DemoInsert类插入数据

代码示例:

package com.wangting.bigdata;

import org.junit.Test;

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

public class DemoInsert {

    @Test
    public void test() throws SQLException {
        // 1.获取Connection对象
        Connection connection = JDBCUtils.getConnection();
        // 2.sql语句(?符号为占位符)
        String sql = "insert into wow_info(id,role,role_cn,role_pinyin,zhuangbei) values(?,?,?,?,?)";

        // 3.对sql预编译
        PreparedStatement ps = connection.prepareStatement(sql);
        // 3-1.给占位符赋值
        ps.setInt(1, 11);
        ps.setString(2, "lr");
        ps.setString(3, "龙人");
        ps.setString(4, "longren");
        ps.setString(5, "锁甲");

        // 3-2.执行sql语句
        int result = ps.executeUpdate();
        System.out.println("[info-]" + result + "行数据受到影响");

        // 4.关闭资源
        JDBCUtils.close(connection, ps);
    }
}

控制台输出内容:

[info-]1行数据受到影响

执行代码后验证:

MariaDB [wow]> select * from wow_info;
+----+------+--------------+-------------+-----------+
| id | role | role_cn      | role_pinyin | zhuangbei |
+----+------+--------------+-------------+-----------+
|  1 | fs   | 法师         | fashi       | 布甲      |
|  2 | ms   | 牧师         | mushi       | 布甲      |
|  3 | ss   | 术士         | shushi      | 布甲      |
|  4 | dz   | 盗贼         | daozei      | 皮甲      |
|  5 | ws   | 武僧         | wuseng      | 皮甲      |
|  6 | xd   | 德鲁伊       | xiaode      | 皮甲      |
|  7 | sq   | 圣骑士       | shengqi     | 板甲      |
|  8 | zs   | 战士         | zhanshi     | 板甲      |
|  9 | dk   | 死亡骑士     | siwangqishi | 板甲      |
| 10 | dh   | 恶魔猎手     | emolieshou  | 皮甲      |
| 11 | lr   | 龙人         | longren     | 锁甲      |
+----+------+--------------+-------------+-----------+
11 rows in set (0.000 sec)

最后一行:11 | lr | 龙人 | longren | 锁甲 则为新增数据,已经可以查询到

Update修改操作

创建DemoUpdate类:

代码示例:

package com.wangting.bigdata;

import org.junit.Test;

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

public class DemoUpdate {

    @Test
    public void test2() throws SQLException {
        // 1.获取Connection对象
        Connection connection = JDBCUtils.getConnection();
        // 2.sql语句
        String sql = "update wow_info set role_pinyin=? where id=?";
        // 3.预编译
        PreparedStatement ps = connection.prepareStatement(sql);
        // 3-1给占位符赋值
        ps.setString(1, "小龙人");
        ps.setInt(2, 11);
        // 3-2执行sql语句
        ps.executeUpdate();
        // 4.关闭资源
        JDBCUtils.close(connection, ps);
    }
}

验证:

MariaDB [wow]> select * from wow_info where id='11';
+----+------+---------+-------------+-----------+
| id | role | role_cn | role_pinyin | zhuangbei |
+----+------+---------+-------------+-----------+
| 11 | lr   | 龙人    | 小龙人      | 锁甲      |
+----+------+---------+-------------+-----------+
1 row in set (0.000 sec)

role_pinyin列的值已经从“longren”被改为“小龙人”。

Delete删除操作

创建DemoDelete类:

代码示例:

package com.wangting.bigdata;

import org.junit.Test;

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

public class DemoDelete {
    @Test
    public void test3() throws SQLException {
        // 1.获取Connection对象
        Connection connection = JDBCUtils.getConnection();
        // 2.sql语句
        String sql = "delete from wow_info where id='11'";
        // 3.预编译
        PreparedStatement ps = connection.prepareStatement(sql);
        // 3-1.执行sql语句
        ps.executeUpdate();
        // 4.关闭资源
        JDBCUtils.close(connection, ps);
    }
}

验证:

MariaDB [wow]> select * from wow_info where id='11';
Empty set (0.000 sec)

Select查询操作

DemoSelect01:尝试查询某条数据

进行条件查询,找出id=xxx的某条数据

代码示例:

package com.wangting.bigdata;

import org.junit.Test;

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

public class DemoSelect01 {
    @Test
    public void test() throws SQLException {
        // 1.获取Connection对象
        Connection connection = JDBCUtils.getConnection();
        // 2.sql语句
        String sql = "select id,role_cn,zhuangbei from wow_info where id=?";
        // 3.预编译
        PreparedStatement ps = connection.prepareStatement(sql);
        // 4.给占位符赋值
        ps.setInt(1, 3);
        // 5.执行sql语句
        // ResultSet :用来遍历查询的结果
        ResultSet rs = ps.executeQuery();
        // 6.通过ResultSet遍历数据
        while (rs.next()) {
            // 7.获取对应的字段中的数据
            int id = rs.getInt("id");
            String role_cn = rs.getString("role_cn");
            String zhuangbei = rs.getString("zhuangbei");
            System.out.println(id + " | " + role_cn + " | " + zhuangbei);
        }
        // 7.关闭资源
        JDBCUtils.close(connection, ps, rs);
    }
}

输出验证:

3 | 术士 | 布甲

DemoSelect02:满足条件的多条数据

进行条件查询,查询满足条件的多条数据

代码示例:

package com.wangting.bigdata;

import org.junit.Test;

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

public class DemoSelect02 {
    @Test
    public void test2() throws SQLException {
        // 1.获取Connection对象
        Connection connection = JDBCUtils.getConnection();
        // 2.sql语句
        String sql = "select id,role_cn,zhuangbei from wow_info limit 5";
        // 3.预编译
        PreparedStatement ps = connection.prepareStatement(sql);
        // 4.执行sql语句
        // ResultSet :用来遍历查询的结果
        ResultSet rs = ps.executeQuery();
        // 6.通过ResultSet遍历数据
        while (rs.next()) {//next() :如果有数据结果为true
            // 7.获取对应的字段中的数据
            int id = rs.getInt("id");
            String role_cn = rs.getString("role_cn");
            String zhuangbei = rs.getString("zhuangbei");
            System.out.println(id + " | " + role_cn + " | " + zhuangbei);
        }
        // 7.关闭资源
        JDBCUtils.close(connection, ps, rs);
    }
}

输出验证:

1 | 法师 | 布甲
2 | 牧师 | 布甲
3 | 术士 | 布甲
4 | 盗贼 | 皮甲
5 | 武僧 | 皮甲

DemoSelect03:获取表中所有的数据

通过调用方法获取表中所有的数据

package com.wangting.bigdata;

import org.junit.Test;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class DemoSelect03 {
    public DemoSelect03() {

    }

    @Test
    public void test3() throws SQLException {
        List<Wow> Wows = getWows();
        for (Wow Wow : Wows) {
            System.out.println(Wow);
        }
    }

    public List<Wow> getWows() throws SQLException {
        // 创建一个集合用来存放对象
        List<Wow> list = new ArrayList<Wow>();

        Connection connection = JDBCUtils.getConnection();
        String sql = "select * from wow_info";
        PreparedStatement ps = connection.prepareStatement(sql);
        ResultSet rs = ps.executeQuery();
        while (rs.next()) {
            int id = rs.getInt("id");
            String role = rs.getString("role");
            String role_cn = rs.getString("role_cn");
            String role_pinyin = rs.getString("role_pinyin");
            String zhuangbei = rs.getString("zhuangbei");
            // 封装
            Wow s = new Wow(id, role, role_cn, role_pinyin, zhuangbei);

            // 将对象放入到集合中
            list.add(s);
        }
        JDBCUtils.close(connection, ps, rs);
        // 返回集合
        return list;
    }
}

输出验证:

1|fs|法师|fashi|布甲
2|ms|牧师|mushi|布甲
3|ss|术士|shushi|布甲
4|dz|盗贼|daozei|皮甲
5|ws|武僧|wuseng|皮甲
6|xd|德鲁伊|xiaode|皮甲
7|sq|圣骑士|shengqi|板甲
8|zs|战士|zhanshi|板甲
9|dk|死亡骑士|siwangqishi|板甲
10|dh|恶魔猎手|emolieshou|皮甲

JDBC事务

事务基本介绍

数据库事务:

​ 事务处理(事务操作):保证所有事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。当在一个事务中执行多个操作时,要么所有的事务都被提交(commit),那么这些修改就永久地保存下来;要么数据库管理系统将放弃所作的所有修改,整个事务回滚(rollback)到最初状态。

JDBC 事务:

  • 当一个连接对象被创建时,默认情况下是自动提交事务:每次执行一个 SQL 语句时,如果执行成功,就会向数据库自动提交,而不能回滚
  • 为了让多个 SQL 语句作为一个事务执行
    • 调用 Connection 对象的 setAutoCommit(false); 以取消自动提交事务
    • 在所有的 SQL 语句都成功执行后,调用 commit(); 方法提交事务
    • 在出现异常时,调用 rollback(); 方法回滚事务

实现流程:

  1. 获取数据库连接

    • conn = JDBCUtils.getConnection();
  2. 开启事务

    • conn.setAutoCommit(false);
  3. 进行数据库操作

    xxx

  4. 若没有异常,则提交事务

    • conn.commit();
  5. 若有异常,则回滚事务

准备实验环境

在wow库中新建一张表 game_gold,插入样例数据

CREATE TABLE game_gold(
NAME VARCHAR(20) comment "游戏角色",
gold INT comment "游戏金币"
);

insert into game_gold (NAME,gold) values ("player01",3000);
insert into game_gold (NAME,gold) values ("player02",1000);


MariaDB [wow]> select * from game_gold;
+----------+------+
| NAME     | gold |
+----------+------+
| player01 | 3000 |
| player02 | 1000 |
+----------+------+
2 rows in set (0.000 sec)

需求:玩家1对玩家2交易金币800,玩家1扣除金币和玩家2获取到金币必须都完成,数据最终才准确

创建GameGold类,进行事务功能测试

代码如下:

package com.wangting.bigdata;


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

public class GameGold {
    public static void main(String[] args) throws SQLException {
        // 获取Connection对象
        Connection connection = JDBCUtils.getConnection();
        PreparedStatement ps = null;
        try {
            // 开启事务(禁止自动提交)
            connection.setAutoCommit(false);

            // sql语句
            String sql = "update game_gold set gold=? where name=?";
            // 预编译
            ps = connection.prepareStatement(sql);
            // 给占位符赋值 player01减少800金币
            ps.setInt(1, 2200);
            ps.setString(2, "player01");
            ps.executeUpdate();

            // 刻意添加报错代码,看是否会出现play01正确的语句成功执行到MySQL
            System.out.println(1 / 0);

            // player02获取增加800金币
            ps.setInt(1, 1800);
            ps.setString(2, "player02");
            ps.executeUpdate();

            // 事务提交
            connection.commit();
        } catch (Exception e) {
            // 事务回滚
            connection.rollback();
            // 打印异常信息
            e.printStackTrace();
        } finally {
            // 允许自动提交
            connection.setAutoCommit(true);
            // 关闭资源
            JDBCUtils.close(connection, ps);
        }
    }
}

因为有System.out.println(1 / 0);代码的存在,结果预期内的抛异常

java.lang.ArithmeticException: / by zero
at com.wangting.bigdata.GameGold.main(GameGold.java:27)

回到MySQL查询数据:

MariaDB [wow]> select * from game_gold;
+----------+------+
| NAME     | gold |
+----------+------+
| player01 | 3000 |
| player02 | 1000 |
+----------+------+

数据并没有发生一半执行一半没执行的情况,说明触发了事务回滚

现在将System.out.println(1 / 0);代码注释掉,再次执行GameGold类main方法

验证最终结果:

MariaDB [wow]> select * from game_gold;
+----------+------+
| NAME     | gold |
+----------+------+
| player01 | 2200 |
| player02 | 1800 |
+----------+------+

总结:

使用 ROLLBACK 语句可使数据变化失效

  • 数据改变被取消
  • 修改前的数据状态可以被恢复

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/157273.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WebGL-iTwin.js】实战篇(二):用nodejs代码详解iTwin.js中PhysicalObject生成方法

PhysicalObject 即真实存在的物理对象&#xff0c;比如&#xff1a;电脑、桌子等。在webgl中&#xff0c;我们人眼能看到的模型都是PhysicalObject&#xff0c;由多种几何图元类型构成&#xff0c;如&#xff1a;网格、实体、曲面、曲线&#xff0c;点云等。 其中带索引的多边…

XCTF:cat

打开是一个输入框&#xff0c;要求输入域名&#xff0c;尝试输入baidu.com进行测试 并无任何回显&#xff0c;测试下127.0.0.1本地地址 执行成功&#xff0c;并出现ping命令结果&#xff0c;这里很容易联想到命令注入&#xff0c;尝试进行命令拼接注入 但测试了常用的拼接字…

【5】变量和常量

一、什么是变量 首先我们要理解这么一个概念&#xff0c;在程序的运行过程中所有数据是保存在内存中的&#xff0c;我们代码中想使用这个数据的时候就要从内存中找&#xff0c;而变量的作用类似就是将内存地址保存&#xff0c;之后直接通过这个变量找内存中的数在Go语言中&…

JNI和Ndk开发

按照一下配置&#xff0c;基本能保证demo跑通 1、下载NDK&#xff0c;下载需要的版本 2、下载Cmake版本 3、项目结构&#xff1a;含C源码 4、编写JNI的加载类 public class YjkModel {static {System.loadLibrary("nativ"); //跟CMakeLists.txt 库名一致}public nat…

基于 APISIX 的服务网格方案 Amesh 积极开发中!

作者lingsamuel&#xff0c;API7.ai 云原生技术专家&#xff0c;Apache APISIX Committer。 在云原生快速发展的前提下&#xff0c;服务网格领域也开始逐渐火热。目前阶段&#xff0c;大家所熟知的服务网格解决方案很多&#xff0c;每种产品又各有其优势。因此在面对不同的行业…

python直接赋值、浅拷贝与深拷贝

本文主要参考这篇博文python浅拷贝与深拷贝 基本概念 首先了解python中的一些基本概念 变量&#xff1a;是一个系统表的元素&#xff0c;拥有指向对象的连接空间对象&#xff1a;被分配的一块内存&#xff0c;存储其所代表的值引用&#xff1a;是自动形成的从变量到对象的指…

ECU Extract + OS Task Mapping 步骤

纲要&#xff1a; 通过 Composition里面的Assembly Connection (Intra-ECU Communication)System Extract 里面的SystemDataMapping (Inter-ECU Communication) 已经把SWC的所有Data Element都连接上了&#xff0c;接下来就是把SWC的Runnable给Mapping到对应的OS Task上&…

(三)redis五大数据类型和key

目录 一、redis键&#xff08;key&#xff09;的常用操作 二、redis字符串&#xff08;String&#xff09; 1、简介 2、常用命令 3、数据结构 三、redis列表&#xff08;List&#xff09; 1、简介 2、常用命令 3、数据结构 四、redis集合&#xff08;Set&#xff09;…

Django(16):rest_framework框架使用指南

目录1.安装配置2.数据序列化2.1 Serializer2.2 ModelSerializer2.3 序列化对象的属性和方法3.请求和响应3.1 Request3.2 Response3.3 状态码3.4 as_view3.5 format_suffix_patterns3.6 示例4.CBV构建&#xff08;基于类的视图&#xff09;4.1 如何构建4.2 类型视图的扩展功能4.…

DMIPS, FLOPS, OPS概念

DMIPS DMIPS(Dhrystone Million Instructions executed Per Second)&#xff1a;Dhrystone是测量处理器运算能力的最常见基准程序之一&#xff0c;常用于处理器的整型运算性能的测量。Dhrystone是一种整数运算测试程序。换句话说&#xff0c;就是使用Dhrystone这种程序在不同的…

【云原生 | 52】Docker三剑客之Docker Compose第三节

&#x1f341;博主简介&#xff1a; &#x1f3c5;云计算领域优质创作者 &#x1f3c5;2022年CSDN新星计划python赛道第一名 &#x1f3c5;2022年CSDN原力计划优质作者 &#x1f3c5;阿里云ACE认证高级工程师 &#x1f3c5;阿里云开发者社区专…

FineReport填报报表

二次确认&#xff0c;删除行&#xff1a;参考&#xff1a; JS实现删除时二次确认- FineReport帮助文档 - 全面的报表使用教程和学习资料JS实现记录填报操作- FineReport帮助文档 - 全面的报表使用教程和学习资料确认后直接校验提交// 二次确认 var cell this.options.location…

开始安装Domino 12.0.2

大家好&#xff0c;才是真的好。 上周我们话题是NotesDomino12.0.2产品发布&#xff0c;主要说到了Domino12.0.2的新特性&#xff0c;新特性很多&#xff0c;要用很多篇来进行测试和说明。 今天我们主要谈谈Domino 12.0.2的系统要求和安装等。 首先&#xff0c;Domino12.0.2…

一、初识FreeRTOS之FreeRTOS简介

目录 一、什么是FreeRTOS&#xff1f; 二、为什么选择FreeRTOS&#xff1f; 三、FreeRTOS的特点 四、FreeRTOS资料与源码下载 五、FreeRTOS源码文件介绍 一、什么是FreeRTOS&#xff1f; Free即免费的&#xff0c;RTOS的全称是Real time operating system,中文就是实时操作…

python数据结构(一):字符串

一、字符串的格式化输出 1.1、格式化运算符 print("我跑完了第" str(lap 1) "圈")上面这段输出的代码使用了两个加号做了字符串拼接&#xff0c;并且将整形转换成了字符串。也可以使用一种更好的办法&#xff0c;格式化输出来打印这句话。 print(&quo…

xilinx srio ip学习笔记之再识srio

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 xilinx srio ip学习笔记之再识srio前言SRIO的理解IP核的理解前言 这段时间&#xff0c;随着对SRIO的学习&#xff0c;又有了更深的一点认识&#xff0c;不像一开始这么慌张了…

年终汇报工作,如何用项目管理工具展现成果

据报道&#xff0c;2022年11月20日的一次京东内部会议上&#xff0c;刘强东痛批京东中高层管理人员&#xff0c;表示部分高管醉心于 PPT 和奇妙词汇&#xff0c;或吹得天花乱坠但是执行一塌糊涂。 不可否认&#xff0c;刘强东提到的现象&#xff0c;的确是当今众多互联网大厂和…

基于frp实现外网访问个人本地服务器

适用对象想要通过frp实现内网服务被外网访问的人。关键词描述内网&#xff1a;内网指的是局域网&#xff0c;几台或者几十台电脑之间互访&#xff0c;也叫私网。外网&#xff1a;指的是我们上的Internet网络&#xff0c;也叫公网。需要具备的知识基础和条件1&#xff1a;外网服…

Java异常分类常见使用场景

今天在自己实现RxJava框架时&#xff0c;发现一些参数异常、流关闭异常等&#xff0c;Rxjava框架是会抛出相应的异常的&#xff0c;所以自己编写实现这块源码的时候&#xff0c;渐渐的也需要使用到这些知识&#xff0c;这里对这块做一下回顾总结。 使用 我们代码编写实现中&am…

开年喜讯!知道创宇一连斩获2022年度“IT168技术卓越奖”三项大奖

近日&#xff0c;业界知名IT垂直门户媒体IT168发布“2022年度IT168技术卓越奖”获奖名单&#xff0c;知道创宇凭借强大的技术优势与出色的产品能力脱颖而出&#xff0c;一举斩获网络安全领域三项大奖&#xff1a; 知道创宇创始人、CEO赵伟获评“数字化转型领军人物” ScanV-互…