多线程与MySQL(十)
1.1 多线程
在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程
线程顾名思义,就是一条流水线工作的过程,一条流水线必须属于一个车间,一个车间的工作过程是一个进程
车间负责把资源整合到一起,是一个资源单位,而一个车间内至少有一个流水线
流水线的工作需要电源,电源就相当于cpu
所以,进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合),而线程才是cpu上的执行单位。
多线程(即多个控制线程)的概念是,在一个进程中存在多个控制线程,多个控制线程共享该进程的地址空间,相当于一个车间内有多条流水线,都共用一个车间的资源。
例如,北京地铁与上海地铁是不同的进程,而北京地铁里的13号线是一个线程,北京地铁所有的线路共享北京地铁所有的资源,比如所有的乘客可以被所有线路拉。
l 创建进程的开销要远大于线程?
如果我们的软件是一个工厂,该工厂有多条流水线,流水线工作需要电源,电源只有一个即cpu(单核cpu),一个车间就是一个进程,一个车间至少一条流水线(一个进程至少一个线程),创建一个进程,就是创建一个车间(申请空间,在该空间内建至少一条流水线),而建线程,就只是在一个车间内造一条流水线,无需申请空间,所以创建开销小
l 进程之间是竞争关系,线程之间是协作关系?
车间直接是竞争/抢电源的关系,竞争(不同的进程直接是竞争关系,是不同的程序员写的程序运行的,迅雷抢占其他进程的网速,360把其他进程当做病毒干死),一个车间的不同流水线式协同工作的关系(同一个进程的线程之间是合作关系,是同一个程序写的程序内开启动,迅雷内的线程是合作关系,不会自己干自己)
1.1.1 为何要用多线程
多线程指的是,在一个进程中开启多个线程,简单的讲:如果多个任务共用一块地址空间,那么必须在一个进程内开启多个线程。详细的讲分为4点:
1. 多线程共享一个进程的地址空间
2. 线程比进程更轻量级,线程比进程更容易创建可撤销,在许多操作系统中,创建一个线程比创建一个进程要快10-100倍,在有大量线程需要动态和快速修改时,这一特性很有用
3. 若多个线程都是cpu密集型的,那么并不能获得性能上的增强,但是如果存在大量的计算和大量的I/O处理,拥有多个线程允许这些活动彼此重叠运行,从而会加快程序执行的速度。
4. 在多cpu系统中,为了最大限度的利用多核,可以开启多个线程,比开进程开销要小的多。(这一条并不适用于python)
1.2 死锁现象与递归锁
进程也有死锁与递归锁。
所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
递归锁,在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock,
这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的例子如果使用RLock代替Lock,则不会发生死锁:
from threading import Thread,Lock,RLock import time # mutexA=Lock() # mutexB=Lock() mutexA=mutexB=RLock() #一个线程拿到锁,counter加1,该线程内又碰到加锁的情况,则counter继续加1,这期间所有其他线程都只能等待,等待该线程释放所有锁,即counter递减到0为止 class MyThread(Thread): def run(self): self.f1() self.f2() def f1(self): mutexA.acquire() print('%s 拿到了A锁' %self.name) mutexB.acquire() print('%s 拿到了B锁' % self.name) mutexB.release() #1 mutexA.release() #0 def f2(self): mutexB.acquire() print('%s 拿到了B锁' % self.name) time.sleep(0.1) mutexA.acquire() print('%s 拿到了A锁' % self.name) mutexA.release() mutexB.release() if __name__ == '__main__': for i in range(10): t=MyThread() t.start()
1.3 信号量Semaphore
同进程的一样,Semaphore管理一个内置的计数器,每当调用acquire()时内置计数器-1;调用release() 时内置计数器+1;计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其他线程调用release()。
实例:(同时只有5个线程可以获得semaphore,即可以限制最大连接数为5):
from threading import Thread,Semaphore,current_thread import time,random sm=Semaphore(5) def task(): with sm: print('%s is laing' %current_thread().getName()) time.sleep(random.randint(1,3)) if __name__ == '__main__': for i in range(20): t=Thread(target=task) t.start()
与进程池是完全不同的概念,进程池Pool(4),最大只能产生4个进程,而且从头到尾都只是这四个进程,不会产生新的,而信号量是产生一堆线程/进程
1.4 Event事件
同进程的一样,线程的一个关键特性是每个线程都是独立运行且状态不可预测。如果程序中的其 他线程需要通过判断某个线程的状态来确定自己下一步的操作,这时线程同步问题就会变得非常棘手。为了解决这些问题,我们需要使用threading库中的Event对象。 对象包含一个可由线程设置的信号标志,它允许线程等待某些事件的发生。在 初始情况下,Event对象中的信号标志被设置为假。如果有线程等待一个Event对象, 而这个Event对象的标志为假,那么这个线程将会被一直阻塞直至该标志为真。一个线程如果将一个Event对象的信号标志设置为真,它将唤醒所有等待这个Event对象的线程。如果一个线程等待一个已经被设置为真的Event对象,那么它将忽略这个事件, 继续执行
event.isSet():返回event的状态值; event.wait():如果 event.isSet()==False将阻塞线程; event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度; event.clear():恢复event的状态值为False。
例如,有多个工作线程尝试链接MySQL,我们想要在链接前确保MySQL服务正常才让那些工作线程去连接MySQL服务器,如果连接不成功,都会去尝试重新连接。那么我们就可以采用threading.Event机制来协调各个工作线程的连接操作
from threading import Thread,Event,current_thread import time event=Event() def check(): print('checking MySQL...') time.sleep(5) event.set() def conn(): count=1 while not event.is_set(): if count > 3: raise TimeoutError('超时') print('%s try to connect MySQL time %s' %(current_thread().getName(),count)) event.wait(1) count+=1 print('%s connected MySQL' %current_thread().getName()) if __name__ == '__main__': t1=Thread(target=check) t2=Thread(target=conn) t3=Thread(target=conn) t4=Thread(target=conn) t1.start() t2.start() t3.start() t4.start()
1.5 定时器
定时器,指定n秒后执行某操作
from threading import Timer def hello(name): print("hello, world %s " %name) t = Timer(3, hello,args=('egon',)) t.start() # after 1 seconds, "hello, world" will be printed
1.6 线程queue
queue队列 :使用import queue,用法与进程Queue一样
import queue q=queue.Queue(3) #队列:先进先出 q.put(1) q.put(2) q.put(3) # q.put(4) # q.put_nowait(4) # q.put(4,block=False) q.put(4,block=True,timeout=3) # print(q.get()) # print(q.get()) # print(q.get()) q=queue.LifoQueue(3) #堆栈:后进先出 q.put(1) q.put(2) q.put(3) print(q.get()) print(q.get()) print(q.get()) q=queue.PriorityQueue(3) #优先级队列 q.put((10,'a')) q.put((-3,'b')) q.put((100,'c')) print(q.get()) print(q.get()) print(q.get())
1.7 进程池线程池
#提交任务的两种方式:
#同步调用:提交完任务后,就在原地等待,等待任务执行完毕,拿到任务的返回值,才能继续下一行代码,导致程序串行执行
#异步调用+回调机制:提交完任务后,不在原地等待,任务一旦执行完毕就会触发回调函数的执行, 程序是并发执行
#进程的执行状态:
#阻塞
#非阻塞
1.7.1 同步调用示例:
# from multiprocessing import Pool
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor import time,random,os def task(n): print('%s is ruuning' %os.getpid()) time.sleep(random.randint(1,3)) return n**2 def handle(res): print('handle res %s' %res) if __name__ == '__main__': #同步调用 pool=ProcessPoolExecutor(2) for i in range(5): res=pool.submit(task,i).result() # print(res) handle(res) pool.shutdown(wait=True) # pool.submit(task,33333) print('主')
1.7.2 异步调用示例:
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor import time,random,os def task(n): print('%s is ruuning' %os.getpid()) time.sleep(random.randint(1,3)) # res=n**2 # handle(res) return n**2 def handle(res): res=res.result() print('handle res %s' %res) if __name__ == '__main__': #异步调用 pool=ProcessPoolExecutor(2) for i in range(5): obj=pool.submit(task,i) obj.add_done_callback(handle) #handle(obj) pool.shutdown(wait=True) print('主')
1.7.3 线程池
from concurrent.futures import ThreadPoolExecutor from threading import current_thread import requests import time def get(url): print('%s GET %s' %(current_thread().getName(),url)) response=requests.get(url) time.sleep(2) if response.status_code == 200: return {'url':url,'content':response.text} def parse(res): res=res.result() print('parse:[%s] res:[%s]' %(res['url'],len(res['content']))) if __name__ == '__main__': pool=ThreadPoolExecutor(2) urls=[ 'https://www.baidu.com', 'https://www.python.org', 'https://www.openstack.org', 'https://www.openstack.org', 'https://www.openstack.org', 'https://www.openstack.org', 'https://www.openstack.org', 'https://www.openstack.org', 'https://www.openstack.org', 'https://www.openstack.org', 'https://www.openstack.org', 'https://www.openstack.org', ] for url in urls: pool.submit(get,url).add_done_callback(parse) pool.shutdown(wait=True)
1.8 协程
单纯地切换反而会降低运行效率
协程:是单线程下的并发,又称微线程,纤程。英文名Coroutine。一句话说明什么是线程:协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的。
总结协程特点:
必须在只有一个单线程里实现并发
修改共享数据不需加锁
用户程序里自己保存多个控制流的上下文栈
附加:一个协程遇到IO操作自动切换到其它协程(如何实现检测IO,yield、greenlet都无法实现,就用到了gevent模块(select机制))
1.8.1 串行执行
import time def consumer(res): '''任务1:接收数据,处理数据''' pass def producer(): '''任务2:生产数据''' res=[] for i in range(10000000): res.append(i) return res start=time.time() #串行执行 res=producer() consumer(res) stop=time.time() print(stop-start)
1.8.2 基于yield并发执行
import time def consumer(): '''任务1:接收数据,处理数据''' while True: print('consumer') x=yield time.sleep(100) def producer(): '''任务2:生产数据''' g=consumer() next(g) for i in range(10000000): print('producer') g.send(i) start=time.time() #基于yield保存状态,实现两个任务直接来回切换,即并发的效果 #PS:如果每个任务中都加上打印,那么明显地看到两个任务的打印是你一次我一次,即并发执行的. producer() stop=time.time() print(stop-start) #
1.9 greenlet模块
如果我们在单个线程内有20个任务,要想实现在多个任务之间切换,使用yield生成器的方式过于麻烦(需要先得到初始化一次的生成器,然后再调用send。。。非常麻烦),而使用greenlet模块可以非常简单地实现这20个任务直接的切换
安装模块
pip3 install greenlet
from greenlet import greenlet import time def eat(name): print('%s eat 1' %name) time.sleep(1000) g2.switch('egon') print('%s eat 2' %name) g2.switch() def play(name): print('%s play 1' % name) g1.switch() #可以在第一次switch时传入参数,以后都不需要 print('%s play 2' % name) g1=greenlet(eat) g2=greenlet(play)
greenlet只是提供了一种比generator更加便捷的切换方式,当切到一个任务执行时如果遇到io,那就原地阻塞,仍然是没有解决遇到IO自动切换来提升效率的问题。
单线程里的这20个任务的代码通常会既有计算操作又有阻塞操作,我们完全可以在执行任务1时遇到阻塞,就利用阻塞的时间去执行任务2。。。。如此,才能提高效率,这就用到了Gevent模块。
1.10 gevent模块
Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是Greenlet, 它是以C扩展模块形式接入Python的轻量级协程。 Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度。
#用法
g1=gevent.spawn(func,1,,2,3,x=4,y=5)创建一个协程对象g1,spawn括号内第一个参数是函数名,如eat,后面可以有多个参数,可以是位置实参或关键字实参,都是传给函数eat的 g2=gevent.spawn(func2) g1.join() #等待g1结束 g2.join() #等待g2结束 #或者上述两步合作一步:gevent.joinall([g1,g2]) g1.value#拿到func1的返回值
from gevent import monkey;monkey.patch_all() import gevent import time def eat(name): print('%s eat 1' %name) # gevent.sleep(3) time.sleep(3) print('%s eat 2' %name) def play(name): print('%s play 1' % name) # gevent.sleep(2) time.sleep(3) print('%s play 2' % name) g1=gevent.spawn(eat,'egon') g2=gevent.spawn(play,'alex') # gevent.sleep(1) # g1.join() # g2.join() gevent.joinall([g1,g2])
练习
通过gevent实现单线程下的socket并发(from gevent import monkey;monkey.patch_all()一定要放到导入socket模块之前,否则gevent无法识别socket的阻塞)
服务端
from gevent import monkey,spawn;monkey.patch_all() from threading import current_thread from socket import * def comunicate(conn): print('子线程:%s' %current_thread().getName()) while True: try: data=conn.recv(1024) if not data:break conn.send(data.upper()) except ConnectionResetError: break conn.close() def server(ip,port): print('主线程:%s' %current_thread().getName()) server = socket(AF_INET, SOCK_STREAM) server.bind((ip,port)) server.listen(5) while True: conn, addr = server.accept() print(addr) # comunicate(conn) # t=Thread(target=comunicate,args=(conn,)) # t.start() spawn(comunicate,conn) server.close() if __name__ == '__main__': g=spawn(server,'127.0.0.1', 8081) g.join()
客户端
多线程并发多个客户端
from socket import * from threading import current_thread,Thread def client(): client=socket(AF_INET,SOCK_STREAM) client.connect(('127.0.0.1',8081)) while True: client.send(('%s say hello' %current_thread().getName()).encode('utf-8')) data=client.recv(1024) print(data.decode('utf-8')) client.close() if __name__ == '__main__': for i in range(500): t=Thread(target=client) t.start()
1.11 MySQL数据库相关概念
MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下公司。MySQL 最流行的关系型数据库管理系统,在 WEB 应用方面MySQL是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件之一。
1、数据库服务器:计算机
2、数据库管理软件:MySQL
3、数据库/库:文件夹
4、表:文件
5、记录:一个事物的一系列典型的特征:egon,male,18,oldgirl
6、数据:事物的特征,sex='male'
1.11.1 mysql是什么
#mysql就是一个基于socket编写的C/S架构的软件
#客户端软件
mysql自带:如mysql命令,mysqldump命令等
python模块:如pymysql
1.11.2 数据库管理软件分类
#分两大类:
关系型:如sqllite,db2,oracle,access,sql server,MySQL,注意:sql语句通用
非关系型:mongodb,redis,memcache
#可以简单的理解为:
关系型数据库需要有表结构
非关系型数据库是key-value存储的,没有表结构
1.11.3 下载安装
1.11.3.1 Linux版本
一、二进制rpm包安装
yum -y install mysql-server mysql
二、源码安装
1.解压tar包
cd /software tar -xzvf mysql-5.6.21-linux-glibc2.5-x86_64.tar.gz mv mysql-5.6.21-linux-glibc2.5-x86_64 mysql-5.6.21
2.添加用户与组
groupadd mysql useradd -r -g mysql mysql chown -R mysql:mysql mysql-5.6.21
3.安装数据库
su mysql cd mysql-5.6.21/scripts ./mysql_install_db --user=mysql --basedir=/software/mysql-5.6.21 --datadir=/software/mysql-5.6.21/data
4.配置文件
cd /software/mysql-5.6.21/support-files cp my-default.cnf /etc/my.cnf cp mysql.server /etc/init.d/mysql vim /etc/init.d/mysql #若mysql的安装目录是/usr/local/mysql,则可省略此步 修改文件中的两个变更值 basedir=/software/mysql-5.6.21 datadir=/software/mysql-5.6.21/data
5.配置环境变量
vim /etc/profile export MYSQL_HOME="/software/mysql-5.6.21" export PATH="$PATH:$MYSQL_HOME/bin" source /etc/profile
6.添加自启动服务
chkconfig --add mysql chkconfig mysql on
7.启动mysql
service mysql start
8.登录mysql及改密码与配置远程访问
mysqladmin -u root password 'your_password' #修改root用户密码 mysql -u root -p #登录mysql,需要输入密码 mysql>GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'your_password' WITH GRANT OPTION; #允许root用户远程访问 mysql>FLUSH PRIVILEGES; #刷新权限
三、源码安装mariadb
1. 解压
tar zxvf mariadb-5.5.31-linux-x86_64.tar.gz mv mariadb-5.5.31-linux-x86_64 /usr/local/mysql //必需这样,很多脚本或可执行程序都会直接访问这个目录
2. 权限
groupadd mysql //增加 mysql 属组 useradd -g mysql mysql //增加 mysql 用户 并归于mysql 属组 chown mysql:mysql -Rf /usr/local/mysql // 设置 mysql 目录的用户及用户组归属。 chmod +x -Rf /usr/local/mysql //赐予可执行权限
3. 拷贝配置文件
cp /usr/local/mysql/support-files/my-medium.cnf /etc/my.cnf //复制默认mysql配置 文件到/etc目录
4. 初始化
/usr/local/mysql/scripts/mysql_install_db --user=mysql //初始化数据库 cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysql //复制mysql服务程序 到系统目录 chkconfig mysql on //添加mysql 至系统服务并设置为开机启动 service mysql start //启动mysql
5. 环境变量配置
vim /etc/profile //编辑profile,将mysql的可执行路径加入系统PATH export PATH=/usr/local/mysql/bin:$PATH source /etc/profile //使PATH生效。
6. 账号密码
mysqladmin -u root password 'yourpassword' //设定root账号及密码 mysql -u root -p //使用root用户登录mysql use mysql //切换至mysql数据库。 select user,host,password from user; //查看系统权限 drop user ''@'localhost'; //删除不安全的账户 drop user root@'::1'; drop user root@127.0.0.1; select user,host,password from user; //再次查看系统权限,确保不安全的账户均被删除。 flush privileges; //刷新权限
7. 一些必要的初始配置
1)修改字符集为UTF8
vi /etc/my.cnf 在[client]下面添加 default-character-set = utf8 在[mysqld]下面添加 character_set_server = utf8
2)增加错误日志
vi /etc/my.cnf 在[mysqld]下面添加: log-error = /usr/local/mysql/log/error.log general-log-file = /usr/local/mysql/log/mysql.log 3) 设置为不区分大小写,linux下默认会区分大小写。 vi /etc/my.cnf 在[mysqld]下面添加: lower_case_table_name=1
修改完重启:
service mysql restart
1.11.3.2 Window版本
安装
#1、下载:MySQL Community Server 5.7.16
http://dev.mysql.com/downloads/mysql/
#2、解压
如果想要让MySQL安装在指定目录,那么就将解压后的文件夹移动到指定目录,如:C:\mysql-5.7.16-winx64
#3、添加环境变量
【右键计算机】--》【属性】--》【高级系统设置】--》【高级】--》【环境变量】--》【在第二个内容框中找到 变量名为Path 的一行,双击】 --> 【将MySQL的bin目录路径追加到变值值中,用 ; 分割】
#4、初始化
mysqld --initialize-insecure
#5、启动MySQL服务
mysqld # 启动MySQL服务
#6、启动MySQL客户端并连接MySQL服务
mysql -u root -p # 连接MySQL服务器
将MySQL服务制作成windows服务
上一步解决了一些问题,但不够彻底,因为在执行【mysqd】启动MySQL服务器时,当前终端会被hang住,那么做一下设置即可解决此问题:
注意:--install前,必须用mysql启动命令的绝对路径
# 制作MySQL的Windows服务,在终端执行此命令:
"c:\mysql-5.7.16-winx64\bin\mysqld" --install
# 移除MySQL的Windows服务,在终端执行此命令:
"c:\mysql-5.7.16-winx64\bin\mysqld" --remove
注册成服务之后,以后再启动和关闭MySQL服务时,仅需执行如下命令:
# 启动MySQL服务
net start mysql
# 关闭MySQL服务
net stop mysql
1.12 重置密码
1.12.1 设置密码
C:\Users\Administrator> mysqladmin -uroot -p password "123"
1.12.2 重置密码
net stop MySQL mysqld --skip-grant-tables mysql -uroot -p update mysql.user set password=password("") where user='root' and host="localhost"; flush privileges; C:\Users\Administrator>tasklist |findstr mysql mysqld.exe 6316 Console 1 454,544 K C:\Users\Administrator>taskkill /F /PID 6316 成功: 已终止 PID 为 6316 的进程。 C:\Users\Administrator>net start MySQL MySQL 服务正在启动 . MySQL 服务已经启动成功。
1.13 统一字符编码
#1. 修改配置文件
[mysqld] default-character-set=utf8 [client] default-character-set=utf8 [mysql] default-character-set=utf8 #mysql5.5以上:修改方式有所改动 [mysqld] character-set-server=utf8 collation-server=utf8_general_ci [client] default-character-set=utf8 [mysql] default-character-set=utf8
#2. 重启服务
#3. 查看修改结果:
mysql> \s show variables like '%char%'
1.14 初识SQL
有了mysql这个数据库软件,就可以将程序员从对数据的管理中解脱出来,专注于对程序逻辑的编写
mysql服务端软件即mysqld帮我们管理好文件夹以及文件,前提是作为使用者的我们,需要下载mysql的客户端,或者其他模块来连接到mysqld,然后使用mysql软件规定的语法格式去提交自己命令,实现对文件夹或文件的管理。该语法即sql(Structured Query Language 即结构化查询语言)
SQL语言主要用于存取数据、查询数据、更新数据和管理关系数据库系统,SQL语言由IBM开发。SQL语言分为3种类型:
#1、DDL语句 数据库定义语言: 数据库、表、视图、索引、存储过程,例如CREATE DROP ALTER
#2、DML语句 数据库操纵语言: 插入数据INSERT、删除数据DELETE、更新数据UPDATE、查询数据SELECT
#3、DCL语句 数据库控制语言: 例如控制用户的访问权限GRANT、REVOKE
1.14.1 操作文件夹(库)
1.14.1.1 增
create database db1 charset utf8;
1.14.1.2 查
show databases; show create database db1;
1.14.1.3 改
alter database db1 charset gbk;
1.14.1.4 删
drop database db1;
1.14.2 操作文件(表)
1.14.2.1 查看当前所在的文件夹:
select database();
1.14.2.2 切换文件夹:
use db1;
1.14.2.3 增
create table t1(id int,name char);
1.14.2.4 查
show tables; show create table t1; desc t1;
1.14.2.5 改
alter table t1 add sex char; alter table t1 drop sex; alter table t1 modify name char(16); alter table t1 change name Name char(13);
1.14.2.6 删
drop table t1;
1.14.3 操作文件的内容(记录)
1.14.3.1 增
insert into db1.t1 values (1,'egon'), (2,'alex'), (3,'wxx');
1.14.3.2 查
select id,name from db1.t1; select * from db1.t1;
1.14.3.3 改
update t1 set name='SB' where id=2;
1.14.3.4 删
delete from t1 where id=2;
1.15 存储引擎
储引擎即表类型,mysql根据不同的表类型会有不同的处理机制
查看引擎
show engines;
创建引擎
create table t1(id int)engine=innodb; create table t2(id int)engine=myisam; create table t3(id int)engine=memory; create table t4(id int)engine=blackhole;
1.16 数值类型
1.16.1 整型(默认有符号)
create table t8(n tinyint); insert into t8 values(-1); insert into t8 values(128); insert into t8 values(-129); create table t9(n tinyint unsigned); insert into t9 values(-1),(256);
#整型的宽度代表显示宽度
create table t11(n int(3) unsigned zerofill); create table t12(n int unsigned zerofill); create table t13( id int );
1.16.2 浮点型
create table t13(x float(255,30)); create table t14(x double(255,30)); create table t15(x decimal(65,30)); insert into t13 values(1.111111111111111111111111111111); insert into t14 values(1.111111111111111111111111111111); insert into t15 values(1.111111111111111111111111111111);
1.17 日期类型
create table student( id int, name char(16), born_year year, birth_date date, class_time time, reg_time datetime ); insert into student values (1,'egon',now(),now(),now(),now()) ; insert into student values (2,'alex','1999','1999-11-11','11:11:11',"1999-11-11 11:11:11")
1.18 字符类型
char:定长
varchar:变长
#宽度代表的是字符的个数
create table t16(name char(5)); create table t17(name varchar(5)); insert into t16 values('李杰 '); #'李杰 ' insert into t17 values('李杰 '); #'李杰 ' select char_length(name) from t16; #5 select char_length(name) from t17; #3 mysql> set sql_mode='PAD_CHAR_TO_FULL_LENGTH'; select * from t16 where name='李杰'; select * from t17 where name='李杰'; select * from t16 where name like '李杰'; name char(5) egon |alex |wxx | name varchar(5) 1bytes+egon|1bytes+alex|1bytes+wxx|
1.19 枚举类型与集合类型
create table employee( id int, name char(10), sex enum('male','female','other'), hobbies set('play','eat','music','read') ); insert into employee values (1,'egon','male','music,read'); insert into employee values (2,'alex','xxxx','music,read');
上一篇: JS排序算法之冒泡排序,选择排序与插入排序实例分析
下一篇: 兰陵王为什么要总戴着面具?真相是什么