1.关系型数据库
Oracle 收费
Mysql 开源 被oracle收购了
SqlServer 微软
DB2 IBM
Postgresql
Sqlite 轻量级
access 轻量级
2.基本sql操作就不写了 看博客
(1)讲下外键:
建立外键 外键约束
KEY ‘key_name’(‘class_id’), CONSTRAINT ‘key_name’ FOREIGN KEY
(‘class_id’) PREFERENCES ‘class’ (‘id’)
key_name 可写可不写
mysql 默认不匹配大小写
(2)mysql连接查询
mtysql 连接查询
inner join (内连接、等值连接):获取两个表中字段匹配关系的记录 left
join(外连接,左连接):获取左表所有记录,即使右边没有匹配的字段 right
join(外连接,右连接):获取右边所有记录,即使左边没有匹配的字段
(3)事务
只有使用了InnoDB作为存储引擎才支持事务
四个特性(ACID):Atomicity 原子性,Consistency 稳定性,Isolation 隔离性,Durability 可靠性
详情见博客
<< begin;
<< insert …
<< rollback 没有begin开始事务就不能回滚
(4)索引
数据库索引:可以先理解为相当于每个字段都hash() 然后哈希值排序,最后二分查找(B树),时间复杂度O(log n),比如42亿个数据
为2^32,最多32次, 这是B树,但是磁盘IO消耗太大了,所以数据库采用的是B+树,是改良的B树(B-tree 或者B-树
但是其实这样叫不准确 容易误导),类似二分查找
索引分单列索引和组合索引。
单列索引:即一个索引只包含单个列,一个表可以有多个单列索引,但这不是组合索引
组合索引:即一个索引包含多个列(在两个字段加起来时才唯一的时候,可以做组合索引,如果两个字段有一个唯一就没必要)
创建索引是应用SQL查询语句的条件(一般WHERE子句的条件)
索引的缺点。。见博客
主键是一种索引,默认的
普通索引创建方式:
查看索引:show index from table
创建索引:create index index_name on table(column(32))
修改索引:alter table add index index_name on (column(32))
删除索引:drop index index_Name on table
唯一索引创建方式:
与上面类似,不同的事索引列的值必须唯一,但允许有空值。
就在上面index 前加 unique
更多见博客
3.python操作mysql
MYSQLdb 在3.0上用不了,因为没更新
3.0用pymysql 与MYSQL语句一样
execute() 单个执行
executemany() 批量插入
import pymysql
# 创建连接
conn = pymysql.connect(host='127.0.0.1',port=3306,user='root',passwd='960314',db='app_version')
# 创建游标,类似mysql终端上的游标
cursor = conn.cursor()
# 执行SQL,返回值是受影响行数
effect_row=cursor.execute("select * from sys_log ")
# print(effect_row)
print(cursor.fetchone()) # 取一条
print(cursor.fetchmany(3)) # 取前三条
# print(cursor.fetchall())
# 取所有,如果没有前面那个取一条,就把所有的取了,如果前面取了多少,就从上次取的地方开始取
# 批量提交
# li =[
# ('alex','usa'),
# ('sb','usa'),
# ]
# reCount = cur.executemany('insert into UserInfo(Name,Address) values(%s,%s)',li)
#
# conn.commit() 默认已经变成了事务 所以要提交,不然不会修改
# cur.close()
4.ORM框架 sqlalchemy
ORM框架(Object-Relational-Mapping) 对象关系映射
python下最著名的ORM框架 SQLAlchemy
用户 openstack,uber等
注意一个小点:
要想写中文 在 engine =create_engine(“mysql+pymysql://root:960314@localhost/pytest”,encoding=‘utf-8’,echo=True) 写了encoding还不管用
必须要写成“mysql+pymysql://root:960314@localhost/pytest?charset=utf8”
以后就直接写“mysql+pymysql://root:960314@localhost/pytest?charset=utf8” 不用写encoding了
使用sqlalchemy流程:
1.engine=create_engine(url…)
2.Base=declarative_base()
3.-----------建表---------------
一般建表法(常用):
class User(Base):
_ tablename _=‘user’ # 表名
id = Column(Integer,primary_key=True)
name = Column(String(32))
password = Column(String(64))
不通过类的建表法(少用,一般在建立用户不用关心的中间表时使用):
book_m2m_author = Table(‘book_m2m_author’, Base.metadata,
Column(‘book_id’,Integer,ForeignKey(‘books.id’)),
Column(‘author_id’,Integer,ForeignKey(‘authors.id’)),
)
4.Base.metadata.create_all(engine)
------------创建数据------------
5.Session_class=sessionmaker(bind=engine) 注意 这里是创建了一个类
6.session=Session_class() 实例化
7.user_obj = User(name=‘yang’,password=‘960314’) 创建数据对象
8.session.add_all([user_obj]) 把数据对象列表作为对象传入
9.seesion.commit() 提交 不提交不会生效
-----------查询数据--------------
filter_by()
10.data=Session.query(User).filter_by(name=‘yang’).all() all是所有 是生成一个列表
11.data=Session.query(User).filter_by(name=‘yang’).first() 是生成一个对象
filter() 最好用filter
12.data=Session.query(User).filter(name==‘yang’).all() all是所有 是生成一个列表
13.data=Session.query(User).filter(name==‘yang’).first() 是生成一个对象
update 查百度
(1)ORM基本写法
import sqlalchemy
'''ORM框架基本写法'''
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column,Integer,String
from sqlalchemy.orm import sessionmaker
engine =create_engine("mysql+pymysql://root:960314@localhost/pytest",
encoding='utf-8',echo=True) # echo=True 打印所有信息
# sqlalchemy 底层也是mysqld、pymsql、oracle等的封装
Base = declarative_base() # 生成orm基类
class User(Base):
__tablename__='user' # 表名
id = Column(Integer,primary_key=True)
name = Column(String(32))
password = Column(String(64))
def __repr__(self):
return "<%s name:%s>"%(self.id,self.name)
Base.metadata.create_all(engine) # 创建表结构 把base下所有子类都创建了
# 创建数据
Session_class=sessionmaker(bind=engine) # 创建与数据库的会话session class,注意,这里返回给session的是个类,不是一个实例
Session=Session_class() # 生成session 实例
# 插入数据
# user_obj = User(name='yang',password='960314') # 生成你要创建的数据对象
# user_obj2 = User(name='hape',password='123456')
# print(user_obj.name,user_obj.id) # 此时还没创建对象,id还是none
#
# Session.add(user_obj) # 把要创建的数据对象添加到这个session里,一会统一创建
# Session.add(user_obj2)
# 查询数据
#data=Session.query(User).filter_by(name='yang').all() # 所有数据取成一个列表
data=Session.query(User).filter(User.id<10).filter(User.id>3).all() # 多条件查询
# filter_by不好用就用filter
print(data) # data是一个装对象的列表
print(data[0].name,data[0].password)
Session.commit() # 现在才统一提交,创建数据
# Session.rollback() 回滚
(2)外键写法
'''建立外键'''
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column,Integer,String,DATE,ForeignKey
from sqlalchemy.orm import sessionmaker,relationship
engine =create_engine("mysql+pymysql://root:960314@localhost/pytest",
encoding='utf-8',echo=True)
Base = declarative_base()
class Student(Base):
__tablename__="student"
id=Column(Integer,primary_key=True)
name=Column(String(32),nullable=False)
register_date=Column(DATE,nullable=False)
def __repr__(self):
return "<%s name:%s>" % (self.id,self.name)
class StudyRecord(Base):
__tablename__="study_record"
id = Column(Integer,primary_key=True)
day = Column(Integer,nullable=False)
status=Column(String(32),nullable=False)
stu_id=Column(Integer,ForeignKey("student.id")) # 创建外键
# 建立关系
student = relationship("Student",backref="my_study_record") # 这个nb,允许你在student表里通过backref 字段反向查出所有它在student_recprd里的信息,也可以反查
# ORM将两个对象关联起来,互相调用,在内存里的关联关系而不是数据库
# 注意!!!relationship的第一个参数是类!!!比如说上面的Student类!!
# 上面相当于 student=query(Student).filter(Student.id==stu_obj.stu_id.first())
def __repr__(self):
return "<%s day:%s status:%s>" % (self.student.name,self.day,self.status)
Base.metadata.create_all(engine)
Session_class=sessionmaker(bind=engine)
session=Session_class()
#
# s1 = Student(name="yang",register_date="2018-12-03")
# s2 = Student(name="lisi",register_date="2016-12-03")
# s3 = Student(name="zhangsan",register_date="2017-12-03")
# s4 = Student(name="wangwu",register_date="2018-09-03")
#
# study_obj1=StudyRecord(day=1,status="yes",stu_id=1)
# study_obj2=StudyRecord(day=2,status="no",stu_id=1)
# study_obj3=StudyRecord(day=3,status="yes",stu_id=1)
# study_obj4=StudyRecord(day=1,status="yes",stu_id=2)
#
# session.add_all([study_obj1,study_obj2,study_obj3,study_obj4])
name_List=[]
stu_obj=session.query(Student.name,Student.id).all() # first()是一个对象 list()是一个对象的列表
for i in range(len(stu_obj)):
name_List.append(stu_obj[i][0]+",id:"+str(stu_obj[i][1]))
print(stu_obj)
print(name_List) # stu_obj 通过my_study_record 反查 多条上课数据,学生和上课数据是一对多的关系。
# 注意返回值是反查出的student_record对象的返回值
session.commit()
(3)多外键写法:
应用场景:一个表中 两个字段的值 都在 另一个表一个字段里
比如快递要发账单,快递发到收快递人的地址,账单发到付款人的地址,都用的是一个地址表
建表
'''多外键关联'''
from sqlalchemy import create_engine, Integer, ForeignKey, String, Column
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
engine =create_engine("mysql+pymysql://root:960314@localhost/pytest",
encoding='utf-8',echo=True)
Base = declarative_base()
class Customer(Base):
__tablename__ = 'customer'
id = Column(Integer, primary_key=True)
name = Column(String(64))
billing_address_id = Column(Integer, ForeignKey("address.id")) # 账单地址
shipping_address_id = Column(Integer, ForeignKey("address.id")) # 邮寄地址
billing_address = relationship("Address",foreign_keys=[billing_address_id])
shipping_address = relationship("Address",foreign_keys=[shipping_address_id])
class Address(Base):
__tablename__ = 'address'
id = Column(Integer, primary_key=True)
street = Column(String(64))
city = Column(String(64))
state = Column(String(64))
def __repr__(self):
return self.street
Base.metadata.create_all(engine)
API
'''多外键的api'''
from day12 import orm_many_fk
from sqlalchemy.orm import sessionmaker
Session_class=sessionmaker(bind=orm_many_fk.engine)
session=Session_class()
#
# addr1=orm_many_fk.Address(street='Tiantongyuan',city='Changping',state='Bj')
# addr2=orm_many_fk.Address(street='Wudaokou',city='Haidian',state='Bj')
# addr3=orm_many_fk.Address(street='Yanjiao',city='Langfang',state='HB')
#
# session.add_all([addr1,addr2,addr3])
#
# c1 = orm_many_fk.Customer(name='yang',billing_address=addr1,shipping_address=addr2)
# c2 = orm_many_fk.Customer(name='jack',billing_address=addr2,shipping_address=addr1)
#
#
# session.add_all([c1,c2])
obj=session.query(orm_many_fk.Customer).filter(orm_many_fk.Customer.name=='yang').first()
print(obj.name,obj.billing_address,obj.shipping_address)
# session.commit()
(4)多对多关联的外键
比如 一本书可以有多个作者,一个作者又可以出版多本书
应用于 多对多关系
建表
'''多对多关联'''
'''一本书可以有多个作者,一个作者又可以出版多本书'''
from sqlalchemy import Table, Column, Integer,String,DATE, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
engine =create_engine("mysql+pymysql://root:960314@localhost/pytest",
encoding='utf-8',echo=True)
Base = declarative_base()
# 创建中间表(使用的是一种很少用的建表方式,不用类的方式创建,是因为用户不用关心这个表)
book_m2m_author = Table('book_m2m_author', Base.metadata,
Column('book_id',Integer,ForeignKey('books.id')),
Column('author_id',Integer,ForeignKey('authors.id')),
)
class Book(Base):
__tablename__ = 'books'
id = Column(Integer,primary_key=True)
name = Column(String(64))
pub_date = Column(DATE)
authors = relationship('Author',secondary=book_m2m_author,backref='books') # 允许author对象调books
# book对象调authors
def __repr__(self):
return self.name
class Author(Base):
__tablename__ = 'authors'
id = Column(Integer, primary_key=True)
name = Column(String(32))
def __repr__(self):
return self.name
Base.metadata.create_all(engine)
API
这里建用户不管心的中间表使用的是非类的创建
删除数据时 orm会自动删除,不用管中间表
'''多对多关联api'''
from day12 import orm_m2m
from sqlalchemy.orm import sessionmaker
Session_class=sessionmaker(bind=orm_m2m.engine)
session=Session_class()
# b1=orm_m2m.Book(name="learn python",pub_date="2018-01-10")
# b2=orm_m2m.Book(name="learn linux",pub_date="2018-02-10")
# b3=orm_m2m.Book(name="learn java",pub_date="2018-03-10")
# session.add_all([b1,b2,b3])
# a1=orm_m2m.Author(name="yang")
# a2=orm_m2m.Author(name="zhangsan")
# a3=orm_m2m.Author(name="lisi")
#
# b1.authors=[a1,a3]
# b3.authors=[a1,a2,a3]
# session.add_all([a1,a2,a3])
# 注意如果 session.add_all([b1,b2,b3,a1,a2,a3]) b3有可能比b2先创建 就会打乱b3和b2的顺序
author_obj=session.query(orm_m2m.Author).filter(orm_m2m.Author.name=="yang").first()
print(author_obj.books) # 返回的是一个对象的列表
print(author_obj.books[1].pub_date)
# book_obj=session.query(orm_m2m.Book).filter(orm_m2m.Book.id==6).first()
# print(book_obj.authors)
session.commit()
# 删除数据时 orm会自动删除,不用管中间表
# 要想写中文 在 engine =create_engine("mysql+pymysql://root:960314@localhost/pytest",encoding='utf-8',echo=True) 写了encoding还不管用
# 必须要写成“mysql+pymysql://root:960314@localhost/pytest?charset=utf8”
# 以后就直接写“mysql+pymysql://root:960314@localhost/pytest?charset=utf8” 不用写encoding了
作业:
基于sqlalchemy ORM框架的学生老师简版管理系统
需求:
用户角色,讲师\学员, 用户登陆后根据角色不同,能做的事情不同,分别如下
讲师视图
管理班级,可创建班级,根据学员qq号把学员加入班级
可创建指定班级的上课纪录,注意一节上课纪录对应多条学员的上课纪录, 即每节课都有整班学员上, 为了纪录每位学员的学习成绩,需在创建每节上课纪录是,同时 为这个班的每位学员创建一条上课纪录
为学员批改成绩, 一条一条的手动修改成绩
学员视图
提交作业
查看作业成绩
一个学员可以同时属于多个班级,就像报了Linux的同时也可以报名Python一样, 所以提交作业时需先选择班级,再选择具体上课的节数
附加:学员可以查看自己的班级成绩排名