2021-08-15

20.设计原则

设计原则:
   开闭原则:
            对现有代码修改关闭,对扩展代码开放
            举例:
                    项目开发完毕,进行更新,不能够修改现有代码,在现有代码的基础上提供扩展!
   接口分离原则
           一个接口中定义一个功能,接口和接口之间独立的,不能相互影响
                   实际开发中:
                          某个接口中,可能将相关的功能都定义在这一个接口中
                          按模块划分:
                                   用户模块        UserDao  接口
                                                       login()/register()/logout()/checkUserName()
                                   商品模块
                                                   ProductDao 接口
                                                       Product findById(Integer id) ;
                                                        List<Product> findAll() ;
                                                        void update(Product product);
                                   订单模块
                                               OrderDao 接口
                                                        List<Order> findPage(int pageSize,int currentPage);
   里氏替换原则:任何父类出现的地方都可以子类替代!
               class Father{
                     public void show(){
                        // ...
                        Class<Son> clazz  = Son.class ;
                        //反射方式---->字节码文件对象就调用method----->将所有的成员方法---->Method
                      }
                }
                class Son extends Father{
                      public void method(){
 
                      }
                }
       23种设计模式都需要遵循 原则"低耦合,高内聚"
       设计模式是一种思想,前人总结出来,不是技术!
 
         创建型:对象的创建 (使用最多)
         结构型:整个结构的组成
               代理模式
                   静态代理
                           代理角色
                           真实角色
         行为型:具备功能性的
创建型设计模式:
         简单工厂:----称为 静态工厂方法模式
         优点:利用多态创建子类对象,能够灵活去创建对象(提供的静态功能)
         弊端:代码量大,一旦有新的类型增加,工厂类的静态功能就需要改动...
1.工厂模式
工厂方法模式:
    1)抽象类:Animal 动物类 (基类)  
    2)提供一些子类,完成方法重写:eat(){} sleep(){}    
    3)提供一个接口 :        
        Factory             
       		 public Animal createAnimal() ;      
        DogFactory /CatFactory具体的子实现类实现对象的创建 
    优点:具体的动物创建,交给类工厂类来实现 (面向接口编程),便于功能维护(代码维护)
    弊端:代码量非常大   
        如果有新的类中增加,那么还必须提供对应具体的工厂类创建当前类实例!
//抽象的动物类
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("狗躺着睡觉...");  
    }
}
//工厂接口 
//    具体的对象的创建工作----交给工厂接口(抽象类)的子实现类完成!
public interface Factory {
    public Animal createAnimal() ;}
// 猫的工厂类
public class CatFactory  implements  Factory{ 
    @Override    public Animal createAnimal() {   
        return new Cat();    }
}
//具体的工厂类 创建狗这个类型的实例
public class DogFactory  implements Factory{  
    @Override   
    public Animal createAnimal() {
        //接口多态中---->抽象类多态   
        return new Dog();    
    }
}public class FactoryPattern {  
    public static void main(String[] args) {  
        //没有工厂方法之前:     
        //使用抽象类多态    
        Animal a = new Dog() ;     
        a.eat();     
        a.sleep();    
        System.out.println("-------------------------------");  
        a = new Cat() ;       
        a.eat();    
        a.sleep();  
        //使用工厂方式模式来操作 
        System.out.println("-------------------------------------");   
        Factory factory = new DogFactory() ;   
        Animal animal = factory.createAnimal();     
        animal.eat();      
        animal.sleep();    
        System.out.println("---------------------------------------");   
        factory = new CatFactory() ;  
        Animal a2 = factory.createAnimal();      
        a2.eat();  
        a2.sleep(); 
    }
}
2.单例模式
单例模式:  始终在内存中创建一个实例分为两种    
    饿汉式:永远不会出现的单例模式(最简单的一种单例)  
    懒汉式:可能出现问题的一种单例模式
1)饿汉式
 饿汉式   
     1)构造方法私有:保证外界不能直接创建当前类对象     
     2)在当前类的成员位置:创建当前类实例    
     3)提供一个静态的功能,返回值就是当前类本身(需要当前类的实例)
public class Student {
    //成员变量
   // public  static Student s = new Student() ; //当前类实例
    private  static Student s = new Student() ; //当前类实例 (静态实例变量)
    private Student(){}
    //静态功能
    //返回是当前类本身
    public static Student getStudentInstance(){
        return s;
    }
}
//测试类
public class Single_Pattern_01 {
    public static void main(String[] args) {
       // Student s1 = new Student() ;
        //Student s2 = new Student() ;
       // System.out.println(s1==s2);
       // System.out.println(s1.getClass()==s2.getClass());
        //class  com.qf.single_pattern.Student
        //调用公共方法
        Student s1 = Student.getStudentInstance();
        Student s2 = Student.getStudentInstance();
        Student s3 = Student.getStudentInstance();
        Student s4 = Student.getStudentInstance();
        System.out.println(s1==s2);
        System.out.println(s1==s3);
        System.out.println(s1==s4);
       // Student.s = null ; // 赋值null,堆内存不开辟空间(外界可以更改当前类地址值)
        //当前这个成员变量的实例s应该被私有修饰(保证安全性)
    }
}
2)懒汉式
懒汉式:可能出现问题的一种单例模式  
    1)构造方法私有化  
    2)在当前成员变量的位置声明变量:数据类型就是当期类 (私有的,静态的)
    3)提供静态功能,返回值还是当前类本身,      
        判断如果当前没有给当前类型变量为null,直接new 当期类的实例      
        如果不为null,就返回当前类的变量!                
        延迟加载或者懒加载----出现安全问题 面试中,问的最多就是懒汉式----->如何解决线程安全问题: 想到同步方法解决
public class Worker {
    //成员变量位置声明变量w
    private static Worker w;//默认值null
    //构造方法私有化
    private Worker() {} //外界不能直接new 对象
    //提供静态功能,返回值是当前类本身
    //w1,w2,w3 互相抢占getWorkerIntance的内容---会造成安全问题
   /*
    public static Worker getWorkerIntance(){
        //w1
        //先判断w变量为null
        if(w == null){ //当为null
            w = new Worker() ; //如果当前w变量为null,创建一个新的对象,返回
            return w;
        }
        return w ;
     }
    */
   //改进:同步代码块---->静态的同步方法
    public synchronized static Worker getWorkerIntance(){ //锁对象:Worker.class
       // synchronized (w){
            //w1
            //先判断w变量为null
            if(w == null){ //当为null
                w = new Worker() ; //如果当前w变量为null,创建一个新的对象,返回
                return w;
            }
            return w ;
        //}
    }
}
public class Single_pattern_02 {
    public static void main(String[] args) {
        //使用Worker第一次调用getInstance方法
        Worker w1 = Worker.getWorkerIntance();   //第一个用户操作这个方法----属于一个线程
        //第二次
        Worker w2 = Worker.getWorkerIntance();      //第二个用户操作---->属于一个线程
        System.out.println(w1==w2);
        Worker w3 = Worker.getWorkerIntance();        //第三个用户操作--->属于一个线程
        System.out.println(w1==w3);
    }
}
3.Runtime类
Runtime:当前获取的当前本地运行环境的实例
    public int availableProcessors():获取本地计算机的处理器的数量
    public Process exec(String command):开启某个软件的进程(参数为字符串命令)
        exec("shutdown -s"):立即关机
        exec("shutdown -s -t 300"):延时关机 
        exec("shutdown -a"):取消关机
public class RuntimeDemo {
    public static void main(String[] args) throws IOException {
        //获取当前类的实例:Runtime  利用单例模式
        Runtime runtime = Runtime.getRuntime();
        System.out.println(runtime.availableProcessors());
        Process notepad = runtime.exec("notepad");
        System.out.println(runtime.exec("QQ"));
        
        //利用关机
        //exec("shutdown -s"):立即关机
        //exec("shutdown -s -t 300"):延时关机
        //exec("shutdown -a"):取消关机
        System.out.println(runtime.exec("shutdown -s -t 300"));
        System.out.println(runtime.exec("shutdown -a"));
    }
}
public class DiGuiDemo {
   /* public DiGuiDemo(){
        //DiGuiDemo() ;//构造方法不能使用递归
    }
*/
   public static void main(String[] args) {
       System.out.println("5的阶乘是:"+jieCheng(5));
   }
    //递归:需要考虑(一定要有规律)
    private static int jieCheng(int i) {
       if(i==1){
           return 1 ;
       }else{
           return i * jieCheng(i-1) ;
       }
    }
}
/*
Runtime类的原码
*
* public class Runtime {  单例模式之饿汉式(类一加载就在当前内存中创建一个实例)
    //静态实例变量
    private static Runtime currentRuntime = new Runtime();

//公共的静态功能:返回值就是当类本身
public static Runtime getRuntime() {
    return currentRuntime;
}

     Don't let anyone else instantiate this class  构造方法私有:外界不能直接访问
    private Runtime() {}
* */
public class DiGuiTest {
    public static void main(String[] args) {
         //描述D盘的demo文件夹
         File srcFloder = new File("d://demo") ;
         //调用递归删除的方法
        deleteFloder(srcFloder) ;
    }

    public static void deleteFloder(File srcFloder) {
        //获取srcFloder下的所有的文件以及文件的File数组
        File[] fileArray = srcFloder.listFiles();
        if(fileArray!=null){
            for(File file:fileArray){
                //获取到每一个file对象
                //如果file是文件夹,继续回到deleteFloder(srcFloder) ; 删除文件夹
                if(file.isDirectory()){
                    deleteFloder(file) ;
                }else{
                    //判断是文件,必须以.java结尾 文件
                    if(file.getName().endsWith(".java")){
                        //删除的同时----获取名称
                        System.out.println(file.getName()+"------------"+file.delete());
                    }
                }
            }
            //删除文件夹
            System.out.println(srcFloder.getName()+"----"+srcFloder.delete());
        }
    }
}

21.递归

1.方法递归:方法调用方法本身的一种现象,并非是方法嵌套方法
   前提条件
    1)必须有一个成员方法
    2)必须有方法递归的出口条件(结束条件),如果没有出口条件,就是死递归...
    3)还存在一定的规律
 
注意事项:构造方法不存在递归
伪代码:
       public void show(int n){ //50   调用
            if(n<0){
                System.out.println(n) ;
            }
            n -- ;//49
            show(n) ;
       }
           
       Math.max(Math.max(10,30),50) ;  //×  嵌套
需求:使用递归方式去删除D盘某个demo文件夹中有很多个目录,
          每个目录中可能还有目录,删除这些所有目录中的带.java文件的文件!
   分析:
        1)描述下D盘下demo文件夹  File srcFile = new File("d://demo")
        2)调用递归删除方法
 		//递归删除多级目录中的java文件
         public void  deleteSrcFile(File srcFile){
               //获取srcFile的所有的文件夹以及文件的File数组
               //非空判断
               //判断如果是文件夹
               回到2)继续调用递归删除
               则,是文件
                      判断是否以.java文件
                      最终删除文件即可!
public class DiGuiTest {
    public static void main(String[] args) {
         //描述D盘的demo文件夹
         File srcFloder = new File("d://demo") ;
         //调用递归删除的方法
        deleteFloder(srcFloder) ;
    }

    public static void deleteFloder(File srcFloder) {
        //获取srcFloder下的所有的文件以及文件的File数组
        File[] fileArray = srcFloder.listFiles();
        if(fileArray!=null){
            for(File file:fileArray){
                //获取到每一个file对象
                //如果file是文件夹,继续回到deleteFloder(srcFloder) ; 删除文件夹
                if(file.isDirectory()){
                    deleteFloder(file) ;
                }else{
                    //判断是文件,必须以.java结尾 文件
                    if(file.getName().endsWith(".java")){
                        //删除的同时----获取名称
                        System.out.println(file.getName()+"------------"+file.delete());
                    }
                }
            }
            //删除文件夹
            System.out.println(srcFloder.getName()+"----"+srcFloder.delete());
        }
    }
}
 有一对兔子,从出生后第三个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,
 假如兔子都不死,问第二十个月的兔子对数为多少?(递归方式实现:找规律)
 
  不死神兔
          月数          兔子对数
         第一个月          1
         第二个月          1
         第三个月          2
         第四个月          3
         第五个月          5
         第六个月          8
         第七个月          13
         ...
  规律
      1)第一个和第二个月:兔子对数都是1
      2) 从第三个月开始:兔子对数等于两个月兔子对数之后

        a,b分别相邻两个月兔子的对数
        第一个月:  1       a
        第二个月: 1        b
        第三个月: 2        a
        第四个月:  3       b
        第五个月:  5       a
        第六个月:  8       b
         方式1)可以使用数组完成
         方式2)递归思想完成
 
  递归:
      1)定义一个方法
      2)得有结束条件(出口条件)
      3)必须有规律
      
        定义变量n:来表示月份数(1,2,3...20)
        public static int getRabit(int n){
             if(n==1 ||n==2){
                 return 1 ;
             } else{
                       //n=3
                       //getRabit(1) +getRabit(2)
                 return getRabit(n-2)+getRabit(n-1) ;
             }
        }
public class Test4 {
    public static void main(String[] args) {
        //创建数组,动态初始化
        //使用x角标:表示月份
        int[] arr = new int[20] ;
        //初始化 第一个月arr[0] ,arr[1]  = 1
        arr[0] = 1 ;
        arr[1] = 1 ;
        //从arr[2] 开始= arr[0]+arr[1]
        //arr[3] = arr[2] + arr[1]
        //遍历arr数组 :角标从2开始:第三个月
        for(int x = 2 ; x < arr.length ;x ++){
            arr[x] = arr[x-2] + arr[x-1] ;
        }
        System.out.println("第二十月兔子的对数是:"+arr[19]); //6765对象
        System.out.println("-----------------------------------------------");
        //递归:方法本身调用方法的中调用
        System.out.println("第二十个月兔子的对数是:"+getRabit(20));
    }
    //n表示月份数
    public static int getRabit(int n){ //20
            //出口条件
        if(n==1||n==2){ //第一个月和第二个月兔子对数1
            return 1 ;
        }else{
            //从第三个月开始:兔子对数等于两个月兔子对数之后
            return getRabit(n-2)+getRabit(n-1) ;
        }
    }
}

22.IO流

1.File
File 文件和目录(文件夹)路径名的抽象表示。
1.构造方法
  	1)File(String pathname)  :参数就是指定的路径/如果没有指定路径(默认是在当前项目下)
   	   通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例
    2)File(File parent, String child)
       从父抽象路径名和子路径名字符串创建新的 File实例。
    3)File(String parent, String child):参数1:父目录地址    参数2:具体的子文件地址
2.成员方法:
       创建/删除/重名
    1)public boolean createNewFile() throws IOException :表示创建文件 :如果不存在,则创建
    2)public boolean mkdir():创建文件夹,如果不存在,则创建;否则就返回false
    3)public boolean mkdirs():创建多个文件,如果父目录不存在,则创建
    4)public boolean delete():删除文件或者文件夹(如果删除文件夹,文件夹必须为空目录)
    5)public boolean renameTo(File dest):重命名
                   参数传递的修改的File对象
public class FileDemo {
    public static void main(String[] args) throws IOException {
        //表示:E盘下的demo文件夹中的a.txt文件
        //File(String pathname) 方式1 (推荐)
       // File file = new File("e://demo//a.txt") ;只是表示这个路径,如果创建a.txt文件,系统找不到指定路径

        //File(File parent, String child) 方式2
      /*  File file2 = new File("E://demo") ;
        File file3 = new File(file2,"a.txt") ;

        //File(String parent, String child):方式3
        File file4 = new File("E://demo","a.txt") ;*/
        
        File file = new File("D:\\EE_2106\\day25\\code\\a.txt"); //绝对路径
        File file2 = new File("aaa.txt");//没有带路径,就默认在当前项目下(相对路径)
        File file3 = new File("D:\\EE_2106\\day25\\code\\demo") ;
        File file4 = new File("aaa\\bbb\\ccc\\ddd") ;

       // public boolean createNewFile()
        System.out.println(file.createNewFile());
        System.out.println(file2.createNewFile());
        System.out.println(file3.mkdir());
        System.out.println(file4.mkdirs());
        System.out.println(file3.delete());
        System.out.println(file.delete());
        System.out.println("------------------------");
        //D:\EE_2106\day25\code路径下logo.jpg :描述下这个地址File
       // File srcFile  = new File("D:\\EE_2106\\day25\\code\\logo.jpg") ;
        File srcFile = new File("D:\\EE_2106\\day25\\code\\mv.jpg") ;
        File destFile = new File("高圆圆.jpg") ;//当前项目路径下了
        //public boolean renameTo(File dest)
        System.out.println(srcFile.renameTo(destFile)) ;
    }
}
3.判断功能     
    1)public boolean canRead()是否可读   
    2)public boolean canWrite()是否可写  
    3)public boolean exists():是否存在   
    4)public boolean isFile():是否是文件    
    5)public boolean isDirectory():是否是文件夹 
    6)public boolean isHidden():是否隐藏
4.高级获取功能: 
    1)public long length()  
    2)public String getName():获取抽象路径 名所表示的文件或者目录的名称 
    3)public File[] listFiles():获取某个目录下的所有的文件以及文件夹的File数组   
    4)public String[] list():获取某个抽象路径名所表示的文件以及目录的字符串数组
public class FileDemo2 {
    public static void main(String[] args) {
        //创建File对象,描述当前项目下的aaa.txt文件
        File file = new File("aaa.txt") ;
        System.out.println(file.canRead());        
        System.out.println(file.canWrite());
        System.out.println(file.exists()); 
        System.out.println(file.isDirectory());
        //false     
        System.out.println(file.isFile());  
        System.out.println(file.isHidden());   
        System.out.println(file.length());   
        System.out.println(file.getName());    
        System.out.println("------------------------");      
        /*需求:获取       
        D盘下的所有的文件夹以及文件的名称....*/     
        // public File[] listFiles():获取某个目录下的所有的文件以及文件夹的File数组   
        //描述D盘   
        File file2 = new File("d://") ;     
        File[] fileArray = file2.listFiles();     
        //防止空指针异常    
        if(fileArray!=null){      
            for(File f :fileArray){         
                System.out.println(f.getName());     
            }    
        }     
        System.out.println("----------------------------------");   
        //public String[] list():获取某个抽象路径名所表示的文件以及目录的字符串数组    
        String[] strArray = file2.list();   
        if(strArray!=null){      
            for(String s:strArray){       
                System.out.println(s);     
            }     
        }   
    }
}
需求2:
       获取D盘下所有的以.jpg结尾的文件
         分析:
            1)描述下D盘
            2)  public File[] listFiles():获取D盘下的所有的文件以及文件夹的File数组
            2.1)对获取到的数组进行非判断
                 如果不为null,再去判断
                 2.2)判断File是一个文件
                 2.3)判断:文件必须以.jpg结尾
                 String类 endsWith(".jpg")
提供了另一个重载功能:
        public File[] listFiles(FilenameFilter filter)
        String[] list(FilenameFilter filter)
          参数为:文件名称过滤器FilenameFilter:接口
              成员方法:
              boolean accept(File dir,String name):测试指定文件是否包含在文件列表中
                    返回如果true,将文件添加到文件列表中
 				1) 描述下D盘
                2) public File[] listFiles(FilenameFilter filenamefilter):
                         获取D盘下的File数组的时候,就已经指定文件进行过滤...
public class FileTest {
    public static void main(String[] args) {
        //方法一
        //1)描述D盘
        File file = new File("D://") ;
        //2)获取盘符下的所有的文件以及文件夹的File数组
        File[] fileArray = file.listFiles();//这一步并没有直接获取到要的.jpg文件
        //后面一些判断
        if(fileArray!=null){
            for(File f:fileArray){
                //判断f是文件
                if(f.isFile()){
                    //是文件
                    //判断它的名称是否以.jpg结尾
                    if(f.getName().endsWith(".jpg")){
                        System.out.println(f.getName());
                    }
                }
            }
        }
        System.out.println("-------------------------------------------------------");
        
        //方法二
        //描述下D盘
        File srcFile = new File("D://") ;
        //获取当前D盘下的所有文件以及文件夹File数组,并进行文件名过滤
        //public File[] listFiles(FilenameFilter filter)
        File[] files = srcFile.listFiles(new FilenameFilter() {//接口的匿名内部类
            @Override
            public boolean accept(File dir, String name) {
                //返回true:表示将指定文件添加列表文件中
                //描述文件所表示抽象路径File
                File file = new File(dir, name);
                //两个条件:file是文件并且file的文件名称以".jpg结尾"
                return file.isFile() && file.getName().endsWith(".jpg");
            }
        });
        if(files!=null){
            for(File f :files){
                System.out.println(f.getName());
            }
        }
    }
}
2.IO流的分类
 IO流的分类:
 按流的方向:
           输入和输出流
 按类型分:
           字节和字符流:字节先出现,后面在有字符流
 
           再次流的方向划分
  				字节输入流:InputStream:表示输入字节流的所有类的超类(父类)
                字节输出流:OutputStream:表示字节输出流的所有类的超类
                
                  字符输入流:Reader表示输入字符流的抽象类
                  字符输出流:Writer表示输出字符流的抽象类
 
      字节/字符流都很多子类
           XXXInputStream
           XXXOutputStream
           XXXReader
           XXXWriter
3.字节流
1)OutputStream
字节输出流:OutputStream抽象类    
子类进行实例化FileOutputStream:将指定的内容写到文件中   
实现步骤:      
	1)创建文件输出流对象 :FileOutputStream(String name) :推荐:可以指定参数地址          		             							   FileOutputStream(File file)             
	写入文件末尾处构造函数:public FileOutputStream(File file,boolean append)throws FileNotFoundException            创建一个向指定 File 对象表示的文件中写入数据的文件输出流。如果第二个参数为 true,则将字节写入文件末尾处,而不是写入文件开始处。          		  
2)写数据            
    public void write(int b) throws IOException 写一个字节   
    public void write(byte[] bytes) throws IOException 写一个字节数组         
    public void write(byte[] bytes,int off,int len) throws IOException:写一部分字节数组    
3)关闭资源
public class FileOutputStreamDemo {
    public static void main(String[] args) throws IOException {
        //创建文件输出流对象
        //指向某个盘符下的文件中(或者当前项目下)
        FileOutputStream fos = new FileOutputStream("my.txt") ;//文件需要被创建当前项目下
        //2)写数据
       /* fos.write(97);
        fos.write(98);
        fos.write(99);*/
       //写一个字节数组
      /*  byte[] bytes = {97,98,99,100,101,102} ;
       // fos.write(bytes);
        fos.write(bytes,2,2);*/
      for(int x = 0 ; x < 10 ; x ++){
          fos.write(("hello world").getBytes());
          //windows操作系统  "\r\n"代表换换行
          fos.write("\r\n".getBytes());
      }
        //3)关闭资源
        fos.close(); //释放fos流对象所指向的my.txt的系统资源
    }
}
public class FileOutputStreamDemo2 {
    public static void main(String[] args) {
       // method1() ;
        method2() ;//
    }
    //标准方式:try...catch...finally
    //统一处理
    private static void method2() {
        FileOutputStream fos = null ;
        //alt+ctrl+t--->
        try {
           fos = new FileOutputStream("fos2.txt") ;
            //写数据
            fos.write("hello,我来了".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //释放资源
            if(fos!=null){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    //分别try...catch...(不用,这种方式阅读性很差)
    private static void method1() {
        //在当前项目下输出fos.txt
        //创建字节输出流对象
        FileOutputStream fos = null ;
        try {
             fos = new FileOutputStream("fos.txt") ;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        //写数据
        try {
            fos.write("hello,IO".getBytes()) ;
        } catch (IOException e) {
            e.printStackTrace();
        }
        //关闭资源
        try {
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
2)InputStream
字节输入流:InputStream 
子类:FileInputStream
实现步骤:   
需要读取当前项目下的fis.txt文件  
	1)创建文件字节输入流对象,指向 fis.txt         
   		 public FileInputStream(String name) throws FileNotFoundException    
	2)读内容    
       public int read(byte[] bytes) throws IOException一次读取一个字节数组  ,返回值值的是每次读取的实际字节数              read():一次读取一个字节    
3)释放资源      
	读取文件的时候,一次读取一个字节,存在中文乱码, 在最终输出的结果 (char)by   (场景:将某一个文件内容打印在控制台上了)
	注意:	
		"abc" 英文 读一个字节  a--->97   b --98  
        针对中文字符: 现在idea环境: 编码格式:utf-8格式: 一个中文对应三个字节 ,和前面的英文拼接出现问题,只要中文都会乱码    才出现了字符流(加入编码和解码的格式)
public class FileInputStreamDemo {  
    public static void main(String[] args) {   
        //创建一个字节输入流对象      
        FileInputStream fis = null ;   
        try {       
            // fis  = new FileInputStream("fis.txt") ;   
            fis  = new FileInputStream("DiGuiTest.java") ; 
            //读取当前项目下的DiGuiTest.java   
            //读取内容      
            //使用循环优化:  结束条件:获取的字节数为-1       
            //当前不知道循环多少次:while循环       
            //将判断,赋值一块去使用 (模板代码)      
            int by = 0 ; //字节数为0        
            while((by=fis.read())!=-1) {      
                System.out.print((char)by);   
            } catch (IOException e) {       
                e.printStackTrace();   
            }finally {      
                //释放资源 
                if(fis!=null){     
                    try {          
                        fis.close();        
                    } catch (IOException e) {         
                        e.printStackTrace();        
                    }        
                }     
            }   
        }
    }
public class FileInputStreamDemo2 {   
    public static void main(String[] args) {    
        //创建字节输入流对象     
        FileInputStream fis = null ;     
        try {        
            fis = new FileInputStream("fis2.txt") ;      
            //一次读取一个字节数组      
            //创建一个数组:长度:1024或者1024的整数倍      
            byte[] buffer = new byte[1024] ;   
            //长度虽然1024个长度        
            int len = 0 ;         
            while((len=fis.read(buffer))!=-1){     
                //每次获取的从0开始获取实际字节长度         
                System.out.println(new String(buffer,0,len)) ;
                //应该描述:每一次从0这个位置读取实际长度     
            }  
        } catch (IOException e) {   
            e.printStackTrace();    
        }finally {          
            try {             
                fis.close();     
            } catch (IOException e) {       
                e.printStackTrace();       
            }     
        } 
    }
}
读写复制操作:一次读取一个字节的方式
     一次读取一个字节数组
需求:
      将当前项目下的DiGuiTest.java 的内容 复制到D盘下的Copy.java文件中
分析:
      源文件:  当前项目下 "DiGuiTest.java"
      封装源文件:FileInputStraem(String pathname)
                一次读取一个字节
      目的地文件:  D://Copy.java
      封装目的地文件:FileOutputStream(String pathname)
                一次写一个字节
public class CopyFileDemo {
    public static void main(String[] args) {

        long start = System.currentTimeMillis() ;//时间毫秒值

       // method("DiGuiTest.java","D://Copy.java") ;
        method2("DiGuiTest.java","D://Copy.java") ;

        long end  = System.currentTimeMillis() ;
        System.out.println("共耗时:"+(end-start)+"毫秒");
    }

    private static void method2(String srcFile, String destFile) {
        FileInputStream fis  = null ;
        FileOutputStream fos = null ;
        try {
            //  封装源文件:FileInputStraem(String pathname)
            //字节输入流
            fis = new FileInputStream(srcFile) ;
            //字节输出流
            // 封装目的地文件:FileOutputStream(String pathname)
            fos = new FileOutputStream(destFile) ;

            //读写复制操作
            //一次读取一个字节数组
            byte[] bytes = new byte[1024] ;
            int len = 0 ;
            while((len=fis.read(bytes))!=-1){
                //赋值
                //fos流对象中写
                //带上len的使用
                fos.write(bytes,0,len);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }finally {

            try {
                fos.close();
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 一次读取一个字节:读写复制
     * @param srcFile  源文件
     * @param destFile 目的地文件
     */
    private static void method(String srcFile, String destFile) {
        FileInputStream fis  = null ;
        FileOutputStream fos = null ;
        try {
            //  封装源文件:FileInputStraem(String pathname)
            //字节输入流
            fis = new FileInputStream(srcFile) ;
            //字节输出流
            // 封装目的地文件:FileOutputStream(String pathname)
            fos = new FileOutputStream(destFile) ;

            //读写复制操作
            //一次读取一个字节
            int by = 0 ;
            while((by=fis.read())!=-1){
                //没有读完,继续复制 :写一个字节
                fos.write(by);

            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {

            try {
                fos.close();
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
4.缓冲字节流
1)BufferedInputStream
字节缓冲输入流构造方法   
    BufferedInputStream(InputStream in) :默认缓冲区大写 (足够大了)    提供一个指定的缓冲区大小    						BufferedInputStream(InputStream in, int size)
public class BufferedInputStreamDemo {
    public static void main(String[] args) throws IOException {
        //创建一个字节缓冲输入流对象
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("bos.txt")) ;
        /**
         *  class BufferedInputStream{
         *
         *      private static int DEFAULT_BUFFER_SIZE = 8192; //8kb
         *
                 *  public BufferedInputStream(InputStream in) {
                 *         this(in, DEFAULT_BUFFER_SIZE);
                 *     }
         *
         *     public BufferedInputStream(InputStream in, int size) {
         *         super(in);
         *         if (size <= 0) {
         *             throw new IllegalArgumentException("Buffer size <= 0");
         *         }
         *         buf = new byte[size];  //底层还是一个字节数组
         *     }
         *     }
         */
        //读内容
        //一次读取一个字节
      /*  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));
        }
    }
}
2)BufferedInputStream
缓冲流的特点:提供缓冲区大写:1024的8倍   还是通过底层流提高读速度(FileInputStream)构造方法:
    BufferedInputStream   
    BufferedOutputStream(OutputStream out)   推荐使用这个:默认缓冲区大小 足够大了  8kb  
    创建一个新的缓冲输出流,以将数据写入指定的底层输出流。  
    BufferedOutputStream(OutputStream out, int size)
public class BufferedOutputStreamDemo {
    public static void main(String[] args) throws IOException {
        //BufferedOutputStream(OutputStream out)  //参数父类:抽象类
        //创建字节缓冲输出流
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt")) ;
        /**
         * 源码:
         * public BufferedOutputStream(OutputStream out) {
         *         this(out, 8192);
         *     }
         *  public BufferedOutputStream(OutputStream out, int size){
         *super(out);
         *if (size <= 0) {
         *throw new IllegalArgumentException("Buffer size <= 0");
         *}
         *buf = new byte[size]; //创建了字节数组  byte[] buf = new  byte[8192]
         *}
         */
        //写数据
        //写一个字节数组
        bos.write("hello.bufferedOutputStream".getBytes());
        //释放资源
        bos.close();
    }
}
复制对比
读取D://a.mp4
  将这个文件内容复制到 当前项目下的copy.mp4中
   基本的字节流一次读取一字节
           共耗时89021毫秒
   基本的字节流一次读取一字节数组
           共耗时116毫秒
   字节缓冲流一次读取一个字节
           共耗时348毫秒
   字节缓冲流一次读取一个字节数组
           共耗时47毫秒
public class CopyMp4 {
    public static void main(String[] args) {
        //起始时间
        long start = System.currentTimeMillis() ;

      //  copyMp4("D://a.mp4","copy.mp4") ;
        //copyMp4_2("D://a.mp4","copy.mp4") ;
        //copyMp4_3("D://a.mp4","copy.mp4") ;
        copyMp4_4("D://a.mp4","copy.mp4") ;

        //结束时间
        long end = System.currentTimeMillis() ;
        System.out.println("共耗时"+(end-start)+"毫秒");
    }

    //缓冲流一次读取一个字节数组
    private static void copyMp4_4(String srcFile, String destFile) {
        BufferedInputStream bis  = null ;
        BufferedOutputStream bos = null ;
        try {
            bis = new BufferedInputStream(new FileInputStream(srcFile)) ;
            bos = new BufferedOutputStream(new FileOutputStream(destFile)) ;
            //读写操作
            byte[] bytes = new byte[1024] ;
            int len = 0 ;
            while((len=bis.read(bytes))!=-1){
                bos.write(bytes,0,len);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                bos.close();
                bis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    //缓冲流一次读取一个字节
    private static void copyMp4_3(String srcFile, String destFile) {
        BufferedInputStream bis  = null ;
        BufferedOutputStream bos = null ;
        try {
            bis = new BufferedInputStream(new FileInputStream(srcFile)) ;
            bos = new BufferedOutputStream(new FileOutputStream(destFile)) ;
            //读写操作
            int by = 0 ;
            while((by=bis.read())!=-1){
                bos.write(by);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                bos.close();
                bis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    //基本的字节流一次读取一个字节数组
    public static void copyMp4_2(String srcFile,String destFile){
        //封装源文件和目的地文件
        FileInputStream fis = null ;
        FileOutputStream fos = null ;
        try {
            fis = new FileInputStream(srcFile) ;
            fos = new FileOutputStream(destFile) ;
            //读写复制
            byte[] bytes = new byte[1024] ;
            int len = 0 ;//实际字节数
            while((len=fis.read(bytes))!=-1){
                fos.write(bytes,0,len);
                //强制输出流将缓冲的这字节数写出来
                fos.flush();
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                fos.close();
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    //基本的字节流一次读取一个字节
    public static void copyMp4(String srcFile, String destFile) {
        //封装源文件和目的地文件
        FileInputStream fis = null ;
        FileOutputStream fos = null ;
        try {
             fis = new FileInputStream(srcFile) ;
             fos = new FileOutputStream(destFile) ;

             //读写复制
            int by = 0 ;
            while((by=fis.read())!=-1){
                fos.write(by);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                fos.close();
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
5.字符流
1)Writer–OutputStreamWriter
Writer:抽象类   (字符流的出现是在字节流的后面,可以解决中文乱码问题)   
提供子类:字符转换输出流: 字节输出流通向字符输出流的桥梁!
构造方法   
    OutputStreamWriter(OutputStream out) :使用平台默认编码集写入数据  
	OutputStreamWriter(OutputStream out, String charsetName) :使用指定的字符集进行编码 写入数据   write         		write(String str)        
        write(int ch):写入字符: 字符--->对应的ASCII码表    
        write(char[] ch)     
        write(char[] ch,int off,int len)     
        write(String str,int off,int len)
public class WriterDemo {  
    public static void main(String[] args) throws Exception {   
        //创建字符缓冲输出流对象    
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt")) ;//使用平台的默认编码集(utf-8)     
        //写入数据    
        /**     
        * write(String str)    
        * write(int ch):写入字符: 字符--->对应的ASCII码表    
        * write(char[] ch)   
        * write(char[] ch,int off,int len)  
        * write(String str,int off,int len)    
        */    
        osw.write("hello,字符流我来了");   
        osw.write(97);    
        char[] chs = {'A','B','C','D','E'} ;     
        osw.write(chs);   
        osw.write(chs,2,2);   
        //使用flush():刷新字符输出流    
        osw.flush();    
        //关闭资源,释放相关的资源    
        osw.close(); 
        //关闭之前,flush    
        //osw.write(98);  
    }
}
2)Reader–InputStreamReader
Reader:抽象类    具体的子类:字符转换输入流 InputStreamReader构造方法    InputStreamReader(InputStream in) :使用平台默认解码集进行读    InputStreamReader(InputStream in,String charset) :使用指定的解码集进行读
public class ReaderDemo {  
    public static void main(String[] args) throws Exception {   
        //创建字符转换输入流对象    
        //InputStreamReader(InputStream in,String charset) :使用指定的解码集进行读      
        // InputStreamReader isr = new InputStreamReader(new FileInputStream("osw.txt"),"UTF-8") ;      
        //InputStreamReader(InputStream in)   
        InputStreamReader isr = new InputStreamReader(new FileInputStream("osw.txt"));
        //平台默认的解码集进行读取       
        //读一个字符数组    
        char[] chs = new char[1024] ; 
        //实际字符数  
        int len = 0 ;      
        while((len=isr.read(chs))!=-1){   
            //打印控制台上:每次获取的实际长度       
            System.out.println(new String(chs,0,len));     
        }    
        //释放资源       
        isr.close();
    }
}
3)便捷类
Reader/Writer子类:转换流     
    InputStreamReader(InputStream in)    
    OutputStreamWriter(OutputStream out)他们不能直接去操作文件,jdk提供了这两种类型的便捷类,可以直接操作文件       				FileReader(File file)      
        FileReader(String pathname)    
        FileWriter(File file)     
        FileWriter(String filename)   
        public FileWriter(File file,boolean append)throws IOException     
		 根据给定的 File 对象构造一个 FileWriter 对象。如果第二个参数为 true,则将字节写入文件末尾处,而不是写入文件开始处。          这两个类:使用的平台的默认编码和解码 (utf-8) 
需求:    当前项目下的ReaderDemo.java  复制到 D://Demo.java    针对文本文件:优先采用字符流
6.字符缓冲流
1)BufferedReader
字符缓冲输入流:     BufferedReader  ---- 键盘录入数据      Scanner(InputSteram in)  
	String nextLine()  
	BufferedReader(Reader in)      
Reader        
InputStreamReader(InputStream in):转换流          
如果直接进行读的操作(直接操作文件)FileReader(String pathName)
创建使用默认大小的输入缓冲区的缓冲字符输入流。
BufferedReader(Reader in, int size)  :指定缓冲区大小特有功能:	
public String readLine() :一次读取一行内容
public class BufferedReaderDemo { 
    public static void main(String[] args) throws IOException {  
        //创建字符缓冲输入流对象  :使用键盘录入数据!(流的方式)
        //        InputStreamReader(InputStream in):     
        //InputStream in = System.in ;
        //标准输入流
        //        BufferedReader(Reader in)      
        //Reader reader = new InputStreamReader(in) ;      
        //BufferedReader br = new BufferedReader(reader) ;    
        //一步走     
        /* BufferedReader br = new BufferedReader(new InputStreamReader(System.in)) ;    
        System.out.println("请您输入一个字符串数据:");
        //        public String readLine()    
        String line = br.readLine();
        //阻塞式方法     
        System.out.println("您输入的数据是:"+line);         
        System.out.println("------------------------------------------");*/    
        //使用BufferedReader读取bw.txt的文件内容   
        //readLine:读取一行内容    
        BufferedReader br2 = new BufferedReader(new FileReader("bw.txt")) ;      
        //定义变量     
        String line2 = null ;      
        while((line2=br2.readLine())!=null){         
            System.out.println(line2);    
        }   
    }
}
2)BufferedWriter
BufferedWriter:字符缓冲输出流   
BufferedWriter(Writer out) :创建默认的缓冲区大小:  默认大小:defaultcharbuffersize:8192(默认值足够大)    BufferedWriter(Writer out, int sz)  :指定的大小      
	public void newLine() throws IOException:写入行的分隔符号特有功能:  
        利用BufferedReader的readLine()读取一行     
        利用BufferedWriter写一行,然后换行 public void newLine() throws IOException:
public class BufferedWriterDemo {  
    public static void main(String[] args) throws IOException {  
        //输出bw.txt文件,并给里面写内容,而且去实现换行效果   write("\r\n")----现在可以使用newLine    
        //创建字符缓冲输出流对象   
        //BufferedWriter(Writer out) :     
        BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));      
        //写入数据   
        //写字符串/写字符       
        bw.write("hello");   
        //public void newLine()     
        bw.newLine();   
        bw.write("world");     
        bw.newLine();    
        bw.write("javaEE");   
        bw.newLine();    
        //刷新流       
        bw.flush();    
        //释放资源     
        bw.close();  
    }
}
3)Copy
BufferedReaer/BufferedWriter  :读写复制操作          
    一次读取一个字符      
    一次读取一个字符数组特有功能:      
    利用BufferedReader的readLine()读取一行     
    利用BufferedWriter写一行,然后换行 将当前项目下的 
ReaderDemo.java 复制到当前项目下:copy.java  
	一个文本文件读写复制:   
        阻塞流 (传统的IO流)         
            当一个线程如果操作的是读的动作,  read(byte[] byte/char[] ..)/readLine():都属于阻塞式方法    
            另一个线程如果操作的是写的动作,读的线程如果开始读,这边写的线程才能开始进行写的复制操作!             
        基本的字节流:
            一次读取一个字节/一次读取一个字节数组             
        字节缓冲流:
            一次读取一个字节/一次读取一个字节数组    
        字符转换流:
            InputStreamReader(InputStream in)            
            OutputStreamWriter(OutputStream out)         
            一次读取一个字符/一次读取一个字符数组     
        转换流的便捷类           
            FileReader(String name)     
            FileWriter(String writer)           
            一次读取一个字符/一次读取一个字符数组
public class CopyFile {    
    public static void main(String[] args) {     
        BufferedReader br = null ;  
        BufferedWriter bw = null ;    
        try {       
            //封装源文件:前项目下的ReaderDemo.java     
            br = new BufferedReader(new FileReader("ReaderDemo.java")) ;      
            bw = new BufferedWriter(new FileWriter("copy.java")) ;      
            //使用特有功能读取一行内容     
            String line = null ;        
            while((line=br.readLine())!=null){        
                //读取一行,bw写一行并换行,然后刷新       
                bw.write(line);     
                bw.newLine();          
                bw.flush();;      
            }     
        } catch (Exception e) {    
            e.printStackTrace();     
        }finally {        
            try {      
            bw.close();      
                br.close();      
            } catch (IOException e) {       
                e.printStackTrace();        
            }      
        }   
    }
}
7.SequenceInputStream
SequenceInputStream:       字节流的逻辑串联!       
可以将两个或者是两个以上的文件进行读的操作 ,只能操作源文件构造方法    	 
	public SequenceInputStream(InputStream s1,InputStream s2)    
        参数1和参数2:分别要读取的字节输入流对象
1)合并两个文件
现在:合并流    
当前项目a.java+b.java---->当前项目下的c.java文件中    
将当前项目下的BufferedWriterDemo.java+copy.java文件---->复制到当前项目下b.java文件中
public class CopyMulFile {    
    public static void main(String[] args) throws Exception {        
        //创建两个字节输入流对象        
        InputStream is = new FileInputStream("BufferedWriterDemo.java") ;        
        InputStream is2 = new FileInputStream("copy.java") ;        
        //public SequenceInputStream(InputStream s1,InputStream s2)        
        //创建字节合并流        
        SequenceInputStream sis = new SequenceInputStream(is,is2) ; 
        //SequenceInputStream extends InputStream        
        //封装目的地文件:        
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.java")) ;        
        //一次读取一个字节数组        
        byte[] bytes = new byte[1024] ;        
        int len = 0 ;        
        while((len = sis.read(bytes))!=-1){            
            bos.write(bytes,0,len);        }        
        //释放资源        
        bos.close();        
        sis.close();    
    }
}
2)合并两个以上文件
public SequenceInputStream(Enumeration<? extends InputStream> e) :将两个以上的文件进行读取        Vector<InputStream>               add(添加多个字节输入流对象)
需求:    
BufferedWriterDemo.java    
ReaderDemo.java    
CopyMp4.java    
复制到D://hello.java文件中
public class CopyFileDemo2 
{    
    public static void main(String[] args) throws Exception {        
    //public SequenceInputStream(Enumeration<? extends InputStream> e)        
        //需要三个字节输入流对象        
        InputStream is1 = new FileInputStream("BufferedWriterDemo.java") ;        
        InputStream is2 = new FileInputStream("ReaderDemo.java") ;        
        InputStream is3 = new FileInputStream("CopyMp4.java") ;                
        //创建一个Vector集合        
        Vector<InputStream> vector = new Vector<>() ;        
        //添加流对象        
        vector.add(is1) ;        
        vector.add(is2) ;        
        vector.add(is3) ;        
        //public Enumeration<E> elements() ---- >类似于Collection的Iterator迭代器        								Enumeration<InputStream> enumeration = vector.elements();        
        //创建合并流对象  封装源文件        
        SequenceInputStream sis = new SequenceInputStream(enumeration);        
        //创建字节缓冲输出流对象        
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d://hello.java")) ;        
        //一次读取一个字节        
        int by = 0 ;        
        while((by=sis.read())!=-1){            
            bos.write(by);            
            bos.flush();        
        }        
        bos.close();        
        sis.close();    
    }
}
8.序列化
序列化:ObjectOutputStream      
将某个实体对象写入到流对象中---->将一个对象变成 流数据      
  构造方法           
    protected ObjectOutputStream()           
    protected ObjectOutputStream(OutputStream out) :
	将某个对象通过底层的基本字节输出进行写的动作      
		public final void writeObject(Object obj) throws IOException       
需求:将Person p = new Person("高圆圆",42) ;---->变成流对象 进行传输反序列化:ObjectInputStream     
	将流数据----还原成 "对象"      
构造方法           
	public ObjectInputStream(InputStream in)      
	public final Object readObject() throws IOException, ClassNotFoundException
   NotSerializableException:未实现序列化接口的异常           
   一个类在进行序列化的时候,(将类的对象写入序列化流中),标记接口Serializable 它有个特点                        
   为当前这个Person进行编码(为类以及类的成员----->序列化化版本ID(签名):SerialversonUID) 
   
     java.io.InvalidClassException: com.qf.serailizable_05.Person; local class incompatible:             
   			stream classdesc serialVersionUID = 2588921225545403990,               
   			local class serialVersionUID = -862808041229244683          
   在进行序列化的时候:当前的    serialVersionUID:序列化版本id号 (假设100):  内存中生成一个id值         
   			在进行反序列化的时候:将流--->对象  :         
   		Person类的字段信息更改了(类的签名信息就会被更改),那么直接进行反序列化产生serialVersionUID=(假设200)         序列化版本id保证,               
   			在idea中生成一个固定的序列版本id号 (一般都针对实体类)          
   	一个实体类:               
   			1)当前类必须为具体类 class 类名{}               
   			2)必须存在私有字段(私有成员变量)               
   			3)必须提供公共的setXXX()/getXXX()               
   			4)如果当前类需要在网络中进行传输(分布式系统中)必须implements Serializable   
   idea- file--->setting---->editor---->Inspections----->java---->序列化serializion issue                                    --->serializable class  打上对钩即可!
public class ObjectStreamDemo {    
    public static void main(String[] args) throws IOException, ClassNotFoundException {      
        //  myWrite() ;
        //写       
        myRead() ;
        //读    
    }    
    //反序列化    
    private static void myRead() throws IOException, ClassNotFoundException {        
        //创建反序列化流对象        
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("oos.txt")) ;       
        //读        
        //public final Object readObject()        
        Object object = ois.readObject();        
        //关闭流        
        ois.close();        
        System.out.println(object);
        //toString()        
        //java.io.StreamCorruptedException: invalid stream header: EFBFBDEF        
        //当从对象流读取的控制信息违反内部一致性检查时抛出。    
    }    
    //序列化    
    //将Person p = new Person("高圆圆",42) ;---->变成流对象 进行传输    
    private static void myWrite() throws IOException {        
        //创建Person对象        
        Person p = new Person("高圆圆",42) ;        
        //protected ObjectOutputStream(OutputStream out):创建一个序列化流对象        
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("oos.txt")) ;                
        //将p对象写入到oos流对象中        
        //public final void writeObject(Object obj)throws IOException        
        oos.writeObject(p);        
        //释放资源        
        oos.close();    
    }
}
public class Person implements Serializable {    
    //产生一个固定的序列化版本Id    
    private static final long serialVersionUID = 8988325735017562383L; 
    //常量值    
    String name ; 
    //姓名    
    private transient int age  ; 
    //年龄  
    //transient :想让某个字段不参与序列化:这个字段(成员变量就使用transient)   
    public Person(){
        
    }    
    public Person(String name, int age) {        
        this.name = name;        
        this.age = age;    
    }    
    @Override   
    public String toString() {        
        return "Person{" +                
            "name='" + name + '\'' +                
            ", age=" + age +                
            '}';    
    }
}

对多个对象进行操作

class Person0 implements Serializable{    
    private static final long serialVersionUID = 9166507990237193254L;    
    private String name ;    
    private int age ;    
    public Person0() {    
    }    
    public Person0(String name, int age) {        
        this.name = name;        
        this.age = age;    
    }    public String getName() {        
        return name;    
    }    
    public void setName(String name) {        
        this.name = name;    
    }    public int getAge() {        
        return age;    
    }    public void setAge(int age) {        
        this.age = age;    }    
    @Override    
    public String toString() {        
        return "Person0{" +                
            "name='" + name + '\'' +                
            ", age=" + age +                
            '}';    
    }
}public class Test {    
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //        write();        
        read();    
    }    
    public static void read() throws IOException, ClassNotFoundException {        
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Object.txt"));        
        Object obj =null;        
        while((obj=ois.readObject())!=null) {            
            System.out.println(obj);        
        }        
        ois.close();    
    }        
    private static void write() throws IOException {        
        //创建序列化流对象        
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Object.txt"));        
        //创建对象       
        Person0 p1 = new Person0("Mike",22);        
        Person0 p2 = new Person0("Like",44);        
        //存入        
        oos.writeObject(p1);        
        oos.writeObject(p2);        
        oos.writeObject(null);
        //加入null 用来判断是否到末尾,如果不加会报错EOFException        
        oos.close();    
    }
}
9.Properties
Properties extends Hashtable<K,V> ,它没有泛型,Key和Value都是String
    表示一组持久的属性。 Properties可以保存到流中或从流中加载。
    属性列表中的每个键及其对应的值都是一个字符串。
  1)可以使用Map的功能
           put(K ,V)
           遍历:
               keySet()通用
  2)有自己特有功能添加元素和遍历
     public Object setProperty(String key,String value):给属性列表中添加属性描述(key和value)
     public Set<String> stringPropertyNames():获取属性列表中的所有的键
     public String getProperty(String key):在属性列表中通过键获取值
public class PropertiesDemo {
    public static void main(String[] args) {
        //Properties() :空参构造
        Properties properties = new Properties() ;
        //利用Map集合的功能去添加元素
        properties.put("高圆圆","赵又廷") ;
        properties.put("文章","姚笛") ;
        properties.put("文章","马伊琍") ;
        properties.put("王宝强","马蓉") ;

        //遍历
        Set<Object> keySet = properties.keySet();
        for(Object key :keySet){
            //通过key获取value
            Object value = properties.get(key);
            System.out.println(key+"---"+value);
        }
        System.out.println("---------------------------------------");
        /**
         * 推荐Properties作为集合类 的遍历方式
         */
        //创建一个空的属性列表
        Properties prop = new Properties() ;
        prop.setProperty("张三","30") ;
        prop.setProperty("李四","40") ;
        prop.setProperty("王五","35") ;
        prop.setProperty("赵六","45") ;
        //遍历:
        Set<String> set = prop.stringPropertyNames();//获取所有键
        for(String key:set){
            String value = prop.getProperty(key);
            System.out.println(key+"---"+value);
        }
    }
}
文件操作
Propeties:键和值都是字符串类型:可能需要在src(类所在的路径:类路径)作为一个配置文件
   xxx.properties
     将字节输入流或者字符输入中所在的文件中的内容加载属性列表中
               void load(Reader reader)
               void load(InputSteram in)
     将Properties里面存储的内容----->保存到某个目录的xxx配置文件中 保存
               public void store(Writer writer,String comments)
               public void store(OutputStream out,String comments)
               将属性列表中的内容保存到指定字节输出流/字符输出流所指向那个文件中
需求:
         有一个文本文件
                 username.txt
                 key1=value1
                 key2=value2
                 ....
                 ...
                 将文本文件中的内容读取到属性列表中Properties  加载
  
               将字节输入流或者字符输入中所在的文件中的内容加载属性列表中
               void load(Reader reader)
               void load(InputSteram in)
   
             将Properties里面存储的内容----->保存到某个目录的xxx配置文件中 保存
                   public void store(Writer writer,String comments)
                   public void store(OutputStream out,String comments)
                   将属性列表中的内容保存到指定字节输出流/字符输出流所指向那个文件中
public class PropertiesDemo2 {
    public static void main(String[] args) throws IOException {
//        myLoad() ;
         myStore() ;
    }
    //将属性集合类中的内容 ---保存到指定文件中
    private static void myStore() throws IOException {
        Properties prop = new Properties() ;
        //添加key-value
        prop.setProperty("张三丰","56") ;
        prop.setProperty("吴奇隆","60") ;
        prop.setProperty("成龙","65") ;
        prop.setProperty("刘德华","70") ;

        //public void store(Writer writer,String comments):
        //参数2:给当前属性列表中加入一个描述
        //保存指定的文件中
        prop.store(new FileWriter("user.txt"),"name's list'");
        System.out.println("保存完毕");
    }

    //加载:需要将names.txt文件加载到属性列表中,然后遍历
    private static void myLoad() throws IOException {
        //创建一个空的属性列表
        Properties prop = new Properties() ;
        System.out.println(prop);

        //void load(Reader reader)
      //  Reader r = new FileReader("names.txt") ;//names.txt是在当前项目下路径下
        // prop.load(r) ;

        //读取src路径下的names.properties  (类路径)
        //使用步骤
        //1)获取当前类所在的字节码文件对象
        Class clazz = PropertiesDemo2.class ;
        //2)获取当前类所在的类加载器Class:public ClassLoader getClassLoader()
        ClassLoader classLoader = clazz.getClassLoader();
        //3)在类加载器中:获取当前资源文件(配置文件names.proprites)所在的输入流对象
        //public InputStream getResourceAsStream(String name) {
        InputStream inputStream = classLoader.getResourceAsStream("names.properties");
        //将inputStream加载到属性集合类中
//        void load(InputSteram in)
        prop.load(inputStream);
        
        System.out.println(prop);
        Set<String> keySet = prop.stringPropertyNames();
        for(String key:keySet){
            String value = prop.getProperty(key);
            System.out.println(key+"---"+value);
        }
    }
}

xxx.txt操作

/* 有一个文本文件user.txt,如果里面键是lisi,
 * 然后将他的年龄改为45,然后重新写入到user.txt文件中
 *
 * 		user.txt
 * 		zhangsan=30
 * 		lisi=40
 * 		wangwu=50
 */
public class Test3 {
    public static void main(String[] args) throws IOException {
        //创建一个属性集合列表:Properties
        Properties prop = new Properties() ;
        //空的,需要将user.txt内容加载到属性列表中
        Reader r  = new FileReader("user.txt") ;
        prop.load(r);
        //System.out.println(prop);
        //遍历属性集合列表,获取每一个元素
        Set<String> keySet = prop.stringPropertyNames();
        for (String key : keySet) {
            //获取每一个元素 :键
            //判断如果"lisi"和key一致,那么改变它的值
            if("lisi".equals(key)){
                //通过属性列表设置
                prop.setProperty(key,"45") ;
            }
        }
        //将修改后的内容,重写在保存到user.txt文件中
        Writer w = new FileWriter("user.txt") ;
        prop.store(w,"name's lis"); //参数2:对属性列表的信息面搜
    }
}

23.网络编程

网络编程------>Socket编程
      特点:
             发送端/客户端
             接收端/服务器端  这两端必须存在Socket对象
网络编程的三要素:
      举例:
               我要找到高圆圆 说一句话
              1)ip:
                   知道高圆圆的ip地址
              2)port     0-65535  (0-1024属于保留端口)
                   知道高圆圆的端口号
              3)规定一种协议
                   协议:
                       udp协议
                            1)不需要建立连接通道
                            2)属于一种不可靠连接
                            4)执行效率高 (不同步的)
                       TCP/Ip协议
                           1)建立连接通道
                           2)属于安全连接(可靠连接)
                           3)发送文件(使用基本字节流),相对udp协议来说没有限制
                           4)执行效率低(同步的)
InetAddress:互联网ip地址
      获取InetAddress:ip地址对象
      public static InetAddress getByName(String host):参数:主机名称(计算机电脑名称)
      public String getHostAddress():获取ip地址字符串形式
public class NetDemo {
    public static void main(String[] args) throws UnknownHostException {
        //如何获取自己电脑上的ip地址----》String形式!
        //10.12.156.107
        InetAddress inetAddress = InetAddress.getByName("DESKTOP-Q62EUJH");
        String ip = inetAddress.getHostAddress();
        System.out.println(ip);
        //10.12.156.107
    }
}
1.udp通信
/*  Udp编程的发送端:
 *  1)创建Socket对象
 *  2)发送内容  :内容数据一种数据报文(报包)DatagramPacket
 *  3)释放资源
 */
public class UdpSend {
    public static void main(String[] args) throws IOException {
        //1)创建Socket对象
        //DatagramSocket:发送和接收数据报数据包的套接字。
        //public DatagramSocket() throws SocketException
        DatagramSocket ds = new DatagramSocket() ;

        //2)创建一个数据报包对象DatagramPacket
        //DatagramPacket(byte[] buf, int length, InetAddress address, int port)
        //参数1:当前数据的字节数组
        //参数2:当前数据的长度
        //参数3:InetAddress:ip地址对象
        //参数4:绑定的端口号
        byte[] bytes = "hello,马三奇".getBytes() ;
        int length = bytes.length ;
        //public static InetAddress getByName(String host)
        InetAddress inetAddress = InetAddress.getByName("10.12.156.107");
        int port = 12306 ;
        DatagramPacket dp = new DatagramPacket(bytes,length,inetAddress,port) ;
        //3)发送数据报包
        //public void send(DatagramPacket p)
        ds.send(dp);
        //4)释放资源
        ds.close();
    }
}

/* Udp接收端
 * 1)创建Socket对象
 * 2)创建一个接收容器:数据报包:DatagramPacket
 * 3)接收
 * 4)解析容器的的实际数据大小
 * 5)展示发送端发送的数据
 */
public class UdpReceive {
    public static void main(String[] args) throws IOException {
        //)创建Socket对象
        //public DatagramSocket(int port)
        DatagramSocket ds = new DatagramSocket(12306) ;
        //2)创建一个接收容器:数据报包:DatagramPacket  实际数据没有这么大
        //public DatagramPacket(byte[] buf, int length)
        //自定义字节缓冲区
        byte[] bytes = new byte[1024] ;
        int lentgth = bytes.length ;
        DatagramPacket dp = new DatagramPacket(bytes,lentgth);
        //3)public void receive(DatagramPacket p)
        ds.receive(dp);
        //4)解析实际数据
        //byte[] getData()   获取实际字节数
        //返回数据缓冲区。
        //int getLength()   获取实际长度
        byte[]  bytes2 = dp.getData();
        int length2 = dp.getLength();
        String receiverStr = new String(bytes2,0,length2) ;
        //获取ip地址
        //InetAddress getAddress()
        //InetAddress
                //public String getHostAddress():
        String ip = dp.getAddress().getHostAddress();
        //展示数据
        System.out.println("data from "+ip+" ,content is :"+receiverStr);
    }
}
发送端不断键盘录入数据,接收端不断接收数据,然后展示内容
接收端端不断的接收数据
       接收端一般不关闭
       接收端只能开启一次,多次就出现 BindException:绑定一次
       Address already in use: Cannot bind:端口号被占用!
public class UdpSend {
    public static void main(String[] args) {
        DatagramSocket ds = null ;
        try {
            //创建发送端的Socket
            ds = new DatagramSocket() ;
            //键盘录入数据
            //IO流的方式
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in)) ;
            //使用readLine()读取一行内容
            String line = null ;
            while((line=br.readLine())!=null){    //readLine():阻塞式方法
                //自定义结束条件
                if("886".equals(line)){
                    break ;
                }
                //创建数据报包
                DatagramPacket dp = new DatagramPacket(line.getBytes(),
                        line.getBytes().length,
                        InetAddress.getByName("10.12.156.107"),6666);
                //发送数据报包
                ds.send(dp);
            }
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //释放资源
            ds.close();
        }
    }
}


public class UdpReceive {
    public static void main(String[] args) {
        //创建接收端的Socket
        try {
            DatagramSocket ds = new DatagramSocket(6666) ;
            while(true){
                //创建一个接收容器
                byte[] bytes = new byte[1024] ;
                DatagramPacket dp = new DatagramPacket(bytes,bytes.length) ;
                //接收
                ds.receive(dp);
                //解析实际数据
                String receiveStr = new String(dp.getData(), 0, dp.getLength());
                //获取ip
                String ip = dp.getAddress().getHostAddress();
                //展示数据
                System.out.println("data from "+ip+"data is--->"+receiveStr);
            }
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //接收不关闭
            //接收socket对象一一直开着
        }
    }
}
2.TCP通信
TCP特点:需要建立连接通道(就是以一种字节流的方式写入,读取)
      什么时候建立连接(服务器端如果监听到端口,客户端就立即和服务器端建立连接!)
TCP客户端写数据
       1)创建TCP客户端的Socket对象
       2)写数据
       3)释放资源
TCP服务器端的实现步骤:
       1)创建服务器端的Socket对象
        public ServerSocket(int port)throws IOException
       2)监听客户端连接
        public Socket accept()throws IOException 返回值就是当前监听到的客户端的Socket对象
       3)获取通道内的输入流
        public InputStream getInputStream() throws IOException
       4)读取数据:一次读取一个字节数组
       5)展示数据 而且获取ip地址
            //public InetAddress getInetAddress()
public class ScoketDemo {
    public static void main(String[] args) throws IOException {
        //1)创建TCP客户端的Socket对象
       // public Socket(String host, int port)throws UnknownHostException, IOException
        //参数1:主机名称/或者ip地址字符串形式
        //参数2:指定的端口(0-65535(不包含0-1024))
        Socket s = new Socket("10.12.156.107",8888) ;
        //2)写数据
        //public OutputStream getOutputStream()throws IOException
        OutputStream out = s.getOutputStream();//获取通道内的输出流对象
        out.write("hello,TCP".getBytes());
        //读取服务器端反馈的数据
        //3)释放资源
        s.close();
    }
}

/*	TCP服务器端的实现步骤:
       1)创建服务器端的Socket对象
      public ServerSocket(int port)throws IOException
        2)监听客户端连接
        public Socket accept()throws IOException 返回值就是当前监听到的客户端的Socket对象
        3)获取通道内的输入流
        public InputStream getInputStream() throws IOException
        4)读取数据:一次读取一个字节数组
        5)展示数据 而且获取ip地址
            //public InetAddress getInetAddress()	*/

public class ServerDemo {
    public static void main(String[] args) throws IOException {
        // 1)创建服务器端的Socket对象
        //public ServerSocket(int port)throws IOException
        ServerSocket ss = new ServerSocket(8888) ;
        System.out.println("服务器正在等待连接...");
        //2)监听客户端连接
//        public Socket accept()throws IOException 返回值就是当前监听到的客户端的Socket对象
        Socket socket = ss.accept(); //阻塞式方法
        //3)取通道内的输入流
        //public InputStream getInputStream() throws IOException
        InputStream inputStream = socket.getInputStream();
        //4)读取数据:一次读取一个字节数组
        byte[] bytes = new byte[1024] ;
        int len = inputStream.read(bytes);
        //获取内容
        String clientStr = new String(bytes,0,len) ;
        //再去反馈数据
        //5)获取ip
        String ip = socket.getInetAddress().getHostAddress();
        //展示数据
        System.out.println("data from "+ip+" content is--->"+clientStr);
        //关闭
        ss.close();
    }
}
一个有回复的TCP通信
public class ScoketDemo {
    public static void main(String[] args) throws IOException {
        //1)创建TCP客户端的Socket对象
       // public Socket(String host, int port)throws UnknownHostException, IOException
        //参数1:主机名称/或者ip地址字符串形式
        //参数2:指定的端口(0-65535(不包含0-1024))
        Socket s = new Socket("10.12.156.107",8888) ;
        //2)写数据
        //public OutputStream getOutputStream()throws IOException
        OutputStream out = s.getOutputStream();//获取通道内的输出流对象
        out.write("hello,TCP".getBytes());
        //读取服务器端反馈的数据
        //获取通道内的输入流
        InputStream in = s.getInputStream();
        //读
        byte[] bytes = new byte[1024] ;
        int len = in.read(bytes);
        String fkMsg = new String(bytes,0,len) ;
        System.out.println("fkMsg:"+fkMsg);
        //3)释放资源
        s.close();
    }
}

public class ServerDemo {
    public static void main(String[] args) throws IOException {
        // 1)创建服务器端的Socket对象
        //public ServerSocket(int port)throws IOException
        ServerSocket ss = new ServerSocket(8888) ;
        System.out.println("服务器正在等待连接...");
        //2)监听客户端连接
//        public Socket accept()throws IOException 返回值就是当前监听到的客户端的Socket对象
        Socket socket = ss.accept(); //阻塞式方法
        //3)取通道内的输入流
        //public InputStream getInputStream() throws IOException
        InputStream inputStream = socket.getInputStream();
        //4)读取数据:一次读取一个字节数组
        byte[] bytes = new byte[1024] ;
        int len = inputStream.read(bytes);
        //获取内容
        String clientStr = new String(bytes,0,len) ;
        //服务器给客户端再去反馈数据,
        //获取通道内的输出流
        OutputStream outputStream = socket.getOutputStream();
        //写入到通道内的流对象中
        outputStream.write("ok,数据已经收到".getBytes());
        outputStream.flush();
        //5)获取ip
        String ip = socket.getInetAddress().getHostAddress();
        //展示数据
        System.out.println("data from "+ip+" content is--->"+clientStr);
        //关闭
        ss.close();
    }
}
可以连续发送的TCP通信
客户端:
    1)TCP客户端不断键盘录入数据,服务器端不断接收数据,然后展示数据
    2)TCP客户端文本文件(XXX.java文件)----->服务器端将文件进行读写复制,输出到当前项目的Copy.java文件中
                   BuferedReader
    3)TCP客户端文本文件(XXX.jpg文件)----->服务器端将文件进行读写复制,输出到当前项目的Copy.jpg文件中
                   BufferedInputStream
public class ClientDemo {
    public static void main(String[] args) {
        //创建客户端的Socket
        Socket socket = null ;
        try {
           socket  = new Socket("10.12.156.107",10010) ;
           //创建BufferedReader
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in)) ;
            //录入一行
            //读取一行
            String line = null ;
            while((line=br.readLine())!=null){//null只是作为 一个文件是否读完
                if("over".equals(line)){
                    break ;
                }
                //获取通道内的输出流(字节流OutputStream)
                //封装通道内字节输出流
                //分步走
                //OutputStream outputStream = socket.getOutputStream();   //字节流---->字符流
                //创建字符缓冲输出流
                //BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream)) ;
                //一步走
                BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())) ;
                 //给封装的通道内的流对象bw写一行
                bw.write(line);
                bw.newLine();
                bw.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //释放资源
                if(socket!=null){
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
        }
        //需要获取服务器端的反馈数据 (已经读完完毕了)
    }
}

//服务器端不断读取数据并展示
public class ServerDemo {
    public static void main(String[] args) {
        //创建服务端的Socket,一直开启
        ServerSocket ss = null ;
        try {
           ss = new ServerSocket(10010) ;
            //ArrayList<Socket>:ArrayList存储一个列表:都是多个客户端 对象
           while(true){
               System.out.println("服务器正在等待连接");
               Socket socket = ss.accept();
               //不断监听,不断展示数据
               //获取通道内的输入流(InputStream)
               //封装通道内的输入流对象
               BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())) ;
               //一次读取一行
               String line = null ;
               while((line=br.readLine())!=null){ //阻塞式方法
                   // //展示数据
                   System.out.println(line);
               }
               //复制完毕之后,给客户端反馈
           }
        } catch (IOException e) {
            e.printStackTrace();
        }
        //服务器端不关闭
    }
}

MySql:

数据库语句:

DDL语句:数据库定义语句

库/表的增删查改

查询当前mysql下所有的数据库
mysql8.0  自带的  跟5.5自带的不一样
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |    mysql默认的一些配置
| mysql              |    mysql库里面包含user表用户表 (权限用户)
| performance_schema |    mysql性能相关的库
| sakila             |    提供其他三个库 sakila sys world  提供了一些例库   练习sql语句
| sys                |
| world              |
| zy                 |  自定义的库(开发者自定义)
+--------------------+
7 rows in set (0.00 sec)


创建数据库

create database 库名 ;

方式1
mysql> create database mydb_01;  
Query OK, 1 row affected (0.02 sec)

create database if not exists 库名;

方式2
mysql> create database if not exists mydb_02;
Query OK, 1 row affected (0.02 sec)
查看创建数据库的默认的字符集(了解)

show create database 库名;

mysql> show create database mydb_01;
+----------+-----------------------------------------------------------------------------------------------------------------------------------+
| Database | Create Database                                                                                                                   |
+----------+-----------------------------------------------------------------------------------------------------------------------------------+
| mydb_01  | CREATE DATABASE `mydb_01` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */ |
+----------+-----------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
修改数据库的字符集(了解)

alter database 库名 (default)可以省略 character set=字符集;

mysql> alter database mydb_01 default character set gbk ;
Query OK, 1 row affected (0.01 sec)
mysql> show create database mydb_01;
+----------+----------------------------------------------------------------------------------------------------+
| Database | Create Database                                                                                    |
+----------+----------------------------------------------------------------------------------------------------+
| mydb_01  | CREATE DATABASE `mydb_01` /*!40100 DEFAULT CHARACTER SET gbk */ /*!80016 DEFAULT ENCRYPTION='N' */ |
+----------+----------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql>
删除库

drop database 库名;

drop database if exists 库名;

mysql> drop database mydb_02;
Query OK, 0 rows affected (0.02 sec)

mysql> drop database if exists mydb_03;
Query OK, 0 rows affected (0.01 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mydb_01            |
| mysql              |
| performance_schema |
| sakila             |
| sys                |
| world              |
| zy                 |
+--------------------+
模糊查询mysql服务中所有的带character字符集的全局变量
show variables like '%character%' ;

mysql> show variables like '%character%' ;
+--------------------------+---------------------------------------------------------+
| Variable_name            | Value                                                   |
+--------------------------+---------------------------------------------------------+
| character_set_client     | gbk                                                      |
| character_set_connection | gbk                                                     |
| character_set_database   | utf8mb4                                                 |
| character_set_filesystem | binary                                                  |
| character_set_results    | gbk                                                     |
| character_set_server     | utf8mb4                                                 |
| character_set_system     | utf8mb3                                                 |
| character_sets_dir       | C:\Program Files\MySQL\MySQL Server 8.0\share\charsets\ |
+--------------------------+---------------------------------------------------------+
8 rows in set, 1 warning (0.01 sec)


如果出现中文乱码:
 character_set_client 客户端  utf8
  character_set_results  结果集 utf8



改动字符集:临时解决中文乱码
mysql> set character_set_client=utf8;
Query OK, 0 rows affected, 1 warning (0.01 sec)

mysql> set character_set_results=utf8;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> show variables like '%character%' ;
+--------------------------+---------------------------------------------------------+
| Variable_name            | Value                                                   |
+--------------------------+---------------------------------------------------------+
| character_set_client     | utf8mb3                                                 |
| character_set_connection | gbk                                                     |
| character_set_database   | ut
f8mb4                                                 |
| character_set_filesystem | binary                                                  |
| character_set_results    | utf8mb3                                                 |
| character_set_server     | utf8mb4                                                 |
| character_set_system     | utf8mb3                                                 |
| character_sets_dir       | C:\Program Files\MySQL\MySQL Server 8.0\share\charsets\ |
+--------------------------+---------------------------------------------------------+
8 rows in set, 1 warning (0.00 sec)


创建表
create table 表明(
	列名1 字段类型1,
    列名2 字段类型2,
    ...
    列名n 字段类型n
) ; 

数据库常用的字段类型
int------>默认int(11)  取的是当前实际长度 (推荐)
		id int,---编号			1 
		 
		
int(长度):指定长度
			id int(3)   		 1---->001 

varchar(字符长度):字符串类型数据   '' "" 不写 引号  ,习惯去使用''或者双引号
double(值1,值2):小数类型  
   举例
   		double(3,2) ----小数类型,3位数,小数点后保留2位
   					123.56
日期类型
  date  仅仅表示日期,不表示时分秒
  		"2021-8-12"
  datatime  不仅表示日期具体的时间
  		"2021-8-12 17:31:00"
  timestap:时间戳  
  		给表中插入数据, 显示当前插入/修改/删除/查询数据那一刻时间 (具体到秒"2021-8-12 18:00:01")
	
    
 注意事项:就是给那一个库中创建表  使用哪个库(选择数据库名)
 use 库名;
mysql> use mydb_01;
Database changed
mysql>


mysql> create table student(
    -> id int,
    -> name varchar(20),
    -> gender varchar(10),
    -> address varchar(50),
    -> age int
    -> )
    -> ;
Query OK, 0 rows affected (0.05 sec)
 
查询当前数据库中有哪些表

show tables ;

mysql> show tables;
+-------------------+
| Tables_in_mydb_01 |
+-------------------+
| student           |
+-------------------+
1 row in set (0.01 sec)
查询当前表的结构

desc 表名 ;

mysql> desc student;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| id      | int         | YES  |     | NULL    |       |
| name    | varchar(20) | YES  |     | NULL    |       |
| gender  | varchar(10) | YES  |     | NULL    |       |
| address | varchar(50) | YES  |     | NULL    |       |
| age     | int         | YES  |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+
5 rows in set (0.01 sec)
修改表

给student表添加一列

alter table 表名 add 字段名称 字段类型;

mysql> alter table student add email varchar(50) ;
Query OK, 0 rows affected (0.04 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc student;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| id      | int         | YES  |     | NULL    |       |
| name    | varchar(20) | YES  |     | NULL    |       |
| gender  | varchar(10) | YES  |     | NULL    |       |
| address | varchar(50) | YES  |     | NULL    |       |
| age     | int         | YES  |     | NULL    |       |
| email   | varchar(50) | YES  |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+
6 rows in set (0.01 sec)

修改表中的字段类型

alter table 表名 modify 字段名称 更改后的字段类型;

mysql> alter table student modify address varchar(30) ;
Query OK, 0 rows affected (0.07 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc student;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| id      | int         | YES  |     | NULL    |       |
| name    | varchar(20) | YES  |     | NULL    |       |
| gender  | varchar(10) | YES  |     | NULL    |       |
| address | varchar(30) | YES  |     | NULL    |       |
| age     | int         | YES  |     | NULL    |       |
| email   | varchar(50) | YES  |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+
6 rows in set (0.00 sec)

修改表中的字段名称

alter table 表名 change 旧列名 新列名 字段类型;

mysql> alter table student change gender sex varchar(10) ;
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc student;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| id      | int         | YES  |     | NULL    |       |
| name    | varchar(20) | YES  |     | NULL    |       |
| sex     | varchar(10) | YES  |     | NULL    |       |
| address | varchar(30) | YES  |     | NULL    |       |
| age     | int         | YES  |     | NULL    |       |
| email   | varchar(50) | YES  |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+
6 rows in set (0.01 sec)

修改表:删除某一列字段

alter table 表名 drop 字段名称;

mysql> alter table student drop email;
Query OK, 0 rows affected (0.06 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc student;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| id      | int         | YES  |     | NULL    |       |
| name    | varchar(20) | YES  |     | NULL    |       |
| sex     | varchar(10) | YES  |     | NULL    |       |
| address | varchar(30) | YES  |     | NULL    |       |
| age     | int         | YES  |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+
5 rows in set (0.01 sec)

修改表的表名

alter table 表名 renameto 新表名;

mysql> alter table student rename to stu;
Query OK, 0 rows affected (0.03 sec)

mysql> show tables;
+-------------------+
| Tables_in_mydb_01 |
+-------------------+
| stu               |
| teacher           |
+-------------------+
2 rows in set (0.01 sec)

复制一张表结构和以前表的结果一样

create table 新表名 like 旧表名;

 
mysql> create table teacher like student; //字段复制
Query OK, 0 rows affected (0.03 sec)

mysql> show tables;
+-------------------+
| Tables_in_mydb_01 |
+-------------------+
| student           |
| teacher           |
+-------------------+
2 rows in set (0.01 sec)
删除表

drop tabble 表名;

drop table if exists 表名;

mysql> drop table if exists teacher;
Query OK, 0 rows affected (0.03 sec)

mysql> show tables;
+-------------------+
| Tables_in_mydb_01 |
+-------------------+
| stu               |
+-------------------+
1 row in set (0.00 sec)

DML语句:操作表的记录

插入语句

insert into 表名 values(值1,值2,值3…) ;插入全表数据 :那么每一个参数值必须和字段类型匹配! (不会报错,警告)

mysql> insert into stu values(1,'高圆圆','女','西安市',30) ;
Query OK, 1 row affected (0.01 sec)

最基本的查询:查询全表数据

select * from 表名;

mysql> insert into stu values(1,'高圆圆','女','西安市',30) ;
Query OK, 1 row affected (0.01 sec)

mysql> select * from stu ;
+------+--------+------+---------+------+
| id   | name   | sex  | address | age  |
+------+--------+------+---------+------+
|    1 | 高圆圆 | 女   | 西安市  |   30 |
+------+--------+------+---------+------+
1 row in set (0.01 sec)

如果中文乱码
改动下面的字符集编码即可
mysql> show variables like '%character%' ;
+--------------------------+---------------------------------------------------------+
| Variable_name            | Value                                                   |
+--------------------------+---------------------------------------------------------+
| character_set_client     | gbk                                                     |
| character_set_connection | gbk                                                     |
| character_set_database   | gbk                                                     |
| character_set_filesystem | binary                                                  |
| character_set_results    | gbk                                                     |
| character_set_server     | utf8mb4                                                 |
| character_set_system     | utf8mb3                                                 |
| character_sets_dir       | C:\Program Files\MySQL\MySQL Server 8.0\share\charsets\ |
+--------------------------+---------------------------------------------------------+
8 rows in set, 1 warning (0.00 sec)

mysql> set character_set_client = utf8;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> set character_set_results = utf8;
Query OK, 0 rows affected, 1 warning (0.00 sec)
sqlYog:

图形界面化工具 写sql,table键提示功能

使用命令:

– 先去使用命令
USE mydb_01 ;

查询表结构:

– 查询表结构
DESC stu ;

DML语句:

– DML语句: 数据库操作语句,操作表记录

insert into 插入数据

– insert into 插入数据
– 1)插入全表数据insert into 表名 values(值1,值2,…);
INSERT INTO stu VALUES(2,‘赵又廷’,‘男’,‘北京市’,32) ;
– 插入全表:一次性插入多条数据
– 语法2) insert into 表名 values(值1,值2…),(值1,值2…),(值1,值2…) ;
INSERT INTO
stu
VALUES
(3,‘文章’,‘男’,‘西安市’,35),
(4,‘马伊琍’,‘女’,‘上海市’,42),
(5,‘德玛西亚’,‘男’,‘艾欧尼亚’,25) ;

– 插入部分字段 :语法3 insert into 表名(部分字段1,字段2…) values(值1,值2…)
INSERT INTO
stu(NAME,sex,address) VALUES(‘王宝强’,‘男’,‘咸阳市’) ;

– 注意:插入部分字段,必须字段数量和插入值的数量必须匹配
– insert into stu(id,name,sex) values(6,‘姚笛’) ;
– 不管插入部分字段还全部字段,那么必须要和当前类型一致
INSERT INTO
stu

VALUES(6,‘男’,‘马嘉钰’,‘西安市’,20) ;

修改表的数据 update:

– 修改表的数据 update
– 语法:按条件修改 update 表名 set 字段名称 = 值 where 字段名称= 值; 修改一个字段
– 修改name是王宝强的将他的id设置为7
UPDATE stu SET id = 7 WHERE NAME = ‘王宝强’ ;
– 修改id为7的age设置为37
UPDATE stu SET age = 37 WHERE id = 7 ;

– 一次修改多个字段
– update 表名 set 字段名称1 =值1 ,字段名称2 =值2 where 条件;
– 将id为的6的姓名修改为 ‘张三丰’ ,性别修改为’男’
UPDATE
stu
SET
NAME = ‘张三丰’,
sex = ‘男’
WHERE
id = 6 ;

– 如果不带条件修改:就是批量修改
– 将修改name为 ‘高圆圆’
UPDATE stu SET NAME = ‘高圆圆’ ; – 一般都是带条件进行修改!

删除:

– 删除
– 带条件来删除
– delete from 表名 where 字段名称 = 值; //删除指定的记录
– 删除id = 6的这条记录
DELETE FROM stu WHERE id = 6 ;

– 删除全表数据
– delete from 表名;
DELETE FROM stu ;
– truncate table 表名;
TRUNCATE TABLE stu ;

/*
删除全表的语法
delete from 表名
truncate table 表名; 两个区别

1)delete from 表名:只是删除全表数据;表的结构还存在,
如果表中 存在主键并且自增长约束,那么不会受影响,下一次在插入数据
继续在之前的基础上继续自增长!

2)truncate table 表名 ;
将表中数据删除的同时删除了表,然后在创建一张一模一样空表,
肯定影响自增长主键的值,再次插入数据,自增长从1开始…

​ 等价于
​ drop table my_use;
​ 创建一个当前一模一样的表结构

*/
– 创建一张新的表 my_user表
CREATE TABLE my_user(
id INT PRIMARY KEY AUTO_INCREMENT, – 用户编号 主键加增长
NAME VARCHAR(20),
age INT ,
gender VARCHAR(5)
) ;

INSERT INTO my_user(NAME ,age ,gender)
VALUES(‘张三’,20,‘男’),(‘李四’,22,‘女’),(‘文章’,25,‘男’) ;

INSERT INTO my_user(NAME,age,gender) VALUES(‘王五’,18,‘男’) ;
– delete from my_user where id = 8 ;

– 删除全表数据
DELETE FROM my_user ;

– 删除全部数据
TRUNCATE TABLE my_user ;

SELECT * FROM my_user;

查询stu的表的数据select;

– DQL之基本的查询语句
SELECT * FROM stu ; – 查询全表数据
– 实际开发中,* (通配符),一般查询全表数据,需要带全部字段
SELECT – 指定全部字段
id ,
NAME,
sex,
address,
age
FROM stu ;

– 查询指定的字段
– select 字段名称列表 from 表名;
SELECT
id ,
NAME ,
address,
age
FROM stu ;

– 查询指定字段时可以通过as 关键字指定别名,as可以省略
SELECT
id AS ‘学生编号’,
NAME AS ‘姓名’,
address AS ‘地址’,
age AS ‘年龄’
FROM stu ;
– as 可以省略
SELECT
id ‘学生编号’,
NAME ‘姓名’,
address ‘地址’,
age ‘年龄’
FROM stu ;
– 基本查询:字段去重

– DQL带条件查询where:

– where条件查询
– 可以基本运算符:比较运算符(<,>,<=,>=,!=)/逻辑运算符(|| && /and /or)/赋值运算符 =
– where后面多个or in(集合数据) 在两个值之间 between 值1 and 值2
– mysql 判断某个字段为null , is null /is not null

– 模糊查询 like
– 聚合函数 count(列名)/max(列名)/min(列名)/sum(列名)/avg(列名)
– 排序查询 order by
– 分组查询 group by
– 筛选查询 having
– 分页查询limit

– 创建一个学生表
CREATE TABLE student (
id INT, – 编号
NAME VARCHAR(20), – 姓名
age INT, – 年龄
sex VARCHAR(5), – 性别
address VARCHAR(100), – 地址
math INT, – 数学
english INT – 英语
);

DESC student ;
INSERT INTO student(id,NAME,age,sex,address,math,english) VALUES
(1,‘马云’,55,‘男’,’ 杭州’,66,78),
(2,‘马化腾’,45,‘女’,‘深圳’,98,87),
(3,‘马景涛’,55,‘男’,‘香港’,56,77),
(4,'柳岩 ',20,‘女’,‘湖南’,76,65),
(5,‘柳青’,20,‘男’,‘湖南’,86,NULL),
(6,‘刘德华’,57,‘男’,'香港 ',99,99),
(7,‘马德’,22,‘女’,‘香港’,99,99),
(8,‘德玛西亚’,18,‘男’,‘南京’,56,65);

– 条件查询
– 查询年龄大于20岁的人的全部信息
SELECT
id ‘编号’,
NAME ‘姓名’,
age ‘年龄’,
sex ‘性别’,
address ‘地址’,

math '数学成绩',
english '英语成绩'

FROM
student
WHERE
age > 20 ;
– 查询年龄在20岁和30岁之间的学生信息
SELECT
*
FROM
student
WHERE
age >= 20 && age <=30 ; – &&:Java的逻辑运算符
– 另一种语法
SELECT
*
FROM
student
WHERE
age >= 20 AND age <=30 ;-- and mysql表示并列关系
– 另一种语法:mysql 在两个值之间 between 值1 and 值2
SELECT – 查询部分字段 并且年龄在20-30
NAME ‘姓名’,
age ‘年龄’,
address ‘地址’,
math ‘数学成绩’,
english ‘英语成绩’

FROM
student
WHERE
age
BETWEEN 20 AND 30 ;

– 查询年龄是18或者20或者30岁的学生的编号,姓名,年龄以及地址 (|| 或者 or)
SELECT

id  '编号',
NAME '姓名',
age '年龄',
address '地址'

FROM
student
WHERE
age = 18 OR age = 20 OR age = 30 ;

– mysql另一种语法 where 字段名称 in(多个值)
SELECT

id  '编号',
NAME '姓名',
age '年龄',
address '地址'

FROM
student
WHERE
age
IN(18,20,30) ;

– 查询英语成绩为null的学号编号,姓名,性别,地址.数学成绩信息
/*
select
id ,
name,
sex,
address,
math
from
student
where
english == null ; – java中的用法可以这样用 == = (都不行)
*/
SELECT
id ,
NAME,
sex,
address,
math,
english
FROM
student
WHERE
english IS NULL ; – mysql用法

– 查询英语成绩不为null的人 ,is not null 的用法

SELECT
id ,
NAME,
sex,
address,
math,
english
FROM
student
WHERE
english IS NOT NULL ;

– 查询英语和数学成绩总分的学生新
SELECT
id 编号 ,
NAME 姓名 ,
sex 性别 ,
address ‘地址’,
– (math+english) as ‘总分’
(math+IFNULL(english,0)) ‘总分’

FROM
student ;

– mysql 内置函数ifnull(值1,值2) ; ifnull(english,0) :
– 如果当前英语成绩为null,给默认值0

– 查询地址
SELECT
address 地址
FROM student ;
– 查询字段,对字段去重 (distinct)
SELECT
DISTINCT address 地址
FROM student ;

– 查询年龄不是20岁的学生信息
SELECT

*

FROM student
WHERE age != 20 ; – != Java中这种语法 !=
– mysql中的不等于 <>
SELECT
*
FROM
student
WHERE
age <> 20 ;

– 模糊查询mysql服务中带字符集相关的变量 show variables like ‘%character%’ ;
– 模糊查询 like
– select 字段列表 from 表名 where 字段名称 like ‘%字符%’ ;
/*
% :包含的指定的字符 使用’%字符值%’ 模糊查询包含指定字符的信息
_ :代表单个字符(一个_下划线代表一个字符)
两个相结合使用: ‘%字符值%’ 三个字符:中间字符包含指定的值进行模糊查询
*/
– 查询当前学生表中姓名包含马的学生信息
SELECT
*
FROM
student
WHERE
NAME
LIKE
‘%马%’ ;
– 查询第二个字符包含化的学生信息
SELECT
*
FROM
student
WHERE
NAME
LIKE
‘_%化%’ ;

– 查询姓名是三个字符的人
SELECT
*
FROM
student
WHERE
NAME
LIKE
‘___’ ;

– 应用场景: 搜索框中输入关键字查询—使用到模糊查询

– 聚合函数查询---- >查询结果:单行单列的数据
– count(列名) :总记录数
– max(列名): 最大值
– min(列名字段):最小值
– sum(字段名称):求和
– avg(列名):平均分
– select 聚合函数(列名) from 表名;

– 查询当前student这个表的全部总记录数
– 如果使用english字段查询总记录数
SELECT
COUNT(english) – 使用业务字段查询(可能某个值为null,不会进行记录)
FROM
student ; – 7条记录
– 可以使用函数设置如果当前某个值null,给默认值
SELECT
COUNT(IFNULL(english,0)) 总记录数
FROM
student;
/*
count(列名)查询总记录数的时候,一般都使用非业务字段查询
student
id(非业务字段) name age gender (业务字段)
学校里面的学生表
某个学生刚开始还在学习, 后面转学了 (非业务字段id—主键+自增长的)
1 张三 20 男
select
count(id)
from 表名;

*/
– 建议id来查询
SELECT
COUNT(id) 总条数
FROM
student ;

– 查询数学的平均成绩 avg(列名)
SELECT
AVG(math) ‘数学平均成绩’
FROM
student ; – 79.5000

– 查询英语成绩—总成绩(求和 sum(列名))
SELECT
SUM(IFNULL(english,0)) 英语总分

FROM
student ;

– 查询英语成绩的最高成绩
SELECT

  MAX(IFNULL(english,0)) 英语最高分

FROM
student ;

– 查询数学成绩最低分
SELECT
MIN(math) 数学最低分
FROM
student ;

– 聚合函数使用最多的:count函数,avg函数

– 排序查询:order by 字段名称 asc/desc (升序/降序)
– select 字段列表 from 表名 order by 字段名 排序规则; – 单个字段进排序

– 数学成绩安装升序排序
SELECT
*
FROM
student
ORDER BY math ; – 如果字段名称后面没有带排序规则:则默认升序排序
– 英语降序排序
SELECT
NAME ,
age,
sex,
address,
IFNULL(english,0) 英语成绩
FROM
student
ORDER BY english DESC ; – 降序

– 针对多个字段同时排序,当前第一字段值相等,则按照第二个字段的排序规则执行
– select 字段列表 from 表名 order by 字段名称1 升序1 ,字段名称2 升序2;
– 查询全表数据,数学成绩降序,英语成绩升序
SELECT
*
FROM
student
ORDER BY
math DESC,
english ASC ;

– 分组查询:group by
– 分组group by 分组字段;
– 查询的时候可以查询分组字段,
– group by 后面不能使用聚合函数

– 问题:如果group by 和where条件语句一块使用,先后顺序? where之后 才能使用group by

– 现在需要按照性别分组-----分组之后查询出总人数
– 性别-- 男/女
SELECT
– 查询分组字段
sex ‘性别’,
COUNT(id) ‘人数’

FROM
student
GROUP BY
sex ; – 性别

– 现在需要按照性别分组-----分组之后查询出总人数,数学的平均分
– 条件:数学成绩不大于70分的人不参与分组;

/*
SELECT
– 查询分组字段
sex ‘性别’,
COUNT(id) ‘人数’

FROM
student
GROUP BY
sex – 性别
where
math > 70 ;
*/

SELECT
sex ‘性别’, – 查询分组字段
COUNT(id) ‘总人数’,
AVG(math) ‘数学平均成绩’

FROM
student
WHERE
math > 70 – 条件:数学成绩大于70分人参与分组
GROUP BY
sex ; – 性别分组

– 筛选 having

– 现在需要按照性别分组-----分组之后查询出总人数,数学的平均分
– 条件:数学成绩不大于70分的人不参与分组
– 筛选条件:总人数大于2的一组

– having 必须置于group by 之后,where 置于 group by 之前
– group by不能聚合函数,但是having后面可以聚合函数
SELECT
sex ‘性别’, – 查询分组字段
COUNT(id) ‘总人数’,
AVG(math) ‘数学平均成绩’

FROM
student
WHERE
math > 70 – 条件:数学成绩大于70分人参与分组
GROUP BY
sex – 性别分组

HAVING
COUNT(id) > 2 ;
– 优化
SELECT
sex 性别, – 查询分组字段
COUNT(id) 总人数,
AVG(math) 数学平均成绩

FROM
student
WHERE
math > 70 – 条件:数学成绩大于70分人参与分组
GROUP BY
sex – 性别分组

HAVING
总人数 > 2 ;

– 分页查询limit
– select 字段列表 from 表名 limit 起始行数,每页显示多少条;

– 给student表在插入三条记录
INSERT INTO student VALUES(9,‘德邦’,19,‘男’,‘西安’,78,58) ,
(10,‘vn’,20,‘女’,‘宝鸡’,89,65),(11,‘亚索’,22,‘男’,‘西安’,95,74);

– 每页显示3条记录
– 查询第一页的数据
– limit 起始行数=(当前页码数-1)*每页显示的条数,每页显示条数;
SELECT * FROM student LIMIT 0,3 ;
– 查询第二页的数据
SELECT * FROM student LIMIT 3 ,3 ;
– 查询第三页数据
SELECT * FROM student LIMIT 6,3 ;
– 第四页数据
SELECT * FROM student LIMIT 9,3 ;

– 查询全表
SELECT * FROM student ;
UPDATE student SET english = 98 WHERE id = 7 ;

– 数据库约束
– 约束用户操作表的一种行为
– 创建一个新的表
CREATE TABLE test(
id INT , – 编号
NAME VARCHAR(10) , – 姓名
gender VARCHAR(2) DEFAULT ‘女’ – 性别 – 默认约束 防止出现非法数据null(没有插入造成null值)

) ;

– 1)默认约束,当前没有给那个字段设置值的时候,此时默认约束就会起作用

DROP TABLE test ;

INSERT INTO test VALUES(1,‘张三’,‘男’) ;
– 可能用户操作数据库的时候,插入非法数据(没有意义的数据)
– insert into test values(2,null,‘女’) ;
– 如果没有给某个字段赋值,默认值null
INSERT INTO test(id,NAME) VALUES(2,‘高圆圆’) ;

– 通过sql语句修改表的类型,删除默认约束
ALTER TABLE test MODIFY gender VARCHAR(2) ;

INSERT INTO test(id,NAME) VALUES(3,‘文章’) ;

– 修改表加入默认约束
ALTER TABLE test MODIFY gender VARCHAR(2) DEFAULT ‘女’ ;
DELETE FROM test WHERE id = 3 ;

– 2)非空约束
DROP TABLE test ;
CREATE TABLE test(
id INT ,
NAME VARCHAR(10) NOT NULL – 非空约束
);

INSERT INTO test VALUES(1,NULL) ; – 直接插入null值
– insert into test (id) values(1) ; 没有给姓名赋值

INSERT INTO test VALUES(1,’’) ; – 存在值,只是空字符 和null不一样

– 删除非空约束
ALTER TABLE test MODIFY NAME VARCHAR(10) ;
UPDATE test SET NAME = ‘高圆圆’ WHERE id = 1 ;
INSERT INTO test VALUES(2,NULL) ; – Column ‘NAME’ cannot be null

– 修改表,加入非空约束
ALTER TABLE test MODIFY NAME VARCHAR(10) NOT NULL ;
DELETE FROM test WHERE id = 2 ;

– 3)唯一约束 nuique
DROP TABLE test;
CREATE TABLE test(
id INT ,
NAME VARCHAR(10),
phone VARCHAR(11) UNIQUE – 唯一约束 :可以有null值,不能重复
) ;
INSERT INTO test VALUES(1,‘张三’,‘13666668888’) ;
– INSERT INTO test VALUES(1,‘张三’,null) ;
– INSERT INTO test(id,name) values(2,‘李四’) ;
INSERT INTO test VALUES(2,‘李四’,‘13666668889’) ;
– INSERT INTO test VALUES(2,‘李四’,‘13666668888’) ;
– Duplicate entry ‘13666668888’ for key ‘test.phone’

– 通过语句删除唯一约束
– alter table test modify phone varchar(11) ; 错误语法
– 删除唯一约束的sql alter table test drop index 字段名称;
ALTER TABLE test DROP INDEX phone ;

INSERT INTO test VALUES(4,‘赵六’,‘13666668878’) ;
DELETE FROM test WHERE id = 4 ;

– 添加唯一约束
ALTER TABLE test MODIFY phone VARCHAR(11) UNIQUE ;

– 主键约束 (非空+唯一特点) primary key
– 都会给当前非业务字段去设置主键(xxid)
DROP TABLE test ;
CREATE TABLE test(
id INT PRIMARY KEY , – 非业务字段
NAME VARCHAR(10),
gender VARCHAR(2)
) ;

INSERT INTO test VALUES(1,‘洪学佳’,‘男’),(2,‘马三奇’,‘男’) ;
– insert into test values(1,‘马嘉钰’,‘男’) ;id值重复 – Duplicate entry ‘1’ for key ‘test.PRIMARY’
– insert into test values(null,‘雷郁’,‘男’) ;-- id直接插入null值 Column ‘id’ cannot be null

SELECT * FROM test ;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值