Python自学day-12 (Mysql、事务、索引、ORM)

mac2022-06-30  86

一、Mysql概述

  RDBMS:关系型数据库管理系统。Mysql是一种RDBMS。

    Oracle:收费

    Mysql:Oracle旗下免费

    Sqlserver:微软

    DB2:IBM

    Postgresql

    Sqlite:轻量级

    access:轻量级

  数据库:数据库是一些关联表的集合。

  数据表:表述数据的矩阵。看起来像一个简单的电子表格(Excel)。

  列:一列包含了相同类型的数据,例如电话号码,名称等。

  行:一行表示一组相关的数据,例如一个用户的相关信息,名称、年龄、性别、电话等。

  冗余:在查询表时,经常跨表关联查询效率会比较低,例如学生表和学院表,学生的属性中如果只保存学院的ID,那么想查询学生属于哪个学院,就需要关联两张表进行查询,如果想要提高效率,就可以在学生表中添加一个冗余字段dept_name,以后在查询时就只需要查询学生表即可。

  主键:主键是唯一的(不重复的)。一个数据表只能有一个主键。可以使用主键来查询数据。

  外键:外键用来关联两个表。(效率比较低)

  复合键:复合键(组合键)将多个列作为一个索引建,一般用于符合索引。

  索引:使用索引可以快速访问数据库表中的特定信息。索引是对数据库中一列或多列的值进行排序的一种结构,类似于书籍的目录。数据库中的索引是用的B+树查找。

  参照完整性:参照的完整性要求关系中不允许引用不存在的实体。与实体完整性是关系模型必须满足的完整性约束条件,目的是保证数据的一致性。例如某表某列只有值1、2、3,我们在另外一个表不能引用4、5、6这些不存在的值。

 

  Mysql数据库的优势:

  Mysql是最流行的关系型数据库管理系统,在WEB应用方面Mysql是最好用的软件之一。由瑞典MySQL AB公司开发,被Oracle收购。

  Mysql是开源的,免费的。

  Mysql使用标准的SQL数据语言形式。

  Mysql可以允许安装在多种系统上,并且支持多种语言。例如C语言、C++、Python、Java、Perl、PHP、Ruby、Tcl等。

  Mysql支持大型数据库,支持5000万条记录的数据仓库,32位系统表文件最大4GB,64位系统支持最大的表文件为8TB。

  Mysql可以定制,采用GPL协议,可以修改源码来开发自己的Mysql系统。

 

   Mysql默认不区分表名大小写,即对表名大小写不敏感。与配置文件中的lower_case_table_names有关:

    lower_case_table_names = 0 : 敏感,区分大小写

    lower_case_table_names = 1 : 不敏感,不区分大小写

 

二、Mysql安装

  Linux下安装:

    1.使用yum install mariadb-server -y安装,或者下载rpm包,使用rpm -ivh xxx.rpm安装。

    3.启动服务systemctl start mariadb.service

    4.设置开机启动systemctl enable mariadb.service

  注:Mariadb是mysql的一个分支版本。效率比普通的mysql高,是mysql之父在Orable收购mysql后,从新发布的一个新的版本,除了名字不一样,使用端口等都是一样的。

  Windows下安装:

    下载exe,双击安装

 

三、mysql使用

  登录mysql:

  刚安装好的Mysql,使用mysql -uroot -p 来登录,默认没有密码。

  查看数据库列表:

    show databases;

   进入某个数据库:

    use mysql;

  查看数据库中的表:

    show tables;

  查看某个表的结构:

    desc user;

  上图字段描述:

    Field:表示一个字段(一列)。

    Type:表示存放数据的类型。

    NULL:是否允许为空。

    KEY:键类型,主键、外键等。如果出现多个主键,说明是复合键。

    DEFAULT:默认值。

    Extra:额外的一些信息。

 

  查看某个表里的所有内容:

    select * from user;

    注:如果在命令行中由于数据太多显示不正常,可以使用select * from user\G来让数据可读。

   

  创建Mysql密码:

    1.无密码进入mysql数据库

    2.执行update mysql.user set password=password('hanxinda123') where user='root';

    3.执行flush privileges;

    注:flush privileges;的作用是,将当前user和privilige表中的用户信息/权限设置从mysql库(MySQL数据库的内置库)中提取到内存里。MySQL用户数据和权限有修改后,希望在"不重启MySQL服务"的情况下直接生效,那么就需要执行这个命令。

  

  创建用户并授权:

    grant all on test.* to 'leo'@'%' identified by 'hanxinda123';

    grant all on test.* to 'leo'@'localhost' identified by 'hanxinda123';  #让用户可以在本机登录

    all:表示所有权限,其中包含select,insert,update,delete,create,drop。

    test.*:表示test数据库中的所有的表。

    'leo'@'%':表示用户leo从除了localhost以外的所有主机登录。想在本机登录,补充执行'leo'@'localhost'

    identified by:指定用户密码。

 

  

    

  查看用户权限:

    show grants for leo;

 

 

  mysql配置文件:

   配置文件/etc/my.cnf,用于配置mysql的一些路径,日志存放位置等,一般不用修改。

 

  管理Mysql的命令:

    use db_name; 切换数据库

    show databases; 查看所有数据库

    show tables; 查看数据库中的所有表

    show columns from table_name;    同desc table_name;

    create database db_name charset utf8; 创建一个数据库,支持中文。默认的charset是latin1,只支持拉丁语类。

    drop database db_name; 删除数据库。

    show index from table_name; 显示某个表的详细索引信息,包含主键。

  

  常用数据类型:

    int,varchar等

   

  创建表:

    create table table_name (column_name column_type);

    例如:

create table student( stu_id int not null auto_increment, name char(32) not null, age int not null, register_date data, primary key (stu_id) )

  primary key (stu_id) 将stu_id设置为主键后,stu_id就变为不能重复的了。复合主键使用primary key (stu_id,name) 

  

  

  

  插入数据:

    insert into table_name (field1, field2,...,fieldn) values (value1, value2, ...,valuen);

    例如:

insert into student   (name, age, register_date) values   ('leo', 23, '2019-01-22')

    

  查询数据:

    select * from table_name; 查询表中所有数据。

    select field1,field2,...,fieldn from table_name;  查询其中部分列。

    select * from table_name where age>20;  按条件过滤查询。

    select * from table_name where register_date like "2019-01%"; 使用like模糊查询。

 

  更新数据:

    update table_name set field1=value1,field2=value2 where stu_id=5; 可以同时修改多条数据,可以加过滤条件。

    

  删除数据:

    delete from table_name where name='alex'; 

 

  排序:

    select * from student order by stu_id asc; 查询结果按stu_id升序排列。

    select * from student order by stu_id desc; 查询结果按stu_id降序排列。

    注:默认是升序。

 

  分组统计:

    select name, count(*) from student group by name;  按名称统计表中每个人有多少条数据。

    例如:

  

    按多个字段进行分组统计:

    select name,age,count(*) from student group by name,age;  按名称统计表中每个人有多少条数据。

  

    统计同名人的平均年龄:

    select name,avg(age) from student group by name;

  

    统计同名人的年龄综合:

    select name,sum(age) from student group by name;

  

    可以再加上一个总数(类似总计):

    select name,sum(age) from student group by name with rollup;

  

    可以给这个NULL取个名字:select coalesce(name,"TOTAL AGE"),sum(age) from student group by name with rollup;

  

 

  创建外键:

    创建两个表,一个表为class,一个表为student,class中的cls_id为student中的外键。

  

create table student (id int not null, name varchar(20) not null, age int not null, class_id int not null, primary key(id), FOREIGN KEY(class_id) REFERENCES class(cls_id) );

  

 

四、Mysql管理命令:

  ALTER命令:

    alter table student drop register_date; 删除student表的register_data列。

    alter table student add score int not null; 添加一列score。

    alter table student modify age char(20) not null; 将age字段的类型修改为char(20)。

    alter table student change name english_name varchar(20) not null; 将name字段的名称修改为english_name 类型为varchar(20)。

    alter table student modify sex enum("F","M") not null default "F"; 将sex修改为枚举型,只能是F或M,默认F。

 

五、NULL值的处理

  在Mysql中,提供三种对NULL的运算:

IS NULL:判断为空。IS NOT NULL:判断不为空。<=>:NULL<=>NULL 返回True。不能使用NULL = NULL来判断(始终返回false)。

  

六、多表查询

  例子:

  

  内连接(inner join):

    按条件查询两个表中共同满足条件的部分结果。(并集)

    select * from A inner join B on A.name = B.name;

   

    使用select a.*,b.* from a,b where A.name=B.name;具有相同效果。

  左连接(left join):

    按A表为基准,结果包含交集部分,也包含其余A的部分。

    select * from A left join B on A.name=B.name;

   

  右连接(right join):

     按B表为基准,结果包含交集部分,也包含其余B的部分。

    select * from A right join B on A.name=B.name;

  

  全连接(full join):

    select * from A full join B on A.name=B.name;  但是mysql并不直接支持这种语法。

    使用另一种方式实现:

    select * from A left join B on A.name=B.name UNION select * from A right join B on A.name=B.name;

  

 

七、事务

  事务主要用于处理操作量大,复杂度高的数据,比如需要删除一个人员,既需要删除人员基本信息,也需要删除与该人员相关的信息,如邮箱、文章等,这样就构成了一个事务。

在Mysql中只有使用了innodb数据库引擎的数据库或表才支持事务。事务用来维护数据库的完整性,保证成批的SQL语句要么全部执行,要不都不执行。事务用来管理insert,update,delete语句。

  事务必须满足4个条件(ACID),Atomicity(原子性)、Consistency(稳定性)、Isolation(隔离性)、Durablity(可靠性)。

原子性:一组事务,要么成功,要么失败。稳定性:有非法数据,事务撤回。隔离性:事务独立运行,一个事务处理后的结果影响了其他事务,那么其他事务会撤回。事务的100%隔离,需要牺牲速度。可靠性:软、硬件崩溃后,InnoDB数据表驱动会利用日志文件重构修改。可靠性和速度不可兼得,Innodb_flush_log_at_trx_commit选项,决定什么时候把事务保存到日志中。

 

  在Mysql控制台使用事务:

begin;  # 事务开始 insert into A (name,age,sex) values ('leo', 22, 'M');  # 插入一条数据 rollback;  # 回滚操作,该事务结束 begin; # 重新开始另一个事务 insert into A (name,age,sex) values ('leo', 32, 'F'); # 插入正确的数据 commit; # 确认无误,提交,事务结束

  其中,rollback和commit都代表当前事务结束。

 

八、索引

  当我们需要关注某个表其中几列关键信息,我们可以对其添加索引。

  索引包含单列索引和组合索引(多列组合形成的)。

  索引创建后,应该确保该索引应用在SQL查询语句的条件部分(WHERE子句中的条件)。

  实际上,索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录。

 

  索引的优点:

    查询速度很快。使用了索引是兰博基尼的话,没使用索引就是人力三轮车。

  索引的缺点:

    索引要避免滥用,虽然索引大大提高了查询速度,同时却降低更新表的速度,如对表进行insert、update和delete。因为更新表时,不仅要保存数据,还要保存一下索引文件。建立索引会占用磁盘空间的索引文件。

  

  查看表的索引:

    show index from table_name;

  

  创建索引:

    create index index_name on student(name(20));  #  为student表的name字段添加索引。这里的20表示索引长度,即使用name列的前多少个字符创建索引,如果这个length与name定义的长度一致,则使用全量创建索引。例如varchar和char适合使用部分长度来创建索引,可以节省磁盘空间。

    在创建表的时候添加index:    

create table mytable ( id int not null primary key, name varchar(20) not null, index index_name (name(20)) );

    通过修改表结构添加索引:

    alter mytable add index index_name on (name(20));

 

  删除索引:

    drop index index_name on table_name;

 

  唯一索引:

    与普通索引类似,不同的是,索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。

    创建方式:

    create UNIQUE index index_name on student(name(20));

    与普通索引相似,只是多了一个UNIQUE关键字。

 

九、python中使用Mysql

  python2.x库安装:

    linux下使用yum安装MySQL-python: yum install MySQL-python -y

    或使用pycharm安装MySQL-python

 

  但是MySQL-python,mysqldb在python3.x上不能使用。

 

  python3.x使用pymysql库:

    首先在pycharm中安装pymysql库。

    执行查询:

import pymysql # 创建连接(socket) conn = pymysql.connect(host='192.168.1.66', port=3306, user='root', passwd='hanxinda123', db='school' ) # 获取游标,类似 "MariaDB [school]>"这个东西 cursor = conn.cursor() # 使用游标来执行SQL effect_row = cursor.execute('select * from class') print(effect_row) # 打印4,说明表class中有4条数据 print(cursor.fetchone()) # 获取一条数据 print(cursor.fetchmany(2)) # 获取前2条数据 print(cursor.fetchall()) # 获取剩下的数据,一条数据只能被获取一次 # 关闭游标和链接 cursor.close() conn.close()

    如果在execute中运行插入、更新、删除等语句,默认开启事务功能,后面需要执行提交(commit):

    一次执行多条SQL:

import pymysql # 创建连接(socket) conn = pymysql.connect(host='192.168.1.66', port=3306, user='root', passwd='hanxinda123', db='school' ) # 获取游标,类似 "MariaDB [school]>"这个东西 cursor = conn.cursor() # 定义多条数据的列表 data = [('class-10', 'leo'), ('class-11', 'jack'), ('class-12', 'lilei') ] # 直接插入多条 effect_row = cursor.executemany('insert into class (cls_name,cls_master_name) values (%s,%s)', data) # 默认是事务模式,需要提交 conn.commit() # 关闭游标和链接 cursor.close() conn.close()

 

 十、ORM

  全称是object relational mapping,对象映射关系。简单来说,Python这种面向对象的程序一切皆对象,但是我们使用的数据库确实关系型的,为了保证一致的使用习惯,通过orm将编程语言的对象模型和数据库的关系模型建立映射关系,这样我们在使用变成语言对数据库进行操作的时候可以直接使用编程语言的对象模型就可以了,而不直接使用原生的SQL语句。

 

  如图所示,传统情况下,我们通过原生SQL直接访问数据库(红色箭头),使用ORM,我们对数据库的操作都采用对象的方式(绿色箭头),由ORM来复制对象模型与SQL之间的转换。

  

 十一、SQLAlchemy

  /'ælkɪmɪ/  魔术、点金术

  在Python中,最有名的ORM框架是SQLAlchemy。用户包含OpenStack等知名应用和公司。

  SQLAlchemy安装:

    在pycharm中安装,或者使用pip3 install sqlalchemy在命令行中安装。

  

  基本使用(创建表):

import sqlalchemy from sqlalchemy import create_engine from sqlalchemy import Column, Integer, String from sqlalchemy.ext.declarative import declarative_base # 链接数据库,告诉sqlalchemy engine = create_engine('mysql+pymysql://root:hanxinda123@192.168.1.66/school', encoding='utf-8', echo=True ) Base = declarative_base() class Teacher(Base): __tablename__= 'teacher' id = Column(Integer, primary_key=True) name = Column(String(32)) cls_name = Column(String(32)) Base.metadata.create_all(engine)

  其中,create_engine代表链接数据库,参数中的mysql+pymysql表示用的哪种数据库,用的哪种底层库。SQLAlchemy可以支持多种数据库和API库。例如:

    Mysql-Python:      mysql+mysqldb

    pymysql:   mysql+pymysql

    Mysql-connector:  mysql+mysqlconnector

    cx_Oracle:  oracle+cx_oracle

  后面的代表<用户名>:<密码>@<主机名或IP>:[<port>]/<db_name>

  echo=True表示打印调试信息,其中包含底层执行的SQL语句等。

 

  创建表并插入数据:

  如果表已经存在,则不会再创建表,但不会报错。

import sqlalchemy from sqlalchemy import create_engine from sqlalchemy import Column, Integer, String from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker # 执行操作需要导入sessionmaker # 链接数据库,告诉sqlalchemy使用哪种数据库和API库,用户、密码、主机、数据库名等。 engine = create_engine('mysql+pymysql://root:hanxinda123@192.168.1.66/school', encoding='utf-8', echo=True ) Base = declarative_base() # 生成ORM基类 class Teacher(Base): __tablename__ = 'teacher' # 表名 id = Column(Integer, primary_key=True) # Integer即int name = Column(String(32)) # String对应sql中的varchar cls_name = Column(String(32)) Base.metadata.create_all(engine) Session_class = sessionmaker(bind=engine) # 创建与数据库的会话的session类,注意是类,不是对象 session = Session_class() # 生成session实例,相当于以前的cursor teacher_obj_1 = Teacher(name='alex', cls_name='class-11') teacher_obj_2 = Teacher(name='jack', cls_name='class-12') print(teacher_obj_1.name, teacher_obj_1.cls_name) # 此时还未创建 session.add(teacher_obj_1) # 将要创建的数据对象添加到session中。 session.add(teacher_obj_2) # 将要创建的数据对象添加到session中。 print(teacher_obj_1.name, teacher_obj_1.cls_name) # 此时还未创建 session.commit() # 统一提交,创建数据

  查询:

from sqlalchemy import create_engine from sqlalchemy import Column, Integer, String from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker # 执行操作需要导入sessionmaker # 链接数据库,告诉sqlalchemy使用哪种数据库和API库,用户、密码、主机、数据库名等。 engine = create_engine('mysql+pymysql://root:hanxinda123@192.168.1.66/school', encoding='utf-8' ) Base = declarative_base() # 生成ORM基类 class Teacher(Base): __tablename__ = 'teacher' # 表名 id = Column(Integer, primary_key=True) # Integer即int name = Column(String(32)) # String对应sql中的varchar cls_name = Column(String(32)) Base.metadata.create_all(engine) Session_class = sessionmaker(bind=engine) # 创建与数据库的会话的session类,注意是类,不是对象 session = Session_class() # 生成session实例,相当于以前的cursor # 取全部数据all() data = session.query(Teacher).filter_by(name='alex').all() for i in data: print(i.name, i.cls_name) # 取第一条数据first() data = session.query(Teacher).filter_by(name='alex').first() print(data.name, data.cls_name) # 条件为大于小于,只能使用filter(),参数必须写Teacher.id而不能直接写id,与filter_by相反 # 判断相等要使用'==',而filter_by使用'='。注意一下 data = session.query(Teacher).filter(Teacher.id > 1).all() for i in data: print(i.name, i.cls_name) # 多条件查询 data = session.query(Teacher).filter(Teacher.id > 1).filter(Teacher.name == 'alex').all() for i in data: print(i.name, i.cls_name)

   修改:

# 取第一条数据first() data = session.query(Teacher).filter_by(name='alex').first() print(data.name, data.cls_name) data.name = 'alex modify' # 直接对数据进行修改 data.cls_name = 'class_100' session.commit() # 提交到数据库

  

  回滚:

teacher_obj_1 = Teacher(name='hello', cls_name='class-3') session.add(teacher_obj_1) # 将要创建的数据对象添加到session中,实际上数据已经到数据库了,使用sql查询不到,但id已经自增了(相当于这条数据已经占了一个位置) session.rollback() # 回滚 data = session.query(Teacher).filter(Teacher.name == 'hello').all() for i in data: print(i.name, i.cls_name) # 无数据,因为回滚了

   统计:

# 统计 ct = session.query(Teacher).filter(Teacher.name.like('hello%')).count() print(ct)

  分组:

from sqlalchemy import func print(session.query(func.count(Teacher.name), Teacher.name).group_by(Teacher.name).all())

   连表查询:

# 第一种形式 res = session.query(Class, Teacher).filter(Class.cls_id == Teacher.id).all() for i in res: print(i[0].cls_id, i[1].id) # 第二种形式,但这种形式必须存在关联关系(外键),如果没有回报错 res = session.query(Class).join(Teacher).all() for i in res: print(i[0].cls_id, i[1].id)

  添加外键:

from sqlalchemy.orm import relationship from sqlalchemy import ForeignKey # 映射Teacher表 class Teacher(Base): __tablename__ = 'teacher' # 表名 id = Column(Integer, primary_key=True) # Integer即int name = Column(String(32)) # String对应sql中的varchar cls_name = Column(String(32)) # 映射class表 class Class(Base): __tablename__ = 'class' cls_id = Column(Integer, primary_key=True) cls_name = Column(String(20), nullable=False) cls_master_name = Column(String(20), nullable=False) teacher_id = Column(Integer, ForeignKey('teacher.id'))  # 创建外键 Base.metadata.create_all(engine)

  在创建表时,导入ForeignKey,然后在映射类中添加外键信息。

 

  添加表关联关系(这个关系不是在数据库中,是在内存中的关系,relationship):

from sqlalchemy import create_engine from sqlalchemy import Column, Integer, String from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker # 执行操作需要导入sessionmaker from sqlalchemy.orm import relationship from sqlalchemy import ForeignKey # 链接数据库,告诉sqlalchemy使用哪种数据库和API库,用户、密码、主机、数据库名等。 engine = create_engine('mysql+pymysql://root:hanxinda123@192.168.1.66/school', encoding='utf-8' ) Base = declarative_base() # 生成ORM基类 # 映射class表 class Class(Base): __tablename__ = 'class' id = Column(Integer, primary_key=True) name = Column(String(20), nullable=False) # 映射Teacher表 class Teacher(Base): __tablename__ = 'teacher' id = Column(Integer, primary_key=True) name = Column(String(32)) cls_id = Column(Integer, ForeignKey('class.id')) # 创建一个关联关系,可以使用cls来获取对应Class表中的所有数据 # 同时创建反向关系,在Class表中可以使用thr获取Teacher表的全量数据 cls = relationship('Class', backref='thr') Session_class = sessionmaker(bind=engine) # 创建与数据库的会话的session类,注意是类,不是对象 session = Session_class() # 生成session实例,相当于以前的cursor # 必须存在关联关系(外键),如果没有回报错 res = session.query(Teacher).all() for i in res: print(i.id, i.name, i.cls.name)

  

  重要:当一个表中有多个字段的外键都是一个表时,例如teacher的普通班级编号和管理班级编号都用外键关联一个班级表。那么需要在relationship("Class", foreign_keys=[mgmt_cls]) 指定关联关系和哪个外键绑定的。如下代码:

from sqlalchemy import create_engine from sqlalchemy import Column, Integer, String from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker # 执行操作需要导入sessionmaker from sqlalchemy.orm import relationship from sqlalchemy import ForeignKey # 链接数据库,告诉sqlalchemy使用哪种数据库和API库,用户、密码、主机、数据库名等。 engine = create_engine('mysql+pymysql://root:hanxinda123@192.168.1.66/school', encoding='utf-8' ) Base = declarative_base() # 生成ORM基类 # 映射class表 class Class(Base): __tablename__ = 'class' id = Column(Integer, primary_key=True) name = Column(String(20), nullable=False) # 映射Teacher表 class Teacher(Base): __tablename__ = 'teacher' id = Column(Integer, primary_key=True) name = Column(String(32)) cls_id = Column(Integer, ForeignKey('class.id')) mgmt_cls_id = Column(Integer, ForeignKey('class.id')) # 创建一个关联关系,可以使用cls来获取对应Class表中的所有数据 # 同时创建反向关系,在Class表中可以使用thr获取Teacher表的全量数据 cls = relationship('Class', foreign_keys=[cls_id]) mgmt_cls = relationship('Class', foreign_keys=[mgmt_cls_id]) # 创建表 Base.metadata.create_all(engine) Session_class = sessionmaker(bind=engine) # 创建与数据库的会话的session类,注意是类,不是对象 session = Session_class() # 生成session实例,相当于以前的cursor # 必须存在关联关系(外键),如果没有回报错 res = session.query(Teacher).all() for i in res: print(i.id, i.name, i.cls.name, i.mgmt_cls.name)

 

  多对多表:

    例如书和作者的关系,一本书可以有多个作者,而一个作者又可以又多本书。

    先创建book表和author表以及中间映射表,并且添加数据:

from sqlalchemy import create_engine from sqlalchemy import Column, Integer, String from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker from sqlalchemy.orm import relationship from sqlalchemy import ForeignKey from sqlalchemy import Table engine = create_engine('mysql+pymysql://root:hanxinda123@192.168.1.66/school', encoding='utf-8' ) Base = declarative_base() # 生成ORM基类 # 为什么要以这种方式创建中间表,因为这张表我们不用直接操作,ORM帮我们管理 m2m_table = Table('book_m2m_author', Base.metadata, Column('book_id', Integer, ForeignKey('book.id')), Column('author_if', Integer, ForeignKey('author.id')) ) class Book(Base): __tablename__ = 'book' id = Column(Integer, primary_key=True) name = Column(String(64), nullable=False) # 通过中间表,与author建立关联关系 authors = relationship('Author', secondary=m2m_table, backref='books') class Author(Base): __tablename__ = 'author' id = Column(Integer, primary_key=True) name = Column(String(20), nullable=False) # 创建表 Base.metadata.create_all(engine) Session_class = sessionmaker(bind=engine) # 创建与数据库的会话的session类,注意是类,不是对象 session = Session_class() # 生成session实 b1 = Book(name='Hello World') b2 = Book(name='Good thing') b3 = Book(name='Sex') b4 = Book(name='Reading Life') a1 = Author(name='jack') a2 = Author(name='leo') a3 = Author(name='alex') a4 = Author(name='xiaoming') # 书和作者的关联关系 b1.authors = [a1, a2] b2.authors = [a2, a3, a4] b3.authors = [a1, a3] b4.authors = [a3, a4] session.add_all([b1, b2, b3, b4, a1, a2, a3, a4]) session.commit()

    创建结果:

    读取结果:

# 通过作者查写了哪些书 author_obj = session.query(Author).filter(Author.name == 'alex').first() for b in author_obj.books: print(author_obj.name, b.name) # 通过书查是哪些作者写的 book_obj = session.query(Book).filter(Book.name == 'Sex').first() for a in book_obj.authors: print(book_obj.name, a.name)

    删除关联关系:

# 通过作者查写了哪些书 author_obj = session.query(Author).filter(Author.name == 'alex').first() # 通过书查是哪些作者写的 book_obj = session.query(Book).filter(Book.name == 'Sex').first() # 从Sex这本书的作者中删除alex book_obj.authors.remove(author_obj) session.commit() # 提交

    不用关心中间表,ORM会自动修改其中的记录。

 

  处理中文的问题:

    我们在创建连接的时候虽然加上了encoding='utf-8',但是并无效果。

engine = create_engine('mysql+pymysql://root:hanxinda123@192.168.1.66/school', encoding='utf-8')

    如何处理呢?

engine = create_engine('mysql+pymysql://root:hanxinda123@192.168.1.66/school?charset=utf8', encoding='utf-8')

    即在链接串的最后加上 " ?charset=utf8 "。

 

转载于:https://www.cnblogs.com/leokale-zz/p/10302410.html

相关资源:JAVA上百实例源码以及开源项目
最新回复(0)