网络编程,sql基本语句

一.网络编程

1.1网络编程的三要素

ip: 使用点分十进制法,中间使用.隔开
	A类  国家大部门---->前一个号段是网络号段,后面三个主机号段
	B类  校园/大公司服务器机房/:前面两个网络号段,后面使用两个注解号段
	C类  私人地址:前面三个为网络号段,后面是主机号段
port端口:
	port端口 360软件都可以查看你电脑所有客户端软件的端口号
	范围:0~65535  里面0~1024属于保留端口
传输协议:
	UDP协议--->数据报包(数据包的报文)
		1)不需要建立连接通道
		2)不可靠协议,不安全的
		3)发送数据大小有限制
	TCP协议--->最基本的字节流的方式发送数据
		1)就必须连接通道
		2)可靠协议,一种安全
		3)发送数据大小无限制

1.2UDP发送端和接收端的实现(了解) —>不可靠连接

1.2.1基本UDP的发送端和接收端代码实现

发送端:

		//1)创建接收端的Socket对象,绑定端口       
        DatagramSocket ds = new DatagramSocket(10086) ;

        //2)创建一个接收容器--->数据包--->自定义字节缓冲区,将发送的数据包
        byte[] bytes = new byte[1024] ;//1024或者1024整数倍
        int length = bytes.length ;
        DatagramPacket dp = new DatagramPacket(bytes,length) ; //将发送端数据缓冲到这个接收容器中

        //3)接收,以上面这个接收容器来接收
        ds.receive(dp);

        //4)从接收容器中解析数据包的实际内容数据
        //从接收容器中获取public byte[] getData() 实际缓冲区的对象(从上bytes分段取数据)
        byte[] bytes2 = dp.getData();
        //获取里面实际缓冲区的长度
       // public int getLength()
        int length2 = dp.getLength();
        //展示数据---分段取数据,每次从0开始取实际长度
        String msg = new String(bytes2,0,length2) ;
        //数据包里面获取哪一个ip地址发来的--->ip地址字符串形式
        String ip = dp.getAddress().getHostAddress() ;
        System.out.println("data from --->"+ip+",发送内容是:"+msg);

        //释放资源
        ds.close();

接收端:

		//1)创建接收端的Socket对象,绑定端口       
        DatagramSocket ds = new DatagramSocket(10086) ;

        //2)创建一个接收容器--->数据包--->自定义字节缓冲区,将发送的数据包
        byte[] bytes = new byte[1024] ;//1024或者1024整数倍
        int length = bytes.length ;
        DatagramPacket dp = new DatagramPacket(bytes,length) ; //将发送端数据缓冲到这个接收容器中

        //3)接收,以上面这个接收容器来接收
        ds.receive(dp);

        //4)从接收容器中解析数据包的实际内容数据
        //从接收容器中获取public byte[] getData() 实际缓冲区的对象(从上bytes分段取数据)
        byte[] bytes2 = dp.getData();
        //获取里面实际缓冲区的长度
       // public int getLength()
        int length2 = dp.getLength();
        //展示数据---分段取数据,每次从0开始取实际长度
        String msg = new String(bytes2,0,length2) ;
        //数据包里面获取哪一个ip地址发来的--->ip地址字符串形式
        String ip = dp.getAddress().getHostAddress() ;
        System.out.println("data from --->"+ip+",发送内容是:"+msg);

        //释放资源
        ds.close();
1.2.2UDP发送端可以不断键盘录入数据,接收端不断展示数据,发送端可以自定义结束条件代码实现

发送端:

        //创建发送端的Socket
        DatagramSocket ds = null;
        try {
            ds = new DatagramSocket();
            //键盘录入可以使用BufferedReader--->读一行
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

            String line = null;
            System.out.println("请输入一个数据");
            while ((line = br.readLine())!=null){
                if ("over".equals(line)){
                    break;
                }
                //创建数据报包,将数据存储在数据包中
                DatagramPacket dp = new DatagramPacket(line.getBytes(),
                                                       line.getBytes().length,
                                                        InetAddress.getByName("127.0.0.1"),
                                                        6666);
                //发送数据报包
                ds.send(dp);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(ds!=null){
                ds.close();
            }
        }

接收端:

 try {
            //创建接收端的Socket对象
            DatagramSocket ds = new DatagramSocket(6666);

            while (true){
                //创建一个接收容器
                //自定义一个字节数组缓冲区
                byte[] buffer = new byte[1024];
                int bufferLength = buffer.length;
                DatagramPacket dp = new DatagramPacket(buffer,bufferLength);
                //接收数据容器
                ds.receive(dp);

                byte[] bytes = dp.getData();
                int length = dp.getLength();
                //每次0开始读取字节数---转成String
                String receiveMsg = new String(bytes, 0, length);
                //获取ip地址字符串
                String ip = dp.getAddress().getHostAddress();
                //展示数据
                System.out.println("data from"+ ip + ",count is"+ receiveMsg);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

1.3TCP客户端和服务器端的实现---->安全—可靠连接

1.3.1基本TCP的服务端和客户端端代码实现

客户端:

		//1)创建客户端的Socket对象,指定ip和端口    
        Socket socket = new Socket("10.35.162.121",1888) ;
        //2)获取客户端通道内容字节输出流对象,写数据        
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("hello,TCP我来了".getBytes());

        //客户端获取通道字节输入流对象,读服务器端的反馈的数据
        InputStream in = socket.getInputStream();
        byte[] bytes = new byte[1024] ;
        int length = in.read(bytes);
        String fkMsg = new String(bytes,0,length) ;
        System.out.println(fkMsg);

        //3)释放资源
        outputStream.close();

服务端:

        //1)创建服务器端的Socket对象
        ServerSocket ss = new ServerSocket(1888) ;
        System.out.println("服务器正在等待客户端连接请求...");
        //2)监听客户端的连接
        Socket socket = ss.accept();//阻塞式方法,没有客户端连接,一直等待
        System.out.println("客户端已连接");

        //3)获取监听到的客户端的通道内的字节输入流对象,读数据
        InputStream inputStream = socket.getInputStream();
        //一次读取一个字节数组
        byte[] bytes = new byte[1024] ;
        int length = inputStream.read(bytes);
        //转换成String
        String receiveMsg =  new String(bytes,0,length) ;

        //获取ip地址对象,同时ip地址字符串形式
        String ip = socket.getInetAddress().getHostAddress();
        System.out.println("data from --->"+ip+",content is-->"+receiveMsg);

        //服务器端反馈给客户端数据
        //服务器端可以获取监听客户端通道内字节输出流,写数据
        OutputStream out = socket.getOutputStream();
        out.write("我这边已经收到数据!".getBytes());

		//4)释放服务器端的资源
        ss.close();
1.3.2TCP客户端不断键盘录入数据,服务器端不断展示数据

客户端:

        //创建客户端Socket
        Socket socket = new Socket("127.0.0.1",1111);
        System.out.println("连接成功");
        //键盘录入数据
        System.out.println("请输入数据");
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        //获取通道字节输出流对象
        OutputStream out = socket.getOutputStream();
        //使用字符流把上面通道内的字节输出流包装
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));

        String line = null;
        while ((line = br.readLine()) != null){
            bw.write(line);
            bw.newLine();
            bw.flush();
        }

        //释放资源
        socket.close();

服务端:

		//创建服务器端的Socket
        ServerSocket ss = new ServerSocket(1111);
        System.out.println("正在等待连接....");
        while (true){
            //监听客户端连接
            Socket socket = ss.accept();
            System.out.println("连接成功");
            //获取监听客户端所在的通道内的字节输入流
            InputStream in = socket.getInputStream();
            //将字节输入流封装成字符流读
            BufferedReader br = new BufferedReader(new InputStreamReader(in));

            //读
            String line = null;
            while ((line = br.readLine()) != null){
                System.out.println(line);
            }
        }
1.3.3TCP客户端文件,服务器端将文件复制到指定文件中, 服务器端加入反馈!(图片或者文本文件)

客户端

        //创建客户端的Socket
        Socket s = new Socket("127.0.0.1",2222);
        //创建字符缓冲输入流对象
        //BufferedReader br = new BufferedReader(new FileReader("a.txt"));
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("aa.jpg"));
        //获取客户端通道的字节输出流
        //BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
        BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream());
        //读
        byte[] bytes = new byte[1024];
        int len = 0;
        while ((len = bis.read(bytes))!=-1){
            bos.write(bytes,0,len);
            //刷新
            bos.flush();
        }
        //关闭输出流
        s.shutdownOutput();
        //客户端要读取服务器反馈数据
        //获取通道内的字节输入流
        InputStream inputStream = s.getInputStream();
        //读取
        byte[] bytes1 = new byte[1024];
        int len1 = inputStream.read(bytes1);
        System.out.println("客户端收到了反馈数据"+new String(bytes1,0,len1));

        //释放资源
        s.close();
        bis.close();

服务端:

       //创建服务器端的Socket对象
        ServerSocket ss = new ServerSocket(2222);
        //创建客户监听连接
        Socket s = ss.accept();
        //获取监听客户端所在的通道内字节输入流对象,包装成字符缓冲输入流
        //BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
        BufferedInputStream bis = new BufferedInputStream(s.getInputStream());
        //将监听客户端的通道内的字节流的内容,通过的字符缓冲输出流写入到文件中
        //BufferedWriter bw = new BufferedWriter(new FileWriter("copy.txt"));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.jpg"));
        //读,写
        byte[] bytes = new byte[1024];
        int len = 0;
        while ((len = bis.read(bytes))!=-1){
            bos.write(bytes,0,len);

            bos.flush();
        }
        //加入反馈,服务器端反馈给客户端数据
        //获取字节输出流
        OutputStream out = s.getOutputStream();
        out.write("文件复制完毕".getBytes());
        out.flush();
        //释放资源
        ss.close();
        bos.close();

二.反射

2.1定义

反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

2.2获取类的字节码文件

三种
    	//对象名.getClass
        Persion p = new Persion();
        Class cls1 = p.getClass();
        System.out.println(cls1);

        //类名.Class
        Class cls2 = Persion.class;
        System.out.println(cls2);

        //class.forName("类的全路径");
        Class cls3 = Class.forName("com.reflect.Persion");
        System.out.println(cls3);

2.3常用方法

//获取包名、类名
clazz.getPackage().getName()//包名
clazz.getSimpleName()//类名
clazz.getName()//完整类名
 
//获取成员变量定义信息
getFields()//获取所有公开的成员变量,包括继承变量
getDeclaredFields()//获取本类定义的成员变量,包括私有,但不包括继承的变量
getField(变量名)
getDeclaredField(变量名)
 
//获取构造方法定义信息
getConstructor(参数类型列表)//获取公开的构造方法
getConstructors()//获取所有的公开的构造方法
getDeclaredConstructors()//获取所有的构造方法,包括私有
getDeclaredConstructor(int.class,String.class)
 
//获取方法定义信息
getMethods()//获取所有可见的方法,包括继承的方法
getMethod(方法名,参数类型列表)
getDeclaredMethods()//获取本类定义的的方法,包括私有,不包括继承的方法
getDeclaredMethod(方法名,int.class,String.class)
 
//反射新建实例
clazz.newInstance();//执行无参构造创建对象
clazz.newInstance(222,"韦小宝");//执行有参构造创建对象
clazz.getConstructor(int.class,String.class)//获取构造方法
 
//反射调用成员变量
clazz.getDeclaredField(变量名);//获取变量
clazz.setAccessible(true);//使私有成员允许访问
f.set(实例,);//为指定实例的变量赋值,静态变量,第一参数给null
f.get(实例);//访问指定实例变量的值,静态变量,第一参数给null
 
//反射调用成员方法
Method m = Clazz.getDeclaredMethod(方法名,参数类型列表);
m.setAccessible(true);//使私有方法允许被调用
m.invoke(实例,参数数据);//让指定实例来执行该方法
2.3.1通过构造方法创建对象
		//方法一:
        Persion p = new Persion();
        System.out.println(p);
        System.out.println("--------------------------");
        //方法二:通过反射获取构造器(Constructor)对象--->创建当前类实例
        //1.获取类字节码文件
        Class cls = Class.forName("com.reflect.Persion");
        //2.获取指定的构造方法所在的Constructor类对象
        Constructor constructor = cls.getConstructor();
        //3.通过它创建当前类实例
        //public T newInstance(Object... initargs):参数就给构造函数中参数进行实际赋值
        Object obj = constructor.newInstance();
        System.out.println(obj);
2.3.2使用反射方式通过构造方法赋值
 		//1.获取当前类的字节码文件对象
        Class cls = Class.forName("com.reflect.Persion");
        //2.获取构造器Constructor类对象--->带两个参数的
        Constructor constructor = cls.getDeclaredConstructor(String.class, String.class);
        //3.提供功能:取消Java语言访问检查,暴力访问
        //setAccessible(boolean flag) true:就是抑制Java语言访问检查功能
        constructor.setAccessible(true);
        //4.通过它创建当前类实例
        Object obj = constructor.newInstance("高圆圆", "女");
        System.out.println(obj);
2.3.3使用反射的方式调用成员方法
		//1)获取类的字节码文件对象
        Class clazz = Class.forName("com.qf.reflect_06.Person") ;

        //2)通过无参构造器创建器Constructor创建当前类实例        
        Constructor con = clazz.getConstructor();
        Object obj = con.newInstance() ;
   		System.out.println(obj);

        //3)获取指定的成员方法所在的Method类对象       
        Method method = clazz.getMethod("show");//方法本身就是空参,获取所有可见的方法,包括继承的方法
        System.out.println(method);        
        method.invoke(obj) ; //本身这个方法没有返回值,单独调用

        System.out.println("----------------------------------------------------------");

        Method m1 = clazz.getDeclaredMethod("method", String.class);//获取本类定义的的方法,包括私有,不包括继承的方法
        //私有方法取消Java语言检查,暴力访问
        m1.setAccessible(true) ;
        m1.invoke(obj,"hello,高圆圆") ;

2.3.4通过反射获取一个类的成员变量的类的对象Field并去赋值
		//获取字节码文件
        Class cls = Class.forName("com.reflect.Person");
        //创建实例对象
        Object obj = cls.newInstance();
        System.out.println(obj);

        //通过字节码文件对象获取成员变量的Field类对象
        Field namefield = cls.getDeclaredField("name");//获取本类定义的成员变量,包括私有
        namefield.setAccessible(true);
        namefield.set(obj,"张三");
        System.out.println(obj);	

2.4反射的应用

2.4.1ArrayList里添加字符串
        //创建集合
        ArrayList<Integer> arr = new ArrayList<>();
        //添加数据
        arr.add(12);
        arr.add(122);
        arr.add(22);
        arr.add(42);
        arr.add(13);
        System.out.println(arr);

        //获取字节码文件
        Class cls = arr.getClass();
        //获取add方法
        Method addmethod = cls.getMethod("add", Object.class);
        //添加其它类型数据
        addmethod.invoke(arr,"张三");
2.4.2通过读取.properties文件的方式,
		//读取配置文件
        InputStream ips = ReflectDemo2.class.getClassLoader().getResourceAsStream("classname.properties");
        //创建空集合列表
        Properties properties = new Properties();
        properties.load(ips);
        System.out.println(properties);
        //通过属性列表获取值
        String className = properties.getProperty("className");
        String methodName = properties.getProperty("methodName");

        //获取字节码文件对象
        Class cls = Class.forName(className);
        //创建当前实例
        Object obj = cls.newInstance();
        //通过字节码文件获取方法
        Method method = cls.getMethod(methodName);
        System.out.println(method);
        method.invoke(obj);

2.5反射—jdk动态代理

结论:使用接口实现方式,运行时,在内存中动态构建出一个类,然后编译,执行。这个类是一次性的,JVM停止,代理类就消失。

三.数据库

3.1什么是数据库

数据库就是存储数据的一种仓库
早期存储数据--->临时变量(局部变量)--->随着方法的调用而存在,随着方法调用的结束而消失
后面-------->成员变量(非静态)----->随着方法对象的创建而存在,随着对象的创建完毕等待垃圾回收器回收而消失
容器-------->数组---->长度固定(弊端)
	--->StringBuffer--->字符串缓冲区中存储各种字符序列,它长度可变,但是stringBuffer使用完毕等待回收
	--->集合---->长度可变,它可以存储任意引用类型数据,使用完毕---->也要被回收掉
	--->Io流---->永久存储,但是IO流的太耗时了
数据库存储数据特点--->
	1)存储空间非常大,可以存储百万条,千万条甚至上亿条数据,用户可以对数据库中数据进行新增,查询,更新,删除等操作
	2)数据独立性高
	3)实现数据共享
	4)减少数据的冗余度
	5)通过数据库里面"事务"--->实现数据的一致性以及维护性!

3.2市面上常见的数据库

数据库分为两大类:
	关系型数据库:Mysql,SqlServer,Oracle
		SqlServer,Oracle:收费
		Oracle:中大型公司使用居多
		Mysql:免费产品,中小型公司使用居多
	非关系型数据库:Redis,Memcache,MongoDb,Hbase	

3.3安装与卸载

3.4使用DOS窗口登录启动mysql

使用管理员打开命令提示符:
开启mysql: net start mysql;
关闭mysql: net stop mysql;

3.5DDL语句的基础语法

DDL语句:数据库定义语句 库和表的基本操作
3.5.1库的操作
1.查询所有库:show databases;
2.创建库的语法
	2.1 create database if not exists 库名; 如果没有这个库则创建该库
	2.2 create database 库名;
3.查看指定库的字符集格式
	show create database 库名;
4.修改库的字符集
	alter database 库名 default(可以省略) character set 字符集格式;
5.删除库
	5.1 drop database if exists 库名; 如果有该库则直接删除
	5.2 drop database 库名; 直接删除
6.使用库 
	use 库名;
3.5.2表的操作
1.创建表的语法
	create table 表名(
		字段名称1 字段类型1,
		字段名称2 字段类型2,
		字段名称3 字段类型3,
		.....
		字段名称n 字段类型n,
	);
2.查询表的结构
	desc 表名;
3.修改表的字段类型
	alter table 表名 modify 字段名称 修改后的字段类型; -- 修改字段类型
	alter table 表名 change 以前的字段名称 修改后的字段名称 字段类型;-- 修改字段名称
4.修改表
	alter table 表名 add 字段名称 字段类型; 添加表的字段
	alter table 表名 drop 字段名称; 删除表中某个字段
	alter table 表名 rename to 新表名; 修改表名
	rename table 表名 to 新表名; 修改表名
5.查看表的字符集
	show create table 表名;
6.修改表的字符集
	alter table 表名 character set 字符集格式;
7.复制表---快速去创建一个结构相同的表
	create table 新表名 like 表名;
	复制表的全数据
	CREATE TABLE 新表名 
	AS 
	SELECT * FROM 表名;
8.删除表
	drop table if exists 表名;如果存在删除表
	drop table 表名;

3.6DML语句:数据库操作语句

3.6.1操作表的记录—插入,修改,删除,查询…
1.插入数据,没插入的值为null
	插入一行:insert into 表名 values(1,2...);
	插入多行:insert into 表名 values(1,2...),values(1,2...)..;
	插入一行部分字段:insert into 表名(字段名称1,字段名称2.,等部分字段)values(1,2,3...);
	插入多行多条数据,部分字段:insert into 表名(字段名称1,字段名称2.,等部分字段)values(1,2,3...),(1,2,3...),(...);
2.修改数据
	一次修改一个数据: update 表名 set 字段名称=where 字段名称=;
	一次修改多个数据: update 表名 set 字段名称=1,字段名称=2,.. where 字段名称=;
3.删除表的记录
	带条件删除
		delete from 表名 where 字段名称 =;
    	delete from 表名 where 字段名称1 =1 and 字段名称1 =1 ...;
    删除全表数据
		方式一:delete from 表名; 只删除 全表数据,表结构还在
		方式二:truncate table 表名; 连表结构删除
4.表的查询
	基本查询:
		1.查询全表:select 全部字段名称 from表名; 使用 select * from 表名;
		查询指定字段并给别名:select id as  '编号',name '姓名' from 表名;
		查询指定字段去重:select distinct 字段 from 表名;
		2.带条件查询
			2.1where 比较运算符 <=,>=,<,>,!=(在mysql使用 <>)
					and  && /or  ||
					between1 and21:查询年龄是20的学生的编号,姓名,年龄,住址信息
			SELECT id '编号',NAME '姓名',age '年龄',address '住址' FROM student2 WHERE age = 20 ;2:查询年龄在1820岁之间学生的所有信息
		方式一:SELECT *FROM student2 WHERE age >=18 && age<=20;
		方式二:SELECT * FROM student2 WHERE age >=18 AND age<=20;	
		方式三:SELECT * FROM student2 WHERE age BETWEEN 18 AND 20;
			2.2where 模糊条件 like关键字
				语句格式:select 字段列表 from 表名 where 字段名称 like '%xx%';
				%:表示任意字符
				_:表示一字符
			2.3排序查询 order by,升序是asc,降序是desc
				单独使用语法:select 字段列表 from 表名 order by 字段名称 排序规则;where语句使用时先满足where条件,在排序
				语法:select 字段列表 from 表名 where 条件 order by 字段名称 排序规则,字段名称2 排序规则2;
			2.4聚合函数查询  结果是单行单列,可以sql语句嵌套
				count():统计表的数据,如果字段为空不会统计
				语法:select count(字段名称) from 表名;
				max(列名称):最大值
				语法:select max(列名称) from 表名;
				min(列名称):最小值
				语句:select min(列名称) from 表名;
				avg(列名称):平均值
				语句:select avg(列名称) from 表名;
				sum(列名称);求和
				语句:select sum(列名称) from 表名;
			2.5分组查询:group by 
				语句:select 字段列表 from 表名 group by 分组的字段名称;
				注意:分组查询里面可以select 查询分组字段 
	    			分组group by后面不能使用聚合函数
	    			where条件和group by,where条件在group by前面;先满足where条件在参与分组
			2.6筛选查询:having
				having的后面可以跟聚合函数,havinggroup by后面,wheregroup by前面
			2.7分页查询:limit wherelimit前面
				方式一;select 字段列表 from 表名 limit 起始行数,每页显示的条数;
				方式二:select 字段列表 from 表名 limit;
				复合查询:有where条件,还有limit,wherelimit前面
				起始行数= (当前页码数-1)*每页显示的条数;	

3.7mysql常见的几种数据类型

int,int(int类型的字符数)
	int:默认11位,
	int(int类型的字符数):int(3):  1---->001
varchar(字符长度):字符串类型
	姓名  varchar(20)---->最大取到20
	在mysql中字符串写的时候可以使用双引号也可以是单引号
date:日期类型--->仅仅表示日期
datetime:日期+时间
timestap:时间戳-->当前插入数据或者修改/删除数据的即时时间
double:小数类型
	double(3,2): 小数是3位数,小数点后保留2位
clob:大字符类型,某个表中某个字段--->使用clob来存储大文本
blob:答字节类型:存储大图片文件---大字节类型

3.8约束

约束:约束用户操作数据库的一种行为

3.8.1默认约束 default
特点:当没有插入这个字段,默认约束起作用
添加默认约束
	创建表时:字段名称 字段类型 default '默认'
	sql语句:alter table 表名 modify 字段名称 字段类型 default '默认';
删除默认约束:修改字段的类型
	alter table 表名 modify 字段名称 修改后的字段类型;
3.8.2非空约束 not null
特点:当前这个值不能为null,不能直接添加数据给一个null
添加非空约束:
	创建表的时候在指定字段后面加入not null
	sql语句:alter table 表名 modify 字段名称 字段类型 not null;
除非空约束:修改字段的类型
	alter table 表名 modify 字段名称 修改后的字段类型;
3.8.3唯一约束 unique
特点:当前值不能为空
添加唯一约束:constraint(声明) 
	创建表的时候在指定字段后面加入 unique
	sql语句:alter table 表名 add constraint 唯一约束索引名称 unique(列名);
删除:
	alter table 表名 drop index 索引名(没给就是默认列的名称)
3.8.4主键约束 primary key
特点:非空且唯一
添加:
	创建表的时候在指定字段后面加入 primary key
	sql语句:alter table 表名 add primary key(列名称);
删除:
	alter table 表名 drop primary key; 
3.8.5自增长约束 auto_increment
特点:一般自增长约束都是在主键字段上,保证唯一
	指定插入数据的值,下次在之前的值上继续自增1.
ysql自带函数---查找数据库表中最后一次自增主键的值
	select last_insert_id();
添加:
	创建表时添加
注意:指定插入id值时会自增,修改后的值不会自增.
3.8.6外键约束 foreign key
特点:外键作用的表是从表,另一张表是主表.
添加:
	创建表时添加:
		constraint -- 声明
		外键名 --起名  主表名_从表名_fk
		foreign key(从表的字段名称)
		references -- 关联
		主表名(主键字段的名称)
	sql语句添加:
		alter table 表名 add constraint 外键名 foreign key(从表的字段名称) references 主表名(主键字段名称);
删除:
	有外键时直接修改或者删除主表数据,前提需要让从表的数据跟主表没有关联,才可以删除该表
	sql删除:
		alter table 表名 drop foreign key 外键名
3.8.7级联操作 cascade
特点:当修改/删除主表的数据,从表数据随之改动
	级联删除/级联修改 on delete cascade /on update cascade
添加:
	创建表示添加:
		constraint -- 声明
		外键名 -- 起名  主表名_从表名_fk
		foreign key(从表的字段名称)
		references -- 关联
		主表名(主键字段的名称)
		on update cascade
		on delete cascade
	sql语句添加:
		alter table 表名 add constraint 外键名 foreign key(从表的字段名称) references 主表名(主键字段名称) on update cascade on delete cascade;

3.9数据库表的关系问题—三大范式

3.9.1表与表之间的关系
表与表的关系关系的维护
一对多主外键的关系
多对多中间表,两个一对多
一对一特殊一对多,从表中的外键设置为唯一,从表中的主键又是外键
3.9.2三大范式
什么是范式:
	好的数据库设计对数据的存储性能和后期的程序开发,都会产生重要的影响。建立科学的,规范的数据库就需
要满足一些规则来优化数据的设计和存储,这些规则就称为范式。
第一范式(1NF):
	数据库表的每一列都是不可分割的原子数据项,不能是集合、数组等非原子数据项。即表中的某个列有多个值
时,必须拆分为不同的列。简而言之,第一范式每一列不可再拆分,称为原子性。
第二范式(2NF):
	在满足第一范式的前提下,表中的每一个字段都完全依赖于主键。
	特点:1.一张表只能描述一件事情.
	    2.表中的每一列都完全依赖于主键
第三范式(3NF):
	在满足第二范式的前提下,表中的每一列都直接依赖于主键,而不是通过其它的列来间接依赖于主键。

范式特点
1NF原子性
2NF不产生局部依赖,一张表只描述一件事情
3NF不产生传递依赖,表中每一列都直接依赖于主键.而不是通过其他列间接依赖于主键

3.10多表查询

笛卡尔乘积:
	针对A表的记录和B表的记录数,两个表的记录相乘.
内连接:
	隐式内连接:where条件
		语句格式:select 字段列表 from 表名1,表名2,..表名n where 表之间的连接条件;
	显示内连接:inner join
		语句格式:select 字段列表 from 表名1 inner join 表名2 in 连接条件;
外连接:
	左外连接:将A表(左表)的和B表(右表)的交集以及A表(左表)中所有数据全部查询!
		语句格式:select 字段列表 from 左表名 left join 表名2 on 连接条件;
子查询:select 嵌套 select
	情况1:使用where后面条件表达式=,<=,>=..
	例:查询员工工资最高的员工信息以及他的部门信息
SELECT 
  e.*,
  d.name '部门名称' 
FROM
  employee e,
  dept d 
WHERE e.dept_id = d.id 
  AND e.salary = 
  (SELECT 
    MAX(salary) 
  FROM
    employee) ;
	情况2:利用in集合语句 
	例:查询在"市场部"和销售部的员工信息
SELECT 
  e.*,
  d.name '部门名称' 
FROM
  employee e,
  dept d 
WHERE e.dept_id = d.id 
  AND e.dept_id IN 
  (SELECT 
    id dept 
  WHERE NAME = '市场部' 
    OR NAME '销售部') ;
	情况3:通过两个表的关系--查询出结果集--当做'虚表'在和其他表之间关联查询
	例:查询入职日期大于"2021-11-11"后入职的员工信息以及部门名称信息
SELECT 
  t.name '员工姓名',
  t.join_date '入职日期',
  d.`name` '部门名称' 
FROM
  (SELECT 
    * 
  FROM
    employee e 
  WHERE e.`join_date` > '2021-11-11') t LEFT JOIN 
  dept d 
 ON  t.dept_id = d.id ;

3.11数据库的事务/事务的特点/事务的隔离级别

3.11.1数据库事务
数据库事务(Transaction):在一个业务中执行多个sql(多张表的sql),这多个语句要么同时执行成功,要么同事执行失败.
	举例: 转账操作 一个转账,一个收款
	      提交订单
	          订单表和订单项 同时添加数据
mysql中如何管理事务-- 单独执行这些指令
			start transaction 开启事务
			rollback 回滚到操作sql之前的状态
			commit 事务不提交,数据只是临时提交,数据无法永久更新
-- 查询级别
SELECT @@tx_isolation;
-- 更改级别 
set global transaction isolation level 级别名;			
3.11.2事务特点
    ACID : 关系型数据库传统事务
    原子性:在使用事务管理的时候,执行多个sql增删改,要么同时执行成功,要么同时执行失败
    一致性:高并发的时候,需要保证事务多次读写,保证数据一致性
    隔离性:事务和事务是独立的,相互不影响
    持久性:事务一旦提交,对数据的影响是永久的,即使关机了,数据还是要更新
3.11.3事务的隔离级别
四个级别:从大到小,安全性:从低到高,效率性:从高到低
    read uncommitted :读未提交  会造成问题'脏读'
	'脏读':是事务管理最严重的问题,一个事务读取到另一个没有提交的事务
    
    read committed :读已提交 有效防止脏读,出现了一个问题 '不可重复读'
	事务多次读取数据不一致
	
    repeatable read :可重复读(默认),防止脏读,不可重复读,会出现幻读(有更新操作影响)
	
    serializable : 串行话 
	一个事务读取到另一个没提交事务,数据查不到,必须将其提交,才能操作数据
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值