【Java】JDBC

本文介绍了JDBC的基础知识,包括使用Statement和PreparedStatement执行SQL的增删查改操作,事务的概念及JDBC中的事务管理,以及简单的ORM映射示例。文章还提及了JDBC连接池的概念,帮助读者为学习更高级的持久层框架如MyBatis打下基础。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

温故知新:回顾一下JDBC

0. 前言

(1)学习目标

JDBC 是 Java 持久层基础,是我们学习 Java 技术栈过程中需要了解的知识。

据说在遥远的年代, Mybatis 尚未流行,Java 工程的持久层基本上就由JDBC完成。学习JDBC,既能巩固面向对象的思想,又能为日后学习持久层框架打下基础。

学习目标

  • 巩固SQL基础,暂未学SQL的同学也可以通过JDBC了解一下SQL
  • 通过JDBC,能深入了解万物皆对象,面向对象的思想
  • 承上启下,JDBC是较为原始的持久层实现方式,为日后学习持久层框架打下基础

(2) 准备工作

准备数据库
目前 Mysql 是最流行的轻量级关系型数据库之一,我们首先要准备一个数据库,可以选择本地的,也可以选择远程的:

Mysql官网下载连接
https://dev.mysql.com/downloads/mysql/

具体安装方式本文不赘述,请参考其他文章。

准备JDBC依赖
MVN仓库-Mysql-Connector-Java

读者可通过 Maven 下载这个JDBC依赖,也可以像我一样手动拉取:
jdbc-jar

若是手动拉取的jar包,可参考以下文章将它添加至项目的Library:
优快云-往项目中添加jar包:https://blog.youkuaiyun.com/pan_1214_/article/details/126283072

测试驱动
黑猫白猫,抓到老鼠就是好猫,无论采用哪种方式,只要能使用JDBC依赖即可,我们做建个类做个测试:

public static void main(String[] args) {
           
        //初始化驱动
        try {
            //驱动类com.mysql.cj.jdbc.Driver
            //如果忘记了导包,就会抛出ClassNotFoundException
            Class.forName("com.mysql.cj.jdbc.Driver");
              
            System.out.println("数据库驱动加载成功 !");
   
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
           
    }

连接数据库
参考下面代码连接数据库:

public static void main(String[] args) {
    //初始化驱动
    try {
        //驱动类com.mysql.cj.jdbc.Driver
        //如果忘记了导包,就会抛出ClassNotFoundException
        Class.forName("com.mysql.cj.jdbc.Driver");  
        //连接数据库
        Connection c = DriverManager.getConnection( 	"jdbc:mysql://127.0.0.1:3306/myfirstdb?characterEncoding=UTF-8",
          "root", "root");
        System.out.println("连接成功,获取连接对象: " + c);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

建表
建个表来做接下来的学习演示:

CREATE TABLE `user` (
  `id` bigint NOT NULL COMMENT '主键id',
  `user_account` varchar(255) DEFAULT NULL COMMENT '登录账号',
  `username` varchar(255) DEFAULT NULL COMMENT '用户名',
  `avatar_url` varchar(255) DEFAULT NULL COMMENT '头像url',
  `gender` tinyint DEFAULT NULL COMMENT '性别',
  `user_password` varchar(255) DEFAULT NULL COMMENT '密码',
  `phone` varchar(255) DEFAULT NULL COMMENT '电话',
  `email` varchar(255) DEFAULT NULL COMMENT '邮箱',
  `user_status` int NOT NULL DEFAULT '0' COMMENT '状态 0-正常',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `is_deleted` int NOT NULL DEFAULT '0' COMMENT '是否删除 ',
  `user_role` int NOT NULL DEFAULT '0' COMMENT '用户角色 0-普通用户 1-管理员',
  `id_card` varchar(255) DEFAULT NULL COMMENT '实名注册,身份证号'
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;

1. CRUD

面向对象编程的一大特点是我们可以直接用大佬们写好的各种类、各种方法。我们在准备工作中引入的JDBC 依赖 jar 包里就是要用到的各种类、方法。

JDBC 提供一个Statement 类 来执行 SQL 语句。

1.1 Statement执行增删查改

Statement对象
我们可以在连接对象中,创建Statement对象,然后通过这个对象执行CRUD

/连接数据库
        Connection c = DriverManager.getConnection(
                "jdbc:mysql://127.0.0.1:3306/myfirstdb?characterEncoding=UTF-8",
                "root", "root");
        Statement s = c.createStatement();
        String insert = "INSERT INTO  `user`  ( id, `user_account` ,  `username` ,  `email` ) VALUES (3,'sharry3', 'sharrycloud1', 'example@example.com')";
        s.execute(insert);
        //关闭连接
        s.close();
        c.close();

在上面例子中,我们不难发现,我们需要将SQL 语句写成String ,作为参数传递进Statement对象,执行完毕后记得像关流一样将其关闭。

CRUD
我们演示 使用 Statement 对象 执行 CRUD

先列举 增删改的例子,因为增删改的返回值都是影响行数,基本上用法都差不多:

public static void main(String[] args) throws SQLException {
        //连接数据库
        Connection c = DriverManager.getConnection(
                "jdbc:mysql://127.0.0.1:3306/myfirstdb?characterEncoding=UTF-8",
                "root", "root");
    	Statement s = c.createStatement();
   
        // 新增
        String insert = "INSERT INTO  `user`  ( id, `user_account` ,  `username` ,  `email` ) VALUES (3,'sharry3', 'sharrycloud1', 'example@example.com')";
        s.execute(insert);
        String insert = "INSERT INTO  `user`  ( id, `user_account` ,  `username` ,  `email` ) VALUES (3,'sharry3', 'sharrycloud1', 'example@example.com')";
        System.out.println("影响了"+s.execute(insert)+"行");
        
        //更新数据
        String update = "UPDATE `user` SET `username` = 'sharrycloud2' WHERE `user_account` = 'sharry2'";
        System.out.println("影响了"+s.executeUpdate(update)+"行");
        
        //删除数据
        String delete = "DELETE FROM `user` WHERE `user_account` = 'sharry2'";
        System.out.println("影响了"+s.executeUpdate(delete)+"行");
    
    	//关闭连接
        s.close();
        c.close();
}

查询举例:
我们可以使用 ResultSet 接收查询结果

	 //查询数据
     String select = "SELECT * FROM `user`";
     ResultSet rs = s.executeQuery(select);
     while (rs.next()){
     	// 获取其他属性,依此类推
        System.out.println(rs.getString("user_account"));
     }

1.2 PreparedStatement

PreparedStatement 是预编译的 Statement ,优点是可以进行参数设置,并且性能与安全性相比Statement有所提升。

当前,除了特别老旧的项目或者特殊业务,我们已经极少直接使用JDBC进行持久层操作,因此哪怕PreparedStatement性能优越,也用得极少,此处作为了解。

由于PreparedStatement是基于SQL语句创建的,既可以当成Statement使用,也可以通过填充值的方式设置SQL语句,我们稍微举个例子,具体使用可以到真要用到的时候,再去查 JDBC 的 API 文档:

String sql = "insert into user values(null,?,?,?)";
        PreparedStatement ps = c.prepareStatement(sql);
        ps.setString(1, "sharry");
        ps.setString(2, "sharrycloud1");
        ps.setString(3, "");
        ps.execute();

2. 事务

事务是持久层需要重视的问题,即便现在JDBC直接使用率很低,但是它也提供了事务处理。

2.1 概念回顾

首先我们来回顾一下事务的八股文:

事务:是一组操作的集合,它是一个不可分割的工作单元,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。

事务的特性:ACID

  • 原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败。
    -一致性(Consistency):事务完成时,必须使所有的数据都保持一致状态。
  • 隔离性(Isolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
  • 持久性(Durability):事务一旦提交或回滚,它对数据库中的数据的改变是永久的。

2.2 JDBC 事务

JDBC 提供的事务处理机制实际代码操作起来也比较简单,举个例子:

		// 使用事务
        c.setAutoCommit(false);
        String sql = "insert into user values(null,?,?,?)";
        PreparedStatement ps = c.prepareStatement(sql);
        ps.setString(1, "sharry");
        ps.setString(2, "sharrycloud1");
        ps.setString(3, "");
        ps.execute();
        
        //提交事务
        c.commit();

需要注意的是,由于 Mysql 的表需要的 InnoDB 才支持事务。具体请自行查阅Mysql 原理。

3. ORM

ORM:Object Relationship Database Mapping, 对象和关系数据库的映射。

ORM 很好理解,就是将对象的属性和值设置成数据库对应的字段和值,然后通过 JDBC 等持久化操作,实现用 Java 代码对数据库表的操作。

ORM 是目前我们常用的 Mybatis 持久层框架 原理, 由于Mybatis也是基于JDBC的,因此ORM其实早早地就由JDBC支持。

其实 使用 JDBC 的方式 实现 ORM 很简单, 就是和我们工作时一样,创建实体类,然后通过 Statement 或者 ResultSet 对相应的值进行对应,根据业务进行下一步操作,我们直接举个例子:

篇幅关系,我们只截取我们创建的表的几个字段来演示:

实体类

public class UserVO {

    private Long id;
    private String userAccount;
    private String username;
    private String avatarUrl;
}

ORM举例

public static void main(String[] args) throws Exception {
        //连接数据库
        Connection c = DriverManager.getConnection(
                "jdbc:mysql://127.0.0.1:3306/myfirstdb?characterEncoding=UTF-8",
                "root", "root");
    	Statement s = c.createStatement();
        //创建执行sql的对象
        Statement s = c.createStatement();
        //执行查询sql
        String sql = "select * from user";
        ResultSet rs = s.executeQuery(sql);
        List<UserVO> userVOS = new ArrayList<>();
        
        //遍历结果集
        while (rs.next()) {
            UserVO userVO = new UserVO();
            userVO.setId(rs.getLong("id"));
            userVO.setUserAccount(rs.getString("user_account"));
            userVO.setUsername(rs.getString("username"));
            userVO.setAvatarUrl(rs.getString("avatar_url"));
            userVOS.add(userVO);
        }
        
        //关闭连接
        s.close();
        c.close();
    }

4. JDBC 连接池

JDBC 也提供了连接池,支持多线程。具体原理可参考线程池原理。我们直接举例:

public class ConnectionPool {
  
    List<Connection> cs = new ArrayList<Connection>();
 	int size;
  	public ConnectionPool(int size) {
        this.size = size;
        init();
    }
  
    public void init() {
        try {
            Class.forName("com.mysql.jdbc.Driver");
            for (int i = 0; i < size; i++) {
                Connection c = DriverManager
 .getConnection("jdbc:mysql://127.0.0.1:3306/myfirstdb?characterEncoding=UTF-8",
                "root", "root");
                cs.add(c);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
  
    public synchronized Connection getConnection() {
        while (cs.isEmpty()) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Connection c = cs.remove(0);
        return c;
    }
  
    public synchronized void returnConnection(Connection c) {
        cs.add(c);
        this.notifyAll();
    }
  
}

5. 总结

本文学习了常见持久层框架的原理:JDBC;通过学习JDBC,我们进一步体验了面向对象的思想,一切皆对象:我们可以直接使用大佬们写好的JDBC相关类与方法、可以通过ORM将数据库表字段与值通过ORM映射到实体类,实现面向对象的方式操作数据库表。最后,我们简单提了一下数据库连接池。通过本文的学习,为接下来持久层框架的学习打下基础。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值