JDBC入门详解

JDBC入门详解,第1张

文章目录 一、什么是JDBC二、安装配置。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层

三、总结

祝大家早日上岸!

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/sjk/991189.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存