java学习笔记7

1.设计模式:

  结构型设计模式:代理模式 
      静态代理
      动态代理
          代理定义:代理角色帮助真是角色完成一些事情.
       静态代理:
          通过代理角色帮助真实角色完成一些事情,真实角色只专注于自己的事情.
          前提条件:代理角色和真实角色必须是同一个接口.
    举例:结婚这件事情
         真实角色:you
         代理角色:WeddingCompany:婚庆公司
//测试类
public class ProxyDemo {
    public static void main(String[] args) {
​
        //没有使用静态代理之前
        //接口多态
        //Mary mary = new You() ;
        //mary.mary() ;
        //具体类
        You y = new You() ;                 // MyRunnable my = new MyRunnable() ;
        y.mary() ;
​
        System.out.println("---------------------------------") ;
​
        //加入代理
        WeddingCompany weddingCompany = new WeddingCompany(y) ; //Thread t = new Thread(my) ;
        weddingCompany.mary() ;
    }
}
​
//接口:结婚接口
interface  Mary{
    void mary() ;//结婚
}
//真实角色:You
class You implements  Mary{
​
    @Override
    public void mary() {
        System.out.println("要结婚了,很开心...") ;
    }
}
//代理角色: 目的:对你mary方法进行增强   要实现结婚的接口
class WeddingCompany implements  Mary{
    private You you ;
    public  WeddingCompany(You you){
        this.you = you ;
    }
    @Override
    public void mary() {
        System.out.println("结婚之前,布置婚礼现场...");
        you.mary() ;//真实角色专注于自己的事情
        System.out.println("结婚之后,婚庆公司需要结算尾款...");
    }
}

2.等待唤醒机制:解决死锁问题代码进行优化 ("信号灯法")

1)将数据:Student类的成员加入私有化
2)在Student类中提供set方法,对学生数据进行赋值,加入同步方法
3)在生产者资源类中,只需要调用当前set方法进行赋值
4)在Student类中提供get方法,获取学生数据,加入同步方法
5)在GetThread:消费者资源类中,调用get方法即可!
举例:
 
public class ThreadDemo {
public static void main(String[] args) {
    //创建一个学生对象
    Student s = new Student() ;
    //创建生产者资源类对象
    SetThread st = new SetThread(s) ;
    //创建消费者资源类对象s
    GetThread gt = new GetThread(s) ;
    //创建线程类对象
    Thread t1 = new Thread(st) ;
    Thread t2 = new Thread(gt) ;
    //启动线程
    t1.start() ;
    t2.start() ;
}
}
public class Student {
private String name ; //姓名
private int age ;//年龄
private boolean flag ; //默认没有数据,通过这标记信号:表示是否存在数据
​
/**
​
给学生数据进行赋值
​
@param name  姓名
​
@param age 年龄
*/
public synchronized  void set(String name,int age){
//如果方法一进来就是一个同步代码块,需要将synchronized定义在方法声明上,锁对象this
    //判断:
    //如果当前生产者没有数据,先等待产生数据
    if (this.flag) {
        try {
            this.wait(); //wait()方法为什么定义Object类中? 因为锁对象可以是任意的Java类对象 (包括Object)
            //     //wait()一旦被调用,会立即释放锁
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
   }
    //赋值
   this.name = name ;
   this.age = age ;
​
//改变标记:有数据了
//改变标记
this.flag = true ;
//调用通知对方:唤醒对方线程
this.notify() ;
}
​
/**
​
获取学生数据
*/
public synchronized void get(){
​
•    //如果当前消费者存在数据
•    if (!this.flag) {
•        //等待将产生的数据消费掉
•        try {
•            this.wait();
•        } catch (InterruptedException e) {
•            e.printStackTrace();
•        }
•    }
•    System.out.println(this.name + "---" + this.age);
​
//改变标记
this.flag= false ;
//通知生成者线程,产生数据
this.notify() ;
}
}
public class SetThread implements  Runnable {
//Student s = new Student() ;
private Student s ; //声明学生变量s
public SetThread(Student s){
this.s = s ;
}
//统计变量
private int x = 0 ;
@Override
public void run() {
while(true){
    if(x % 2 ==0){
        s.set("高圆圆",42);
    }else {
        s.set("赵又廷",45);
    }
    x++ ;//原子性操作
}
}
}
public class GetThread implements Runnable {
//声明学生变量s
private Student s ;
public GetThread(Student s) {
this.s =  s ;
}
//Student s= new Student() ;
@Override
public void run() {
//使用学生数据
//System.out.println(s.name+"-"+s.age) ;
//不断的去使用数据
while(true){
    s.get();
}
}
}

3.线程池

工厂类:里面有一个静态方法:
        public static ExecutorService newFixedThreadPool(int nThreads):创建一个固定的可重复的线程数的线程池
        ExecutorService:接口,它可以进行多个异步任务的执行
举例:
 public class ThreadPoolTest {
    public static void main(String[] args) {
        //public static ExecutorService newFixedThreadPool(int nThreads)
        //创建线程池
        ExecutorService threadPool = Executors.newFixedThreadPool(2);
​
        //<T> Future<T> submit(Callable<T> task)
        //接口多态
        Callable callable = new MyCallable() ;
        //两个线程分别执行异步任务
        threadPool.submit(callable) ;
        threadPool.submit(callable) ;
​
        //使用完毕,关闭线程池
        //线程需要归还到线程池中
        //void shutdown()
        threadPool.shutdown() ;
    }
}
public class MyCallable implements Callable {
    //不计算结果,仅仅展示:多个线程并发执行
    @Override
    public Object call() throws Exception {
​
        for(int x = 0 ; x < 100 ; x ++){
            System.out.println(Thread.currentThread().getName()+":"+x);
        }
        return null;
    }
}

4.wait()和notify()为什么定义在Object类中,不定义在Thread类中

wait()和notify():代表线程处于等待或者线程唤醒,他们的调用是要通过同步机制中的锁对象来访问的,(锁对象可以是任意的Java类对象)
当前某个线程持有锁的时候,调用wait(),处于等待过程,但是立即释放锁,然后可以通过锁对象.notify()唤醒对方线程,解决死锁问题; 
​
​
等待唤醒机制:
    生产者线程不断的产生数据,没有数据了,等待先产生数据,有数据了之后,需要通知消费者线程来使用数据;
    消费者线程不断的使用数据,有数据了,先等待使用数据,当数据使用完毕,没有数据了,需要通知生产者线程产生数据;
​

5.sleep()和wait()方法的区别 (面试题)

1)来源不同
    sleep()来自于Thread类中,表示线程睡眠 sleep(long time):时间毫秒值  
    wait()来自于Object类中,表示线程等待,需要被锁对象来访问
2)是否会释放锁
     sleep(long time):属于一个普通方法,调用该方法,不会去释放锁,只是导致线处于睡眠(线程阻塞),当线程的睡眠时间到了,就继续执行线程;
     wait():属于锁方法,被锁对象访问之后,会立即释放锁,才能够使用同步等待唤醒机制解决死锁问题,通过锁对象调用notify(),唤醒对方线程;
3)这两个方法都会抛出异常(中断异常),都是属于本地方法,底层非Java语言实现
当线程睡眠过程中,睡眠还没到,导致的睡眠状态被打断,就会出现InterruptedException
当线程处于等待状态,被中断,就抛出这个异常!
         public static native void sleep(long millis) throws InterruptedException
         public final native void wait(long timeout) throws InterruptedException;
            

6.Lock接口

比synchronized具有扩展性的功能
子实现类ReetrantLock:可重入的互斥锁
public void lock()获取锁
public void unlock()释放锁
处理异常:try...cath...finally.
 throws:抛出异常:抛出在方法声明上;
 举例:模拟电影院三个窗口买100张票
 package com.qf.jhq;
​
/**
 * className:LockTest
 * package:com.qf.jhq
 * date2021/10/26  19:10
 * Author:ly
 */
public class LockTest {
    public static void main(String[] args) {
        SellTick  s=new SellTick();
        Thread t1=new Thread(s,"窗口1");
        Thread t2=new Thread(s,"窗口2");
        Thread t3=new Thread(s,"窗口3");
        t1.start();
        t2.start();
        t3.start();
    }
}
package com.qf.jhq;
​
import java.util.concurrent.locks.ReentrantLock;
​
/**
 * className: SellTick
 * package: com.qf.jhq
 * date 2021/10/26  19:12
 * Author: ly
 */
public class SellTick  implements Runnable{
    //电影票数
    private static  int ticks=100;
     // 无参构造私有化;
     SellTick(){}
    // 创建Lock锁
    ReentrantLock lock=new ReentrantLock();
    @Override
    public void run() {
       //模拟一直有票
        while (true) {
            lock.lock();//调用锁方法
            try {
                if(ticks>0){
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"正在售卖"+(ticks--)+"票");
                }
            }finally {
                lock.unlock();
            }
        }
    }
}

7.Timer

java.util.Timer:javaSE的定时器:处理一次或者重复执行的任务(TimerTask:抽象类)
构造方法:
 public Timer():创建一个新的定时器,不是守护线程
成员方法:
 public void cancel():取消定时器
 public void schedule(TimerTask task,long delay):经过多少毫秒后执行一次定时任务
 public void schedule(TimerTask task,long delay,long period):经过delay毫秒后指向定时任务,每经过period重复执行定时任务
 public void schedule(TimerTask task,Date time):在指定时间的时候(精确到毫秒)执行定时任务.
 TimerTask:抽象类,不能实例化:自定义子类或者匿名内部类
 public abstract void run()定时器要执行的操作.

8.设计模式

8.1简单工厂模式

也称为"静态工厂方法模式",主要的作用是负责某些类的实例的创建过程.
优点:
      通过工厂类完成各个类的对象的创建
缺点:
       当有新的类行增加,需要不断的修稿工厂类,维护性难度大.
 举例:动物,猫,狗
 
package factory;
​
/**
 * className: SimpleFactory
 * package: factory
 * date 2021/10/26  20:09
 * Author: ly
 */
public class SimpleFactory {
    public static void main(String[] args) {
        //优化前
//        Cat c = AnimalFactory.creatCat();
//        c.eat();
//        c.sleep();
//        Dog d = AnimalFactory.creatDog();
//        d.eat();
//        d.sleep();
        //优化后
        Animal a = AnimalFactory.creatAnimal(new Cat());
              if(a!=null){
                  a.eat();
                  a.sleep();
              }
        Animal a2 = AnimalFactory.creatAnimal(new Dog());
              if(a2!=null){
                  a2.sleep();
                  a2.eat();
              }
    }
}
public abstract class Animal {
   public abstract void eat();
    public abstract  void sleep();
}
public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫喜欢吃鱼");
    }
​
    @Override
    public void sleep() {
        System.out.println("猫喜欢躺着睡");
    }
}
public class Dog extends  Animal {
    @Override
    public void eat() {
        System.out.println("狗喜欢啃骨头");
    }
​
    @Override
    public void sleep() {
        System.out.println("狗喜欢趴着睡");
    }
}package factory;
​
/**
 * className: AnimalFactory
 * package: factory
 * date 2021/10/26  20:12
 * Author: ly
 */
public class AnimalFactory {
    //无参构造私有化
    public AnimalFactory() {
    }
    //用方法创建默猫的对象
//    public static Cat creatCat(){
//        return new Cat();
//    }
    //调用方法创建狗的对象
//    public static Dog creatDog(){
//        return new Dog();
//    }
    //优化后
    //调用方法创建动物的对象
    public static Animal creatAnimal(Object o) {//向上转型
        if (o instanceof Cat) {//判断当前类是不是猫的对象
            return new Cat();
        } else if (o instanceof Dog) {//判断当前类是不是狗的对象
            return new Dog();
        }
        return null;
    }

8.2工厂方法模式

工厂方法模式中抽象工厂类负责定义创建对象的接口,具体对象的创建工作由继承抽象工厂的具体类实现.
 优点:
     集体的工厂类负责创建当前具体的实例,结构层次很清晰,有具体类/工厂类/抽象类接口;
 缺点:
      有新的类型增加,需要编写外外的代码,所有代码增加,导致工作也增加了
举例 猫 狗
package factory1;
​
/**
 * className: Factory
 * package: factory1
 * date 2021/10/26  20:40
 * Author: ly
 */
public class Factory {
    public static void main(String[] args) {
          FactoryMethod d=new DogFactory();
           d.creatAnimal().eat();
           d.creatAnimal().sleep();
           d=new CatFactory();
           d.creatAnimal().sleep();
           d.creatAnimal().eat();
    }
}
public interface FactoryMethod {
    Animal creatAnimal();
}
public abstract class Animal {
    public abstract void eat();
    public abstract  void sleep();
}
public class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗喜欢啃骨头");
    }
​
    @Override
    public void sleep() {
        System.out.println("狗喜欢趴着睡");
    }
}
public class CatFactory implements FactoryMethod {
    @Override
    public Animal creatAnimal() {
        return new Cat();
    }
}
public class DogFactory implements FactoryMethod {
    @Override
    public  Animal creatAnimal() {
        return new Dog();
    }
}

8.3单例模式

定义:一个类的实例在内存中有且只有一个.
分为两种情况:
    饿汉式:永远不会出现问题的一种单例模式.
          1)自定义类:具体类
          2)无参构造方法私有化,目的:外界不能创建对象了
          3)在当前类的成员位置:创建自己本身对象
          4)在当前类中提供一个对外的公共的静态的功能,返回值是它本身
 举例:

 package com.qf.jhq;
public class StudentTest {
    public static void main(String[] args) {
        Student s1 = Student.getInstance();
        Student s2 = Student.getInstance();
        System.out.println(s1==s2);
    }
}
package com.qf.jhq;
//单例模型-饿汉式
public class Student {
    private static Student s=new Student();
    private Student(){}
    public  static Student getInstance(){
        return s;
    }
}
    懒汉式:可能出现安全问题的一种单例模型.
          1)自定义类:具体类
          2)无参构造方法私有化,外界不能创建当前类对象
          3)需要在成员位置,声明当前类型的变量
          4)提供一个对外公共的并且静态的访问方法,返回值就是当前类本身
懒汉式可能会出现的问题:
        (1)懒加载(延迟加载)Mybatis框架:延迟加载
        (2)可能会存在一种多线程问题
  举例:
 
 package com.qf.jhq;
​
public class StudentTest2 {
    public static void main(String[] args) {
        Student2 s3 = Student2.getInstance();
        Student2 s4 = Student2.getInstance();
        System.out.println(s3==s4);
    }
}
package com.qf.jhq;
​
public class Student2 {
    private static Student2 s1;
    private Student2(){}
    public static Student2 getInstance(){
        if(s1==null){
            s1=new Student2();
        }
        return s1;
    }
}

9.Runtime类:

每个java程序都有自己的运行环境,通过Runtime创建的实例表示:当前系统的运行环境
使用到了饿汉式
  源码如下:
   public class Runtime {
               private static Runtime currentRuntime = new Runtime();
               private Runtime() {}
                public static Runtime getRuntime() { //创建当前类实例
                       return currentRuntime;
                 }
 
      }

10.递归:

定义:方法调用方法本身的一种现象!而不是方法嵌套方法
递归思想:
  (1)必须定义一个方法(函数)
  (2)有一定的规律
  (3)必须有出口条件(结束条件),如果没有结束条件就是死递归.
 举例: 有一对兔子,从出生后第三个月起每个月产生一对兔子,小兔子长到第三个月后每个月又产生一对兔子;如果兔子都不死,第二十个月兔子的对数是多少?     (不死神兔)
  已知就是前两个月的兔子的对数都是1;
                        规律:
                             第一个月:1
                             第二个月:1
                             第三个月:2
                           第四个月:3
                             第五个月:5
                             第六个月:8
                              第七个月:13
                             几种方式:
                                 1)数组方式解决
                                2)递归:定义方法/找规律/找出口条件

  规律:
        已知第一个月和第二个月的兔子对数都是1
        从三个月开始,每个月兔子对数是前两个月之和
 
      
 public class DiGuiTest2 {

    public static void main(String[] args) {

        //数组方式
        //已知前两个的兔子对数都是1
        //创建一个数组,长度20
        int[] arr = new int[20] ;
        arr[0] = 1 ;
        arr[1] = 1 ;

        //第三个月,从三个月开始,每个月兔子对数是前两个月之和
        for(int x =  2;  x <arr.length; x++){
            arr[x] = arr[x-1] + arr[x-2] ;
        }
        System.out.println("第二十个月的兔子对数是:"+arr[19]);//6765
        System.out.println("----------------------------------------") ;

        System.out.println("第二十个月的兔子对数是:"+getRabbit(20)) ;
    }

    //定义一个方法
    public static int getRabbit(int n){//第n个月
        //出口条件
        //n==1或者n==2: 兔子的对数1
        if(n==1|| n==2){
            return 1 ;
        }else{
           return getRabbit(n-1) + getRabbit(n-2) ;
        }
    }
}

11.IO流之File

描述的一个文件/目录的抽象路径名的形式.
 File(File parent, String child)
 从父抽象路径名和子路径名字符串创建新的 File实例。
 File(String pathname)  :直接描述地址路径
 File(String parent, String child)
 成员方法:
   创建文件/创建文件夹相关的方法:
     public boolean createNewFile() throws IOException:创建文件,如果文件不存在,就会自动创建,创建了,返回true
     public boolean mkdir():创建文件夹,如果文件夹不存在,则自动创建,创建成功返回true,否则返回false;
     public boolean mkdirs():如果父目录不存在,不会自动创建:针对带多级目录创建;
     public boolean delete():删除文件或者目录,如果File表示的目录,删除必须为空目录.
     如果没有带盘符,创建的文件默认就是当前项目下.
高级功能:
      public File[] listFiles():获取某个目录下的所有文件以及文件夹的File数组
      public String[] list():获取的抽象路径名表示下的所有文件以及文件夹中的字符串数组.
       FilenameFilter接口:里面有一个抽象方法
        boolean accept(File dir,String name) :是否将name:文件名称添加抽象类路径名所表示的列表中,取决于返回值
         true,表示将name添加的文件过滤列表中,否则false,不添加!
 举例:删除当前D盘下的所有的以.jpg结尾的文件.
 使用文件名称过滤器作为参数传递:
      
  public String[] list(FilenameFilter filter)
        public File[] listFiles(FilenameFilter filter)
 public class FileTest {

    public static void main(String[] args) {

        //   1)表示d盘
        File file = new File("d:\\") ;
        //2)需要将d盘下的里面的文件以及文件夹的名称都获取到
        File[] fileArray = file.listFiles() ;
        //3)先判断fileArray是否为空,防止空指针
        if(fileArray!=null){
            //遍历
            for(File f :fileArray){
                //f就是获取到的每一个file对象: 文件还是文件夹?  判断
                //1)判断当前File对象所表示的抽象路径名是否是一个文件
                if(f.isFile()){
                    //是文件
                    //需要满足,它的文件名称必须以.jpg结尾
                    if(f.getName().endsWith(".jpg")){
                        //就满足,删除文件
                        System.out.println(f.getName()+"----"+f.delete());
                    }
                }
            }
        }
    }
}

12.字节输出流

如何在写入文件的时候,进行换行操作呢?
Windows操作系统中:写入数据的时候,换行符号"\r\n;

12.1FileOutputStream

FileOutputStream的构造方法
    public FileOutputStream(String pathname,boolean append):如果第二个参数为true,则自动后面追加
    开发中,需要处理异常:
   throws:抛出---抛在方法声明上,谁调用这个方法,谁就是调用者,通过调用者进行处理
  try...catch...finally:捕获----通过业务逻辑代码(业务层代码:service层)
              业务层数据service----->来源于dao层代码(数据访问对象: JDBC)
                       dao层代码抛出,业务service代码调用dao层代码,需要捕获异常!
            try{
                可能出现问题的代码;---一旦这有问题:Jvm 就会创建异常对象
            }   catch   (异常类名 e)  { //如果和当前异常类名匹配了
                   //处理异常
                   //System.out.println("数组角标越界了") ;
                  e.printStackTrace() ;//可以看到你自己写的代码哪块出错了以及底层原码
           }finally{
                //释放资源
            }
            try...catch
            try...catch...catch...catch
           try...finally
读数据的方式:
构造方法 FileInputStream
 public FileInputStream(String name) throws FileNotFoundException:创建文件字节输入流对象
 成员方法:
   read这些方法:都是阻塞式方法:只要文件没有读完,一直等待要读取!
   abstract int read():一次读取一个字节,返回的读取的字节数
  一次读取一个字节,将文件内容打印在控制台: 如果文件中有中文,出现乱码
  原因就是我们对读取的字节数by----强转(char)by   :一个英文对应一个字节,但是中文(idea中:utf-8):一个中文8个字节,拼接不上导致乱码
  举例:

  public class FileInputStreamDemo3 {
    public static void main(String[] args) throws IOException {
        //创建文件字节输入流对象
        FileInputStream fis = new FileInputStream("fis.txt") ;//当前项目下的fis.txt
        //读取的是当前项目下的java文件FileOutputStreamDemo2.java
        FileInputStream fis = new FileInputStream("FileOutputStreamDemo2.java") ;
   //刚开始:还没还是读 字节数0
        int by = 0 ;
        while((by=fis.read())!=-1){
            System.out.print((char)by);
        }
        //3)释放资源
       fis.close() ;
    }
}
 int read(byte[] b)  :一次读取一个字节数组
 举例:
 
public class FileInputStreamDemo4 {
    public static void main(String[] args) throws IOException {
        //读取是当前项目下的fis2.txt文件
        //创建文件字节输入流对象
        FileInputStream fis = new FileInputStream("fis2.txt") ;
 byte[] bytes = new byte[1024] ;//提供字节缓冲区
        //实际的长度:根据内容判断 :获取实际字节数
        int len = 0 ;
        //判断和获取一块使用
        while((len=fis.read(bytes))!=-1){
            System.out.println(new String(bytes,0,len)); //每次从0开始获取实际字节数---转换成字符串
        }
        //释放资源
        fis.close() ;
    }
}

12.2BufferedOutputStream和BufferedInputStream

字节缓冲输出流BufferedOutputStream:又称字节高效流
  这个流仅仅是在内部提供了一个缓冲区(字节数组),针对文件的输出并且同时写入数据使用的还是底层OutputStream.
 构造方法:
    public BufferedOutputStream(OutputStream out):构造一个默认的缓冲区大小,通过底层流进行输出(写入数据)
          buf = new byte[size];//创建字节数组:作为缓冲区,长度8192字节缓冲输入流:BufferedInputStream
    构造方法
           BufferedInputStream(InputStream in)
           成员方法:使用InputStream的read的功能:
              一次读取一个字节/一次读取一个字节数组
举例:

public class BufferedOutputSteamDemo {
    public static void main(String[] args) throws IOException {
        //write();
        //读
        read() ;
    }
    //读取 当前项目下的bos.txt的内容
    private static void read() throws IOException {
        //创建字节缓冲输入流对象
        //BufferedInputStream(InputStream in)
        BufferedInputStream bis = new BufferedInputStream(
                new FileInputStream("bos.txt")) ;

        //一次读取一个字节
       /* int by = 0 ;
        while((by=bis.read())!=-1){
            //展示出来
            System.out.print((char)by);
        }*/
       //一次读取一个字节数组
        byte[] bytes = new byte[1024] ;
        int len = 0 ;
        while((len=bis.read(bytes))!=-1){
            //展示
            System.out.println(new String(bytes,0,len));
        }
        //释放资源
        bis.close() ;
    }
    private static void write() throws IOException {
        //创建字节缓冲输出流对象
        //public BufferedOutputStream(OutputStream out):形式参数是一个抽象类,需要子类对象
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt")) ;
        //写数据:使用的底层流的OutputStream的方法
        bos.write("hello,BufferedStream".getBytes());
        //释放资源
        bos.close();
    }
}

12.3SequenceInpuStream

合并流:可以实现a.txt/b.txt/c.txt---->复制到一个文件中.
      是InputStream的子类:只能操作源文件.
构造函数:
        public SequenceInputStream(Enumeration<? extends InputStream> e)
        public SequenceInputStream(InputStream s1,InputStream s2):将两个字节输入流对象指向的文件进行合并
  举例:
 
 public class SequenceInpuStreamTest {
    public static void main(String[] args) throws IOException {
        //method1();
        method2() ;//多个文件进行复制(两个以上的文件)
    }

    private static void method2() throws IOException {
        //当前项目下的FileOutputStreamDemo.java/FileOutputStreamDemo2.java/InputAndOutputStreamCopy.java
        //复制到D:\EE_2110\day26\code\\MyCopy.java

        // public SequenceInputStream(Enumeration<? extends InputStream> e)
        //创建Vector集合<InputStream>
        Vector<InputStream> v  = new Vector<>() ;
        v.add(new FileInputStream("FileOutputStreamDemo.java")) ;
        v.add(new FileInputStream("FileOutputStreamDemo2.java")) ;
        v.add(new FileInputStream("InputAndOutputStreamCopy.java")) ;

        //类似于迭代器:获取Enumeration枚举组件接口对象
        Enumeration<InputStream> enumeration = v.elements();
        //直接创建合并流对象
        SequenceInputStream sis = new SequenceInputStream(enumeration) ;
        //封装目的地文件

        BufferedOutputStream bos = new BufferedOutputStream(
                new FileOutputStream("D:\\EE_2110\\day26\\code\\MyCopy.java")) ;

        //一次读取一个字节数组
        byte[] bytes = new byte[1024] ;
        int len = 0 ;
        while((len=sis.read(bytes))!=-1){
            bos.write(bytes,0,len) ;
            bos.flush() ;
        }
        //释放
        bos.close() ;
        sis.close();
    }
    private static void method1() throws IOException {
        //创建两个字节文件输入流对象:指向两个文件
        InputStream in = new FileInputStream("FileOutputStreamDemo.java") ;
        InputStream in2 = new FileInputStream("FileOutputStreamDemo2.java") ;
        //封装到合并流中
        SequenceInputStream sis = new SequenceInputStream(in,in2) ;

        //目的地文件D:\EE_2110\day26\code\Copy.java
        //BufferedOutputStream流
        BufferedOutputStream bos = new BufferedOutputStream(
                new FileOutputStream("D:\\EE_2110\\day26\\code\\Copy.java")) ;

        //一次读取一个字节数组
        byte[] bytes = new byte[1024] ;
        int len = 0 ;
        while((len=sis.read(bytes))!=-1){
            bos.write(bytes,0,len) ;
            bos.flush() ;
        }
        //释放
        bos.close() ;
        sis.close();
    }
}

12.4Reader

抽象类,字符输入流:
子类:InputStreamReader:字符缓冲输入流:通向字节输入流的桥梁
  构造方法
  InputStreamReader(InputStream in) :使用平台默认的字符集进行解码,里面包装的字节流
  InputStreamReader(InputStream in,String charsetName):使用指定的字符集进行解码
 读取:
      读一个字符read()
      读一个字符数组read(char[] chs)
举例:
public class InputStreamReaderDemo {
    public static void main(String[] args) throws IOException {

        //需要读取oos.txt
        //创建字符缓冲输入流对象
        //InputStreamReader(InputStream in)
        InputStreamReader isr = new InputStreamReader(
                new FileInputStream("oos.txt"),"GBK") ;
        //一次读取一个字符
      /*  int ch = 0 ;//字符数 ()
        while((ch=isr.read())!=-1){
            System.out.print((char)ch);
        }*/
      //一次读取一个字符数组
        char[] chs = new char[1024] ;
        int len = 0 ;
        while((len=isr.read(chs))!=-1){
            System.out.print((new String(chs,0,len))) ;
        }
        //释放资源
        isr.close() ;
    }
}

12.5Writer

子类 :字符转换输出流OutputStreamWriter:里面包装的是字节流
  构造方法
  OutputStreamWriter(OutputStream out) :使用平台默认的编码字符集进行编码--->写入数据
  OutputStreamWriter(OutputStream out,String charsetName )使用指定的编码字符集进行编码--->写入数据
  写的功能:
         write(int ch):写一个字符
         write(char[] chs):写字符数组
         write(char[] chs,int index,int len):写字符数组的一部分
         writer(String str):写字符串
         writer(String str,int index,int len):写字符串的一部分
举例:
public class OutputStreamWriterDemo {
    public static void main(String[] args) throws IOException {
        //创建字符输出流对象
        //OutputStreamWriter(OutputStream out)
       // Writer out = new OutputStreamWriter(new FileOutputStream("out.txt")) ;
        /*OutputStreamWriter oos = new OutputStreamWriter(
                    new FileOutputStream("oos.txt")) ;*///默认平台 utf-8 编码
        OutputStreamWriter oos = new OutputStreamWriter(
                new FileOutputStream("oos.txt"),"GBK") ;// 指定GBK 编码
        oos.write("hello,字符流");
        //释放资源
        oos.close() ;
    }

12.6FileReader和FileWriter

Read和Write的子类:字符转换流.
    使用FileReader和FileWriter可以直接操作文件.
    FileReader(String pathname):使用平台默认字符集:进行解码
  FileWriter(String pathname)使用平台默认字符集:进行编码
       字符流针对文本文件操作:
     当前项目 FileOutputStreamDemo.java------>拷贝到当前项目下;My.java
     图片文件: 字节流
                       四种:基本字节流以及字节缓冲流
 举例:
public class CopyFileTest {
    public static void main(String[] args) {
        //捕获异常
        //创建字符输入流对象:操作源文件
        FileReader fr = null ;
        FileWriter fw = null ;
        try {
           fr = new FileReader("FileOutputStreamDemo.java") ;
           fw = new FileWriter("My.java") ;
            //读写操作
            //一次读取一个字符数组
            char[] chs = new char[1024] ;
            int len = 0 ;//实际字符数
            while((len=fr.read(chs))!=-1){
                //写
                fw.write(chs,0,len) ;
                fw.flush() ;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(fw!=null){
                try {
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(fr!=null){
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

17.序列化和反序列化

序列化定义:在将java对象变成一种流数据,他们里面的数据存储流中,就可以在网络中传输.
构造方法:
    public ObjectOutputStream)(OutputStream out)
成员方法:
     public final void writeObject(Object obj)throws IOException:写入一个实体对象 .
反序列化定义: 就是将流数据(存储的一些相关的实体类数据)--还原成java对象
public ObjectInputStream(inputStream in)throws IOException:将文件中的数据,进行读取
public final Object readObject()throws IOException,ClassNotFoundException

18.Propertis

属性集合类(属性列表)是一个Map,但是没有泛型,键和值都是String
特有功能: 
     public Object setProperty(String key,String value):添加键和值
     public Set<String>stringPropertyNames():获取所有的键的集合
     public String getProperty(String key):获取键对应的值
举例:有一个文本文件中存储了几个名字,要随机获得随机人的名字

public class Test2 {
    public static void main(String[] args) throws IOException {
            //文件中有内容了,将文件内容读取出来,保存在集合List中,做任何操作
       BufferedReader br = new BufferedReader(new FileReader("lucy_name.txt")) ;
        //创建一个集合ArrayList
        ArrayList<String> array = new ArrayList<>() ;
        //一次读取一行
        String line = null ;
        while((line=br.readLine())!=null){
           array.add(line) ;
        }
       // System.out.println(array);//进行遍历
        //创建随机数生成器
        Random random = new Random() ;
        int index = random.nextInt(array.size());
        System.out.println("当前幸运的人是:"+array.get(index));
        //如何读取src(类路径下)的配置文件.properties
        method() ;
    }
    private static void method() throws IOException {
        //文件在哪个了中要读:
        //1)获取当前了类的字节码文件对象
        /*Class c = Test2.class ;
        //2)获取类加载器
        ClassLoader classLoader = c.getClassLoader();
        //3)通过类加载获取当前src目录下面的配置文件所在的输入流对象
        InputStream inputStream = classLoader.getResourceAsStream("name.properties");*/
        InputStream inputStream =
                Test2.class.getClassLoader().getResourceAsStream("name.properties");
        //创建Properties
        Properties prop = new Properties() ;
        prop.load(inputStream);

        System.out.println(prop) ;
    }
}

19.网络编程

ip地址:使用的一种"点分十进制法"
10.12.159.190
  A类: 国家部门
                前一个号段:网络号段
                后面三个号段:主机号段
         B类: 大学/教育部门:
                前两个号段:网络号段
                后面两个号段:主机号段
         C类:私人地址 (家庭/单位...)
                    前三个号段:网络号段
                    后面这个号段:主机号段
         windows系统:查看ipconfig
         Linux系统:查看ifconfig
port:端口号:360软件---可以查看计算机中所有软件的端口!
         范围:0-65535
         0-1024属于保留端口
         常见端口:tomcat服务器  默认:8080        (极域软件:端口号8080)
                               mysql:3306
                               redis(NOSQL数据库)客户端端口:6575
                                   key:value
协议:
            网络通信协议
              TCP/IP协议
              UDP协议
              UDP
                1)属于不可靠协议
                2)不需要建立连接通道,所以执行效率高,但是安全性低!
                3)发送内容的时候,有大写数据!

              TCP/IP协议
                1)属于可靠协议
                2)需要建立连接通道,
                    服务器端监听客户端连接,如果客户端没有跟服务器端口进行绑定,服务器一直等待,执行效率低,但是安全性高
                3)发送内容的时候,数据大小没有限制!

InetAddress:表示地址
静态方法:
   public static inetAddress getByNmae(String host)throws UnkonownHostException:通过主机名称获取ip地址对象
   public String getHostName():获取ip地址对象所描述的主机的名称(计算机名称)
   public String getHostAddress():获取ip地址:以字符串形式展示
UDP实现客户端发送数据,服务端接收数据:
客户端:
 * 1)创建UDP发送端的Socket对象
 * 2)创建数据报包
 * 3)发送
 * 4)释放资源
 *     socket对象.close()
 *
 */

public class SendDemo {
    public static void main(String[] args) throws Exception {
        //1)创建UDP发送端的Socket对象
        //public DatagramSocket()  throws SocketException
        DatagramSocket ds = new DatagramSocket() ;
        //创建一个BufferedReader流对象:键盘录入
        BufferedReader br = new BufferedReader(
                new InputStreamReader(System.in)) ;
        String line = null ;
        while((line=br.readLine())!=null){

            //自定义结束条件
            if("886".equals(line)){
                break ;
            }
            //2)创建数据报包---- >包含ip和端口+里面的数据
            //DatagramPacket
            //public DatagramPacket(byte[] buf ,int length,InetAddress address,int port)
            DatagramPacket dp = new DatagramPacket(line.getBytes(),line.getBytes().length,
                    InetAddress.getByName("10.12.159.190"),10086) ;
            //3)发送
            //public void send(DatagramPacket p)
            ds.send(dp) ;
        }
        //4)释放资源
        ds.close() ;
    }
}
服务端:
1)创建接收端的Socket对象
 * 2)创建一个接收容器: 自定义一个缓冲区byte[]  (创建数据包报)
 * 3)接收
 * 4)解析真实数据
 * 5)展示ip和发送的内容
 *
 */

public class ReceiveDemo {
    public static void main(String[] args) throws IOException {
        //1)创建接收端的Socket对象DatagramSocket
        //public DatagramSocket(int port)
        DatagramSocket ds = new DatagramSocket(10086) ;
        while(true){
            //创建一个接收容器: 自定义一个缓冲区byte[]
            byte[] bytes = new byte[1024] ;
            int length = bytes.length ;
            //(创建数据包报)
            //public DatagramPacket(byte[] buf,int length)
            DatagramPacket dp = new DatagramPacket(bytes,length) ;
            //3)接收
//        public void receive(DatagramPacket p)
            ds.receive(dp);
            //4)解析接收容器中的真实内容
            //public byte[] getData():获取缓冲区中的真实的字节数组
            //public int getLength():获取缓冲区中的长度
            //获取实际内容
            String str = new String(dp.getData(),0,dp.getLength()) ;
            //获取ip地址
//        public InetAddress getAddress()
            String ip = dp.getAddress().getHostAddress() ;
            System.out.println("data from "+ip +",content is :"+str) ;
        }
        //释放资
//        ds.close() ;
    }
}
TCP/IP实现客户端发送数据,服务端接收数据
客户端:
1)创建客户端的Socket对象
 *  2)获取客户端所在的通道内的字节输出流OutputStream
 *  3)给客户端通道内的流中写入数据
 *  4)释放客户端的资源对象
 *
 *  客户端不断的键盘录入数据,服务器端不断的接收数据,展示数据
 */

public class ClientDemo {
    public static void main(String[] args) throws IOException {
        //1)创建客户端的Socket对象
        //public Socket(String host, int port)
        Socket socket = new Socket("10.12.159.190",10010) ;
        //只要服务器端一开,监听端口10010,客户端就会和服务器端进行握手通信
        //2)获取客户端所在的通道内的字节输出流OutputStream
        //public OutputStream getOutputStream()
        OutputStream out = socket.getOutputStream();
        //3)写数据:给通道流中写入数据
        out.write("hello,TCP,我来了".getBytes());
        //4)释放资源
        socket.close() ;
    }
}
服务端 接收数据
    1)创建服务器端的Socket对象
 * 2)监听客户端的连接 ---一旦监听到了,就获取到那个客户端的Socket
 * 3)获取连接的客户端的通道内的输入流,读取数据
 * 4)展示数据
 * 5)释放资源
 */

public class ClientDemo {
    public static void main(String[] args) throws IOException {
        //1)创建客户端的Socket对象
        //public Socket(String host, int port)
        Socket socket = new Socket("10.12.159.190",10010) ;
        //只要服务器端一开,监听端口10010,客户端就会和服务器端进行握手通信
        //2)获取客户端所在的通道内的字节输出流OutputStream
        //public OutputStream getOutputStream()
        OutputStream out = socket.getOutputStream();
        //3)写数据:给通道流中写入数据
        out.write("hello,TCP,我来了".getBytes());
        //4)释放资源
        socket.close() ;
    }
}
例题: TCP客户端的文本文件,服务器端将文件复制,到指定文件中.
  
  public class ClientDemo {
    public static void main(String[] args) throws IOException {
        //创建socket
        Socket socket = new Socket("10.12.159.190",12306) ;
        //读取当前项目下的Copy.java文件
        //使用BufferedReader 封装源文件
        BufferedReader br = new BufferedReader(new FileReader("Copy.java")) ;
        //封装通道内的字节输出流
        //分步走
        /*OutputStream outputStream = socket.getOutputStream();
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream)) ;*/
        //一步走
        BufferedWriter bw = new BufferedWriter(
                new OutputStreamWriter(
                        socket.getOutputStream())) ;
        //一次读取一行进行读写复制,将文件中的内容写到封装通道 的流对象中 bw
        String line = null ;
        while((line=br.readLine())!=null){
            bw.write(line) ;
            bw.newLine() ;
            bw.flush() ;
        }
        //释放资源
        br.close() ;
        socket.close() ;
    }
}
服务器端将文件复制,到指定文件中(当前项目下)
 public class ServerDemo {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(12306) ;
        //监听
        Socket socket = ss.accept();
        //获取当前客户端的Socket通道内的输入流InputStream
        //分步走
        /*InputStream inputStream = socket.getInputStream();
        //封装BufferedReader
        BufferedReader br = new BufferedReader(
                new InputStreamReader(inputStream)) */;
        //一步走
        //封装通道内的字节输入流
        BufferedReader br = new BufferedReader(
                new InputStreamReader(
                        socket.getInputStream())) ;
        //将读取的内容,输出在当前项目下的My.java文件中
        BufferedWriter bw = new BufferedWriter(new FileWriter("My.java")) ;
        //一次读取一行
        String line = null ;
        while((line=br.readLine())!=null){
            bw.write(line) ;
            bw.newLine() ;
            bw.flush();
        }
        //是否资源
        bw.close() ;
        ss.close() ;
    }
} 
TCP客户端的文本文件,服务器端将文件复制到指定文件(当前项目下),加入服务器端反馈...
 * 发现问题:
 *      文件是已经完毕了,但是客户端并没有收到服务器端的反馈,服务器也没关闭; 出现了互相阻塞了
 *      针对 文件的复制,如果是文本文件,我们通过BufferedReader的readLine的返回值是否为null,判断文件是否复制完毕
 *      null.表示文件复制完了,但是对于Server服务器端来说,他不知道通道内的流中是否还有数据需要在写过来;等待客户端通知
 *      我们的服务器端,文件已经复制完毕;客户端在等着服务器端的反馈的消息,所以就出现了互相等待;
 *      解决方案:
 *         1)自定义结束条件,只要服务器端读取到这个自定义内容,就打破了阻塞,可以给客户端反馈
 *          如果当前这个文件:一开头"over",直接服务器端读取到这个就结束了,可能没复制完毕!
 *         2)直接使用客户端的功能完成:
 *          public void shutdownOutput():禁用客户端的输出流;不会写在流中写入数据了,服务器端就得到了通知,没有数据写过了
 *
public class ClientDemo {
    public static void main(String[] args) throws IOException {

        //创建socket
        Socket socket = new Socket("10.12.159.190",12306) ;

        //读取当前项目下的Copy.java文件
        //使用BufferedReader 封装源文件
        BufferedReader br = new BufferedReader(new FileReader("Copy.java")) ;
        //封装通道内的字节输出流
        //分步走
        /*OutputStream outputStream = socket.getOutputStream();
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream)) ;*/
        //一步走
        BufferedWriter bw = new BufferedWriter(
                new OutputStreamWriter(
                       socket.getOutputStream())) ;
        //一次读取一行进行读写复制,将文件中的内容写到封装通道 的流对象中 bw
                String line = null ;
                while((line=br.readLine())!=null){ //readLine()阻塞式方法
                    bw.write(line) ;
                    bw.newLine() ;
                    bw.flush() ;
        }
                //方式1
                //自定义结束条件
              /*  bw.write("over") ;
                bw.newLine() ;
                bw.flush() ;*/
             socket.shutdownOutput();
        //读取服务器端的的反馈
        //获取客户端所在的通道内的字节输入流
        InputStream inputStream = socket.getInputStream();
        byte[] bytes = new byte[1024] ;
        int len = inputStream.read(bytes);
        String fkMsg = new String(bytes,0,len) ;
        System.out.println("接收的服务器端反馈的数据是:"+fkMsg);
        //释放资源
        br.close() ;
        socket.close() ;
    }
}
 服务器端将文件复制到指定文件(当前项目下),加入服务器端反馈...
 */
public class ServerDemo {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(12306) ;
        //监听
        Socket socket = ss.accept();  //监听:阻塞式方法
        //获取当前客户端的Socket通道内的输入流InputStream
        //分步走
        /*InputStream inputStream = socket.getInputStream();
        //封装BufferedReader
        BufferedReader br = new BufferedReader(
                new InputStreamReader(inputStream)) */;
        //一步走
        //封装通道内的字节输入流
        BufferedReader br = new BufferedReader(
                new InputStreamReader(
                        socket.getInputStream())) ;
        //将读取的内容,输出在当前项目下的My.java文件中
        BufferedWriter bw = new BufferedWriter(new FileWriter("Hello.java")) ;
        //一次读取一行
        String line = null ;
        while((line=br.readLine())!=null){ //阻塞式方法

          /*  if("over".equals(line)){
                break ;
            }*/
            bw.write(line) ;
            bw.newLine() ;
            bw.flush();
        }
        //服务器端需要进行反馈
        //获取通道内的输出流
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("文件已经复制完毕;".getBytes());
        //是否资源
        bw.close() ;
        ss.close() ;
    }
}

20.MySQL数据库

1.数据库的定义语句:DDL库的增删查改

-- 查询当前所有的数据库名称
show databases;
-- 创建自己的数据库
create database 库名;
-- 删除库
drop database 库名;
-- 查询创建数据库的默认的字符集格式
show create database 库名;
-- 创建表的前提,先选择库,进入到库中;
 use 库名;
-- 查询这个库中所有的表
 show tables;
-- 创建表的语法
创建表的语法
		create table 表名(
			字段名称1 字段类型1,
			字段名称2 字段类型2,
			字段名称3 字段类型3
			... 
		) ;
字段类型:mysql   varchar(字符个数)  	---代表String 字符串
                int类型:整数类型
                int:默认的字符个数int(11):当前真实age年龄的长度 (所占的实际的字符数) 整数默认int(11)
                举例:	age int,
                			7
                int(指定字符个数):int(4)
                age int(4)
                	  0007  
               date :日期 仅仅是日期
               datetiem :日期+时间
               timestamp:时间戳  (即时时间)
               			当你在执行给这个字段插入某个指定的时候,当前的那个日期+时间
               			
               double(3,2) :这个字段值是3位数,小数后保留2位
               		举例:3.56
               double 
               			999.0
-- 查询表的结构
  desc 表名;
-- 修改表的字段名称
 alter table 表名 change 旧字段名字 新字段名称 数据类型;
-- 修改字段类型
alter table 表名 modify 字段名称 新的字段类型;
-- 添加新的字段
alter table 表名 add 新的字段名称 类型;
-- 修改表:将某一个字段删除
 alter table 表名 drop 字段名称;
-- 复制一张新的表跟以前的表的结构相同
create table 新的表名 like 需要复制的表名;
-- 修改表的名称
alter table 需要修改的表名 rename to 新的表名;
-- 删除表
-- drop table 表名;

2.数据库的操作语句:DML语句:

-- 给表中插入数据
语法1:一次性插入全部字段值  insert into 表名 values(字段名称值);
INSERT INTO student VALUES(1,'张三','男','西安市鄠邑区','1970-03-27') ;
语法2:插入部分字段 insert into 表名(字段名称1,字段名称2...),
insert into 表名(字段名1,字段名2...) values(值1,值2,值...);
INSERT INTO student(id,NAME,sex,address) VALUES(3,'文章','男','西安市未央区') 
语法3:一次性可以插入多条记录;
insert into表名 values(值1,值2,值3...)(值1,值2...);
INSERT INTO student VALUES
(4,'王宝强','男','北京市昌平区','1980-04-30'),
(5,'马云','男','杭州市','1970-6-21'),
(6,'马化腾','男','深圳市','1970-7-30') ;
注意:插入的顺序必须对应.
-- 修改表的语句update:
-- 修改的时候使用where语句
update 表名 set 字段名称 = 值 where 其他字段: 
UPDATE student SET birthday = '1982-06-30' WHERE id = 3 ;
--修改多个字段
update 表名 set 字段名称1 = 值1,字段名称2 = 值2...where 条件语句
UPDATE student SET NAME = '赵又廷' ,sex = '男' WHERE id = 7 ;
-- 批量修改
update 表名 set 字段名称 = 值;
UPDATE student SET address = '西安市雁塔区' ;
-- 删除语句
delete from 表名 where 带条件删除
DELETE FROM student WHERE id =  7 ;
-- 删除全表记录
truncate table 表名;
TRUNCATE TABLE student ;
查询语法:DQL语句
select 全部字段名 from 表名;
-- 查询字段时去重
ELECT 
	DISTINCT(字段)  -- 数据库的DISTINCT(字段名称),可以实现字段去重
FROM 表名 ;
-- 高级查询
-- where后面跟表达式(关系运算符/逻辑运算符 ||(or) &&(and) between.. and..)
例题 -- 查询年龄大于20岁的所有的学生的id,姓名,年龄,性别,地址
SELECT 
	id '编号',
	NAME '姓名',
	age '年龄',
	sex '性别',
	address '地址'
FROM
	student 
WHERE 
	age >20 ; -- 比较运算符
-- 查询学生年龄不等于20岁的学生的信息  Java中的语法!= 或者<>
SELECT
	id,
	NAME,
	age,
	sex,
	address
FROM
	student
WHERE 
	age <> 20 ;
--查询年龄在20-30岁之间的学生信息  (Java中逻辑符号呢?&& 可以,数据库and ,使用between 值1 and 值2
SELECT
    id,
    NAME,
    age,
    sex,
    address,
    math,
    english
FROM 
    student 
WHERE 
     age BETWEEN 20 AND 30 ;
-- 要查询英语成绩为null的学生信息
-- 数据库中:某个字段名称 is null   /某个字段名称 is not null   
SELECT
	id,
	NAME,
	age ,
	address,
	english
FROM 
	student
WHERE 
     english IS  NULL ;
要查询年龄是18或者20,或者30的学生信息
SELECT 
	id ,
	NAME,
	age,
	sex,
	address
FROM
	student
WHERE 
	age =18 OR age = 20 OR age = 30 ;  -- || 或者 or
优化
SELECT 
	*
FROM
	student
WHERE 
	age IN(18,20,30) ;
模糊查询 关键字 like	
-- select 字段列表 from 表名 where 字段名称 like '包含%符号或者_下划线符号'
-- 查询学生姓名中包含马的学生
SELECT
     id,
     NAME,
     age,
     sex,
     address
FROM 
     student
WHERE 
	NAME LIKE '%马%' ; 
-- 姓名中第二个字符是化的学生新'%_化%'
SELECT
	*
FROM
	student
WHERE 
	NAME LIKE '%_化%' ;
-- 聚合函数-- 一般查询都是单行单列的数据
-- count(字段名称) 查询总记录数
--    count(字段名称:一般情况使用的非业务字段
-- max(字段名称)  求某个列中的最大值
-- min(字段名称)  ...最小值
-- sum(字段名称) 针对某个字段列表进行求和
-- avg(字段):针对某个字段列求平均分
-- count(字段名称) 查询student表中的总记录数
-- 如果使用业务字段:使用英语字段来查询
-- (它不会null字段,只统计有内容的字段	
SELECT
	COUNT(IFNULL(english,0))  '总记录数' -- ifnull(字段名称,预期值) 
FROM
	student ;
-- count(表中的id字段:非业务字段,开发中都会设置为主键并且自增长)
SELECT 
	COUNT(id) '总人数'
FROM 
	student ;
-- 查询数学成绩的最高分
SELECT 
	MAX(math)
FROM 	
	student ;
-- -- 查询英语成绩的最低分
SELECT 
	MIN(IFNULL(english,0)) '最低分'
FROM 
	student ;
-- 求数学成绩的平均分
SELECT
	AVG(math) '数学平均分'
FROM 
	student ;
 排序查询
-- select 字段列表 from 表名 order by  字段名称 排序方式;
-- 排序方式:asc(默认(当字段名称后面没有带排序方式):升序) ,desc	
-- 将学生成绩按照升序排序
SELECT
	*
FROM 
	student
ORDER BY  
	math ; -- 不带排序方式:默认 asc
-- 将英语成绩按照降序排序
SELECT
	*
FROM
	student
ORDER BY 
	english DESC ;
	
-- 分组查询 group by
-- 分组查询的时候,可以查询分组的字段
-- 按照性别分组,查询他们的数学的平均分以及总人数 
SELECT
	sex '性别',-- 可以查询分组字段
	COUNT(id) '总人数',
	AVG(math) '数学平均分'
FROM
	student
GROUP BY 
	sex  ; -- 性别分组
-- 筛选(过滤) having	
-- 按照性别分组,查询他们的数学的平均分以及总人数
-- 1):数学成绩不大于70分的人不参与分组 
-- 2):筛选出总人数大于2的一组
  SELECT
	sex 性别,
	AVG(math) 数学平均分,
	COUNT(id) 总人数
FROM
	student
WHERE 
	math > 70  -- 条件
GROUP BY 
	sex  -- 分组
-- 筛选出总人数大于2的一组
HAVING 
       总人数 > 2 ;
-- 分页查询 limit  (mysql和oracle有方言差异这个这个语法上)
-- select 字段列表 from 表名 limit 起始行数(起始索引),每页显示的条数;
-- 起始行数(起始索引):从0开始计算 = (当前页码-1)*每页显示的条数
-- 查询当前学生表中第一页数据,每页显示2条数据;
  SELECT
	*
FROM
	student
LIMIT 0,2 ;

-- 查询第二页的数据
-- 起始行数= (2-1)*2 
SELECT
	*
FROM
	student
LIMIT 2,2 ;
-- 查询第三页数据 : 每页显示2条
SELECT 
	*
FROM 
	student
LIMIT 4, 2;
-- 查询第四页数据
SELECT 
	*
FROM
	student
LIMIT 6,2 ;
-- 数据库的约束
-- 约束:约束用户操作表时候的行为,防止无意义的数据在表中存在!
-- 默认约束 default
-- 创建一张表stu_test
CREATE TABLE stu_test(
	id INT ,
	NAME VARCHAR(20),
	gender VARCHAR(5)  DEFAULT '女' -- 创建的时候给性别添加默认约束,default
);
INSERT INTO stu_test VALUES(1,'张三','男'),(2,'李四','女') ;
-- 如果插入部分字段的时候,没有插入的字段就是NULL,没有意义 ,需要加入约束这种非法行为
INSERT INTO stu_test(id,NAME) VALUES(3,'高圆圆') ; -- 加入约束,不插入默认约束就起作用                      
-- 非空约束 not null
CREATE TABLE stu_test(
	id INT ,
	NAME VARCHAR(20)  NOT NULL -- 非空约束
)  ;

INSERT INTO stu_test VALUES(1,'高圆圆'),(2,'文章') ;
--  插入数据的时候,直接插入null值
-- insert into stu_test values(3,null) ;-- Column 'name' cannot be null :非空约束起作用
-- INSERT INTO stu_test(id) VALUES(3) ;
-- 通过修改表:删除非空约束
ALTER TABLE stu_test MODIFY NAME VARCHAR(20) ;
INSERT INTO stu_test VALUES(3,NULL) ;
-- 通过修改表:添加非空约束
ALTER TABLE stu_test MODIFY NAME VARCHAR(20) NOT NULL  ;
DELETE FROM stu_test WHERE id = 3 ;                       
-- 唯一约束 unique
-- 创建一张表
CREATE TABLE stu_test(
	id INT ,
	NAME VARCHAR(20),
	
	phone VARCHAR(11) UNIQUE  -- 添加唯一约束
) ;
INSERT INTO stu_test VALUES(1,'高圆圆','13688889999'),
(2,'王聪','13866668888') ;
INSERT INTO stu_test VALUES(3,'赵又廷','13688889999') ;
-- Duplicate entry '13688889999' for key 'stu_test.phone' :值重复了,唯一约束起作用
-- 修改表:删除唯一约束 (drop index 唯一约束的字段名称)
--  alter table stu_test modify phone varchar(11) ;
ALTER TABLE stu_test DROP INDEX phone ;
DELETE FROM stu_test WHERE id = 3 ;
-- 添加唯一约束
ALTER TABLE stu_test MODIFY phone VARCHAR(11) UNIQUE ;                     
-- 主键约束 primary key 
-- 自增长约束 auto_incrment
CREATE TABLE stu_test(
	id INT PRIMARY KEY AUTO_INCREMENT,-- 自增长的主键
	NAME VARCHAR(20),
	gender VARCHAR(5)
) ;
-- 添加数据
INSERT INTO stu_test(NAME,gender) VALUES('螳螂','男'),('咔沙','女'),('皇子','男') ;
-- id 给定值,下次它会随着之前的值继续自增
INSERT INTO stu_test VALUES(6,'小法','男') ;
INSERT INTO stu_test(NAME,gender) VALUES('盲僧','男') ;
-- mysql自带 的函数 select last_insert_id() :
-- 查询最后一次自增长主键的值(后期mybatis框架中使用:获取最后一次自增长主键的id值)
SELECT LAST_INSERT_ID() ;
SELECT * FROM stu_test ;                       
-- 外键约束 foreign key
-- 外键约束基础,可以进行级联操作(级联修改和级联删除)CASCADE
-- 级联操作:CASCADE
-- 用户在操作主表的时候,跟主表相关的从表的数据也随之更改;
-- 如果不使用操作:针对修改或者删除,都应该先执行从表,然后主表;
-- 级联删除和级联修改 on delete cascade  /on update cascade

-- 通过sql语句:外键删除

ALTER TABLE employee DROP FOREIGN KEY dept_emp_fk ;

-- 添加外键约束的同时,添加级联删除和级联修改
ALTER TABLE employee ADD 
	CONSTRAINT dept_emp_fk  -- 声明  跟的外键名称
	FOREIGN KEY (dept_id) -- 作用在外键上
	REFERENCES dept(id) -- 关联与主表的主键id
	ON DELETE CASCADE 
	ON UPDATE CASCADE ;
SELECT  * FROM dept ; -- 主表
SELECT * FROM employee ;-- 从表的外键关联与主键的主键
-- 将运维部的编号--变成4号部门
UPDATE dept SET id = 4 WHERE id = 3 ;
-- 直接部门表的4号部门,那么在4号部门的员工也随着 删除了
DELETE FROM dept WHERE id = 4 ;
-- 数据库的备份和还原
-- 数据库的备份:需要将数据库进行存储(计算机磁盘上或者是硬盘)
-- 方式1:命令行的方式
-- 方式2:图形界面化的方式:简单/直观/易于上手
-- 进入dos控制台:mysqldump -uroot -p密码 数据库 > 磁盘地址...
-- 举例
/*
	不需要登录:
	mysqldump -uroot -p123456 ee_2110 > D:\EE_2110\day30\code\mydb.sql
*/
-- 还原过程
-- 方式1:命令行方式 
-- mysql8---进入mysql自动控制台或者dos登录mysql
-- 先将数据库删除掉,重新创建一个新的库,使用这个use 库名
-- souce 将备份的地址 (自动将原先备份的库中的表数据全部执行)
-- 方式2:图形界面化
-- 在sqlYog或者navicat里面都可以用,直接将库选中, 删除,删除之后,
-- 在创建的新库右键---选择 import---> Execute Sql Scripts:执行sql脚本 
-- 选择备份的地址,直接执行sql文件!
CREATE DATABASE JavaEE_2110 ;

TRUNCATE TABLE 表名 ;它和 delete from 表名 ; 两者有什么区别

delete from 表名 ;仅仅只是删除表的记录,
不会删除这个表的结构,那么针对自增长约束的字段不影响
后者TRUNCATE TABLE 表名 ;删除了表,
	它重新创建一张一模一样的空表,(表的结构存在)
	前一些自增长的主键约束(数据库约束)者这个语法它会将影响
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值