Java第十六课

1 JDBC-2:

1.1 回顾(上周):

1) 集合框架 :
常见的接口和类,以及方法;
Collection
List(有序,可以重复):
ArrayList LinkedList Vector
Set(无序,不能重复):
HashSet TreeSet

 Map:键和值
    HashMap:

 简单的泛型:  ArrayList<String>
 Iterator: 迭代器
 Arrays.sort() ; 

2) 数据库:MySQL,数据库有关概念;数据库软件的安装,创建库,表操作;常见的SQL(结构化查询语言)语句 ;重点要掌握的是: 查询语句(基本查询,带条件的查询,排序,分组,分组后的筛选,表联结,模糊查询)

3) 应用程序+数据库: java语言中有一种操作数据库的技术,JDBC;

4) JDBC有关的常见接口和类:
Java.sql.DriverManager:
驱动管理器.创建连接对象; DriverManager.getConnection(url,user,password);
Java.sql.Connection:
连接对象,用来创建[预]处理对象:[ PreparedStatement] conn.prepareStatement(sql语句);
Java.sql.PreparedStatement:
用来执行实际的数据库访问操作:
setXX(index,value) ;// 设置参数,index =>1开始

int n=executeUpdate(); //执行 增加 删除 修改
ResultSet rs=executeQuery(); //执行 查询操作

释放资源:
PreparedStatement => close();
Connection =>close()

1.2 作业讲解:

1) 设计一个网吧计费系统设计(用户表 计算机表 上机记录表),同时模拟添加(用户注册)用户,计算机(添加设备),用户上机,换机,下机操作,用sql完成. [电子版作业发我邮箱]

修改后的表结构: (参考 ,感谢佩琪的友情提供
用户表cybercafeUser netbar
列名 類型 說明
cyber_userid int 用戶編號,自动增长,主键
cyber_username varchar(20) 用戶姓名
cyber_password varchar(32) 用户密码
cyber_regDate datetime 用户注册时间
cyber_balance double 用户余额

计算机表cybercafePC
列名 類型 說明
cyber_pcid int 電腦編號,自动增长,主键
cyber_pcdesc varchar(50) 電腦描述
cyber_pcstatus int 电脑的状态,0 空闲,1使用中

上机记录表 cybercafeRecord
列名 類型 說明
cyber_recid int 紀錄編號,自动增长,主键
cyber_pcid int 使用的電腦編號,关联的是pc表中的pcid
cyber_userid int 用戶編號,关联的是用户表中的 userId
cyber_beginTime datetime 用戶上机時間
cyber_endTime datetime 用戶下机時間
cyber_fee Double 上机的费用

-- 添加(用户注册)用户
select * from cyberusers;
insert into cyberusers values(null,'admin','123456',now(),10);
insert into cyberusers values(null,'user01','qqqqqqq',now(),100);
insert into cyberusers values(null,'user02','qqqqq',now(),1000);
insert into cyberusers values(null,'user03','qq',now(),150);
insert into cyberusers values(null,'user04','qqqq',now(),50);
insert into cyberusers values(null,'user05','12qwqwq',now(),70);


-- 计算机(添加设备),
select * from cyberpc;
insert into cyberpc values(null,'512固态,16G内存,飞一般的享受',0);
insert into cyberpc values(null,'512固态,8G内存,飞一般的享受',0);
insert into cyberpc values(null,'512固态,4G内存,飞一般的享受',0);
insert into cyberpc values(null,'512固态,2G内存,飞一般的享受',0);
insert into cyberpc values(null,'512固态,1G内存,飞一般的享受',0);

-- 用户上机,换机,下机操作

-- 谁? 使用哪台机器? 增加了一条记录?
-- admin (1)这个用户  编号为 1 那台机器  ,上机时间应该为 now()

-- ①验证这个人是否存在 [验证密码]
select * from cyberusers where cyber_username = 'admin'; --1

-- ② 要使用的是1台机器 ,要验证一下这台机器是否有人使用

select cyber_pcstatus from cyberpc where cyber_pcid = 1 ;  

-- ③ 插入记录
select * from cyberrecord
insert INTO cyberrecord values(null,1,1,now(),null,2); -- 2表示的上机就要记录2元,但是还没有扣钱,等结账的时候才扣钱

-- ④ 插入记录表之后,明确,第一台电脑已经被admin使用了,所以pc表中的记录状态要发生改变
update  cyberpc set cyber_pcstatus = 1 where  cyber_pcid = 1;



-- 换机 admin用1号机器 不爽,我要换到5号机器,

-- ① 要使用的是5台机器 ,要验证一下这台机器是否有人使用

select cyber_pcstatus from cyberpc where cyber_pcid = 5 ;

-- 修改记录表 pcId
update  cyberrecord set cyber_pcid = 5 where cyber_recid =1;

-- 或者 pcId =1 and endtime  is  null 
update  cyberrecord set cyber_pcid = 5 where cyber_pcid =1 and cyber_endtime is null;

-- 修改我们计算机表 pcid为1的状态为0  5的状态为1 

update cyberpc set cyber_pcstatus = 0 where cyber_pcid = 1;

update cyberpc set cyber_pcstatus = 1 where cyber_pcid = 5;


 select * from cyberrecord;
 select * from cyberpc;
select * from cyberusers;


-- 下机操作

-- 下机 admin用5号机器用完了,要去约会了,下机

-- 扣钱 (按小时来扣钱 1小时2元)

-- ① 修改下机记录 为当前时间
update  cyberrecord set cyber_endtime = now() where cyber_recid =1;

-- ② 计算一下 本次上机 上机时间 下机时间差值 ->小时 *2
--  思考问题 解决问题(mysql 计算两个时间的差值?)

-- 直接做计算 减法 得到是秒差值 不好计算为小时
select cyber_endtime - cyber_begintime from cyberrecord;

-- mysql 计算两个时间的差值 用到mysql中的函数
select TIMESTAMPDIFF(HOUR,'2018-01-01','2018-01-01 12:01')

select TIMESTAMPDIFF(HOUR,cyber_begintime,cyber_endtime) from cyberrecord where cyber_recid = 1;

-- 如果计算差值 hour 为0 表示不满1小时 ;如果不满1小时,我们什么都不做(不用再更新record表)

-- ③ 将计算的结果 写入记录表(更新)

-- ④ 扣钱 用户表中的balance - 
select  cyber_userId,cyber_fee from cyberrecord where cyber_recid = 1;

update cyberusers set cyber_balance = cyber_balance - 2 where cyber_userid = 1;

select * from cyberusers;

-- ⑤ 计算机表中的状态要变 5号=>1  =>0
update cyberpc set cyber_pcstatus = 0 where cyber_pcid =5 ;




-- 扩展  MySQL 的函数
select now();
select ABS(-1);

-- datediff 得到的是两个时间之间差值(天数的部分) 第一个参数 - 第二个参数
select DATEDIFF('2018-01-01',now());

select DATEDIFF(now(),'2018-01-01');

-- unit year ,month,day ,HOUR 等等
-- datetime_expr1 第一个时间的值 小
-- datetime_expr2 第二个时间的值 大
select TIMESTAMPDIFF(HOUR,'2018-01-01','2018-01-01 12:01')

2) 回去完成 员工的添加,删除,修改操作; 从控制台输入进来;


package testJdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Scanner;

import com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException;

/**
 * 删除操作的代码
 * 
 * @author Administrator
 *
 */
public class TestDeleteDept {
    public static void main(String[] args) throws SQLException, ClassNotFoundException {

        // ① : 创建url user password
        String url = "jdbc:mysql://localhost:3306/companydb";
        String user = "root";
        String password = "root";

        // ② 建立一个连接
        // 两个对象 Connection DriverManager
        // url - jdbc:subprotocol:subname 形式的数据库 url
        Connection conn = DriverManager.getConnection(url, user, password);

        // 使用conn
        // System.out.println(conn);

        // 使用conn对象得到一个 执行sql语句的对象 statement/preparedstatement

        // ③ 编写sql语句 这里我们要操作MySQL数据库

        // 控制台输入
        Scanner input = new Scanner(System.in);

        System.out.println("请输入部门编号");

        // 这列deptNo写什么类型?
        // 最好写和表中列类型一致 int->int varchar->String
        // 此时 也可以写成String =->sql语句在执行的时候要拼接
        // String deptNo = input.next();

        int deptNo = input.nextInt();

        // 方式2 字符串拼接
        String sql = "delete from dept where deptno =?";

        // ④ 通过连接对象得到 PreparedStatement
        PreparedStatement pstmt = conn.prepareStatement(sql);

        // 用输入进来的值和我们的 ?匹配 推荐使用
        // 匹配 ,注意注意注意,索引从1开始
        pstmt.setInt(1, deptNo);

        // ⑤ 执行增删改 ,并处理结果
        int n = 0;
        try {
            n = pstmt.executeUpdate();
        } catch (MySQLIntegrityConstraintViolationException e) {
            // TODO Auto-generated catch block
            // e.printStackTrace();
            System.out.println("数据库表关联关系异常(外键),请联系管理员");

        } finally {
            // ⑥ 释放资源
            if (null != pstmt)
                pstmt.close();

            // 连接放在最后来释放
            if (null != conn)
                conn.close();
        }
        if (n > 0)
            System.out.println("删除成功");
        else
            System.out.println("删除失败");

    }

}

修改操作代码:


package testJdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Scanner;

import com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException;

/**
 * 修改操作的代码
 * 
 * @author Administrator
 *
 */
public class TestUpdateDept {
    public static void main(String[] args) throws SQLException, ClassNotFoundException {

        // ① : 创建url user password
        String url = "jdbc:mysql://localhost:3306/companydb";
        String user = "root";
        String password = "root";

        // ② 建立一个连接
        // 两个对象 Connection DriverManager
        // url - jdbc:subprotocol:subname 形式的数据库 url
        Connection conn = DriverManager.getConnection(url, user, password);

        // ③ 编写sql语句 这里我们要操作MySQL数据库

        // 控制台输入
        Scanner input = new Scanner(System.in);

        System.out.println("请输入要修改的部门编号");

        // 这列deptNo写什么类型?
        // 最好写和表中列类型一致 int->int varchar->String
        // 此时 也可以写成String =->sql语句在执行的时候要拼接
        // String deptNo = input.next();

        int deptNo = input.nextInt();

        System.out.println("要修改哪一项(1 部门名称 2 部门描述 3 名称+描述)");
        // 要修改什么? 部门名称,部门描述
        String choice = input.next();
        String deptName = null, deptDesc = null;

        String sql = "update dept set deptName=? where deptNo = ?";

        switch (choice) {
        case "1":
            System.out.println("请输入部门名称");
            deptName = input.next();

            break;
        case "2":
            System.out.println("请输入部门描述");
            deptDesc = input.next();
            sql = "update dept set deptDesc=? where deptNo = ?";
            break;
        case "3":
            System.out.println("请输入部门名称和描述");
            deptName = input.next();
            deptDesc = input.next();
            sql = "update dept set deptName=?,deptDesc=? where deptNo = ?";
            break;
        }

        // ④ 通过连接对象得到 PreparedStatement
        PreparedStatement pstmt = conn.prepareStatement(sql);

        // 用输入进来的值和我们的 ?匹配 推荐使用
        // 匹配 ,注意注意注意,索引从1开始

        if (null != deptName && null == deptDesc) // 用户输入了deptName ,deptDesc为空
        {

            pstmt.setString(1, deptName);
            pstmt.setInt(2, deptNo);
        } else if (null == deptName && null != deptDesc) // 用户输入了deptDesc,deptName 为空
        {

            pstmt.setString(1, deptDesc);
            pstmt.setInt(2, deptNo);
        } else if (null != deptName && null != deptDesc) {
            pstmt.setString(1, deptName);
            pstmt.setString(2, deptDesc);
            pstmt.setInt(3, deptNo);
        }

        // 题外话: 如果觉得以上的判断太多了,就直接写一条sql

        // ⑤ 执行增删改 ,并处理结果
        int n = 0;
        try {
            n = pstmt.executeUpdate();
        } catch (MySQLIntegrityConstraintViolationException e) {
            // TODO Auto-generated catch block
            // e.printStackTrace();
            System.out.println("数据库表关联关系异常(外键),请联系管理员");

        } finally {
            // ⑥ 释放资源
            if (null != pstmt)
                pstmt.close();

            // 连接放在最后来释放
            if (null != conn)
                conn.close();
        }
        if (n > 0)
            System.out.println("修改成功");
        else
            System.out.println("修改失败");

    }

}

3) 回去预习 查询的操作;

1.3 修改成我们HashMap:

1.4 数据库表结构存储:

在Navicate 中数据库上点击右键->转储sql [结构和数据 ;结构] -> 生成一个.sql文件:

这里写图片描述

1.5 Sql文件:直接运行:

这里写图片描述

1.6 关于接口

这里写图片描述
继承了Statement接口; 预编译的sql对象;所以可以更高效执行sql; 提供了setxx的方法来设置参数;它更安全; 可以避免sql注入
Statement
这里写图片描述
是PreparedStatement对象的父接口;静态的非预编译;比较低效率;因为静态,不能提供 ?参数写法,只能用字符串的拼接方式,无法避免sql的注入,相对不够安全;

1.7 关于JDBC中的加载驱动:

这里写图片描述
高版本的Mysql驱动:例如:
这里写图片描述
就可以省略Class.forName这个加载驱动的动作;

1.8 比较难,慎入,辣眼睛:

去看看我们加载到项目中的那个jdbc驱动包;

下载jdbc驱动的源码包:

方式1:
这里写图片描述

方式2:
这里写图片描述

Com.mysql.jdbc.Driver: 的源码
这里写图片描述
所以,我们只要让我们的静态代码段能执行,就可以
这里写图片描述
Mysql驱动包的高版本和低版本的不同:

5.1.5
这里写图片描述
5.1.18 :我们发现,5.1.5多了个services录;java.sql.Driver文件
这里写图片描述
这里写图片描述
在jdk中有个特性: SPI(服务提供接口) => 所以JVM会将 jar包Meta-Inf\Services\某个接口中所定义的那个类自动加载到JVM;
所以,高版本的jdbc驱动不需要写 Class.forName(…);

1.9 F3=>mysqlconnector.jar中的某些源代码:

前提是本地有源代码的文件:
这里写图片描述
这里写图片描述

1.10 Jdbc增删改小结:

这里写图片描述
修改:
这里写图片描述
这里写图片描述
修改:
这里写图片描述

1.11 小练习[外键]:

部门增加 删除和修改操作; 如果删除部门的时候,有关联的那个部门(有员工)信息,提醒用户该部门下有员工,是否删除?如果用户输入是,我们就先删除员工表的对应记录,然后将部门表对应那个信息删除;

重点代码段:

这里写图片描述
详细代码请看:
这里写图片描述

1.12 查询:

查询部门的所有记录
这里写图片描述
这里写图片描述
这里写图片描述

1.12.1 参考代码

/**
 * 查询代码
 * @author Administrator
 *
 */
public class TestQuery01 {

    public static void main(String[] args) {

        // 加载驱动(5.1.18 可以省略)
        // url user password
        // /jdbc:mysql://localhost:3306/mydb?useunicode=true&characterEncoding=utf-8....
        String url = "jdbc:mysql://localhost:3306/companydb";
        String user = "root";
        String password = "root";

        // 准备sql语句
        String sql = "select deptNo,deptName,deptDesc from dept";

        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        // 通过DriverManager类得到Connection对象
        try {
            conn = DriverManager.getConnection(url, user, password);

            // 通过connection对象得到PreparedStatement
            pstmt = conn.prepareStatement(sql);

            // 通过preparedStatement对象执行sql
            rs = pstmt.executeQuery();

            // 遍历 next getxx
            // 得到结果要做处理?
            while (rs.next()) {
                // 一行记录拼接在info中
                // getXX(查询语句列名) getXX(索引)
                String info = rs.getInt("deptNo") + "," + rs.getString(2) + "," + rs.getString(3);
                System.out.println(info);
            }

            // executeUpdate() executeQuery
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        finally {
            // 释放资源
            // result
            if (null != rs)
                try {
                    rs.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            // preparedstatement
            if (null != pstmt)
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            // connection

            if (null != conn)
                try {
                    conn.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
        }

    }
}

1.12.2 认识ResultSet

这里写图片描述

1.12.3 Next()

这里写图片描述
这里写图片描述

1.12.4 getXX方法:

getInt(列索引或者列名称); //参数应该是我们查询语句中对应的那个列
这里写图片描述

1.12.5 练习:

1) 查询部门表中的所有数据
2) 查询员工表中的某个部门中的数据(dept 1)

package query;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;

/**
 * 查询代码
 * 
 * @author Administrator
 *
 */
public class TestQuery_Employee {

    public static void main(String[] args) {

        // 加载驱动(5.1.18 可以省略)
        // url user password
        // /jdbc:mysql://localhost:3306/mydb?useunicode=true&characterEncoding=utf-8....
        String url = "jdbc:mysql://localhost:3306/companydb";
        String user = "root";
        String password = "root";

        // 准备sql语句
        String sql = "select empno,empName,salary as sal,status from employee where deptno = ?";

        System.out.println("请输入您要查询的部门编号(列出这个部门下的员工信息)");
        Scanner input = new Scanner(System.in);

        int deptNo = input.nextInt();

        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        // 通过DriverManager类得到Connection对象
        try {
            conn = DriverManager.getConnection(url, user, password);

            // 通过connection对象得到PreparedStatement
            pstmt = conn.prepareStatement(sql);

            pstmt.setInt(1, deptNo);

            // 通过preparedStatement对象执行sql
            rs = pstmt.executeQuery();

            // 遍历 next getxx
            // 得到结果要做处理?
            while (rs.next()) {
                // 一行记录拼接在info中
                // getXX(查询语句列名) getXX(索引)
                String info = rs.getInt("empno") + "," + rs.getString("empName") + "," + rs.getString("sal") + ","
                        + rs.getString("status");
                System.out.println(info);
            }

            // executeUpdate() executeQuery
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        finally {
            // 释放资源
            // result
            if (null != rs)
                try {
                    rs.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            // preparedstatement
            if (null != pstmt)
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            // connection

            if (null != conn)
                try {
                    conn.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
        }

    }
}

3) 查询部门表和员工表中的数据
员工姓名 部门
小a 行政部

这里写图片描述
我们的代码的问题是: 所有的执行都在一个main中,这样一定是不行的;
所以需要拆开,我们以query-Employee为案例:
1. 根据表结构创建一个实体类
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

package com.etc.dao;

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

import com.etc.entity.Employee;

/**
 * 数据库的访问操作 增 删 修改 查 ,这个dao还不是最终的dao,明天再优化,要体会这种分层的思想
 * 
 * @author Administrator
 *
 */
public class EmployeeDao {

    // 暂时放在这里
    String url = "jdbc:mysql://localhost:3306/companydb";
    String user = "root";
    String password = "root";

    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;

    // 查询 的结果要返回
    public List<Employee> queryAll() {

        List<Employee> list = new ArrayList<>();

        String sql = "select empno,empName,deptNo,salary as sal,status from employee";
        try {

            conn = DriverManager.getConnection(url, user, password);

            // 通过connection对象得到PreparedStatement
            pstmt = conn.prepareStatement(sql);

            // 通过preparedStatement对象执行sql
            rs = pstmt.executeQuery();

            // 遍历 next getxx
            // 得到结果要做处理?
            Employee emp = null;
            while (rs.next()) {
                // 一行记录拼接在info中
                // getXX(查询语句列名) getXX(索引)
                int empNo = rs.getInt("empno");
                String empName = rs.getString("empName");
                double salary = rs.getDouble("sal");
                int status = rs.getInt("status");
                int deptNo = rs.getInt("deptNo");
                // 构造一个Employee对象
                emp = new Employee(empNo, empName, deptNo, salary, status);

                // 将emp对象添加到集合中来
                list.add(emp);

            }

            // executeUpdate() executeQuery
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        finally {
            // 释放资源
            // result
            if (null != rs)
                try {
                    rs.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            // preparedstatement
            if (null != pstmt)
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            // connection

            if (null != conn)
                try {
                    conn.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
        }

        return list;

    }

}
  1. 入口测试:
package com.etc.test;

import java.util.List;

import com.etc.dao.EmployeeDao;
import com.etc.entity.Employee;

public class TestQueryEmployee {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        EmployeeDao empdao = new EmployeeDao();
        List<Employee> list = empdao.queryAll();

        for (Employee employee : list) {
            System.out.println(employee);
        }

    }

}

1.13 总结:

1) 回顾中:模拟一些网吧业务;jdbc加载驱动;
2) JDBC的接口和类: java.sql.ResultSet ; 常见属性和方法: next() getXX的方法
3) 分层思想: 数据库的访问集中到一个类中 Dao

1.14 作业布置:

将今天的Dao 部分再优化和简单的封装;

使用jdbc完成对商品数据库中的商品表和商品类型表的增删改查操作
这里写图片描述
这里写图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值