• 14、知识回顾


    就业班课程回顾:

    第一部            XML

               XML技术 (2天)

                         --》 写XML

                         --》 读XML

    第二部分:JavaWeb开发

               Servlet / JSP

       相关接口:

                         HttpServletRequest/response/ServletContext/HttpSession…….

    第三部分:数据库

               MySQL数据库

    第四部分:JDBC

               JDBC技术: java数据库连接技术!

               接口:

                         Connection:  连接对象

                         Statement:   执行命令对象: 把SQL语句发送到数据库执行

                         ResultSet:    (在线式)结果集接口, 必须要保持与数据库的连接!

              

               开发步骤:

    1. 建项目,引入数据库驱动包
    2. 加载驱动  

    Class.forName(..);

    1. 获取连接对象
    2. 创建执行sql语句的stmt对象;  写sql
    3. 执行sql

    a)       更新    delete/insert/update

                                            i.           executeUpdate();      

    b)       查询    select

                                            i.           executeQuery();

    1. 关闭/异常

    目标:

    1. 预编译sql处理(防止sql注入)
    2. 批处理
    3. 插入数据,获取自增长值
    4. 事务
    5. Jdbc中大文本类型的处理
    6. Jdbc综合练习

    明天/后天:

               Jdbc技术优化、DbUtils组件、分页、连接池

    1. 预编译sql处理(防止sql注入)

    -- 创建数据库

    CREATE DATABASE jdbc_demo DEFAULT CHARACTER SET utf8;i

    -- 创建表

    USE jdbc_demo;

    CREATE TABLE admin(

        id INT PRIMARY KEY AUTO_INCREMENT,

        userName VARCHAR(20),

        pwd VARCHAR(20)

    )

    |--Statement      执行SQL命令

               |-- CallableStatement,     执行存储过程

    |-- PreparedStatement    预编译SQL语句执行

    使用预编译SQL语句的命令对象,好处:

    1. 避免了频繁sql拼接 (可以使用占位符)
    2. 可以防止sql注入

    登陆模块,

               输入用户名,密码!

    注意,

    要避免用户输入的恶意密码!

     

    public class App {

       

        // 连接参数

        //private String url = "jdbc:mysql://localhost:3306/jdbc_demo";

        private String url = "jdbc:mysql:///jdbc_demo";

        private String user = "root";

        private String password = "root";

       

        private Connection con;

        private Statement stmt;

        private PreparedStatement pstmt;

        private ResultSet rs;

       

     

        // 1. 没有使用防止sql注入的案例

        @Test

        public void testLogin() {

           

            // 1.0 模拟登陆的用户名,密码

            String userName = "tom";

            //String pwd = "8881";

            String pwd = " ' or 1=1 -- ";

           

            // SQL语句

            String sql = "select * from admin where userName='"+userName+"'  and pwd='"+pwd+"' ";

            System.out.println(sql);

            try {

                 // 1.1 加载驱动,创建连接

                 Class.forName("com.mysql.jdbc.Driver");      

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

                 // 1.2 创建stmt对象

                 stmt = con.createStatement();

                 // 1.3 执行查询

                 rs = stmt.executeQuery(sql);

                 // 业务判断

                 if (rs.next()) {

                     System.out.println("登陆成功, 编号:" + rs.getInt("id"));

                 }

            } catch (Exception e) {

                 e.printStackTrace();

            } finally {

                 // 1.4 关闭

                 try {

                     rs.close();

                     stmt.close();

                     con.close();

                 } catch (Exception e) {

                     e.printStackTrace();

                 }

            }

        }

       

       

        // 2. 使用PreparedStatement, 防止sql注入

        @Test

        public void testLogin2() {

        

         // 1.0 模拟登陆的用户名,密码

         String userName = "tom";

         //String pwd = "8881";

         String pwd = " ' or 1=1 -- ";

        

         // SQL语句

         String sql = "select * from admin where userName=?  and pwd=? ";

         try {

            // 1.1 加载驱动,创建连接

            Class.forName("com.mysql.jdbc.Driver");  

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

            // 1.2 创建pstmt对象

            pstmt = con.prepareStatement(sql);   // 对sql语句预编译

            // 设置占位符值

            pstmt.setString(1, userName);

            pstmt.setString(2, pwd);

           

            // 1.3 执行

            rs = pstmt.executeQuery();

            if (rs.next()) {

               System.out.println("登陆成功," + rs.getInt("id"));

            }

           

         } catch (Exception e) {

            e.printStackTrace();

         } finally {

            // 1.4 关闭

            try {

               rs.close();

               pstmt.close();

               con.close();

            } catch (Exception e) {

               e.printStackTrace();

            }

         }

       }

      

      

    }

    2. 存储过程调用

    -- 存储过程

    -- 定义分隔符

    DELIMITER $$

    CREATE PROCEDURE proc_login()

    BEGIN

       SELECT * FROM admin;

    END $$

    -- 调用

    CALL proc_login;

    public class App_call {

       

        // 全局参数

        private Connection con;

        private Statement stmt;

        private PreparedStatement pstmt;

        private CallableStatement cstmt;  // 存储过程

        private ResultSet rs;

       

     

        // 程序中调用存储过程

        @Test

        public void testCall() throws Exception {

           

            try {

                 //1 . 创建连接

                 con = JdbcUtil.getConnection();

                 //2.  创建执行存储过程的stmt对象

                 CallableStatement cstmt = con.prepareCall("CALL proc_login");

                 //3.  执行(存储过程)

                 rs = cstmt.executeQuery();

                

                 // 遍历结果,测试

                 if (rs.next()) {

                     String name = rs.getString("userName");

                     String pwd = rs.getString("pwd");

                     // 测试

                     System.out.println(name + pwd);

                 }

                

            } catch (Exception e) {

                 e.printStackTrace();

            }

        }

    }

    3. 批处理

    很多时候,需要批量执行sql语句!

    需求:批量保存信息! 

    设计:

               AdminDao

                         Public  void  save(List<Admin list){    // 目前用这种方式

                                    // 循环

                                    // 保存  (批量保存)

                         }

                         Public  void  save(Admin  admin ){

                                    // 循环

                                    // 保存

                         }

    技术:

               |-- Statement

               批处理相关方法

                          void addBatch(String sql)     添加批处理

                         void clearBatch()            清空批处理

    int[] executeBatch()         执行批处理

    实现:

               Admin.java         实体类封装数据

               AdminDao.java      封装所有的与数据库的操作

               App.java           测试

    public class Admin {

     

        private String userName;

        private String pwd;

     

    public class App {

        // 测试批处理操作

        @Test

        public void testBatch() throws Exception {

           

            // 模拟数据

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

            for (int i=1; i<21; i++) {

                 Admin admin = new Admin();

                 admin.setUserName("Jack" + i);

                 admin.setPwd("888" + i);

                 list.add(admin);

            }

           

            // 保存

            AdminDao dao = new AdminDao();

            dao.save(list);

        }

    }

     

    // 封装所有的与数据库的操作

    public class AdminDao {

       

        // 全局参数

        private Connection con;

        private PreparedStatement pstmt;

        private ResultSet rs;

     

        // 批量保存管理员

        public void save(List<Admin> list) {

            // SQL

            String sql = "INSERT INTO admin(userName,pwd) values(?,?)";

           

            try {

                

                 // 获取连接

                 con = JdbcUtil.getConnection();

                 // 创建stmt

                 pstmt = con.prepareStatement(sql);         // 【预编译SQL语句】

                

                 for (int i=0; i<list.size(); i++) {

                     Admin admin = list.get(i);

                     // 设置参数

                     pstmt.setString(1, admin.getUserName());

                     pstmt.setString(2, admin.getPwd());

                    

                     // 添加批处理

                     pstmt.addBatch();                         // 【不需要传入SQL】

                    

                     // 测试:每5条执行一次批处理

                     if (i % 5 == 0) {

                         // 批量执行

                         pstmt.executeBatch();

                         // 清空批处理

                         pstmt.clearBatch();

                     }

                    

                 }

                

                 // 批量执行

                 pstmt.executeBatch();

                 // 清空批处理

                 pstmt.clearBatch();

                

            } catch (Exception e) {

                 e.printStackTrace();

            } finally {

                 JdbcUtil.closeAll(con, pstmt, rs);

            }

        }

    }

    4. 插入数据,获取自增长值

    ü  需求:       

                         李俊杰     18

                         张相       19

    如何设计数据库?

               编号    员工姓名    年龄    部门

               01       李俊杰      18     开发部

               02       张三        19     开发部’

    思考:

               如何减少数据冗余?

               à 设置外键约束

    所以,

               编号    员工姓名    年龄    部门

               01       李俊杰      18     1

               02       张三        19     1

               部门编号     部门名称   

               1             开发部           

    部门与员工,

               一对多的关系

    ü  设计数据库:

               员工表 (外键表) 【员工表有一个外键字段,引用了部门表的主键】

               部门表(主键表)

    ü  编码总体思路:

               保存员工及其对应的部门!

               步骤:

    1. 先保存部门
    2. 再得到部门主键,再保存员工

    开发具体步骤:

    1. 设计javabean
    2. 设计dao
    3. 测试

    部门

    CREATE TABLE dept(

       deptId INT PRIMARY KEY AUTO_INCREMENT,

       deptName VARCHAR(20)

    );

    -- 员工

    CREATE TABLE employee(

       empId INT PRIMARY KEY AUTO_INCREMENT,

       empName VARCHAR(20),

       dept_id  INT   --  外键字段  

    );

    -- 给员工表添加外键约束

    ALTER TABLE employee ADD CONSTRAINT FK_employee_dept_deptId

               FOREIGN KEY(dept_id) REFERENCES dept(deptId) ;

     

    public class EmpDao {

       

        private Connection con;

        private PreparedStatement pstmt;

        private ResultSet rs;

     

        // 保存员工,同时保存关联的部门

        public void save(Employee emp){

           

            // 保存部门

            String sql_dept = "insert into dept(deptName) values(?)";

            // 保存员工

            String sql_emp = "INSERT INTO employee (empName,dept_id) VALUES (?,?)";

            // 部门id

            int deptId = 0;

           

            try {

                 // 连接

                 con = JdbcUtil.getConnection();

                

                 /*****保存部门,获取自增长*******/

                 // 【一、需要指定返回自增长标记】

                 pstmt = con.prepareStatement(sql_dept,Statement.RETURN_GENERATED_KEYS);

                // 设置参数

                 pstmt.setString(1, emp.getDept().getDeptName());

                 // 执行

                 pstmt.executeUpdate();

                

                 // 【二、获取上面保存的部门子增长的主键】

                 rs =  pstmt.getGeneratedKeys();

                 // 得到返回的自增长字段

                 if (rs.next()) {

                     deptId = rs.getInt(1);

                 }

                

                 /*****保存员工*********/

                 pstmt = con.prepareStatement(sql_emp);

                 // 设置参数

                 pstmt.setString(1, emp.getEmpName());

                 pstmt.setInt(2, deptId);

                 pstmt.executeUpdate();

                

            } catch (Exception e) {

                 e.printStackTrace();

            } finally {

                 JdbcUtil.closeAll(con, pstmt, rs);

            }

        }

    }

    5. 事务

    基本概念:

    事务使指一组最小逻辑操作单元,里面有多个操作组成。 组成事务的每一部分必须要同时提交成功,如果有一个操作失败,整个操作就回滚。

    事务ACID特性

    原子性(Atomicity
    原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。 

    一致性(Consistency
    事务必须使数据库从一个一致性状态变换到另外一个一致性状态。

    隔离性(Isolation
    事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。

    持久性(Durability
    持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响

    事务的特性:

    原子性,是一个最小逻辑操作单元 !

    一致性,事务过程中,数据处于一致状态。

    持久性, 事务一旦提交成功,对数据的更改会反映到数据库中。

    隔离性, 事务与事务之间是隔离的。

    案例

    需求: 张三给李四转账

    设计: 账户表

    技术

    |-- Connection

    void setAutoCommit(boolean autoCommit) ;  设置事务是否自动提交

                                                                                              如果设置为false,表示手动提交事务。

    void commit() ();                                                                手动提交事务

    void rollback() ;                                                        回滚(出现异常时候,所有已经执行成功的代码需要回退到事务开始前的状态。)

    Savepoint setSavepoint(String name)

    代码:

    -- 账户表

    CREATE TABLE account(

       id INT PRIMARY KEY AUTO_INCREMENT,

       accountName VARCHAR(20),

       money DOUBLE

    );

    -- 转账

    UPDATE account SET money=money-1000 WHERE accountName='张三';

    UPDATE account SET money=money+1000 WHERE accountName='李四';

     

    public class AccountDao {

     

        // 全局参数

        private Connection con;

        private PreparedStatement pstmt;

     

        // 1. 转账,没有使用事务

        public void trans1() {

     

            String sql_zs = "UPDATE account SET money=money-1000 WHERE accountName='张三';";

            String sql_ls = "UPDATE account SET money=money+1000 WHERE accountName='李四';";

     

            try {

                 con = JdbcUtil.getConnection(); // 默认开启的隐士事务

                 con.setAutoCommit(true);

     

                 /*** 第一次执行SQL ***/

                 pstmt = con.prepareStatement(sql_zs);

                 pstmt.executeUpdate();

     

                 /*** 第二次执行SQL ***/

                 pstmt = con.prepareStatement(sql_ls);

                 pstmt.executeUpdate();

     

            } catch (Exception e) {

                 e.printStackTrace();

            } finally {

                 JdbcUtil.closeAll(con, pstmt, null);

            }

     

        }

     

        // 2. 转账,使用事务

        public void trans2() {

     

            String sql_zs = "UPDATE account SET money=money-1000 WHERE accountName='张三';";

            String sql_ls = "UPDATE1 account SET money=money+1000 WHERE accountName='李四';";

     

            try {

                 con = JdbcUtil.getConnection(); // 默认开启的隐士事务

                 // 一、设置事务为手动提交

                 con.setAutoCommit(false);

     

                 /*** 第一次执行SQL ***/

                 pstmt = con.prepareStatement(sql_zs);

                 pstmt.executeUpdate();

     

                 /*** 第二次执行SQL ***/

                 pstmt = con.prepareStatement(sql_ls);

                 pstmt.executeUpdate();

     

            } catch (Exception e) {

                 try {

                     // 二、 出现异常,需要回滚事务

                     con.rollback();

                 } catch (SQLException e1) {

                 }

                 e.printStackTrace();

            } finally {

                 try {

                     // 三、所有的操作执行成功, 提交事务

                     con.commit();

                     JdbcUtil.closeAll(con, pstmt, null);

                 } catch (SQLException e) {

                 }

            }

     

        }

     

        // 3. 转账,使用事务, 回滚到指定的代码段

        public void trans() {

            // 定义个标记

            Savepoint sp = null;

           

            // 第一次转账

            String sql_zs1 = "UPDATE account SET money=money-1000 WHERE accountName='张三';";

            String sql_ls1 = "UPDATE account SET money=money+1000 WHERE accountName='李四';";

           

            // 第二次转账

            String sql_zs2 = "UPDATE account SET money=money-500 WHERE accountName='张三';";

            String sql_ls2 = "UPDATE1 account SET money=money+500 WHERE accountName='李四';";

     

            try {

                 con = JdbcUtil.getConnection(); // 默认开启的隐士事务

                 con.setAutoCommit(false);       // 设置事务手动提交

     

                 /*** 第一次转账 ***/

                 pstmt = con.prepareStatement(sql_zs1);

                 pstmt.executeUpdate();

                 pstmt = con.prepareStatement(sql_ls1);

                 pstmt.executeUpdate();

                

                 // 回滚到这个位置?

                 sp = con.setSavepoint();

                

                

                 /*** 第二次转账 ***/

                 pstmt = con.prepareStatement(sql_zs2);

                 pstmt.executeUpdate();

                 pstmt = con.prepareStatement(sql_ls2);

                 pstmt.executeUpdate();

                

     

            } catch (Exception e) {

                 try {

                     // 回滚 (回滚到指定的代码段)

                     con.rollback(sp);

                 } catch (SQLException e1) {

                 }

                 e.printStackTrace();

            } finally {

                 try {

                     // 提交

                     con.commit();

                 } catch (SQLException e) {

                 }

                 JdbcUtil.closeAll(con, pstmt, null);

            }

     

        }

    }

    6. Jdbc中大文本类型的处理

    Oracle中大文本数据类型,

               Clob    长文本类型   (MySQL中不支持,使用的是text)

               Blob    二进制类型

    MySQL数据库,

               Text    长文本类型

               Blob    二进制类型

    需求: jdbc中操作长文本数据。

    设计: 测试表

    编码:

               保存大文本数据类型

               读取大文本数据类型

               保存二进制数据

               读取二进制数据

    -- 测试大数据类型

    CREATE TABLE test(

         id INT PRIMARY KEY AUTO_INCREMENT,

         content LONGTEXT,

         img LONGBLOB

    );

    Text:

     

    public class App_text {

       

        // 全局参数

        private Connection con;

        private Statement stmt;

        private PreparedStatement pstmt;

        private ResultSet rs;

       

     

        @Test

        // 1. 保存大文本数据类型   ( 写longtext)

        public void testSaveText() {

            String sql = "insert into test(content) values(?)";

            try {

                 // 连接

                 con = JdbcUtil.getConnection();

                 // pstmt 对象

                 pstmt = con.prepareStatement(sql);

                 // 设置参数

                 // 先获取文件路径

                 String path = App_text.class.getResource("tips.txt").getPath();

                 FileReader reader = new FileReader(new File(path));

                 pstmt.setCharacterStream(1, reader);

                

                 // 执行sql

                 pstmt.executeUpdate();

                

                 // 关闭

                 reader.close();

            } catch (Exception e) {

                 e.printStackTrace();

            } finally {

                 JdbcUtil.closeAll(con, pstmt, null);

            }

        }

       

        @Test

        // 2. 读取大文本数据类型   ( 读longtext)

        public void testGetAsText() {

            String sql = "select * from  test;";

            try {

                 // 连接

                 con = JdbcUtil.getConnection();

                 // pstmt 对象

                 pstmt = con.prepareStatement(sql);

                 // 读取

                 rs = pstmt.executeQuery();

                 if (rs.next()) {

                     // 获取长文本数据, 方式1:

                     //Reader r = rs.getCharacterStream("content");

                    

                     // 获取长文本数据, 方式2:

                     System.out.print(rs.getString("content"));

                 }

                

            } catch (Exception e) {

                 e.printStackTrace();

            } finally {

                 JdbcUtil.closeAll(con, pstmt, null);

            }

        }

    }

    blob

     

    public class App_blob {

       

        // 全局参数

        private Connection con;

        private Statement stmt;

        private PreparedStatement pstmt;

        private ResultSet rs;

       

     

        @Test

        // 1. 二进制数据类型   ( 写longblob)

        public void testSaveText() {

            String sql = "insert into test(img) values(?)";

            try {

                 // 连接

                 con = JdbcUtil.getConnection();

                 // pstmt 对象

                 pstmt = con.prepareStatement(sql);

                 // 获取图片流

                 InputStream in = App_text.class.getResourceAsStream("7.jpg");

                 pstmt.setBinaryStream(1, in);

                

                 // 执行保存图片

                 pstmt.execute();

                

                 // 关闭

                 in.close();

                

            } catch (Exception e) {

                 e.printStackTrace();

            } finally {

                 JdbcUtil.closeAll(con, pstmt, null);

            }

        }

       

        @Test

        // 2. 读取大文本数据类型   ( 读longblob)

        public void testGetAsText() {

            String sql = "select img from  test where id=2;";

            try {

                 // 连接

                 con = JdbcUtil.getConnection();

                 // pstmt 对象

                 pstmt = con.prepareStatement(sql);

                 // 读取

                 rs = pstmt.executeQuery();

                 if (rs.next()) {

                     // 获取图片流

                     InputStream in = rs.getBinaryStream("img");

                     // 图片输出流

                     FileOutputStream out = new FileOutputStream(new File("c://1.jpg"));

                     int len = -1;

                     byte b[] = new byte[1024];

                     while ((len = in.read(b)) != -1) {

                         out.write(b, 0, len);

                     }

                     // 关闭

                     out.close();

                     in.close();

                 }

                

            } catch (Exception e) {

                 e.printStackTrace();

            } finally {

                 JdbcUtil.closeAll(con, pstmt, null);

            }

        }

    }

    7. 综合案例

    需求分析:

               登陆、注册、注销;

               登陆成功,

                         显示所有的员工

    设计

    数据库设计:

               Admin,  存放所有的登陆用户

               Employee, 存放所有的员工信息

    系统设计

    1. 系统结构

    分层: 基于mvc模式的分层

    1. 项目用到的公用组件、类 (了解)

    编码

              

    练习:

      1. 案例
      2. Jdbc增强知识点
  • 相关阅读:
    打开控制面板中的程序
    内存使用情况监控
    监视剪切板内容
    检测系统启动模式
    启动Windows服务
    开机启动项管理
    docker部署war+tomcat8
    docker安装mysql5.6和redis3.2
    nginx命令和配置
    nginx安装
  • 原文地址:https://www.cnblogs.com/GJ-ios/p/6037371.html
Copyright © 2020-2023  润新知