Python操做MySQL主要使用两种方式:python
原生模块 pymsqlmysql
ORM框架 SQLAchemysql
pymql
pymsql是Python中操做MySQL的模块,在windows中的安装:数据库
pip install pymysql
入门:咱们链接虚拟机中的centos中的mysql,而后查询test数据库中student表的数据编程
import pymysql #建立链接 conn = pymysql.connect(host='192.168.123.207',port=3306,user='root',passwd='root',db="test"); #建立游标 cursor = conn.cursor() #执行sql,并返回受影响的行数 effect_row = cursor.execute("select * from student") print(effect_row)
运行结果:windows
须要给权限centos
mysql> grant all on *.* to 'root'@'%' identified by 'root'; Query OK, 0 rows affected, 1 warning (0.01 sec) mysql> flush privileges; Query OK, 0 rows affected (0.01 sec)
这个时候咱们在运行上面的程序咱们就能够看到,运行成功session
这是说明查询到了5条数据,那若是咱们须要查看这五条具体的数据是什么,咱们要用:数据结构
print(cursor.fetchone())
cursor.fetchone()是一条一条的把数据取出来app
这里咱们用了两条cursor.fetchone()
若是咱们想要只取出前3条数据:
print('>>>>>',cursor.fetchmany(3))
一次性取出全部数据:
print('------',cursor.fetchall())
若是咱们要插入多条数据:
import pymysql #建立链接 conn = pymysql.connect(host='192.168.123.207',port=3306,user='root',passwd='root',db="test"); #建立游标 cursor = conn.cursor() data = [ ("N1",23,"2015-01-01","M"), ("N2",24,"2015-01-02","F"), ("N3",25,"2015-01-03","M"), ] #执行sql,并返回受影响的行数 effect_row = cursor.executemany("insert into student (name,age,register_date,gender)values(%s,%s,%s,%s)",data) conn.commit()
注:executemany默认会启动一个事务,若是没有conn.commit(),数据将不会被插入成功
sqlalchemy ORM
1.ORM介绍
orm英文全称object relational mapping,就是对象映射关系程序,简单来讲相似python这种面向对象的程序来讲一切皆对象,咱们实例化一个对象,经过点的形式来调用里面的函数。orm至关于把数据库给实例化了,数据库都是关系型的,经过orm将编程语言的对象模型和数据库的关系模型创建映射关系,这样咱们在使用编程语言对数据库进行操做的时候能够直接使用编程语言的对象模型进行操做就能够了,而不用直接使用sql语言。
优势:
1.隐藏了数据访问细节,“封闭”的通用数据库交互,ORM的核心。他使得咱们的通用数据库交互变得简单易行,而且彻底不用考虑该死的SQL语句
2.ORM使咱们构造固化数据结构变得简单易行
2.sqlalchemy安装
安装:
pip install sqlalchemy
3.sqlalchemy基本使用
首先咱们看一下咱们没有用orm以前咱们建立一个数据表是这个样的:
create table student( id int auto_increment, name char(32) not null, age int not null, register_date date not null, primary key(id) );
使用了orm,实现上面的表的建立,代码以下:
import sqlalchemy from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column,Integer,String engine = create_engine("mysql+pymysql://root:root@192.168.123.207/test",encoding='utf-8',echo=True) Base = declarative_base()#生成orm基类 class User(Base): __tablename__ = 'user'#表名 id = Column(Integer,primary_key=True) name = Column(String(32)) password = Column(String(64)) Base.metadata.create_all(engine)#建立表结构
用orm建立一条数据:
import sqlalchemy 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:root@192.168.123.207/test",encoding='utf-8',echo=True) Base = declarative_base()#生成orm基类 class User(Base): __tablename__ = 'user'#表名 id = Column(Integer,primary_key=True) name = Column(String(32)) password = Column(String(64)) Base.metadata.create_all(engine)#建立表结构 Session_class = sessionmaker(bind=engine)#建立与数据库的会话session class ,注意这里返回给session的是一个类,不是实例 Session = Session_class()#生成session实例 user_obj = User(name = "xiaoming" , password = "123456")#生成你要建立的数据对象 user_obj2 = User(name = "jack" , password = "123564")#生成你要建立的数据对象 print(user_obj.name,user_obj.id)#此时尚未建立对象,打印一下会发现id仍是None Session.add(user_obj) Session.add(user_obj2) print(user_obj.name,user_obj.id)#此时也依然尚未建立 Session.commit()#如今才统一提交,建立数据
插入数据是使用sessionmaker,经过绑定上面建立的链接建立出一个类,生成session实例(至关于以前的cursor),用面向对象的方式建立两条记录,而后添加,最后commit就能够了
下面咱们来看看数据库的增删改查:
查询:
import sqlalchemy
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:root@192.168.123.207/test",encoding='utf-8')
Base = declarative_base()#生成orm基类
class User(Base):
__tablename__ = 'user'#表名
id = Column(Integer,primary_key=True)
name = Column(String(32))
password = Column(String(64))
Base.metadata.create_all(engine)#建立表结构
Session_class = sessionmaker(bind=engine)#建立与数据库的会话session class ,注意这里返回给session的是一个类,不是实例
Session = Session_class()#生成session实例
data=Session.query(User).filter_by(name="xiaoming").all() #print(data[0].name,data[0].password) print(data)
若是只是Session.query(User).filter_by(name="xiaoming"),只会看到一条sql语句:
filter_by()查出来的是一个列表,是一组数据
加上.all()
这个是一个对象,这也看不出来是那个,因此咱们要手动去调出数据
咱们用print(data[0].name,data[0].password):
这样就查出了数据
如今是查一条数据,若是filter_by()里面什么都不写:
data=Session.query(User).filter_by().all()
咱们就查出了好几条数据,咱们要循环才能看出来具体的数据。咱们想要直接看到谁是谁,咱们怎么办呢?
import sqlalchemy 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:root@192.168.123.207/test",encoding='utf-8') 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)#建立表结构 Session_class = sessionmaker(bind=engine)#建立与数据库的会话session class ,注意这里返回给session的是一个类,不是实例 Session = Session_class()#生成session实例 data=Session.query(User).filter_by().all() print(data)
咱们添加了__repr__()函数,这样看看运行结果:
这样就显现出咱们查询的结果了。就至关于,若是你要查看什么数据,以什么格式的方式显示,就能够在__repr__这个函数中设置
在这里,咱们用filter_by().all()查询出全部的数据,那咱们用filter_by().first(),就能够查询出数据库中的第一条数据
上面咱们用filter_by(name="xiaoming")查询出了姓名为xiaoming的数据,那咱们想要查询用户id>1的数据应该怎么查询呢?
data=Session.query(User).filter(User.id>1).all()
多个条件查询:再加几个filter
data=Session.query(User).filter(User.id>1).filter(User.id<3).all()
修改:
data=Session.query(User).filter(User.id>1).first() print(data) data.name = "Jack Chen" data.password = "555555" Session.commit()
查询到你要修改的这个数据,而后想修改面向对象里的数据同样,对数据进行修改,最后commit()就能够了
删除:
data = Session.query(User).filter_by(name = 'Rain').first() Session.delete(data) Session.commit()
一样的,先查询到要删除的数据,而后对数据进行删除,最后提交commit
回滚:
fake_user = User(name = 'Rain',password = "123456") Session.add(fake_user) print(Session.query(User).filter(User.name.in_(['jack','rain'])).all())#这时候看看session里有了刚刚添加的数据 Session.rollback()#此时你rollback一下 print(Session.query(User).filter(User.name.in_(['jack','rain'])).all())#再查就发现刚刚添加的数据就没有了
运行结果看看:
这个时候能够看到一开始咱们是可以看到刚刚插入的数据,可是回滚以后咱们就看不到了,咱们到数据库中看看:
咱们插入一条数据看看
能够看出咱们插入的数据的id是4,这样看来确实是先插入进去,而后回滚以后删除的
分组 统计:
统计:
Session.query(User).filter(User.name.in_(['xiaoming','rain'])).count()
分组:
from sqlalchemy import func print(Session.query(func.count(User.name),User.name).group_by(User.name).all())
join多表查询:
Session.query(User,Student).filter(User.id == Student.id).all() Session.query(User).join(Student).all()#这种写法必需要求两个表有外键关联
外键关联
咱们先建立两个表student,study_record:
import sqlalchemy 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 engine = create_engine("mysql+pymysql://root:root@192.168.123.207/xumingdb",encoding='utf-8') Base = declarative_base()#生成orm基类 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")) def __repr__(self): return "<%s day:%s>" % (self.id,self.day) Base.metadata.create_all(engine)#建立表结构
外键表的建立,要用到ForeignKey("student.id")里面就直接是表名.字段名
而后向两个表中插入数据:
Base.metadata.create_all(engine)#建立表结构 Session_class = sessionmaker(bind=engine) session = Session_class() s1 = Student(name = "xiaoming",register_date="2015-06-07") s2 = Student(name = "huahua",register_date="2015-06-08") s3 = Student(name = "caicai",register_date="2015-06-09") s4 = Student(name = "zhazha",register_date="2015-06-04") 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([s1,s2,s3,s4]) session.add_all([study_obj1,study_obj2,study_obj3,study_obj4]) session.commit()
批量插入用add_all,里面用一个列表放入要插入的数据,注意的是,由于创建了外键,因此在添加数据的时候,study_record的数据必定要在student表数据插入以后才可以被插入,若是一块儿插入就会报错
如今咱们要查询xiaoming一共上了几节课,那应该怎么作呢:
import sqlalchemy 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:root@192.168.123.207/xumingdb",encoding='utf-8') Base = declarative_base()#生成orm基类 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") 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()
stu_obj = session.query(Student).filter(Student.name=='xiaoming').first()
print(stu_obj.my_study_record)
session.commit()
注意上面代码标红的这个语句,咱们引入了relationship,而后这个容许你在study_record表里经过backref字段反向查出全部它在student表里的关联项,实现了一个双向查找,即关联student表,在studyrecord中经过student字段就能够查 student表中的全部字段,反过来,咱们能够在student表中经过 my_study_record字段反查studyrecord里面的数据,而后表明着咱们在下面查到的xiaoming,能够.my_study_record就能够查询出在studyrecord表中还有xiaoming的id的数据项
多外键关联
首先咱们建立两个表customer和address两个表,其中customer表中有address的两个外键:
import sqlalchemy from sqlalchemy import Integer, ForeignKey, String, Column from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import relationship from sqlalchemy import create_engine engine = create_engine("mysql+pymysql://root:root@192.168.123.207/xumingdb",encoding='utf-8') 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") shipping_address = relationship("Address") 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) # 建立表结构
而后咱们向两个表中插入数据:
from day12 import sqlalchemy_multi_fk from sqlalchemy.orm import sessionmaker Session_class = sessionmaker(bind=sqlalchemy_multi_fk.engine) session = Session_class() addr1 = sqlalchemy_multi_fk.Address(street="XiZangBeiLu",city="ShangHai",state="ShangHai") addr2 = sqlalchemy_multi_fk.Address(street="YuHu",city="XiangTan",state="HuNan") addr3 = sqlalchemy_multi_fk.Address(street="ZhongXinZhen",city="SuQian",state="JiangSu") session.add_all([addr1,addr2,addr3]) c1 = sqlalchemy_multi_fk.Customer(name="xiaoming",billing_address=addr1,shipping_address=addr2) c2 = sqlalchemy_multi_fk.Customer(name="jack",billing_address=addr3,shipping_address=addr3) session.add_all([c1,c2]) session.commit()
这样插入会出现一个错误:
sqlalchemy.exc.AmbiguousForeignKeysError: Could not determine join condition between parent/child tables on relationship Customer.billing_address - there are multiple foreign key paths linking the tables. Specify the 'foreign_keys' argument, providing a list of those columns which should be counted as containing a foreign key reference to the parent table.
说白了就是咱们如今在作关联查询的时候,有两个字段同时关联到了Address表中 ,在作反向查询的时候它分不清楚谁是谁,经过address反向查的时候分不清哪一个字段表明billing_address,哪一个字段是表明了shipping_address.那咱们怎么解决呢?
billing_address = relationship("Address",foreign_keys=[billing_address_id]) shipping_address = relationship("Address",foreign_keys=[shipping_address_id])
在建立反向查询的语句中添加foreign_keys参数就能够了
添加数据成功!!
这个时候咱们要查询customer的地址:
obj = session.query(sqlalchemy_multi_fk.Customer).filter(sqlalchemy_multi_fk.Customer.name=="xiaoming").first() print(obj.name,obj.billing_address,obj.shipping_address)
多对多关系
如今让咱们设计一个能描述“图书”与“做者”的关系的表结构,需求是:
1.一本书能够有好几个做者一块儿出版
2.一个做者能够写好几本书
首先咱们看一下通常的思路 :
两个表,而后咱们在遇到一本书有多个做者共同参与出版,就把做者id写在一块儿,可是这样不利于查询
那咱们能够再添加一张表:
这就实现了双向的一对多,一个做者能够包含多本书,一本书能够包含多个做者。这就造成了多对多。
来看代码的实现:
首先仍是先创建数据表:
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 engine = create_engine("mysql+pymysql://root:root@192.168.123.207/xumingdb",encoding='utf-8') Base = declarative_base() 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') 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) # 建立表结构
这里咱们使用了另一种创建表的方式,创建了第三张表book_m2m_auther,这张表创建起来后基本上不须要咱们去人为的添加数据,对用户来说是不用关心这里面有什么数据,是由orm自动帮你维护的。也就不须要给它创建映射关系了。
可是在mysql端其实已经关联上了,由于外键已经创建好了,在orm查询的时候,还要作一个orm级别的 内存对象的映射:relationship,告诉book表和author表在查询数据的时候去哪张表里查询。
因此看上面的红色的代码,经过secondary这个字段去查第三张表。
这个时候就创建好了多对多的关系。咱们就能够插入数据看效果:(先把表创建起来再说)
from day12 import sqlalchemy_multitomulti from sqlalchemy.orm import sessionmaker Session_class=sessionmaker(bind=sqlalchemy_multitomulti.engine) session = Session_class() b1 = sqlalchemy_multitomulti.Book(name="book1",pub_date="2014-05-16") b2 = sqlalchemy_multitomulti.Book(name="book2",pub_date="2012-03-16") b3 = sqlalchemy_multitomulti.Book(name="book3",pub_date="2016-06-16") a1 = sqlalchemy_multitomulti.Author(name="xiaoming") a2 = sqlalchemy_multitomulti.Author(name="jack") a3 = sqlalchemy_multitomulti.Author(name="Rain") b1.authors = [a1,a3] b2.authors = [a2,a3] b3.authors = [a1,a2,a3] session.add_all([b1,b2,b3,a1,a2,a3]) session.commit()
上面红色标记是创建关联关系,这样创建出来以后,book_m2m_author表自动就会有数据。
固然若是咱们想要插入中文的书。即插入的数据有中文,咱们要怎么作呢:
engine = create_engine("mysql+pymysql://root:root@192.168.123.207/xumingdb?charset=utf8",encoding='utf-8') Base = declarative_base()
须要在建立数据库链接的时候在数据库后面加上?charset=utf8
如今数据插入以后,最终要实现查询数据:
1.查看做者xiaoming出版了多少本书:
author_obj = session.query(sqlalchemy_multitomulti.Author).filter(sqlalchemy_multitomulti.Author.name=="xiaoming").first() print(author_obj.books)
2.查看书b2是哪些做者出版的 :
book_obj = session.query(sqlalchemy_multitomulti.Book).filter(sqlalchemy_multitomulti.Book.id==2).first() print(book_obj.authors)
多对多删除:
在删除数据的时候咱们也一样的不须要管book_m2m_author表,sqlalchemy会自动帮咱们把对应的数据删除:
经过书删除做者:
author_obj = session.query(sqlalchemy_multitomulti.Author).filter(sqlalchemy_multitomulti.Author.name=="xiaoming").first() book_obj = session.query(sqlalchemy_multitomulti.Book).filter(sqlalchemy_multitomulti.Book.id==2).first()
book_obj.authors.remove(author_obj) session.commit()
这个时候图书2的关联关系会自动少一个
直接删除做者:
author_obj = session.query(sqlalchemy_multitomulti.Author).filter(sqlalchemy_multitomulti.Author.name=="xiaoming").first() session.delete(author_obj) session.commit()