zoukankan      html  css  js  c++  java
  • 学习笔记-mysql基本操作

    数据库

    数据库基本概念:

      DDL:数据库的定义,与数据库/表结构:create,drop,alter

      DML:数据库操纵语言:操作表数据 insert update delete

      DCl:数据库控制语言:设置用户的访问权限 安全

      DQL:数据库查询语言:Select from where

    数据库的基本操作:

      创建数据库:create databases 数据库的名字

      查看数据库:1、查看所有数据库:show databases;

            2、查看数据库定义:show create database 数据库名

            3、查看当前正在使用的数据库:select database();

      修改数据库:later database character set 字符集

      删除数据库:drop database 数据库名字

      选中数据库:use 数据库的名字

     表结构的基本操作:

      创建表:1、create table 表名(

              列名 列的类型(长度) 约束,

              列名 列的类型(长度) 约束

            );

          2列的约束:①主键约束:primary key

                 ②唯一约束:unique

                 ③非空约束:not null

      删除表:drop table 表名

      查看表:1、show tables:查看当前数据库中的所有的表名

          2、show create table 表名:查看表的定义结构/创建语句

          3、desc 表名:查看表的结构

      修改表:1、添加列:alter table 表名 add 列名 列的类型 列的约束

          2、修改列:alter table 表名 modify 列名 列的类型 列的约束

          3、修改列名:alter table 表名 change 旧列名 新列名 列的类型 列的约束

          4、删除列:alter table 表名 drop 列名

           5、修改表的字符集:alter table 表名 character set 字符集

          6、修改表名:rename table 旧表名 to 新的表名

    表中数据的CRUD操作:

      插入数据:1、insert into 表名(列名1,列名2)values(值1,值2);

           2、insert into 表名values (值1,值2);

           3、insert into 表名values(值1,值2),(值1,值2),(值1,值2);——批量插入

      删除数据:1、delete from 表名【where 条件】

           2、truncate table 表名;——先删除表,再创建表

      更新数据:update 表名 set 列名=值,列名=值【where 条件】

      查询数据:1、通用格式:select 【distinct】【*】【列名1,列名2】 from 表名 where 条件 group by....having 条件过滤 order by 排序

            2、关系运算符:and or not

           3、在范围内:in

           4、模糊查询:like (_表示的单个字符,%表示 的是多个字符)

           5、别名查询:as

           6、聚合函数:求和:sum()

                   平均值:avg()

                   统计数量:count()

                   最大值:max()

                  最小值:min()

            7、排序:order by   :asc:ascend

                     desc:descend

           8、分组:group by

     多表之间的关系如何来维护

         外键约束: foreign key

      alter table 前者 add foreign key(前者id)  references  后者(后者id);

         首先得去前表, 删除所有分类后者id的表项

    建数据库原则:

      通常情况下,一个项目/应用建一个数据库

    多表之间的建表原则

       一对多 : 商品和分类

         建表原则: 在多的一方添加一个外键,指向一的一方的主键

      多对多: 老师和学生, 学生和课程

        建表原则: 建立一张中间表,将多对多的关系,拆分成一对多的关系,中间表至少要有两个外键,分别指向原来的那两张表

      一对一: 班级和班长, 公民和身份证, 国家和国旗

        建表原则:  将一对一的情况,当作是一对多情况处理,在任意一张表添加一个外键,并且这个外键要唯一,指向另外一张表

              1、直接将两张表合并成一张表

              2、将两张表的主键建立起连接,让两张表里面主键相等

             实际用途: 用的不是很多.    (拆表操作  )

                拆表操作 : 将个人的常用信息和不常用信息,减少表的臃肿。

    用户表 (用户的ID,用户名,密码,手机)
    
      ```sql
      create table user(
          uid int primary key auto_increment,
            username varchar(31),
            password varchar(31),
            phone  varchar(11)
      );
    
      insert into user values(1,'zhangsan','123','13811118888');
      ```
    订单表 (订单编号,总价,订单时间 ,地址,外键用户的ID)
    
      ```sql
        create table orders(
            oid int primary key auto_increment,
              sum int not null,
            otime timestamp,
              address varchar(100),
              uno int,
              foreign key(uno) references user(uid)
        );
        insert into orders values(1,200,null,'黑马前台旁边小黑屋',1);
        insert into orders values(2,250,null,'黑马后台旁边1702',1);
      ```
    
    商品表 (商品ID, 商品名称,商品价格,外键cno)
    
        ```sql
        create table product(
            pid int primary key auto_increment,
              pname varchar(10),
              price double,
              cno int,
              foreign key(cno) references category(cid)
        );
    
        insert into product values(null,'小米mix4',998,1);
        insert into product values(null,'锤子',2888,1);
        insert into product values(null,'阿迪王',99,2);
        insert into product values(null,'老村长',88,3);
        insert into product values(null,'劲酒',35,3);
        insert into product values(null,'小熊饼干',1,4);
        insert into product values(null,'卫龙辣条',1,5);
        insert into product values(null,'旺旺大饼',1,5);
        ```
    
     订单项: 中间表(订单ID,商品ID,商品数量,订单项总价)
    
      ```sql
      create table orderitem(
          ono int,
            pno int,
            foreign key(ono) references orders(oid),
            foreign key(pno) references product(pid),
            ocount int,
            subsum double
      );
      --给1号订单添加商品 200块钱的商品
      insert into orderitem values(1,7,100,100);
      insert into orderitem values(1,8,101,100);
    
      --给2号订单添加商品 250块钱的商品 ()
      insert into orderitem values(2,5,1,35);
      insert into orderitem values(2,3,3,99);
      ```
    
    商品分类表(分类ID,分类名称,分类描述)
    
        ```sql
        create table category(
            cid int primary key auto_increment,
              cname varchar(15),
              cdesc varchar(100)
        );
    
        insert into category values(null,'手机数码','电子产品,黑马生产');
        insert into category values(null,'鞋靴箱包','江南皮鞋厂倾情打造');
        insert into category values(null,'香烟酒水','黄鹤楼,茅台,二锅头');
        insert into category values(null,'酸奶饼干','娃哈哈,蒙牛酸酸乳');
        insert into category values(null,'馋嘴零食','瓜子花生,八宝粥,辣条');
        ```
    用户购物流程

    交叉连接查询  笛卡尔积

      笛卡尔积 ,查出来是两张表的乘积 ,查出来的结果没有意义

      SELECT * FROM表一名,表二名;

    内连接查询

      隐式内链接

                SELECT * FROM表一名 p,表二名 c WHERE p.cno=c.cid;

      显示内链接

                SELECT * FROM 表一名 p INNER JOIN 表二名 c ON p.cno=c.cid;    

      区别:

                  隐式内链接: 在查询出结果的基础上去做的WHERE条件过滤

                  显示内链接: 带着条件去查询结果, 执行效率要高

    左外连接

                左外连接,会将左表中的所有数据都查询出来, 如果右表中没有对应的数据,用NULL代替

                  SELECT * FROM 表一名 p LEFT OUTER JOIN 表二名 c ON p.cno=c.cid;

    右外连接: 会将右表所有数据都查询出来, 如果左表没有对应数据的话, 用NULL代替

                SELECT * FROM 表一名 p RIGHT OUTER JOIN 表二名 c ON p.cno=c.cid;

    子查询:

         SELECT * FROM 表一名WHERE cno = (SELECT cid FROM 表二名 WHERE cname='手机数码');

     分页查询:

      select * from 表名 limit 0,3;

      第一个参数是索引

      第二个参数显示的个数

    CREATE TABLE emp(
        empno INT,
        ename VARCHAR(50),
        job VARCHAR(50),
        mgr    INT,
        hiredate DATE,
        sal    DECIMAL(7,2),
        comm DECIMAL(7,2),
        deptno INT
    ) ;
    
    INSERT INTO emp VALUES(7369,'SMITH','CLERK',7902,'1980-12-17',800,NULL,20);
    INSERT INTO emp VALUES(7499,'ALLEN','SALESMAN',7698,'1981-02-20',1600,300,30);
    INSERT INTO emp VALUES(7521,'WARD','SALESMAN',7698,'1981-02-22',1250,500,30);
    INSERT INTO emp VALUES(7566,'JONES','MANAGER',7839,'1981-04-02',2975,NULL,20);
    INSERT INTO emp VALUES(7654,'MARTIN','SALESMAN',7698,'1981-09-28',1250,1400,30);
    INSERT INTO emp VALUES(7698,'BLAKE','MANAGER',7839,'1981-05-01',2850,NULL,30);
    INSERT INTO emp VALUES(7782,'CLARK','MANAGER',7839,'1981-06-09',2450,NULL,10);
    INSERT INTO emp VALUES(7788,'SCOTT','ANALYST',7566,'1987-04-19',3000,NULL,20);
    INSERT INTO emp VALUES(7839,'KING','PRESIDENT',NULL,'1981-11-17',5000,NULL,10);
    INSERT INTO emp VALUES(7844,'TURNER','SALESMAN',7698,'1981-09-08',1500,0,30);
    INSERT INTO emp VALUES(7876,'ADAMS','CLERK',7788,'1987-05-23',1100,NULL,20);
    INSERT INTO emp VALUES(7900,'JAMES','CLERK',7698,'1981-12-03',950,NULL,30);
    INSERT INTO emp VALUES(7902,'FORD','ANALYST',7566,'1981-12-03',3000,NULL,20);
    INSERT INTO emp VALUES(7934,'MILLER','CLERK',7782,'1982-01-23',1300,NULL,10);
    INSERT INTO emp VALUES(7981,'MILLER','CLERK',7788,'1992-01-23',2600,500,20);
    
    
    CREATE TABLE dept(
        deptno        INT,
        dname        VARCHAR(14),
        loc        VARCHAR(13)
    );
    
    INSERT INTO dept VALUES(10, 'ACCOUNTING', 'NEW YORK');
    INSERT INTO dept VALUES(20, 'RESEARCH', 'DALLAS');
    INSERT INTO dept VALUES(30, 'SALES', 'CHICAGO');
    INSERT INTO dept VALUES(40, 'OPERATIONS', 'BOSTON');
    
    
    DESC SELECT dname FROM dept WHERE deptno=10;
    
    
    -- 单行子查询(> < >= <= = <>)
        -- 查询出高于10号部门的平均工资的员工信息
        1.查询出10号部门的平均工资
        SELECT AVG(sal) FROM emp WHERE deptno = 10;
        2.查询出高于10号部门平均工资的员工信息
        SELECT * FROM emp WHERE sal > (SELECT AVG(sal) FROM emp WHERE deptno = 10);
    -- 多行子查询(in  not in any all)    >any  >all
        -- 查询出比10号部门任何员工薪资高的员工信息
        1. 查询出10号部门的所有工资信息
        SELECT sal FROM emp WHERE deptno=10;
        2.得出结果
        SELECT * FROM emp WHERE sal >ALL(SELECT sal FROM emp WHERE deptno=10); 
    
    -- 多列子查询(实际使用较少)   in
        -- 和10号部门同名同工作的员工信息
        1.查出10号部门员工名字和工作信息
        SELECT ename,job FROM emp WHERE deptno=10;
        2. 得出结果:
        SELECT * FROM emp WHERE (ename,job) IN (SELECT ename,job FROM emp WHERE deptno=10) AND deptno!=10;
    -- Select接子查询
        -- 获取员工的名字和部门的名字
        1.查出员工的名字和部门编号信息
        SELECT ename,deptno FROM emp;
        2.得出结果
        SELECT ename,(SELECT dname FROM dept WHERE dept.deptno=emp.deptno) FROM emp;
    -- from后面接子查询
        -- 查询emp表中经理信息
        1.查询出所有经理的ID
        SELECT DISTINCT mgr FROM emp;
        2. 查出经理的信息,只要id在第一步的查询结果中就可以了
        SELECT * FROM emp,(SELECT DISTINCT mgr FROM emp) mgrs WHERE emp.empno = mgrs.mgr;
    -- where 接子查询
        -- 薪资高于10号部门平均工资的所有员工信息
        1.查询出10号部门的平均工资
        SELECT AVG(sal) FROM emp WHERE deptno=10;
        2.得出结果:
        SELECT * FROM emp WHERE sal > (SELECT AVG(sal) FROM emp WHERE deptno=10);
    -- having后面接子查询
        -- 有哪些部门的平均工资高于30号部门的平均工资
        1.30号部门的平均工资
        SELECT AVG(sal) FROM emp WHERE deptno=30;
        2. 统计所有部门的平均工资
        SELECT deptno,AVG(sal) FROM emp GROUP BY deptno ;
        3. 得出最终的结果
        SELECT deptno,AVG(sal) FROM emp GROUP BY deptno HAVING AVG(sal) > (SELECT AVG(sal) FROM emp WHERE deptno=30);
            
    -- 工资>JONES工资的员工信息
        1.查处JONES的工资信息
        SELECT sal FROM emp WHERE ename='JONES';
        2.得出结果
        SELECT * FROM emp WHERE sal > (SELECT sal FROM emp WHERE ename='JONES');
    -- 查询与SCOTT同一个部门的员工
        1.查处SCOTT的部门编号
        SELECT deptno FROM emp WHERE ename = 'SCOTT';
        2.得出结果
        SELECT * FROM emp WHERE deptno = (SELECT deptno FROM emp WHERE ename = 'SCOTT');
    -- 工资高于30号部门所有人的员工信息
        1.得出30号部门的最大工资
        SELECT MAX(sal) FROM emp WHERE deptno = 30;
        2.得出结果
        SELECT * FROM emp WHERE sal > (SELECT MAX(sal) FROM emp WHERE deptno = 30);
    -- 查询工作和工资与MARTIN完全相同的员工信息
        1.查处MARTIN的工作和工资
        SELECT job,sal FROM emp WHERE ename='MARTIN';
        2.得出结果
        SELECT * FROM emp WHERE (job,sal) IN (SELECT job,sal FROM emp WHERE ename='MARTIN');
    -- 有两个以上直接下属的员工信息
        1.查出emp表中mgr信息
        SELECT mgr FROM emp;
        2.分组统计mgr的信息
        SELECT mgr,COUNT(*) FROM emp GROUP BY mgr HAVING COUNT(*)>2;
        3.得出结果
        SELECT * FROM emp e1 WHERE e1.empno IN (SELECT e2.mgr FROM emp e2 GROUP BY e2.mgr HAVING COUNT(*)>2);
    -- 查询员工编号为7788的员工名称,员工工资,部门名称,部门地址
        1.将员工表和部门表链接起来
        SELECT * FROM emp ,dept WHERE emp.deptno = dept.deptno;
        2.得出ID为7788的所有信息
        SELECT * FROM emp ,dept WHERE emp.deptno = dept.deptno AND empno=7788;
        3.只显示其中的需要的信息
        SELECT ename,sal ,dname, loc FROM emp ,dept WHERE emp.deptno = dept.deptno AND empno=7788;
    
    -- 1. 查询出高于本部门平均工资的员工信息
        1. 分组统计每个部门的平均工资
        SELECT deptno,AVG(sal) FROM emp GROUP BY deptno;
        2. 得出相应的结果
        SELECT * FROM emp e1 WHERE e1.sal > (SELECT AVG(e2.sal) FROM emp e2 WHERE e1.deptno=e2.deptno  GROUP BY e2.deptno);
        
    -- 1. 列出达拉斯加工作的人中,比纽约平均工资高的人
        0. 查处DALLAS 的部门编号
        SELECT deptno FROM dept WHERE loc='DALLAS';
        1.查处达拉斯工作的人的信息
        SELECT * FROM emp WHERE deptno = (SELECT deptno FROM dept WHERE loc='DALLAS');
        2. 查处纽约的部门编号
        SELECT deptno FROM dept WHERE loc='NEW YORK';
        3. 查村纽约平均工资
        SELECT AVG(sal) FROM emp WHERE deptno = (SELECT deptno FROM dept WHERE loc='NEW YORK');
        4.得出结果:
        SELECT * FROM emp WHERE deptno = (SELECT deptno FROM dept WHERE loc='DALLAS')
        AND sal > (SELECT AVG(sal) FROM emp WHERE deptno = (SELECT deptno FROM dept WHERE loc='NEW YORK'));
        
        
    -- 2. 查询7369员工编号,姓名,经理编号和经理姓名
        SELECT e1.empno,e1.ename,e1.mgr,mgrtable.ename FROM emp e1,emp mgrtable WHERE e1.mgr = mgrtable.empno; 
        
    -- 3. 查询出各个部门薪水最高的员工所有信息
        1.分组统计每个部门员工最高的薪资是多少
        SELECT MAX(sal),deptno FROM emp GROUP BY deptno;
        2.算出结果
        SELECT * FROM emp e1 WHERE e1.sal = (SELECT MAX(sal) FROM emp e2 WHERE e1.deptno = e2.deptno GROUP BY deptno);
        
        
    CREATE TABLE test(
      NAME CHAR(20),
      kecheng CHAR(20),
      fenshu CHAR(20)
    );
    
    INSERT INTO test VALUES
    ('张三','语文',81),
    ('张三','数学',75),
    ('李四','语文',76),
    ('李四','数学',90),
    ('王五','语文',81),
    ('王五','数学',82);
    
    
    SELECT NAME FROM test WHERE fenshu < 80 ;
    SELECT NAME FROM test WHERE NAME NOT IN(SELECT NAME FROM test WHERE fenshu < 80 );
    
        
        
    练习

     JDBC

    JDBC概念和数据库驱动程序

    JDBCJava Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。是Java访问数据库的标准规范

    JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。

    JDBC需要连接驱动,驱动是两个设备要进行通信,满足一定通信数据格式,数据格式由设备提供商规定,设备提供商为设备提供驱动软件,通过软件可以与该设备进行通信。

    总结:  JDBCjava提供给开发人员的一套操作数据库的接口

                         数据库驱动就是实现该接口的实现类

    JDBC原理

                  Java提供访问数据库规范称为JDBC,而生产厂商提供规范的实现类称为驱动

                  JDBC是接口,驱动是接口的实现,没有驱动将无法完成数据库连接,从而不能操作数据库!每个数据库厂商都需要提供自己的驱动,用来连接自己公司的数据库,也就是说驱动一般都由数据库生成厂商提供。

    JDBC的开发步骤

           JDBC的开发步骤

                         1.注册驱动

                                告知JVM使用的是哪一个数据库的驱动

                         2.获得连接

                                使用JDBC中的类,完成对MySQL数据库的连接

                         3.获得语句执行平台

                                通过连接对象获取对SQL语句的执行者对象

                         4.执行sql语句

                                使用执行者对象,向数据库执行SQL语句

                                获取到数据库的执行后的结果

                         5.处理结果

                         6.释放资源  一堆close()             

    public class JDBCDemo {
                    public static void main(String[] args)throws ClassNotFoundException,SQLException{
                        //1.注册驱动 反射技术,将驱动类加入到内容
                        // 使用java.sql.DriverManager类静态方法 registerDriver(Driver driver)
                        // Diver是一个接口,参数传递,MySQL驱动程序中的实现类
                        //DriverManager.registerDriver(new Driver());
                        //驱动类源代码,注册2次驱动程序
                        Class.forName("com.mysql.jdbc.Driver");
                        
                        //2.获得数据库连接  DriverManager类中静态方法
                        //static Connection getConnection(String url, String user, String password)  
                        //返回值是Connection接口的实现类,在mysql驱动程序
                        //url: 数据库地址  jdbc:mysql://连接主机IP:端口号//数据库名字
                        String url = "jdbc:mysql://localhost:3306/mybase";
                        String username="root";
                        String password="123";
                        Connection con = DriverManager.getConnection(url, username, password);
                        
                        //3.获得语句执行平台, 通过数据库连接对象,获取到SQL语句的执行者对象
                        // con对象调用方法   Statement createStatement() 获取Statement对象,将SQL语句发送到数据库
                        // 返回值是 Statement接口的实现类对象,,在mysql驱动程序
                        Statement stat = con.createStatement();
                        //    4.执行sql语句
                        // 通过执行者对象调用方法执行SQL语句,获取结果
                        // int executeUpdate(String sql)  执行数据库中的SQL语句, insert delete update
                        // 返回值int,操作成功数据表多少行
                        int row = stat.executeUpdate
                                ("INSERT INTO sort(sname,sprice,sdesc) VALUES('汽车用品',50000,'疯狂涨价')");
                        System.out.println(row);
                        
                        //6.释放资源  一堆close()
                        stat.close();
                        con.close();
                    }
                }
    案例 

    导入mysql数据库驱动程序jar

                  步骤

                         创建lib目录,用于存放当前项目需要的所有jar

                         选择jar包,右键执行build path / Add to Build Path

     

    执行select语句获取结果集:

    public class JDBCDemo1 {
                    public static void main(String[] args) throws Exception{
                        //1. 注册驱动
                        Class.forName("com.mysql.jdbc.Driver");
                        //2. 获取连接对象
                        String url = "jdbc:mysql://localhost:3306/mybase";
                        String username="root";
                        String password="123";
                        Connection con = DriverManager.getConnection(url, username, password);
                        //3 .获取执行SQL 语句对象
                        Statement stat = con.createStatement();
                        // 拼写查询的SQL
                        String sql = "SELECT * FROM sort";
                        //4. 调用执行者对象方法,执行SQL语句获取结果集
                        // ResultSet executeQuery(String sql)  执行SQL语句中的select查询
                        // 返回值ResultSet接口的实现类对象,实现类在mysql驱动中
                        ResultSet rs = stat.executeQuery(sql);
                        //5 .处理结果集
                        // ResultSet接口方法 boolean next() 返回true,有结果集,返回false没有结果集
                        while(rs.next()){
                            //获取每列数据,使用是ResultSet接口的方法 getXX方法参数中,建议写String列名
                            System.out.println(rs.getInt("sid")+"   "+rs.getString("sname")+
                                    "   "+rs.getDouble("sprice")+"   "+rs.getString("sdesc"));
                        }
                        
                        rs.close();
                        stat.close();
                        con.close();
                    }
                }
    案例

    SQL注入攻击

                  注入问题

                          假设有登录案例SQL语句如下:

                          SELECT * FROM 用户表 WHERE NAME = 用户输入的用户名 AND PASSWORD = 用户输的密码;

                          此时,当用户输入正确的账号与密码后,查询到了信息则让用户登录。但是当用户输入的账号为XXX 密码为:XXX’  OR ‘a’=’a时,则真正执行的代码变为: * SELECT * FROM 用户表 WHERE NAME = ‘XXX’ AND PASSWORD =’ XXX’  OR ’a’=’a’;

                         此时,上述查询语句时永远可以查询出结果的。那么用户就直接登录成功了,显然我们不希望看到这样的结果,这便是SQL注入问题。

                public class JDBCDemo2 {
                    public static void main(String[] args)throws Exception {
                        Class.forName("com.mysql.jdbc.Driver");
                        String url = "jdbc:mysql://localhost:3306/mybase";
                        String username = "root";
                        String password = "123";
                        Connection con = DriverManager.getConnection(url, username, password);
                        Statement stat = con.createStatement();
                        
                        Scanner sc = new Scanner(System.in);
                        String user = sc.nextLine();
                        String pass = sc.nextLine();
                        
                        //执行SQL语句,数据表,查询用户名和密码,如果存在,登录成功,不存在登录失败
                //        String sql = "SELECT * FROM users WHERE username='dsfsdfd' AND PASSWORD='wrethiyu' OR 1=1";
                        String sql = "SELECT * FROM users WHERE username='"+user+"' AND PASSWORD='"+pass+"'";
                        System.out.println(sql);
                        ResultSet rs = stat.executeQuery(sql);
                        while(rs.next()){
                            System.out.println(rs.getString("username")+"   "+rs.getString("password"));
                        }
                        
                        rs.close();
                        stat.close();
                        con.close();
                    }
                }
    案例

    PrepareStatement接口预编译SQL语句:

                  预处理对象:

                         使用PreparedStatement预处理对象时,建议每条sql语句所有的实际参数,都使用逗号分隔。

                         String sql = "insert into sort(sid,sname) values(?,?)";

                          PreparedStatement预处理对象代码:

                           PreparedStatement psmt = conn.prepareStatement(sql)

                  执行SQL语句的方法介绍:

                         int executeUpdate(); --执行insert update delete语句.

                         ResultSet executeQuery(); --执行select语句.

                         boolean execute(); --执行select返回true 执行其他的语句返回false.

                  设置实际参数:

                         void setXxx(int index, Xxx xx) 将指定参数设置为给定Javaxx值。在将此值发送到数据库时,驱动程序将它转换成一个 SQL Xxx类型值。

                          例如: setString(2, "家用电器") SQL语句中第2个位置的占位符?替换成实际参数 "家用电器" 

    /*
                 *  Java程序实现用户登录,用户名和密码,数据库检查
                 *  防止注入攻击
                 *  Statement接口实现类,作用执行SQL语句,返回结果集
                 *  有一个子接口PreparedStatement  (SQL预编译存储,多次高效的执行SQL) 
                 *  PreparedStatement的实现类数据库的驱动中,如何获取接口的实现类
                 *  
                 *  是Connection数据库连接对象的方法
                 *  PreparedStatement prepareStatement(String sql) 
                          
                 */
                public class JDBCDemo3 {
                    public static void main(String[] args)throws Exception {
                        Class.forName("com.mysql.jdbc.Driver");
                        String url = "jdbc:mysql://localhost:3306/mybase";
                        String username = "root";
                        String password = "123";
                        Connection con = DriverManager.getConnection(url, username, password);
                        Scanner sc = new Scanner(System.in);
                        String user = sc.nextLine();
                        String pass = sc.nextLine();
                        
                        //执行SQL语句,数据表,查询用户名和密码,如果存在,登录成功,不存在登录失败
                        String sql = "SELECT * FROM users WHERE username=? AND PASSWORD=?";
                        //调用Connection接口的方法prepareStatement,获取PrepareStatement接口的实现类
                        //方法中参数,SQL语句中的参数全部采用问号占位符
                        PreparedStatement pst =  con.prepareStatement(sql);
                        System.out.println(pst);
                        //调用pst对象set方法,设置问号占位符上的参数
                        pst.setObject(1, user);
                        pst.setObject(2, pass);
                        
                        //调用方法,执行SQL,获取结果集
                        ResultSet rs = pst.executeQuery();
                        while(rs.next()){
                            System.out.println(rs.getString("username")+"   "+rs.getString("password"));
                        }
                        
                        rs.close();
                        pst.close();
                        con.close();
                    }
                }
    案例

    PrepareStatement接口预编译SQL语句执行修改

                /*
                 *  使用PrepareStatement接口,实现数据表的更新操作
                 */
                public class JDBCDemo {
                    public static void main(String[] args) throws Exception{
                        Class.forName("com.mysql.jdbc.Driver");
                        String url = "jdbc:mysql://localhost:3306/mybase";
                        String username="root";
                        String password="123";
                        Connection con = DriverManager.getConnection(url, username, password);    
                        
                        //拼写修改的SQL语句,参数采用?占位
                        String sql = "UPDATE sort SET sname=?,sprice=? WHERE sid=?";
                        //调用数据库连接对象con的方法prepareStatement获取SQL语句的预编译对象
                        PreparedStatement pst = con.prepareStatement(sql);
                        //调用pst的方法setXXX设置?占位
                        pst.setObject(1, "汽车美容");
                        pst.setObject(2, 49988);
                        pst.setObject(3, 7);
                        //调用pst方法执行SQL语句
                        pst.executeUpdate();
                        
                        pst.close();
                        con.close();
                    }
                }
    案例

    PrepareStatement接口预编译SQL语句执行查询

                /*
                 *  PrepareStatement接口实现数据表的查询操作
                 */
                public class JDBCDemo1 {
                    public static void main(String[] args) throws Exception{
                        Class.forName("com.mysql.jdbc.Driver");
                        String url = "jdbc:mysql://localhost:3306/mybase";
                        String username="root";
                        String password="123";
                        Connection con = DriverManager.getConnection(url, username, password);    
                        
                        String sql = "SELECT * FROM sort";
                        
                        PreparedStatement pst = con.prepareStatement(sql);
                        
                        //调用pst对象的方法,执行查询语句,Select
                        ResultSet rs=pst.executeQuery();
                        while(rs.next()){
                            System.out.println(rs.getString("sid")+"  "+rs.getString("sname")+"  "+rs.getString("sprice")+"  "+rs.getString("sdesc"));
                        }
                        rs.close();
                        pst.close();
                        con.close();
                    }
                }
    案例

    JDBC的工具类和测试:

    //JDBCUtils工具类代码
                public class JDBCUtils {
                    private JDBCUtils(){}
                    private static Connection con ;
                    
                    static{
                        try{
                            Class.forName("com.mysql.jdbc.Driver");
                            String url = "jdbc:mysql://localhost:3306/mybase";
                            String username="root";
                            String password="123";
                            con = DriverManager.getConnection(url, username, password);
                        }catch(Exception ex){
                            throw new RuntimeException(ex+"数据库连接失败");
                        }
                    }
                    
                    /*
                     * 定义静态方法,返回数据库的连接对象
                     */
                    public static Connection getConnection(){
                        return con;
                    }
                    
                    
                    public static void close(Connection con,Statement stat){
                         
                         if(stat!=null){
                             try{
                                 stat.close();
                             }catch(SQLException ex){}
                         }
                         
                         if(con!=null){
                             try{
                                 con.close();
                             }catch(SQLException ex){}
                         }
                         
                    }
                    
                    
                    public static void close(Connection con,Statement stat , ResultSet rs){
                         if(rs!=null){
                             try{
                                 rs.close();
                             }catch(SQLException ex){}
                         }
                         
                         if(stat!=null){
                             try{
                                 stat.close();
                             }catch(SQLException ex){}
                         }
                         
                         if(con!=null){
                             try{
                                 con.close();
                             }catch(SQLException ex){}
                         }
                         
                    }
                }
    工具类代码
    测试JDBCUtils工具类的代码
            public class TestJDBCUtils {
                public static void main(String[] args)throws Exception {
                    Connection con = JDBCUtils.getConnection();
                    PreparedStatement pst = con.prepareStatement("SELECT sname FROM sort");
                    ResultSet rs = pst.executeQuery();
                    while(rs.next()){
                        System.out.println(rs.getString("sname"));
                    }
                    JDBCUtils.close(con, pst, rs);
                }
            }
    测试类代码

     properties配置文件

    开发中获得连接的4个参数(驱动、URL、用户名、密码)通常都存在配置文件中,方便后期维护,程序如果需要更换数据库,只需要修改配置文件即可。

    通常情况下,我们习惯使用properties文件,此文件做如下要求:

    1. 文件位置:任意,建议src下
    2. 文件名称:任意,扩展名为properties
    3. 文件内容:一行一组数据,格式是“key=value”.

        a)key命名自定义,如果是多个单词,习惯使用点分隔。例如:jdbc.driver

        b)value值不支持中文,如果需要使用非英文字符,将进行unicode转换。

    driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/mydb
    user=root
    password=root
    案例
    public class JDBCUtils {
    
        private static String driver;
        private static String url;
        private static String user;
        private static String password;
        // 静态代码块
        static {
            try {
                // 1 使用Properties处理流
                // 使用load()方法加载指定的流
                Properties props = new Properties();
                Reader is = new FileReader("db.properties");
                props.load(is);
                // 2 使用getProperty(key),通过key获得需要的值,
                driver = props.getProperty("driver");
                url = props.getProperty("url");
                user = props.getProperty("user");
                password = props.getProperty("password");
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
        /**
         * 获得连接
         */
        public static Connection getConnection() {
            try {
                // 1 注册驱动
                Class.forName(driver);
                // 2 获得连接
                Connection conn = DriverManager.getConnection(url, user, password);
                return conn;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
    JDBCUtils工具类
    public class Demo {
        @Test
        public void insert(){
            try{
                //1,获取连接对象
                Connection conn = JDBCUtils.getConnection();
                //2,指定要执行的SQL语句
                String sql = "INSERT INTO zhangwu(name,money,parent) VALUES(?,?,?)";
                //4,获取SQL语句的执行对象 PreparedStatement
                PreparedStatement ppstat = conn.prepareStatement(sql);
                //5,执行SQL语句
                ppstat.setString(1, "股票收入");
                ppstat.setDouble(2, 5000);
                ppstat.setString(3, "收入");
                int line = ppstat.executeUpdate();
                //6,处理结果集
                System.out.println("line=" + line);
                //7,关闭连接
                ppstat.close();
                conn.close();
            } catch(SQLException e){
                throw new RuntimeException(e);
            }
        }
    }
    测试类

    DBUtils

     如果只使用JDBC进行开发,我们会发现冗余代码过多,为了简化JDBC开发,本案例我们讲采用apache commons组件一个成员:DBUtils。

          DBUtils就是JDBC的简化开发工具包。需要项目导入commons-dbutils-1.6.jar才能够正常使用DBUtils工具。

     DBUtils是java编程中的数据库操作实用工具,小巧简单实用。

     DBUtils封装了对JDBC的操作,简化了JDBC操作,可以少写代码。

     Dbutils三个核心功能介绍:

      QueryRunner中提供对sql语句操作的API.

      ResultSetHandler接口,用于定义select操作后,怎样封装结果集.

      DbUtils类,它就是一个工具类,定义了关闭资源与事务处理的方法

     QueryRunner核心类(np)

    update(Connection conn, String sql, Object... params) :用来完成表数据的增加、删除、更新操作

    query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params) :用来完成表数据的查询操作

    QueryRunner实现添加、更新、删除操作(update)

    public void insert(){
        try {
            //获取一个用来执行SQL语句的对象   QueryRunner
            QueryRunner qr = new QueryRunner();
            
            String sql = "INSERT INTO zhangwu(name,money,parent) VALUES(?,?,?)";
            Object[] params = {"股票收入", 5500, "收入"};
            Connection conn = JDBCUtils.getConnection();
            int line = qr.update(conn,sql,params);// 用来完成表数据的增加、删除、更新操作
            //结果集处理
            System.out.println("line = " + line);
            
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
    添加
    public void update(){
        try {
            //创建一个QueryRunner对象,用来完成SQL语句的执行
            QueryRunner qr = new QueryRunner();
            //执行SQL语句
            String sql = "UPDATE zhangwu SET money = money+1000 WHERE name=?";
            Object[] params = {"股票收入"};
            Connection conn = JDBCUtils.getConnection();
            int line = qr.update(conn, sql, params);
            //结果集的处理
            System.out.println("line="+line);
            
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
    更新
    public void delete(){
        try {
            //创建一个QueryRunner对象,用来完成SQL语句的执行
            QueryRunner qr = new QueryRunner();
            //执行SQL语句
            String sql = "DELETE FROM zhangwu WHERE name = ?";
            Object[] params = {"股票收入"};
            Connection conn = JDBCUtils.getConnection();
            int line = qr.update(conn, sql, params);
            //结果集的处理
            System.out.println("line="+line);
            
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
    删除

    QueryRunner实现查询操作(query)

    结果集处理类:

    ArrayHandler

    将结果集中的第一条记录封装到一个Object[]数组中,数组中的每一个元素就是这条记录中的每一个字段的值

    ArrayListHandler

    将结果集中的每一条记录都封装到一个Object[]数组中,将这些数组在封装到List集合中。

    BeanHandler

    将结果集中第一条记录封装到一个指定的javaBean中。

    BeanListHandler

    将结果集中每一条记录封装到指定的javaBean中,将这些javaBean在封装到List集合中

    ColumnListHandler

    将结果集中指定的列的字段值,封装到一个List集合中

    ScalarHandler

    它是用于单数据。例如select count(*) from 表操作。

    MapHandler

    将结果集第一行封装到Map集合中,Key 列名, Value 该列数据

    MapListHandler

    将结果集第一行封装到Map集合中,Key 列名, Value 该列数据,Map集合存储到List集合

    ArrayHandler与ArrayListHandler查询:

    1、ArrayHandler:将结果集中的第一条记录封装到一个Object[]数组中,数组中的每一个元素就是这条记录中的每一个字段的值。

    public class ArrayHandlerDemo {
        
        @Test
        public void method(){
            try {
                //获取QueryRunner对象
                QueryRunner qr = new QueryRunner();
                //执行SQL语句
                String sql = "SELECT * FROM zhangwu";
                Object[] params = {};
                Connection conn = JDBCUtils.getConnection();
                Object[] objArray = qr.query(conn, sql, new ArrayHandler(), params);
                //结果集的处理
                System.out.println( Arrays.toString(objArray) );
                
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    案例

    2、ArrayListHandler:将结果集中的每一条记录都封装到一个Object[]数组中,将这些数组在封装到List集合中。

    public class ArrayListHandlerDemo {
        @Test
        public void method(){
            try {
                //获取QueryRunner对象
                QueryRunner qr = new QueryRunner();
                //执行SQL语句
                String sql = "SELECT * FROM zhangwu WHERE money>?";
                Object[] params = {2000};
                Connection conn = JDBCUtils.getConnection();
                 List<Object[]> list = qr.query(conn, sql, new ArrayListHandler(), params);
                //结果集的处理
                 for (Object[] objArray : list) {
                    System.out.println(  Arrays.toString(objArray) );
                }
                
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    案例

    BeanHandler与BeanListHandler查询:

    1、BeanHandler :将结果集中第一条记录封装到一个指定的javaBean中。

    public class BeanHandlerDemo {
        @Test
        public void method(){
            try{
                //获取QueryRunner 
                QueryRunner qr = new QueryRunner();
                //执行SQL语句
                String sql = "SELECT * FROM zhangwu WHERE id=?";
                Object[] params = {1};
                Connection conn = JDBCUtils.getConnection();
                ZhangWu zw = qr.query(conn, sql, new BeanHandler<ZhangWu>(ZhangWu.class), params);
                //结果集处理
                System.out.println(zw);
                
                conn.close();
            } catch(SQLException e){
                throw new RuntimeException(e);
            }
        }
    }
    案例

    2、BeanListHandler :将结果集中每一条记录封装到指定的javaBean中,将这些javaBean在封装到List集合中

    public class BeanListHandlerDemo {
        @Test
        public void method(){
            try{
                //获取QueryRunner 
                QueryRunner qr = new QueryRunner();
                //执行SQL语句
                String sql = "SELECT * FROM zhangwu WHERE money>?";
                Object[] params = {2000};
                Connection conn = JDBCUtils.getConnection();
                List<ZhangWu> list = qr.query(conn, sql, new BeanListHandler<ZhangWu>(ZhangWu.class), params);
                //结果集处理
                for (ZhangWu zw : list) {
                    System.out.println(zw);
                }
                
                conn.close();
            } catch(SQLException e){
                throw new RuntimeException(e);
            }
        }
    }
    案例

    ColumnListHandler与ScalarHandler查询:

    1、ColumnListHandler:将结果集中指定的列的字段值,封装到一个List集合中

    public class ColumnListHandlerDemo {
        @Test
        public void method(){
            try {
                //获取QueryRunner对象
                QueryRunner qr = new QueryRunner();
                //执行SQL语句
                String sql = "SELECT name FROM zhangwu WHERE money>?";
                Object[] params = {2000};
                Connection conn = JDBCUtils.getConnection();
                List<String> list = qr.query(conn, sql, new ColumnListHandler<String>(), params); 
                //结果集的处理
                for (String str : list) {
                    System.out.println(str);
                }
    
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    案例

     2、ScalarHandler:它是用于单数据。例如select count(*) from 表操作。

    public class ScalarHandlerDemo {
        @Test
        public void method(){
            try {
                //获取QueryRunner对象
                QueryRunner qr = new QueryRunner();
                
                //执行SQL语句
                String sql = "SELECT MAX(money) FROM zhangwu";
                Object[] params = {};
                Connection conn = JDBCUtils.getConnection();
                Double max = qr.query(conn, sql, new ScalarHandler<Double>(), params);
                //结果集的处理
                System.out.println("max=" + max);
                
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    案例

     连接池

      实际开发中“获得连接”或“释放资源”是非常消耗系统资源的两个过程,为了解决此类性能问题,通常情况我们采用连接池技术,来共享连接Connection。这样我们就不需要每次都创建连接、释放连接了,这些操作都交给了连接池。

    用池来管理Connection,这样可以重复使用Connection。有了池,所以我们就不用自己来创建Connection,而是通过池来获取Connection对象。当使用完Connection后,调用Connection的close()方法也不会真的关闭Connection,而是把Connection“归还”给池。池就可以再利用这个Connection对象了。

    DBCP连接池

      DBCP也是一个开源的连接池,是Apache Common成员之一,在企业开发中也比较常见,tomcat内置的连接池。

     编写工具类:

    连接数据库表的工具类, 采用DBCP连接池的方式来完成,Java中提供了一个连接池的规则接口 :

      DataSource : 它是java中提供的连接池,作为 DriverManager 工具的替代项。在DBCP包中提供了DataSource接口的实现类,我们要用的具体的连接池 BasicDataSource类

    public class JDBCUtils {
        public static final String DRIVER = "com.mysql.jdbc.Driver";
        public static final String URL = "jdbc:mysql://localhost:3306/daydb";
        public static final String USERNAME = "root";
        public static final String PASSWORD = "root";
        /*
         * 创建连接池BasicDataSource
         */
        public static BasicDataSource dataSource = new BasicDataSource();
        //静态代码块
        static {
            //对连接池对象 进行基本的配置
            dataSource.setDriverClassName(DRIVER); // 这是要连接的数据库的驱动
            dataSource.setUrl(URL); //指定要连接的数据库地址
            dataSource.setUsername(USERNAME); //指定要连接数据的用户名
            dataSource.setPassword(PASSWORD); //指定要连接数据的密码
        }
        /*
         * 返回连接池对象
         */
        public static DataSource getDataSource(){
            return dataSource;
        }
    }
    工具类
    /*
     * 演示使用DBUtils工具  完成数据库表的增加操作
     */
    public class Demo {
        // 插入功能 
        @Test
        public void insert(){
            try {
                //获取一个用来执行SQL语句的对象   QueryRunner
                QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
    String sql = "INSERT INTO zhangwu(name,money,parent) VALUES(?,?,?)";
                Object[] params = {"股票收入", 5500, "收入"};    
                 int line = qr.update(sql,params);
                //结果集处理
                System.out.println("line = " + line);
                
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        
        //删除功能
        @Test
        public void delete(){
            try {
                //创建一个QueryRunner对象,用来完成SQL语句的执行
                QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
                //执行SQL语句
                String sql = "DELETE FROM zhangwu WHERE name = ?";
                Object[] params = {"股票收入"};
                int line = qr.update(sql, params);
                //结果集的处理
                System.out.println("line="+line);
                
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        
        //更新功能
        @Test
        public void update(){
            try {
                //创建一个QueryRunner对象,用来完成SQL语句的执行
                QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
                //执行SQL语句
                String sql = "UPDATE zhangwu SET money = money+1000 WHERE name=?";
                Object[] params = {"股票收入"};
                int line = qr.update(sql, params);
                //结果集的处理
                System.out.println("line="+line);
                
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        
        //查询功能,将结果集中第一条记录封装到一个指定的javaBean中。
        @Test
        public void search(){
            try{
                //获取QueryRunner 
                QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
                //执行SQL语句
                String sql = "SELECT * FROM zhangwu";
                Object[] params = {};
                Product p = qr.query(sql, new BeanHandler<Product>(Product.class), params);
                //结果集处理
                System.out.println(p);
                
            } catch(SQLException e){
                throw new RuntimeException(e);
            }
        }
    }
    测试

     常见配置项

    分类

    属性

    描述

    必须项

    driverClassName

    数据库驱动名称

    url

    数据库的地址

    username

    用户名

    password

    密码

    基本项(扩展)

    maxActive

    最大连接数量

    minIdle

    最小空闲连接

    maxIdle

    最大空闲连接

    initialSize

    初始化连接

    你好

  • 相关阅读:
    P4665 [BalticOI 2015]Network 题解
    NOIp2020游记
    独立集(bubble) 题解
    密码(substring) 题解
    8.20被题虐
    开通博客了!
    CSP-S2021 记
    「CSP-S 2020」函数调用(拓扑排序+DP)
    OI生涯回忆录
    [UOJ79]一般图最大匹配(带花树)
  • 原文地址:https://www.cnblogs.com/wz46265381/p/14134188.html
Copyright © 2011-2022 走看看