老男孩14期自動化運維day12隨筆和作業
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:[email protected]/pytest”,encoding=‘utf-8’,echo=True) 寫了encoding還不管用
必須要寫成“mysql+pymysql://root:[email protected]/pytest?charset=utf8”
以後就直接寫“mysql+pymysql://root:[email protected]/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:[email protected]/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:[email protected]/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:[email protected]/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:[email protected]/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:[email protected]/pytest",encoding='utf-8',echo=True) 寫了encoding還不管用
# 必須要寫成“mysql+pymysql://root:[email protected]/pytest?charset=utf8”
# 以後就直接寫“mysql+pymysql://root:[email protected]/pytest?charset=utf8” 不用寫encoding了
作業:
基於sqlalchemy ORM框架的學生老師簡版管理系統
需求:
使用者角色,講師\學員, 使用者登陸後根據角色不同,能做的事情不同,分別如下
講師檢視
管理班級,可建立班級,根據學員qq號把學員加入班級
可建立指定班級的上課紀錄,注意一節上課紀錄對應多條學員的上課紀錄, 即每節課都有整班學員上, 為了紀錄每位學員的學習成績,需在建立每節上課紀錄是,同時 為這個班的每位學員建立一條上課紀錄
為學員批改成績, 一條一條的手動修改成績
學員檢視
提交作業
檢視作業成績
一個學員可以同時屬於多個班級,就像報了Linux的同時也可以報名Python一樣, 所以提交作業時需先選擇班級,再選擇具體上課的節數
附加:學員可以檢視自己的班級成績排名