Django模块笔记【一】
入门笔记翻译整理自:https://docs.djangoproject.com/en/1.8/topics/
*该笔记将对各个模块进行单独介绍
*Model&Database
1. 模型(models)
模型是数据的唯一信息源,它指示了数据的域(fields)和行为(behaviors)。每个模型都对应一个数据库表。
①每个模型都是django.db.models.Model的子类;②模型的每个属性代表了数据库的域;③数据库入口API,参考making queries部分。
比如,
1 from django.db import models 2 3 class Person(models.Model): 4 first_name = models.CharField(max_length=30) 5 last_name = models.CharField(max_length=30)
对应的数据库表:
1 CREATE TABLE myapp_person ( 2 "id" serial NOT NULL PRIMARY KEY, 3 "first_name" varchar(30) NOT NULL, 4 "last_name" varchar(30) NOT NULL 5 );
使用模型:
INSTALLED_APPS = ( #... 'myapp', #... )
2. 域(Fields)
Django使用Field类来决定:①数据库的列类型(如INTEGER, VARCHAR);②HTML widget(如<input type="text">,<select>)
各种Field的属性不尽相同,但是它们也有一些共同的可选属性。null=True,将空值存储为NULL,默认为False;blank=True,允许空值,默认为False;choices,举例如下:
1 from django.db import models 2 3 class Person(models.Model): 4 SHIRT_SIZES = ( 5 ('S', 'Small'), 6 ('M', 'Medium'), 7 ('L', 'Large'), 8 ) 9 name = models.CharField(max_length=60) 10 shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES)
1 >>> p = Person(name="Fred Flintstone", shirt_size="L") 2 >>> p.save() 3 >>> p.shirt_size 4 'L' 5 >>> p.get_shirt_size_display() 6 'Large'
default,定义field的默认值;help_text,在表单widget中显示帮助文档;primary_key=True,相应Field为主键,否则会自动生成主键,主键不可更改,比如:
1 from django.db import models 2 3 class Fruit(models.Model): 4 name = models.CharField(max_length=100, primary_key=True)
1 >>> fruit = Fruit.objects.create(name='Apple') 2 >>> fruit.name = 'Pear' 3 >>> fruit.save() 4 >>> Fruit.objects.values_list('name', flat=True) 5 ['Apple', 'Pear']
unique=True,相应Field的值必须为独一无二的。
大多数域可以直接设置域别名(Verbose field names):
1 # verbose name is "person's first name" 2 first_name = models.CharField("person's first name", max_length=30) 3 # verbose name is "first name" 4 first_name = models.CharField(max_length=30)
ForeighKey,ManyToManyField和OneToOneField需要使用verbose_name参数,来设置域别名:
1 poll = models.ForeignKey(Poll, verbose_name="the related poll") 2 sites = models.ManyToManyField(Site, verbose_name="list of sites") 3 place = models.OneToOneField(Place, verbose_name="related place")
数据库中常见的三种关系为:多对一,多对多,一对一。
①多对一
1 from django.db import models 2 3 class Manufacturer(models.Model): 4 # ... 5 pass 6 7 class Car(models.Model): 8 manufacturer = models.ForeignKey(Manufacturer) 9 # ...
②多对多
1 from django.db import models 2 3 class Topping(models.Model): 4 # ... 5 pass 6 7 class Pizza(models.Model): 8 # ... 9 toppings = models.ManyToManyField(Topping)
或者
1 from django.db import models 2 3 class Person(models.Model): 4 name = models.CharField(max_length=128) 5 6 def __str__(self): # __unicode__ on Python 2 7 return self.name 8 9 class Group(models.Model): 10 name = models.CharField(max_length=128) 11 members = models.ManyToManyField(Person, through='Membership') 12 13 def __str__(self): # __unicode__ on Python 2 14 return self.name 15 16 class Membership(models.Model): 17 person = models.ForeignKey(Person) 18 group = models.ForeignKey(Group) 19 date_joined = models.DateField() 20 invite_reason = models.CharField(max_length=64)
③一对一
1 from django.db import models 2 3 class Place(models.Model): 4 name = models.CharField(max_length=50) 5 address = models.CharField(max_length=80) 6 7 def __str__(self): # __unicode__ on Python 2 8 return "%s the place" % self.name 9 10 class Restaurant(models.Model): 11 place = models.OneToOneField(Place, primary_key=True) 12 serves_hot_dogs = models.BooleanField(default=False) 13 serves_pizza = models.BooleanField(default=False) 14 15 def __str__(self): # __unicode__ on Python 2 16 return "%s the restaurant" % self.place.name
3. 文档间模型(Models across files)
需要先导入相应模块:
1 from django.db import models 2 from geography.models import ZipCode 3 4 class Restaurant(models.Model): 5 # ... 6 zip_code = models.ForeignKey(ZipCode)
4. 元选项(Meta options)
meta用于接收一切不是Field的数据。
1 from django.db import models 2 3 class Ox(models.Model): 4 horn_length = models.IntegerField() 5 6 class Meta: 7 ordering = ["horn_length"] 8 verbose_name_plural = "oxen"
5. 重写方法(Override predefined model methods)
1 from django.db import models 2 3 class Blog(models.Model): 4 name = models.CharField(max_length=100) 5 tagline = models.TextField() 6 7 def save(self, *args, **kwargs): 8 do_something() 9 super(Blog, self).save(*args, **kwargs) # Call the "real" save() method. 10 do_something_else()
重写为
1 from django.db import models 2 3 class Blog(models.Model): 4 name = models.CharField(max_length=100) 5 tagline = models.TextField() 6 7 def save(self, *args, **kwargs): 8 if self.name == "Yoko Ono's blog": 9 return # Yoko shall never have her own blog! 10 else: 11 super(Blog, self).save(*args, **kwargs) # Call the "real" save() method.
6. 模型继承(Model inheritance)
①抽象基类(Abstract base classes)
1 from django.db import models 2 3 class CommonInfo(models.Model): 4 name = models.CharField(max_length=100) 5 age = models.PositiveIntegerField() 6 7 class Meta: 8 abstract = True 9 10 class Student(CommonInfo): 11 home_group = models.CharField(max_length=5)
元继承
1 from django.db import models 2 3 class CommonInfo(models.Model): 4 # ... 5 class Meta: 6 abstract = True 7 ordering = ['name'] 8 9 class Student(CommonInfo): 10 # ... 11 class Meta(CommonInfo.Meta): 12 db_table = 'student_info'
②多表继承
父类和子类使用不同的数据库表。
1 from django.db import models 2 3 class Place(models.Model): 4 name = models.CharField(max_length=50) 5 address = models.CharField(max_length=80) 6 7 class Restaurant(Place): 8 serves_hot_dogs = models.BooleanField(default=False) 9 serves_pizza = models.BooleanField(default=False)
1 >>> p = Place.objects.get(id=12) 2 # If p is a Restaurant object, this will give the child class: 3 >>> p.restaurant 4 <Restaurant: ...>
元继承
1 class ChildModel(ParentModel): 2 # ... 3 class Meta: 4 # Remove parent's ordering effect 5 ordering = []
③代理模型(Proxy model)
父类和子类使用相同的数据库表。
1 from django.db import models 2 3 class Person(models.Model): 4 first_name = models.CharField(max_length=30) 5 last_name = models.CharField(max_length=30) 6 7 class MyPerson(Person): 8 class Meta: 9 proxy = True 10 11 def do_something(self): 12 # ... 13 pass
1 >>> p = Person.objects.create(first_name="foobar") 2 >>> MyPerson.objects.get(first_name="foobar") 3 <MyPerson: foobar>
1 class OrderedPerson(Person): 2 class Meta: 3 ordering = ["last_name"] 4 proxy = True
7. 多重继承
1 class Article(models.Model): 2 headline = models.CharField(max_length=50) 3 body = models.TextField() 4 5 class Book(models.Model): 6 title = models.CharField(max_length=50) 7 8 class BookReview(Book, Article): 9 pass
————————————————————————————————————————————————————————————————————————————————————————————
8. 创建队列(Making queries)
以下模型创建了一个网页博客应用,将以此为例:
1 from django.db import models 2 3 class Blog(models.Model): 4 name = models.CharField(max_length=100) 5 tagline = models.TextField() 6 7 def __str__(self): # __unicode__ on Python 2 8 return self.name 9 10 class Author(models.Model): 11 name = models.CharField(max_length=50) 12 email = models.EmailField() 13 14 def __str__(self): # __unicode__ on Python 2 15 return self.name 16 17 class Entry(models.Model): 18 blog = models.ForeignKey(Blog) 19 headline = models.CharField(max_length=255) 20 body_text = models.TextField() 21 pub_date = models.DateField() 22 mod_date = models.DateField() 23 authors = models.ManyToManyField(Author) 24 n_comments = models.IntegerField() 25 n_pingbacks = models.IntegerField() 26 rating = models.IntegerField() 27 28 def __str__(self): # __unicode__ on Python 2 29 return self.headline
创建和更改对象
1 >>> from blog.models import Blog 2 >>> b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.') 3 >>> b.save() 4 >>> b5.name = 'New name' 5 >>> b5.save()
储存外键和多对多域
1 >>> from blog.models import Entry 2 >>> entry = Entry.objects.get(pk=1) 3 >>> cheese_blog = Blog.objects.get(name="Cheddar Talk") 4 >>> entry.blog = cheese_blog 5 >>> entry.save()
1 >>> john = Author.objects.create(name="John") 2 >>> paul = Author.objects.create(name="Paul") 3 >>> george = Author.objects.create(name="George") 4 >>> ringo = Author.objects.create(name="Ringo") 5 >>> entry.authors.add(john, paul, george, ringo)
检索对象(Retrieve objects)
1 >>> Blog.objects 2 <django.db.models.manager.Manager object at ...> 3 >>> b = Blog(name='Foo', tagline='Bar') 4 >>> b.objects 5 Traceback: 6 ... 7 AttributeError: "Manager isn't accessible via Blog instances."
1 >>> all_entries = Entry.objects.all()
1 Entry.objects.filter(pub_date__year=2006)
1 >>> Entry.objects.filter( 2 ... headline__startswith='What' 3 ... ).exclude( 4 ... pub_date__gte=datetime.date.today() 5 ... ).filter( 6 ... pub_date__gte=datetime(2005, 1, 30) 7 ... )
1 one_entry = Entry.objects.get(pk=1)
1 >>> Entry.objects.all()[:5] 2 >>> Entry.objects.all()[:10:2]
1 Entry.objects.order_by('headline')[0]
查询域(Field lookup)
类似于检索对象,主要以双下划线的形式实现。
1 >>> Entry.objects.filter(pub_date__lte='2006-01-01') 2 >>> Entry.objects.get(headline__exact="Man bites dog") 3 >>> Blog.objects.get(name__iexact="beatles blog") 4 >>> Entry.objects.get(headline__contains='Lennon')
此外,还有icontains, startswith, endswith, istartswith, iendswith等。
可以多次使用双下划线,来扩展关系,比如:
1 Blog.objects.filter(entry__headline__contains='Lennon')
可以使用F表达式来进行不同域之间的比较:
1 >>> from django.db.models import F 2 >>> Entry.objects.filter(n_comments__gt=F('n_pingbacks')) 3 >>> Entry.objects.filter(rating__lt=F('n_comments') + F('n_pingbacks')) 4 >>> Entry.objects.filter(authors__name=F('blog__name'))
编码时注意缓冲区(Cache)可以减少内存消耗,此处略过。
可以使用Q表达式进行复杂的查询功能,配合使用&,|,~三个运算符:
1 from django.db.models import Q 2 Q(question__startswith='What') 3 Q(question__startswith='Who') | ~Q(pub_date__year=2005)
比较和删除对象:
1 >>> some_entry == other_entry 2 >>> some_entry.id == other_entry.id 3 >>> e.delete() 4 >>> Entry.objects.filter(pub_date__year=2005).delete()
拷贝模型:
1 blog = Blog(name='My blog', tagline='Blogging is easy') 2 blog.save() # blog.pk == 1 3 4 blog.pk = None 5 blog.save() # blog.pk == 2
更复杂一点的拷贝模型:
1 class ThemeBlog(Blog): 2 theme = models.CharField(max_length=200) 3 4 django_blog = ThemeBlog(name='Django', tagline='Django is easy', theme='python') 5 django_blog.save() # django_blog.pk == 3 6 7 django_blog.pk = None 8 django_blog.id = None 9 django_blog.save() # django_blog.pk == 4
更新对象:
1 Entry.objects.filter(pub_date__year=2007).update(headline='Everything is the same')
关系对象:
1 >>> e = Entry.objects.get(id=2) 2 >>> e.blog # Returns the related Blog object.
———————————————————————————————————————————————————————————————————————————————————————————
9. 整合(Aggregation)
整合和队列功能类似,适合在求平均,总和时使用。
1 from django.db import models 2 3 class Author(models.Model): 4 name = models.CharField(max_length=100) 5 age = models.IntegerField() 6 7 class Publisher(models.Model): 8 name = models.CharField(max_length=300) 9 num_awards = models.IntegerField() 10 11 class Book(models.Model): 12 name = models.CharField(max_length=300) 13 pages = models.IntegerField() 14 price = models.DecimalField(max_digits=10, decimal_places=2) 15 rating = models.FloatField() 16 authors = models.ManyToManyField(Author) 17 publisher = models.ForeignKey(Publisher) 18 pubdate = models.DateField() 19 20 class Store(models.Model): 21 name = models.CharField(max_length=300) 22 books = models.ManyToManyField(Book) 23 registered_users = models.PositiveIntegerField()
以上面这个模型为例:
1 # Total number of books. 2 >>> Book.objects.count() 3 # Total number of books with publisher=BaloneyPress 4 >>> Book.objects.filter(publisher__name='BaloneyPress').count() 5 6 # Average price across all books. 7 >>> from django.db.models import Avg 8 >>> Book.objects.all().aggregate(Avg('price')) 9 {'price__avg': 34.35} 10 11 # Max price across all books. 12 >>> from django.db.models import Max 13 >>> Book.objects.all().aggregate(Max('price')) 14 {'price__max': Decimal('81.20')} 15 16 # Cost per page 17 >>> Book.objects.all().aggregate( 18 ... price_per_page=Sum(F('price')/F('pages'), output_field=FloatField())) 19 {'price_per_page': 0.4470664529184653} 20 21 # All the following queries involve traversing the Book<->Publisher 22 # many-to-many relationship backward 23 24 # Each publisher, each with a count of books as a "num_books" attribute. 25 >>> from django.db.models import Count 26 >>> pubs = Publisher.objects.annotate(num_books=Count('book')) 27 >>> pubs 28 [<Publisher BaloneyPress>, <Publisher SalamiPress>, ...] 29 >>> pubs[0].num_books 30 31 # The top 5 publishers, in order by number of books. 32 >>> pubs = Publisher.objects.annotate(num_books=Count('book')).order_by('-num_books')[:5] 33 >>> pubs[0].num_books
———————————————————————————————————————————————————————————————————————————————————————————
10. 管理器(Managers)
每个Django应用中都有管理器,创建队列一节中已经解释了管理器的工作原理,这节介绍自定义管理器行为。
管理器可以重设名称:
1 # Person.people.all() will provide a list of all Person objects. 2 3 from django.db import models 4 5 class Person(models.Model): 6 #... 7 people = models.Manager()
额外添加管理器方法:
1 from django.db import models 2 3 class PollManager(models.Manager): 4 def with_counts(self): 5 from django.db import connection 6 cursor = connection.cursor() 7 cursor.execute(""" 8 SELECT p.id, p.question, p.poll_date, COUNT(*) 9 FROM polls_opinionpoll p, polls_response r 10 WHERE p.id = r.poll_id 11 GROUP BY p.id, p.question, p.poll_date 12 ORDER BY p.poll_date DESC""") 13 result_list = [] 14 for row in cursor.fetchall(): 15 p = self.model(id=row[0], question=row[1], poll_date=row[2]) 16 p.num_responses = row[3] 17 result_list.append(p) 18 return result_list 19 20 class OpinionPoll(models.Model): 21 question = models.CharField(max_length=200) 22 poll_date = models.DateField() 23 objects = PollManager() 24 25 class Response(models.Model): 26 poll = models.ForeignKey(OpinionPoll) 27 person_name = models.CharField(max_length=50) 28 response = models.TextField()
修改初始管理器查询集:
1 # First, define the Manager subclass. 2 class DahlBookManager(models.Manager): 3 def get_queryset(self): 4 return super(DahlBookManager, self).get_queryset().filter(author='Roald Dahl') 5 6 # Then hook it into the Book model explicitly. 7 class Book(models.Model): 8 title = models.CharField(max_length=100) 9 author = models.CharField(max_length=50) 10 11 objects = models.Manager() # The default manager. 12 dahl_objects = DahlBookManager() # The Dahl-specific manager.
也可以在模型中多次调用管理器,这里略过。
此外,可以自定义查询集方法,并在管理器调用:
1 class PersonQuerySet(models.QuerySet): 2 def authors(self): 3 return self.filter(role='A') 4 5 def editors(self): 6 return self.filter(role='E') 7 8 class PersonManager(models.Manager): 9 def get_queryset(self): 10 return PersonQuerySet(self.model, using=self._db) 11 12 def authors(self): 13 return self.get_queryset().authors() 14 15 def editors(self): 16 return self.get_queryset().editors() 17 18 class Person(models.Model): 19 first_name = models.CharField(max_length=50) 20 last_name = models.CharField(max_length=50) 21 role = models.CharField(max_length=1, choices=(('A', _('Author')), ('E', _('Editor')))) 22 people = PersonManager()
如果想同时自定义查询集和管理器,可以使用from_queryset()方法:
1 class BaseManager(models.Manager): 2 def manager_only_method(self): 3 return 4 5 class CustomQuerySet(models.QuerySet): 6 def manager_and_queryset_method(self): 7 return 8 9 class MyModel(models.Model): 10 objects = BaseManager.from_queryset(CustomQueryset)()
管理器可以随类继承,多重继承时需小心,此处略过。
可以通过use_for_related_fields方法设置自定义管理器为默认管理器:
1 class MyManager(models.Manager): 2 use_for_related_fields = True 3 # ...
———————————————————————————————————————————————————————————————————————————————————————————
11. 使用原始SQL队列(Performing raw SQL queries)
在Django提供的语句不足以实现复杂的SQL时,可以使用Manager.raw()来编写原始队列。比如对于以下模型:
1 class Person(models.Model): 2 first_name = models.CharField(...) 3 last_name = models.CharField(...) 4 birth_date = models.DateField(...)
可以以如下方式执行:
1 >>> for p in Person.objects.raw('SELECT * FROM myapp_person'): 2 ... print(p) 3 John Smith 4 Jane Jones
也可以运用Connection实现原始SQL查询:
1 from django.db import connection 2 3 def my_custom_sql(self): 4 cursor = connection.cursor() 5 6 cursor.execute("UPDATE bar SET foo = 1 WHERE baz = %s", [self.baz]) 7 8 cursor.execute("SELECT foo FROM bar WHERE baz = %s", [self.baz]) 9 row = cursor.fetchone() 10 11 return row
关于Connection和Cursor的具体用法,可以参见Python DB-API的内容。
———————————————————————————————————————————————————————————————————————————————————————————
12. 数据库事务(Database transactions)
处理网页事务的方法是将每个请求放入一个事务中,同时在数据库的配置(Configuration)中设置ATOMIC_REQUESTS为True。
当ATOMIC_REQUESTS激活时,可以使用non_atomic_requests来阻止某视图在事务中运行。比如:
1 from django.db import transaction 2 3 @transaction.non_atomic_requests 4 def my_view(request): 5 do_stuff() 6 7 @transaction.non_atomic_requests(using='other') 8 def my_other_view(request): 9 do_stuff_on_the_other_database()
可以使用atomic来将代码块设置为事务,如果事务运行成功则操作数据库,否则,会执行回滚。例如:
1 # as a decorator 2 3 from django.db import transaction 4 5 @transaction.atomic 6 def viewfunc(request): 7 # This code executes inside a transaction. 8 do_stuff() 9 10 # as a context manager 11 12 from django.db import transaction 13 14 def viewfunc(request): 15 # This code executes in autocommit mode (Django's default). 16 do_stuff() 17 18 with transaction.atomic(): 19 # This code executes inside a transaction. 20 do_more_stuff()
以下代码在部分代码出现错误时,也会执行事务操作:
1 from django.db import IntegrityError, transaction 2 3 @transaction.atomic 4 def viewfunc(request): 5 create_parent() 6 7 try: 8 with transaction.atomic(): 9 generate_relationships() 10 except IntegrityError: 11 handle_exception() 12 13 add_children()
事务以任意一种方式结束:commit或者rollback。
事务中savepoint的使用如下:
1 from django.db import transaction 2 3 # open a transaction 4 @transaction.atomic 5 def viewfunc(request): 6 7 a.save() 8 # transaction now contains a.save() 9 10 sid = transaction.savepoint() 11 12 b.save() 13 # transaction now contains a.save() and b.save() 14 15 if want_to_keep_b: 16 transaction.savepoint_commit(sid) 17 # open transaction still contains a.save() and b.save() 18 else: 19 transaction.savepoint_rollback(sid) 20 # open transaction now contains only a.save()
———————————————————————————————————————————————————————————————————————————————————————————
13. 多个数据库
在settings.py设置多个数据库:
1 DATABASES = { 2 'default': { 3 'NAME': 'app_data', 4 'ENGINE': 'django.db.backends.postgresql_psycopg2', 5 'USER': 'postgres_user', 6 'PASSWORD': 's3krit' 7 }, 8 'users': { 9 'NAME': 'user_data', 10 'ENGINE': 'django.db.backends.mysql', 11 'USER': 'mysql_user', 12 'PASSWORD': 'priv4te' 13 } 14 }
同步数据库:
1 $ ./manage.py migrate 2 $ ./manage.py migrate --database=users
数据库路由,假设有如下多个数据库:
1 DATABASES = { 2 'auth_db': { 3 'NAME': 'auth_db', 4 'ENGINE': 'django.db.backends.mysql', 5 'USER': 'mysql_user', 6 'PASSWORD': 'swordfish', 7 }, 8 'primary': { 9 'NAME': 'primary', 10 'ENGINE': 'django.db.backends.mysql', 11 'USER': 'mysql_user', 12 'PASSWORD': 'spam', 13 }, 14 'replica1': { 15 'NAME': 'replica1', 16 'ENGINE': 'django.db.backends.mysql', 17 'USER': 'mysql_user', 18 'PASSWORD': 'eggs', 19 }, 20 'replica2': { 21 'NAME': 'replica2', 22 'ENGINE': 'django.db.backends.mysql', 23 'USER': 'mysql_user', 24 'PASSWORD': 'bacon', 25 }, 26 }
路由的实现如下:
1 class AuthRouter(object): 2 """ 3 A router to control all database operations on models in the 4 auth application. 5 """ 6 def db_for_read(self, model, **hints): 7 """ 8 Attempts to read auth models go to auth_db. 9 """ 10 if model._meta.app_label == 'auth': 11 return 'auth_db' 12 return None 13 14 def db_for_write(self, model, **hints): 15 """ 16 Attempts to write auth models go to auth_db. 17 """ 18 if model._meta.app_label == 'auth': 19 return 'auth_db' 20 return None 21 22 def allow_relation(self, obj1, obj2, **hints): 23 """ 24 Allow relations if a model in the auth app is involved. 25 """ 26 if obj1._meta.app_label == 'auth' or \ 27 obj2._meta.app_label == 'auth': 28 return True 29 return None 30 31 def allow_migrate(self, db, app_label, model=None, **hints): 32 """ 33 Make sure the auth app only appears in the 'auth_db' 34 database. 35 """ 36 if app_label == 'auth': 37 return db == 'auth_db' 38 return None
1 import random 2 3 class PrimaryReplicaRouter(object): 4 def db_for_read(self, model, **hints): 5 """ 6 Reads go to a randomly-chosen replica. 7 """ 8 return random.choice(['replica1', 'replica2']) 9 10 def db_for_write(self, model, **hints): 11 """ 12 Writes always go to primary. 13 """ 14 return 'primary' 15 16 def allow_relation(self, obj1, obj2, **hints): 17 """ 18 Relations between objects are allowed if both objects are 19 in the primary/replica pool. 20 """ 21 db_list = ('primary', 'replica1', 'replica2') 22 if obj1._state.db in db_list and obj2._state.db in db_list: 23 return True 24 return None 25 26 def allow_migrate(self, db, app_label, model=None, **hints): 27 """ 28 All non-auth models end up in this pool. 29 """ 30 return True
最后设置:
1 DATABASE_ROUTERS = ['path.to.AuthRouter', 'path.to.PrimaryReplicaRouter']
此外,可以使用using属性手动操作Database。
———————————————————————————————————————————————————————————————————————————————————————————
14. 表空间(Tablespace)及数据库接入优化(Database access optimization)
使用表空间可以优化数据库运行。略过。
数据库接入优化。略过。
-- The End --