JDBC入门详解

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介: JDBC入门详解

一、什么是JDBC

JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。也就是我们Java操作数据库的工具接口。

二、安装配置。

1.下载mysql5地址:

https://mvnrepository.com/

如图:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
然后:

下载的jar包
在java工程中创建lib目录,将复制到工程的lib目录:

在这里插入图片描述

配置让我们的mysql的jar包生效:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

认识jdbc的api中常用的接口java.sql. 和javax.sql.

在这里插入图片描述
ava.sql.Driver(驱动的接口),java.sql.DriverManager(驱动管理器)
java.sql.ResultSet(查询的结果放置的地方-结果集)
java.sql.Statement(用于操作数据库完成CRUD,有bug,有sql注入漏洞)
java.sql.PreparedStatement(用于操作数据库完成CRUD,推荐使用,防sql注入漏洞)
java.sql.Connection(完成数据库连接)

在这里插入图片描述
javax.sql.DataSource(连接池)

JDBC操作数据库的流程

下载和在工程中配置mysql驱动
package com.xja.test;

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

/**
 * 连接数据库的测试类
 * 1.需要加载驱动mysql5,这个驱动针对mysql5这个版本的驱动,mysql-connector-java-5.1.49.jar
 * 2.下载驱动的方法  https://mvnrepository.com/
 */
public class TestJDBC1 {
    public static void main(String[] args) {
        //1.下载和在工程中配置mysql驱动
        try {
            //2.加载驱动
            Class.forName("com.mysql.jdbc.Driver");
            //3.创建连接mysql的url,mytest为连接的数据库
            String url = "jdbc:mysql://127.0.0.1:3306/mytest?useUnicode=true&characterEncoding=utf-8";
            //连接数据库的账号
            String user = "root";
            //连接数据库的密码
            String password = "root";
            //4.连接数据库 java.sql.Connection
            Connection conn = DriverManager.getConnection(url,user,password);
            //5.测试连接是否成功
            System.out.println(conn);
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
    }
}

如图:
在这里插入图片描述

完成数据库的查询

在这里插入图片描述

package com.xja.test;

import java.sql.*;

/**
 * 连接数据库的测试类
 * 1.需要加载驱动mysql5,这个驱动针对mysql5这个版本的驱动,mysql-connector-java-5.1.49.jar
 * 2.下载驱动的方法  https://mvnrepository.com/
 */
public class TestJDBC1 {
    public static void main(String[] args) {
        //1.下载和在工程中配置mysql驱动
        try {
            //2.加载驱动
            Class.forName("com.mysql.jdbc.Driver");
            //3.创建连接mysql的url,mytest为连接的数据库
            String url = "jdbc:mysql://127.0.0.1:3306/mytest?useUnicode=true&characterEncoding=utf-8";
            //连接数据库的账号
            String user = "root";
            //连接数据库的密码
            String password = "root";
            //4.连接数据库 java.sql.Connection
            Connection conn = DriverManager.getConnection(url,user,password);
            //5.测试连接是否成功
            //System.out.println(conn);
            //6.创建操作的对象
            Statement stmt = conn.createStatement();
            //7.创建sql
            String sql = "select * from dept";
            //8.执行查询
            ResultSet rs = stmt.executeQuery(sql);
            System.out.println("编号\t名称\t地址\t创建时间");
            while(rs.next()){
                int deptNo = rs.getInt(1);
                String dname = rs.getString(2);
                String loc = rs.getString(3);
                java.sql.Timestamp timestamp = rs.getTimestamp(4);
                System.out.println(deptNo + "\t" + dname + "\t" + loc + "\t" + timestamp);
            }

        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
    }
}
完成数据库的插入

主键不是自动增长:


String sql = "insert into dept values(60,'computer','cq',now())";

int count = stmt.executeUpdate(sql);//count  
System.out.println("插入了" + count + "行");

主键是自动增长:
在这里插入图片描述
创建sql 使用null 主键必须为自动增长
String sql = "insert into teacher values(null,'王老师')";
//8.执行修改 插入 删除 都是一个方法 executeUpdate() jdbc也采用了默认就提交了
int count = stmt.executeUpdate(sql);//count 为修改 插入 删除影响的行数
System.out.println("插入了" + count + "行");

完成数据库的修改

String sql = "update dept set loc = 'chongqing' where deptno = 60";

int count = stmt.executeUpdate(sql);
System.out.println("修改了" + count + "行");
完成数据库的删除
String sql = "delete from dept  where deptno = 60";

int count = stmt.executeUpdate(sql);
System.out.println("删除了" + count + "行");
Statement的子接口

Statement 不能防sql注入漏洞
PreparedStatement 可以预编译sql语句,效率高,防sql注入漏洞,传递参数使用占位符?,使用很方便
CallableStatement 用途为调用存储过程(不在使用,了解即可)

使用PreparedStatement 完成查询
//创建sql
String sql = "select * from dept where deptno = ? and dname = ?";//从左边到右边 顺序为第一个?为1
//6.创建操作的对象
stmt = conn.prepareStatement(sql);
//给占位符赋值
stmt.setInt(1,50);
stmt.setString(2,"PROGRAMING");
rs = stmt.executeQuery();//不要在传递sql语句作为参数

连接池:

在这里插入图片描述
对比租赁汽车:
在这里插入图片描述

实现连接池的步骤一,添加jar包,配置jar包

在这里插入图片描述

在src目录下创建dbcp.properties文件,用于配置dbcp参数,代码如下:
在这里插入图片描述

创建连接工具类ConnectionUtil:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
工具类的代码:

package com.xja.test.util;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
public class ConnectionUtil {

        // 数据源对象(连接池)
        private static DataSource ds;
        //定义连接对象
        private static Connection conn;

        // 私有构造方法。外部不能new
        private ConnectionUtil () {
        }
        static {
            //加载数据源ds对象
//            String path = System.getProperty("user.dir");
//            path = path + "\\src\\dbcp.properties";
//            InputStream inputStream = new FileInputStream(path);
            InputStream is = ConnectionUtil.class.getResourceAsStream("/dbcp.properties");
            Properties properties = new Properties();
            try {
                properties.load(is);
                ds = BasicDataSourceFactory.createDataSource(properties);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        public static Connection getConnection()
                throws SQLException {
            if (conn == null || conn.isClosed()) {
                // 创建数据库连接(从连接池中获取连接)
                conn = ds.getConnection();
            }
            return conn;
        }

        public static void closeConnection() {
            try {
                if (conn != null && !conn.isClosed()) {
                    conn.close();//在使用DBCP时,释放连接对象。
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }


        //测试连接
        public static void main(String[] args) throws SQLException {
            System.out.println(getConnection());
        }
}
创建案例用的表格

账户表:
在这里插入图片描述
操作记录表:
在这里插入图片描述
在这里插入图片描述
添加了账户的测试数据:
在这里插入图片描述

系统分层

在这里插入图片描述
系统分层的好处为:利于开发、利于维护、利于调试、利于开发效率、利于分工
分层后的开发流程:
在这里插入图片描述
系统分层(就是分包)的实现步骤:
8.1使用orm的原理,应该为数据库的表格创建映射的实体类Account账户类和AccountRecord账户记录类,创建com.xja.domain包,创建Account账户类和AccountRecord账户记录类:
在这里插入图片描述
在这里插入图片描述
创建dao层(注意:dao层如果有异常,一律不处理直接使用throws抛出异常,异常在业务层service处理),创建com.xja.dao包,创建AccountDao接口和在com.xja.dao.impl包AccountDaoImpl实现类:
在这里插入图片描述
创建service业务层,创建包com.xja.service,创建AccountService接口,com.xja.service.impl包创建AccountServiceImpl实现类
在这里插入图片描述
创建View视图层的界面创建包com.xja.view创建类AccountListView
在这里插入图片描述
根据银行账号查询账户信息(正确开发的流程:开发dao层-测试,开发service层-测试,开发控制器(还没有学习)-测试,开发视图层-测试,这样开发很容易找到问题所在的层,提高开发效率)
第一步开发dao 层:
在这里插入图片描述
在这里插入图片描述
第二步开发service 层:
在这里插入图片描述
在这里插入图片描述

第三步开发view层:
在这里插入图片描述
测试结果:
在这里插入图片描述
根据银行账号和金额实现存钱业务:
第一步:创建一个自定义的异常com.xja.exception.AccountDepositException
在这里插入图片描述
第二步:开发dao层
在这里插入图片描述
在这里插入图片描述
第三步:开发service层
1.需要处理系统异常SQLException
2.需要抛出自定义异常AccountDepositException
3.开启事物处理
在这里插入图片描述
在这里插入图片描述
第四步:开发view层
在这里插入图片描述
补充业务层的操作:
在这里插入图片描述

改进一下,将账户处理的自定义异常,统统的叫AccountException,将AccountDepositException删除:
在这里插入图片描述
根据银行账号和金额实现取钱业务:
第一步: 开发dao层
在这里插入图片描述
在这里插入图片描述

第二步: 开发service层:
在这里插入图片描述

AccountServiceImpl实现类的代码:

package com.xja.service.impl;

import com.xja.dao.AccountDao;
import com.xja.dao.AccountRecordDao;
import com.xja.dao.impl.AccountDaoImpl;
import com.xja.dao.impl.AccountRecordDaoImpl;
import com.xja.domain.Account;
import com.xja.domain.AccountRecord;
import com.xja.exception.AccountException;
import com.xja.service.AccountService;
import com.xja.util.ConnUtil;

import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * 账户的业务层的实现类,实现业务逻辑和处理异常和事物管理
 */
public class AccountServiceImpl implements AccountService {

    //业务层调用数据访问层
    private AccountDao accountDao = new AccountDaoImpl();

    private AccountRecordDao accountRecordDao = new AccountRecordDaoImpl();

    /**
     * 查询所有的账户信息
     * @return
     */
    @Override
    public List<Account> getAllAccount() {
        List<Account> accountList = null;
        try {
            accountList = accountDao.getAllAccount(); //业务层需要处理异常,不要直接抛出异常
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            //关闭数据库连接,释放连接
            ConnUtil.closeConnection();
        }
        return accountList;
    }

    /**
     * 根据银行账号查询账户信息
     * @param accNo
     * @return
     */
    @Override
    public Account selectAccountByAccNo(String accNo) {
        Account account = null;
        try {
            account =  accountDao.selectAccountByAccNo(accNo);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            //关闭数据库连接,释放连接
            ConnUtil.closeConnection();
        }
        return account;
    }

    /**
     * 根据账户信息和金额实现存钱
     * 1.需要处理系统异常SQLException
     * 2.需要抛出自定义异常AccountDepositException
     * 3.开启事物处理(增加,修改,删除都需要事物处理)
     * 4.关闭数据库,释放连接
     * @param acc
     * @param amount
     * @throws SQLException
     */
    @Override
    public void updateAccountBalance(Account acc, double amount) throws AccountException {
        try {
            //同学们完善,实现要查询存钱钱的账号是否存在

            //3.开启事物处理
            //因为jdbc默认提交,所以出现了异常,没有办法回滚,将jdbc的默认提交设置为默认不提交,没有异常才提交,有异常就回滚
            ConnUtil.getConnection().setAutoCommit(false);//交设置为默认不提交
            accountDao.updateAccountBalance(acc,amount);//执行操作
            //需要同学们完善,要向记录表插入存钱的记录日志数据


            ConnUtil.getConnection().commit();//没有异常才提交,该代码一定要写到所有操作的最后
        } catch (SQLException throwables) {////1.需要处理系统异常SQLException
            try {
                ConnUtil.getConnection().rollback();//有异常就回滚
            } catch (SQLException e) {
                e.printStackTrace();
            }
            //2.需要抛出自定义异常AccountDepositException
            throw new AccountException("账户存钱发生错误,存钱失败");
        }finally {
            //4.关闭数据库连接,释放连接
            ConnUtil.closeConnection();
        }
    }
    /**
     * 根据账户信息和金额实现取钱
     * 1.需要处理系统异常SQLException
     * 2.需要抛出自定义异常AccountDepositException
     * 3.开启事物处理(增加,修改,删除都需要事物处理)
     * 4.关闭数据库,释放连接
     * @param acc
     * @param amount
     * @throws SQLException
     */
    @Override
    public void withdrawal(Account acc, double amount) throws AccountException {
        try {
            //实现要查询取钱的账号是否存在和余额不足
            Account account = accountDao.selectAccountByAccNo(acc.getAccNo());
            if(Objects.isNull(account)){//没有查询到账户信息
                throw new AccountException("账户不存在");
            }else{//有查询到账户信息
               if(account.getAccBalance() < amount){//余额金额不足
                   throw new AccountException("余额金额不足");
               }else{
                   //3.开启事物处理
                   //因为jdbc默认提交,所以出现了异常,没有办法回滚,将jdbc的默认提交设置为默认不提交,没有异常才提交,有异常就回滚
                   ConnUtil.getConnection().setAutoCommit(false);//交设置为默认不提交
                   //执行取钱操作
                   accountDao.withdrawal(acc,amount);
                   //同时要完成向账户记录表中插入当前操作的记录数据
                   AccountRecord accountRecord = new AccountRecord();
                   accountRecord.setReAcc(account);
                   accountRecord.setReAction("取钱");
                   accountRecord.setReAccTo(account);
                   accountRecord.setReAmt(amount);
                   //插入账户记录表
                   accountRecordDao.inertAccRecord(accountRecord);
                   ConnUtil.getConnection().commit();//没有异常才提交,该代码一定要写到所有操作的最后
               }
            }
        } catch (SQLException throwables) {////1.需要处理系统异常SQLException
            try {
                ConnUtil.getConnection().rollback();//有异常就回滚
            } catch (SQLException e) {
                e.printStackTrace();
            }
            //2.需要抛出自定义异常AccountDepositException
            throw new AccountException("账户取钱发生错误,取钱失败");
        }finally {
            //4.关闭数据库连接,释放连接
            ConnUtil.closeConnection();
        }

    }
}

第三步 :创建AccountRecord的dao层,名字叫AccountRecordDao和实现类AccountRecordDaoImpl:
在这里插入图片描述
在这里插入图片描述

第四步 :创建view层
在这里插入图片描述
测试结果需要三个结果同时都有:
在这里插入图片描述
看到金额较少:
在这里插入图片描述
日志表有数据:
在这里插入图片描述
根据开户业务(知识点:在插入数据时返回自动增加的主键的值,拿到account表中acc_id)这个需要jdbc第二章的知识点才能完成该功能:
业务需求:在插入account表时(开户),自动增加的主键acc_id的值要返回,因为该值要插入到我们的acc_record表(开户日志)中的re_acc_id字段中

dao层:
在这里插入图片描述
在这里插入图片描述

第二步:开发service层
在这里插入图片描述

业务层的实现类:

/**
 * 开户
 * @param acc
 * @throws AccountException
 */
@Override
public void createNewAccount(Account acc) throws AccountException {
    String accNo = AccountNoUtil.getAccountNo();
    try {
        Account account = accountDao.selectAccountByAccNo(accNo);
        if(Objects.isNull(account)){//账号不重复
            //3.开启事物处理
            //因为jdbc默认提交,所以出现了异常,没有办法回滚,将jdbc的默认提交设置为默认不提交,没有异常才提交,有异常就回滚
            ConnUtil.getConnection().setAutoCommit(false);//交设置为默认不提交
            //执行开户操作
            acc.setAccNo(accNo);
            int accId = accountDao.createNewAccount(acc);
            if(accId != -1){
                //同时要完成向账户记录表中插入当前操作的记录数据
                AccountRecord accountRecord = new AccountRecord();
                Account account1 = new Account();
                account1.setAccId(accId);
                accountRecord.setReAcc(account1);
                accountRecord.setReAction("开户");
                accountRecord.setReAccTo(account1);
                accountRecord.setReAmt(acc.getAccBalance());
                //插入账户记录表
                accountRecordDao.inertAccRecord(accountRecord);
                ConnUtil.getConnection().commit();//没有异常才提交,该代码一定要写到所有操作的最后
            }else{
                throw new AccountException("主键生成失败");
            }
        }else{
            //重新生成账号
        }
    } catch (SQLException throwables) {
        try {
            ConnUtil.getConnection().rollback();//有异常就回滚
        } catch (SQLException e) {
            e.printStackTrace();
        }
        //2.需要抛出自定义异常AccountDepositException
        throw new AccountException("账户取钱发生错误,取钱失败");
    }finally {
        //4.关闭数据库连接,释放连接
        ConnUtil.closeConnection();
    }


}

第三步:开发view层
在这里插入图片描述

三、总结

祝大家早日上岸!

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
6月前
|
SQL Java 关系型数据库
javaweb实训第四天上午——JDBC入门(2)
3.1.3 拿到连接(贾琏) 注册驱动成功之后,接着拿到链接;(贾琏是一个人名字) 贾:加载驱动; 链:建立连接;
74 0
|
6月前
|
SQL Java 数据库连接
Java从入门到精通:2.3.1数据库编程——学习JDBC技术,掌握Java与数据库的交互
ava从入门到精通:2.3.1数据库编程——学习JDBC技术,掌握Java与数据库的交互
|
6月前
|
SQL Java 关系型数据库
零基础轻松入门Java数据库连接(JDBC)
零基础轻松入门Java数据库连接(JDBC)
58 0
|
6月前
|
SQL Java 数据库连接
JDBC技术【分页查询、数据库连接池、应用程序分层、封装通用的BaseDao】(四)-全面详解(学习总结---从入门到深化)(下)
JDBC技术【分页查询、数据库连接池、应用程序分层、封装通用的BaseDao】(四)-全面详解(学习总结---从入门到深化)
511 1
|
6月前
|
SQL Java 关系型数据库
JDBC技术【JDBC概述、获取数据库连接、 下载数据库驱动】(一)-全面详解(学习总结---从入门到深化)
JDBC技术【JDBC概述、获取数据库连接、 下载数据库驱动】(一)-全面详解(学习总结---从入门到深化)
168 0
JDBC技术【JDBC概述、获取数据库连接、 下载数据库驱动】(一)-全面详解(学习总结---从入门到深化)
|
6月前
|
SQL Java 数据库连接
javaweb实训第四天上午——JDBC入门(3)
3.6 查询对象(返回一条数据) 增,删,改已经完成,接下来完成查询,在完成查询之前,需要了解一个查询对象 代码:
67 1
|
6月前
|
SQL druid Java
JDBC技术【分页查询、数据库连接池、应用程序分层、封装通用的BaseDao】(四)-全面详解(学习总结---从入门到深化)
JDBC技术【分页查询、数据库连接池、应用程序分层、封装通用的BaseDao】(四)-全面详解(学习总结---从入门到深化)
68 0
|
6月前
|
SQL Java 数据库连接
JDBC技术【分页查询、数据库连接池、应用程序分层、封装通用的BaseDao】(四)-全面详解(学习总结---从入门到深化)(中)
JDBC技术【分页查询、数据库连接池、应用程序分层、封装通用的BaseDao】(四)-全面详解(学习总结---从入门到深化)
62 0
|
6月前
|
SQL Java 关系型数据库
JDBC技术【SQL注入、JDBC批量添加数据、JDBC事务处理、其他查询方式】(三)-全面详解(学习总结---从入门到深化)
JDBC技术【SQL注入、JDBC批量添加数据、JDBC事务处理、其他查询方式】(三)-全面详解(学习总结---从入门到深化)
73 0
|
6月前
|
SQL 存储 Java
JDBC技术【封装JDBC工具类、Statement的使用、PreparedStatement的使用(重点)、ResultSet的使用】(二)-全面详解(学习总结---从入门到深化)
JDBC技术【封装JDBC工具类、Statement的使用、PreparedStatement的使用(重点)、ResultSet的使用】(二)-全面详解(学习总结---从入门到深化)
343 0