Java —— JDBC与批处理、事务

什么是JDBC

  • JDBC代表Java数据库连接(Java Database Connectivity)
  • 用于Java编程语言和数据库之间进行数据库连接的标准Java API
前期准备1:创建表格
  • Navicat查看建表代码
  • 双击要打开的表,右侧顶端点击ddl小方框
CREATE TABLE `s` (
  `id` int(6) NOT NULL,
  `name` varchar(20) COLLATE utf8_bin DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `gender` varchar(2) COLLATE utf8_bin DEFAULT NULL,
  `dept` varchar(20) COLLATE utf8_bin DEFAULT NULL,
  `dept_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
前期准备2:插入数据

201801 刚子 18 男 数学系 1
201802 严子 18 女 计算机系 2
201803 谢子 20 男 数学系 1
201804 周子 11 女 计算机系 2
201805 喜子 22 男 信息系 3
201806 万子 23 女 数学系 1
201807 婷子 10 男 计算机系 2
201808 周钱系 18 女 信息系 3
201809 雨子 19 男 计算机系 2
201810 小子 18 女 信息系 3
201811 晓子 21 男 计算机系 2

JDBC代码
package cs.kaoyan.mysql.com;

import com.mysql.jdbc.Driver;

import java.sql.*;
import java.util.LinkedHashMap;

public class Test1 {
    private static final String url =
            //jdbc:mysql:连接mysql的协议
            //db47指的数据库
            "jdbc:mysql://localhost:3306/db47?useSSL=false&characterEncoding=utf8";
    private static final String username = "root";
    private static final String password = "123456";

    public static void main(String[] args) throws SQLException {
        //第1步. 注册/加载驱动
        //用户要想操作数据库需要数据库的驱动
        //导import com.mysql.jdbc.Driver包
        //注册驱动写法1:需要排除异常
        DriverManager.registerDriver(new Driver());

        // 注册驱动写法2
        // new Driver();
        // 注册驱动写法3
        // Class.forName("com.mysql.jdbc.Driver");

        //第2步. 建立链接
        Connection connection = DriverManager.getConnection(url, username, password);
        
        // 3. 获取Statement对象
        // 数据库连接对象Connection并不能直接去发送SQL语句给MySQL服务器
        // 需要借助于Statement对象包装请求之后发送
        Statement statement = connection.createStatement();

        //提交sql语句
        //s指的是数据库db47中的一张表
        //新增一条二郎神的数据(增)
        /*String sql = "insert into s values (201812,'二郎神',2000,'男','计算机系',2);";
        statement.executeUpdate(sql);*/


        //更新二郎神的年龄为3000岁(改)
        /*String sql  = "update s set age = 3000 where id = 201812;";
        statement.executeUpdate(sql);*/

        //删除新插入的二郎神的数据(查)
        /*String sql = "delete from s where id = 201812;";
        statement.executeUpdate(sql);*/

        //使用有序结构LinkedHashMap用来存储查询到的数据
        LinkedHashMap<Integer, String> map = new LinkedHashMap<>();

        //statement连接中的executeQuery方法提供了查询功能
        //返回以恶搞结果集resultSet
        String sql = "select *  from s;";
        ResultSet resultSet = statement.executeQuery(sql);

        //查询结果集
        while (resultSet.next()){
            String name = resultSet.getString("name");
            int id = resultSet.getInt("id");

            map.put(id,name);
        }

        //输出结果
        System.out.println(map);
        
        //关闭链接
        connection.close();
        statement.close();
    }
}

数据库的批处理操作

在实际应用中,我们经常会遇到数据的批量添加问题。例如在学校的学生管理系统中,每年开学之际,学校都会新来一批同学,我们需要根据同学的报道情况统计出一个学生信息表(Excel表),然后录入到管理系统中,后续可以进行选课操作,如何实现将excel数据导入数据库之中呢?

前期准备:创建学生表
CREATE TABLE `user` (
  `id` int(11) DEFAULT NULL,
  `username` varchar(20) COLLATE utf8_bin DEFAULT NULL,
  `userpassword` varchar(20) COLLATE utf8_bin DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
code1 使用for循环单条插入(用时42s)

时间开销:

  • sql语句在网络中传输开销: 每一次的网络请求都是固定开销
  • sql被数据库服务编译的开销
  • 数据库读外存和写外存的开销
  • 无预编译,无批处理,向MySQL服务器发送了SQL语句 1w次,SQL语句被编译了1w次,SQL语句也被执行了1w次,故效率极慢
package cs.kaoyan.mysql.batch;

import com.mysql.jdbc.Driver;

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

public class Batch1 {
    //连接数据库需要的数据
    private static final String url =
            //jdbc:mysql:连接mysql的协议
            //db47指的数据库
            "jdbc:mysql://localhost:3306/db47?useSSL=false&characterEncoding=utf8";
    private static final String username = "root";
    private static final String password = "123456";

    public static void main(String[] args) throws SQLException {
        //注册驱动
        new Driver();

        //获取连接
        Connection connection = DriverManager.getConnection(url,username,password);
        //获取statement,需要抛出异常
        Statement statement = connection.createStatement();
        //插入数据(10000条数据)
        for (int i = 1; i <= 10000; i++) {
            //生成姓名
            String name = "stu" + i;
            String sql = "insert into user values (" + i + ",'" + name + "','123')";
            //执行插入操作
            statement.executeUpdate(sql);
        }

        //关闭连接
        connection.close();
        statement.close();
    }
}

code2 使用PreparedStatement方式(用时45s)

时间开销:

  • 虽然只编译一次,但是仍然需要执行sql语句1w次,故效率不会差别太大
  • 有预编译,无批处理,向MySQL服务器发送了SQL语句 1次,SQL语句被编译了一次,发送了数据1w次,SQL语句被执行了1w次
package cs.kaoyan.mysql.batch;

import com.mysql.jdbc.Driver;

import java.sql.*;

public class Batch2 {
    //连接数据库需要的数据
    private static final String url =
            //jdbc:mysql:连接mysql的协议
            //db47指的数据库
            "jdbc:mysql://localhost:3306/db47?useSSL=false&characterEncoding=utf8";
    private static final String username = "root";
    private static final String password = "123456";

    public static void main(String[] args) throws SQLException {
        //注册驱动
        new Driver();

        //获取连接
        Connection connection = DriverManager.getConnection(url,username,password);

        //sql语句,其中的?是占位符
        String sql = "insert into user values (?,?,?)";
        //使用预编译减少数据库的编译次数
        //只编译一次
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        //插入数据
        for (int i = 1; i <= 10000; i++) {
            //生成姓名
            String name = "stu" + i;
            //把数据库db47中的user表的第1列设置为i
            preparedStatement.setInt(1,i);
            //把数据库db47中的user表的第2列设置为name
            preparedStatement.setString(2,name);
            //把数据库db47中的user表的第3列设置为123,即密码写死
            preparedStatement.setString(3,"123");

            //执行sql语句
            preparedStatement.execute();
        }
        //关闭连接
        connection.close();
        preparedStatement.close();
    }
}
code3 使用Statement的批处理方式(用时42s)

时间开销:
向MySQL服务器发送了SQL语句1次,这一次中包含1w条SQL语句信息,SQL语句被编译了1w次,SQL语句也被执行了1w次,时间开销大

package cs.kaoyan.mysql.batch;

import com.mysql.jdbc.Driver;

import java.sql.*;

public class Batch3 {
    //连接数据库需要的数据
    private static final String url =
            //jdbc:mysql:连接mysql的协议
            //db47指的数据库
            "jdbc:mysql://localhost:3306/db47?useSSL=false&characterEncoding=utf8";
    private static final String username = "root";
    private static final String password = "123456";

    public static void main(String[] args) throws SQLException {
        //注册驱动
        new Driver();

        //获取connection连接
        Connection connection = DriverManager.getConnection(url,username,password);
        //获取statement连接
        Statement statement = connection.createStatement();

        //插入数据
        for (int i = 1; i <= 10000; i++) {
            String name = "stu" + i;
            String sql = "insert into user values (" + i + ",'" + name + "','123')";

            //暂时没有发送请求(类似加入缓存)
            statement.addBatch(sql);
        }

        //执行批处理:一次把上面10000条sql语句发送走
        //数据库编译了10000条sql语句
        statement.executeBatch();
        //关闭连接
        connection.close();
        statement.close();
    }
}

code4 使用PreparedStatement的批处理方式(用时43s)

时间开销:

  • 数据库编译了1条,连接发送了两次: 1次sql,1次批处理的数据
  • 有预编译,有批处理,效率较好
package cs.kaoyan.mysql.batch;

import com.mysql.jdbc.Driver;

import java.sql.*;

public class Batch4 {
    //连接数据库需要的数据
    private static final String url =
            //jdbc:mysql:连接mysql的协议
            //db47指的数据库
            "jdbc:mysql://localhost:3306/db47?useSSL=false&characterEncoding=utf8";
    private static final String username = "root";
    private static final String password = "123456";

    public static void main(String[] args) throws SQLException {
        //注册驱动
        new Driver();

        //获取connection连接
        Connection connection = DriverManager.getConnection(url,username,password);

        //sql语句,其中的?是占位符
        String sql = "insert into user values (?,?,?)";
        //使用预编译减少数据库的编译次数
        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        //插入数据
        for (int i = 1; i <= 10000; i++) {
           String name = "stu" + i;
           preparedStatement.setInt(1,i);
           preparedStatement.setString(2,name);
           preparedStatement.setString(3,"123");
           //批处理
           preparedStatement.addBatch();
        }

        //执行sql
        preparedStatement.executeBatch();

        //关闭连接
        connection.close();
        preparedStatement.close();
    }
}

事务

假如我们在维护一个银行的用户表,在我们维护这个表的过程中比较常见的行为就是转账,假如在某个时刻两个用户存在相互转账的需求,我们在实现这个转账逻辑中又有可能遇到SQL错误、链接失败等问题,通过事务可以保证转账的正确性,防止一方付了钱但是另一方并未收到转账的情况出现。

前期准备1:创建表格

银行账户表:

CREATE TABLE `account` (
`id` int(10) NOT NULL PRIMARY KEY AUTO_INCREMENT,
`name` varchar(10) DEFAULT NULL,
`money` float DEFAULT NULL
)ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
前期准备2:插入数据
insert into account values(1, "鹅城黄四郎1",  30000 );
insert into account values(2, "鹅城家族2",  2000 );
insert into account values(3, "鹅城家族3",  2000 );
insert into account values(4, "鹅城家族4",  2000 );
insert into account values(5, "张麻子",  10 );
初始状态

在这里插入图片描述

code
package cs.kaoyan.mysql.transaction;

import com.mysql.jdbc.Driver;

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

public class Demo1 {
    //连接数据库需要的数据
    private static final String url =
            //jdbc:mysql:连接mysql的协议
            //db47指的数据库
            "jdbc:mysql://localhost:3306/db47?useSSL=false&characterEncoding=utf8";
    private static final String username = "root";
    private static final String password = "123456";

    public static void main(String[] args) throws SQLException {
        //注册驱动
        new Driver();
        //connection连接
        Connection connection = DriverManager.getConnection(url, username, password);
        //statement连接
        Statement statement = connection.createStatement();
        //开启事务,同一个事务里面的操作要么都成功,要么都失败
        //保证转账的正确性
        connection.setAutoCommit(false);

        String sql1 = "update account set money = money - 200 where id = 1";
        String sql2 = "update account set money = money + 200 where id = 5";

        try{
            statement.executeUpdate(sql1);
            statement.executeUpdate(sql2);
        }catch (Exception e){
            //若sql语句出现了问题,则回滚事务
            //回滚事务之后,之前所有的操作都会失效
            connection.rollback();
        }

        //执行到这里说明sql没出问题,可以提交事务
        //提交事务之后,从开启事务到提交事务之间所有的操作才会生效
        connection.commit();

        //关闭资源
        connection.close();
        statement.close();
    }
}
结束时数据库状态

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值